e7ebf51e50
## Overview This PR replaces the dynamic agent handoff system with a more predictable planning-based router that decides upfront how to handle multi-agent coordination. ## Major Changes ### 🔄 Architecture Shift: Handoffs → Planning **Removed:** - `AgentHandoffEntity` and handoff tracking system - `AgentHandoffService` and `AgentHandoffExecutorService` - Dynamic agent-to-agent transfers during execution - Handoff tool generation and description templates **Added:** - `AiRouterService` with two strategies: `simple` (single agent) and `planned` (multi-agent) - `AgentPlanExecutorService` for executing multi-step plans - Plan validation (cycle detection, dependency resolution) - `UnifiedRouterResult` type with discriminated union ### 🤖 New Standard Agents Added two new specialized agents: - **Researcher Agent**: Web search, fact-finding, competitive intelligence - **Code Agent**: TypeScript function generation for serverless workflows ### 🏗️ Router Refactoring (Latest) Split router responsibilities into focused services: - `AiRouterStrategyDeciderService`: Decides simple vs planned strategy - `AiRouterPlanGeneratorService`: Generates and validates execution plans - `AiRouterService`: Coordinates between services (reduced from 426→275 lines) ### ⚙️ Configuration Improvements - Added `outputStrategy` to agent definitions (`direct` vs `synthesize`) - Removed hardcoded special cases for workflow-builder - Added `plannerModel` field to workspace entity - Increased `MAX_STEPS` from 10 to 25 for complex workflows ### 📝 Agent Prompt Refinements Significantly simplified prompts for better clarity: - Workflow Builder: 51→36 lines - Helper: 49→28 lines - Data Manipulator: Enhanced with sorting guidance ### 🔍 Enhanced Debugging - Plan reasoning and step count in data message parts - Router debug info with token usage tracking - Better logging throughout execution pipeline ## Benefits 1. **Simpler Mental Model**: Router decides upfront vs dynamic transfers 2. **Better Predictability**: Users see the plan before execution 3. **Cleaner Architecture**: SRP with focused services 4. **Configuration Over Code**: Agent behavior via config, not hardcoded logic 5. **Plan Validation**: Catches invalid dependencies and cycles ## Migration Notes - Database migration removes `agentHandoff` table - Adds `plannerModel` column to workspace table - No API breaking changes (agent endpoints unchanged) ## Testing - Integration tests updated to remove handoff dependencies - Agent tool test utilities simplified - Plan validation covered by new logic ## Next Steps (Future PRs) - Parallel execution of independent plan steps - Dynamic re-planning based on results - Plan caching for common routing patterns - Error recovery strategies in plan executor
58 lines
2.2 KiB
TypeScript
58 lines
2.2 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Post,
|
|
Res,
|
|
UseFilters,
|
|
UseGuards,
|
|
} from '@nestjs/common';
|
|
|
|
import { UIDataTypes, UIMessage, UITools } from 'ai';
|
|
import { Response } from 'express';
|
|
|
|
import { RestApiExceptionFilter } from 'src/engine/api/rest/rest-api-exception.filter';
|
|
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
|
import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator';
|
|
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
|
import { JwtAuthGuard } from 'src/engine/guards/jwt-auth.guard';
|
|
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
|
|
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
|
import { type RecordIdsByObjectMetadataNameSingularType } from 'src/engine/metadata-modules/ai-agent/types/recordIdsByObjectMetadataNameSingular.type';
|
|
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
|
|
import { AgentChatService } from 'src/engine/metadata-modules/ai-chat/services/agent-chat.service';
|
|
import { AgentStreamingService } from 'src/engine/metadata-modules/ai-chat/services/agent-streaming.service';
|
|
|
|
@Controller('rest/agent-chat')
|
|
@UseGuards(JwtAuthGuard, WorkspaceAuthGuard)
|
|
@UseFilters(RestApiExceptionFilter)
|
|
export class AgentChatController {
|
|
constructor(
|
|
private readonly agentChatService: AgentChatService,
|
|
private readonly agentStreamingService: AgentStreamingService,
|
|
) {}
|
|
|
|
@Post('stream')
|
|
@UseGuards(SettingsPermissionGuard(PermissionFlagType.AI))
|
|
async streamAgentChat(
|
|
@Body()
|
|
body: {
|
|
threadId: string;
|
|
messages: UIMessage<unknown, UIDataTypes, UITools>[];
|
|
recordIdsByObjectMetadataNameSingular?: RecordIdsByObjectMetadataNameSingularType;
|
|
},
|
|
@AuthUserWorkspaceId() userWorkspaceId: string,
|
|
@AuthWorkspace() workspace: WorkspaceEntity,
|
|
@Res() response: Response,
|
|
) {
|
|
this.agentStreamingService.streamAgentChat({
|
|
threadId: body.threadId,
|
|
messages: body.messages,
|
|
userWorkspaceId,
|
|
workspace,
|
|
recordIdsByObjectMetadataNameSingular:
|
|
body.recordIdsByObjectMetadataNameSingular || [],
|
|
response,
|
|
});
|
|
}
|
|
}
|