feat(M4-009,M4-010,M4-011): routing rules CRUD API, per-user overrides, agent capabilities
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/push/ci Pipeline failed

- Add routing.dto.ts with validation DTOs for create, update, and reorder operations
- Add routing.controller.ts with full CRUD: GET list, POST create, PATCH update,
  DELETE remove, PATCH reorder, GET effective (merged priority view)
- Users can only create/modify/delete their own user-scoped rules; system rules are
  protected with ForbiddenException
- GET /api/routing/rules/effective returns merged rule set with user rules taking
  precedence over system rules at the same priority level (M4-010)
- Extend agent-config.dto.ts with capability shorthand fields: domains, preferredModel,
  preferredProvider, toolSets (M4-011)
- Update agent-configs.controller.ts to merge capability fields into config.capabilities
  so agent's preferred model/provider can influence routing decisions
- Register RoutingController in agent.module.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 19:47:23 -05:00
parent 059962fe33
commit f22ce0096b
6 changed files with 590 additions and 10 deletions

View File

@@ -138,30 +138,56 @@ export class CommandExecutorService {
args: string | null,
conversationId: string,
): Promise<SlashCommandResultPayload> {
if (!args) {
if (!args || args.trim().length === 0) {
// Show current override or usage hint
const currentOverride = this.chatGateway?.getModelOverride(conversationId);
if (currentOverride) {
return {
command: 'model',
conversationId,
success: true,
message: `Current model override: "${currentOverride}". Use /model <name> to change or /model clear to reset.`,
};
}
return {
command: 'model',
conversationId,
success: true,
message: 'Usage: /model <model-name>',
message:
'Usage: /model <model-name> — sets a per-session model override (bypasses routing). Use /model clear to reset.',
};
}
// Update agent session model if session is active
// For now, acknowledge the request — full wiring done in P8-012
const modelName = args.trim();
// /model clear removes the override and re-enables automatic routing
if (modelName === 'clear') {
this.chatGateway?.setModelOverride(conversationId, null);
return {
command: 'model',
conversationId,
success: true,
message: 'Model override cleared. Automatic routing will be used for new sessions.',
};
}
// Set the sticky per-session override (M4-007)
this.chatGateway?.setModelOverride(conversationId, modelName);
const session = this.agentService.getSession(conversationId);
if (!session) {
return {
command: 'model',
conversationId,
success: true,
message: `Model switch to "${args}" requested. No active session for this conversation.`,
message: `Model override set to "${modelName}". Will apply when a new session starts for this conversation.`,
};
}
return {
command: 'model',
conversationId,
success: true,
message: `Model switch to "${args}" requested.`,
message: `Model override set to "${modelName}". The override is active for this conversation and will be used on the next message if a new session is needed.`,
};
}