feat(llm): add LLM call support to worker IPC chain
- ProviderManager: align API with contracts ProviderAdapter - WorkerProtocol: add llm.request/llm.response message types - WorkerRuntime: add call_llm() for worker→parent→LLM flow - WorkerManager: support tool_registry and provider_manager injection P1-1 complete, P1-2 protocol layer complete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,20 @@ export interface ToolCallResult {
|
||||
content: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface LLMRequest {
|
||||
messages: Array<{ role: string; content: unknown }>
|
||||
model?: string
|
||||
max_tokens?: number
|
||||
temperature?: number
|
||||
tools?: unknown[]
|
||||
}
|
||||
|
||||
export interface LLMResponse {
|
||||
content: string
|
||||
usage?: { input_tokens: number; output_tokens: number }
|
||||
tool_calls?: Array<{ name: string; arguments: Record<string, unknown> }>
|
||||
}
|
||||
|
||||
export class WorkerRuntime {
|
||||
private agent_id: string
|
||||
private session_id: string
|
||||
@@ -63,6 +77,36 @@ export class WorkerRuntime {
|
||||
return promise
|
||||
}
|
||||
|
||||
/**
|
||||
* Call LLM through parent process via IPC.
|
||||
* INV-3: This is the ONLY way workers access LLM.
|
||||
*/
|
||||
async call_llm(request: LLMRequest): Promise<LLMResponse> {
|
||||
const call_id = crypto.randomUUID()
|
||||
|
||||
const promise = new Promise<LLMResponse>((resolve, reject) => {
|
||||
this.pending_calls.set(call_id, { resolve: resolve as any, reject })
|
||||
|
||||
// Set timeout (LLM calls can be long)
|
||||
setTimeout(() => {
|
||||
this.pending_calls.delete(call_id)
|
||||
reject(new Error(`LLM call timeout: ${request.model || 'default'}`))
|
||||
}, 300000) // 5 minutes
|
||||
})
|
||||
|
||||
// Send llm.request via IPC
|
||||
this.send_message('llm.request', {
|
||||
call_id,
|
||||
messages: request.messages,
|
||||
model: request.model || 'claude-haiku-4-5-20251001',
|
||||
max_tokens: request.max_tokens || 4096,
|
||||
temperature: request.temperature,
|
||||
tools: request.tools
|
||||
})
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit an event to the parent.
|
||||
*/
|
||||
@@ -118,6 +162,22 @@ export class WorkerRuntime {
|
||||
// Respond to ping
|
||||
this.send_message('worker.heartbeat', { timestamp: new Date().toISOString() })
|
||||
break
|
||||
|
||||
case 'llm.response': {
|
||||
const call_id = payload.call_id as string
|
||||
const pending = this.pending_calls.get(call_id)
|
||||
if (pending) {
|
||||
this.pending_calls.delete(call_id)
|
||||
// Resolve with LLM response
|
||||
const response: LLMResponse = {
|
||||
content: (payload.content as string) || '',
|
||||
usage: payload.usage as LLMResponse['usage'],
|
||||
tool_calls: payload.tool_calls as LLMResponse['tool_calls']
|
||||
}
|
||||
pending.resolve(response as any)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user