import { Injectable } from '@nestjs/common'; import { ExamsService } from '../../exams/exams.service'; import { AgentBusinessScopeFactory } from '../agent-business-scope.factory'; import type { AgentToolContext, ToolDef, ToolInputResult } from '../agent-tool.types'; import { optionalPositiveInt, optionalString, rejectUnknownKeys } from './tool-input'; interface Input { keyword?: string; examType?: string; classId?: number; limit?: number } @Injectable() export class SearchExamsTool implements ToolDef { readonly name = 'search_exams'; readonly skillKey = 'student'; readonly description = '查询当前用户有权查看的考试及成绩录入进度(考试名称、类型、日期、班级、应录/已录人数)。'; readonly requiredPermission = 'exam:view'; readonly inputSchema = { type: 'object', properties: { keyword: { type: 'string', maxLength: 100, description: '考试名称关键词' }, examType: { type: 'string', maxLength: 50, description: '考试类型' }, classId: { type: 'integer', minimum: 1, description: '班级ID' }, limit: { type: 'integer', minimum: 1, maximum: 50 }, }, additionalProperties: false, }; constructor( private readonly service: ExamsService, private readonly scopes: AgentBusinessScopeFactory, ) {} validate(raw: Record): ToolInputResult { const invalid = rejectUnknownKeys(raw, ['keyword', 'examType', 'classId', 'limit']); if (invalid) return invalid; const keyword = optionalString(raw.keyword, 'keyword', 100); if (!keyword.ok) return keyword; const examType = optionalString(raw.examType, 'examType', 50); if (!examType.ok) return examType; const classId = optionalPositiveInt(raw.classId, 'classId'); if (!classId.ok) return classId; const limit = optionalPositiveInt(raw.limit, 'limit', 50); if (!limit.ok) return limit; return { ok: true, value: { keyword: keyword.value, examType: examType.value, classId: classId.value, limit: limit.value }, }; } execute(input: Input, context: AgentToolContext) { return this.service.agentSearchExams( context.userId, this.scopes.canManageAllClasses(context), input, ); } }