fix(agents): resolve NestJS route collision for evaluation-rules endpoints
AdminConversationController's GET /:id was intercepting requests to AdminEvaluationRuleController (matching "evaluation-rules" as an id param). Similarly, DELETE /:id was matching "cache" as an id. Changes: - conversation.module.ts: Register AdminMcpController and AdminEvaluationRuleController before AdminConversationController (more specific prefixes must come first in NestJS) - admin-evaluation-rule.controller.ts: Move static routes (POST /test, DELETE /cache) before dynamic routes (GET/:id, DELETE/:id) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
51a7589fbf
commit
b75d607e2b
|
|
@ -7,6 +7,9 @@
|
|||
* 2. 开关规则
|
||||
* 3. 测试规则(dry-run)
|
||||
* 4. 清除规则缓存
|
||||
*
|
||||
* ⚠️ 路由顺序重要:静态路由(test, cache)必须在动态路由(:id)之前声明,
|
||||
* 否则 NestJS 会把 "test"/"cache" 当作 :id 参数匹配。
|
||||
*/
|
||||
|
||||
import {
|
||||
|
|
@ -71,6 +74,45 @@ export class AdminEvaluationRuleController {
|
|||
}
|
||||
}
|
||||
|
||||
// ─── 静态路由(必须在 :id 之前) ─────────────────────────
|
||||
|
||||
// POST /conversations/admin/evaluation-rules/test
|
||||
@Post('test')
|
||||
async testEvaluation(
|
||||
@Headers('authorization') auth: string,
|
||||
@Body() dto: TestEvaluationDto,
|
||||
) {
|
||||
const admin = this.verifyAdmin(auth);
|
||||
const tenantId = admin.tenantId || null;
|
||||
|
||||
if (!dto.stage || !dto.responseText) {
|
||||
throw new BadRequestException('stage and responseText are required');
|
||||
}
|
||||
|
||||
const result = await this.evaluationGate.evaluate(tenantId, {
|
||||
stage: dto.stage,
|
||||
collectedInfo: dto.collectedInfo || null,
|
||||
assessmentResult: dto.assessmentResult || null,
|
||||
responseText: dto.responseText,
|
||||
turnCount: dto.turnCount || 1,
|
||||
messageCount: dto.messageCount || 1,
|
||||
hasConverted: false,
|
||||
agentsUsed: [],
|
||||
});
|
||||
|
||||
return { success: true, data: result };
|
||||
}
|
||||
|
||||
// DELETE /conversations/admin/evaluation-rules/cache
|
||||
@Delete('cache')
|
||||
async clearCache(@Headers('authorization') auth: string) {
|
||||
this.verifyAdmin(auth);
|
||||
this.evaluationGate.clearCache();
|
||||
return { success: true, message: 'Cache cleared' };
|
||||
}
|
||||
|
||||
// ─── 集合路由 ──────────────────────────────────────────
|
||||
|
||||
// GET /conversations/admin/evaluation-rules
|
||||
@Get()
|
||||
async listRules(
|
||||
|
|
@ -97,22 +139,6 @@ export class AdminEvaluationRuleController {
|
|||
};
|
||||
}
|
||||
|
||||
// GET /conversations/admin/evaluation-rules/:id
|
||||
@Get(':id')
|
||||
async getRule(
|
||||
@Headers('authorization') auth: string,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
this.verifyAdmin(auth);
|
||||
|
||||
const rule = await this.repo.findById(id);
|
||||
if (!rule) {
|
||||
return { success: false, error: 'Rule not found' };
|
||||
}
|
||||
|
||||
return { success: true, data: this.toResponse(rule) };
|
||||
}
|
||||
|
||||
// POST /conversations/admin/evaluation-rules
|
||||
@Post()
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
|
|
@ -156,6 +182,24 @@ export class AdminEvaluationRuleController {
|
|||
return { success: true, data: this.toResponse(saved) };
|
||||
}
|
||||
|
||||
// ─── 动态路由(:id 在静态路由之后) ───────────────────────
|
||||
|
||||
// GET /conversations/admin/evaluation-rules/:id
|
||||
@Get(':id')
|
||||
async getRule(
|
||||
@Headers('authorization') auth: string,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
this.verifyAdmin(auth);
|
||||
|
||||
const rule = await this.repo.findById(id);
|
||||
if (!rule) {
|
||||
return { success: false, error: 'Rule not found' };
|
||||
}
|
||||
|
||||
return { success: true, data: this.toResponse(rule) };
|
||||
}
|
||||
|
||||
// PUT /conversations/admin/evaluation-rules/:id
|
||||
@Put(':id')
|
||||
async updateRule(
|
||||
|
|
@ -233,40 +277,7 @@ export class AdminEvaluationRuleController {
|
|||
return { success: true, data: this.toResponse(updated) };
|
||||
}
|
||||
|
||||
// POST /conversations/admin/evaluation-rules/test
|
||||
@Post('test')
|
||||
async testEvaluation(
|
||||
@Headers('authorization') auth: string,
|
||||
@Body() dto: TestEvaluationDto,
|
||||
) {
|
||||
const admin = this.verifyAdmin(auth);
|
||||
const tenantId = admin.tenantId || null;
|
||||
|
||||
if (!dto.stage || !dto.responseText) {
|
||||
throw new BadRequestException('stage and responseText are required');
|
||||
}
|
||||
|
||||
const result = await this.evaluationGate.evaluate(tenantId, {
|
||||
stage: dto.stage,
|
||||
collectedInfo: dto.collectedInfo || null,
|
||||
assessmentResult: dto.assessmentResult || null,
|
||||
responseText: dto.responseText,
|
||||
turnCount: dto.turnCount || 1,
|
||||
messageCount: dto.messageCount || 1,
|
||||
hasConverted: false,
|
||||
agentsUsed: [],
|
||||
});
|
||||
|
||||
return { success: true, data: result };
|
||||
}
|
||||
|
||||
// DELETE /conversations/admin/evaluation-rules/cache
|
||||
@Delete('cache')
|
||||
async clearCache(@Headers('authorization') auth: string) {
|
||||
this.verifyAdmin(auth);
|
||||
this.evaluationGate.clearCache();
|
||||
return { success: true, message: 'Cache cleared' };
|
||||
}
|
||||
// ─── 私有方法 ─────────────────────────────────────────
|
||||
|
||||
private toResponse(rule: EvaluationRuleEntity) {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { ConversationGateway } from '../adapters/inbound/conversation.gateway';
|
|||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([ConversationORM, MessageORM, TokenUsageORM, AgentExecutionORM])],
|
||||
controllers: [ConversationController, InternalConversationController, AdminConversationController, AdminMcpController, AdminEvaluationRuleController],
|
||||
controllers: [ConversationController, InternalConversationController, AdminMcpController, AdminEvaluationRuleController, AdminConversationController],
|
||||
providers: [
|
||||
ConversationService,
|
||||
ConversationGateway,
|
||||
|
|
|
|||
Loading…
Reference in New Issue