diff --git a/packages/runtime/src/agents/main/MainAgent.ts b/packages/runtime/src/agents/main/MainAgent.ts index 953c686..6742152 100755 --- a/packages/runtime/src/agents/main/MainAgent.ts +++ b/packages/runtime/src/agents/main/MainAgent.ts @@ -27,17 +27,25 @@ export type MainAgentState = | 'ERROR' | 'TERMINATED' +export type ClassifyMode = 'regex' | 'llm' + export interface MainAgentConfig { session_id: SessionID project_id: ProjectID + classify_mode?: ClassifyMode // Alpha default: 'regex'; GA target: 'llm' + provider_manager?: any // ProviderManager for LLM-based classify (GA) } export class MainAgent { private config: MainAgentConfig + private classify_mode: ClassifyMode + private provider_manager?: any state: MainAgentState = 'IDLE' constructor(config: MainAgentConfig) { this.config = config + this.classify_mode = config.classify_mode || 'regex' + this.provider_manager = config.provider_manager } /** @@ -49,9 +57,9 @@ export class MainAgent { tasks?: string[] response?: string }> { - // Classify intent + // Classify intent (passes through a Promise.resolve for regex mode) this.state = 'CLASSIFYING' - const classification = this.classify(message) + const classification = await Promise.resolve(this.classify(message)) switch (classification) { case 'simple_question': @@ -76,15 +84,27 @@ export class MainAgent { /** * Classify user message intent. + * - regex mode: pattern matching (Alpha scope, deterministic, synchronous) + * - llm mode: calls ProviderManager for LLM-based classification (GA target, async) */ - private classify(message: string): string { + classify(message: string): string | Promise { + if (this.classify_mode === 'llm' && this.provider_manager) { + return this.classify_via_llm(message) + } + return this.classify_regex(message) + } + + /** + * Regex-based intent classification (Alpha scope, 5 patterns). + */ + private classify_regex(message: string): string { const lower = message.toLowerCase() if (/^(what|how|why|when|where|who|can you|could you|explain)/.test(lower)) { return 'simple_question' } - if (/^(implement|create|build|write|add|fix|change|update|remove|delete|refactor)/.test(lower)) { + if (/^(\/direct|\/done|implement|create|build|write|add|fix|change|update|remove|delete|refactor)/.test(lower)) { return 'implementation_request' } @@ -95,6 +115,32 @@ export class MainAgent { return 'simple_question' } + /** + * LLM-based intent classification (GA target). + * Calls ProviderManager→Adapter→LLM to classify intent into the state machine route. + * TODO(GA): Implement by sending a classification prompt to the configured model. + */ + private async classify_via_llm(message: string): Promise { + const classification_prompt = [ + 'Classify this user message into one of:', + ' simple_question | implementation_request | direct_command', + '', + `Message: "${message}"`, + '', + 'Respond with ONLY the classification string, no other text.', + ].join('\n') + + try { + // GA: const result = await this.provider_manager.complete(classification_prompt, ...) + // GA: return parse_classification(result.content) + // For now, fall through to regex as a safety net + console.warn('[MainAgent] LLM classify not yet wired (GA); falling back to regex') + return this.classify_regex(message) + } catch { + return this.classify_regex(message) + } + } + /** * Handle confirmation from user. */ diff --git a/packages/runtime/src/workers/WorkerProtocol.ts b/packages/runtime/src/workers/WorkerProtocol.ts index 5a2c815..155f7a6 100755 --- a/packages/runtime/src/workers/WorkerProtocol.ts +++ b/packages/runtime/src/workers/WorkerProtocol.ts @@ -10,8 +10,13 @@ export type WorkerMessageDirection = 'parent_to_worker' | 'worker_to_parent' export interface WorkerMessage { id: string - type: string + kind: string // IpcKind: control|event|log|tool.call|tool.result|tool.stream|worker.result|worker.checkpoint|protocol.error + type: string // kept for backward compat (alias for kind) direction: WorkerMessageDirection + session_id: string + agent_id: string + correlation_id?: string + protocol_version?: number timestamp: string payload: Record } @@ -85,12 +90,18 @@ export class WorkerProtocol { /** * Create a new message with auto-generated ID and timestamp. + * kind derived from type (IpcKind), session_id/agent_id from payload or default. */ - create_message(type: WorkerMessageType, payload: Record, direction: WorkerMessageDirection): WorkerMessage { + create_message(type: WorkerMessageType, payload: Record, direction: WorkerMessageDirection, opts?: { session_id?: string; agent_id?: string; correlation_id?: string }): WorkerMessage { return { id: crypto.randomUUID(), + kind: type, // kind aliases type per contracts §10 IpcKind type, direction, + session_id: opts?.session_id || (payload.session_id as string) || '', + agent_id: opts?.agent_id || (payload.agent_id as string) || '', + correlation_id: opts?.correlation_id, + protocol_version: PROTOCOL_VERSION, timestamp: new Date().toISOString(), payload } diff --git a/packages/runtime/test/regression/main-agent-states.test.ts b/packages/runtime/test/regression/main-agent-states.test.ts index c0bafa7..c82eb15 100755 --- a/packages/runtime/test/regression/main-agent-states.test.ts +++ b/packages/runtime/test/regression/main-agent-states.test.ts @@ -59,11 +59,16 @@ describe('C2: MainAgent states audit', () => { expect(classifying_idx).toBeLessThan(classify_call_idx) }) - it('classify still uses regex (Alpha scope)', () => { - // Verify the classify method uses regex patterns - expect(source).toContain('/^(what|how|why|when|where|who') - expect(source).toContain('/^(implement|create|build|write|add|fix') - expect(source).toContain('/^(run|execute|test|debug|check|inspect') + it('classify uses regex fallback + LLM framework (B13 fixed)', () => { + // Verify classify_regex method exists with patterns + expect(source).toContain('classify_regex') + // Verify the three regex patterns (with /direct /done added for B13) + expect(source).toContain('what|how|why|when|where|who') + expect(source).toContain('implement|create|build|write|add|fix') + expect(source).toContain('run|execute|test|debug|check|inspect') + // Verify LLM classify framework exists (GA target) + expect(source).toContain('classify_via_llm') + expect(source).toContain("classify_mode === 'llm'") }) it('transition methods exist', () => { diff --git a/packages/workers/src/WorkerRuntime.ts b/packages/workers/src/WorkerRuntime.ts index 4a0947a..e7902fe 100755 --- a/packages/workers/src/WorkerRuntime.ts +++ b/packages/workers/src/WorkerRuntime.ts @@ -147,8 +147,12 @@ export class WorkerRuntime { private send_message(type: string, payload: Record): void { const msg = { id: crypto.randomUUID(), + kind: type, // IpcKind per contracts §10 type, direction: 'worker_to_parent', + session_id: this.session_id, + agent_id: this.agent_id, + protocol_version: 1, timestamp: new Date().toISOString(), payload }