Phase 3.2: Function Calling — tool_call loop for AI services

- llm/provider.go: extend ChatMessage with ToolCalls, ToolCallID, Name
  fields; add ToolCall + ToolCallFunction structs for parsing LLM
  function call responses
- tool_execution_service.go (new): ToolExecutionService that converts
  CaptainCustomTool → LLM ToolDefinition, executes HTTP tool calls
  (GET/POST/PUT with bearer/basic/api-key auth), and runs the full
  tool_call loop (LLM → tool_call → execute → result → LLM → final
  answer) with maxIterations safeguard
- captain_conversation_service.go: add toolExecSvc field +
  SetToolExecutionService method; use RunToolCallLoop in
  generateConversationResponse when tools are available, with graceful
  fallback to plain LLM call on error
- bootstrap.go: instantiate ToolExecutionService and inject into
  CaptainConversationService

Verified: go build + go vet + go test all pass
This commit is contained in:
2026-07-08 15:38:08 +08:00
parent c72e359e48
commit b2f36a20a0
4 changed files with 326 additions and 2 deletions
+4
View File
@@ -593,6 +593,10 @@ func Bootstrap(env string) (*App, error) {
copilotService.SetWorkerPool(workerPool)
captainConversationService := service.NewCaptainConversationService(db, llmProvider)
captainConversationService.SetWorkerPool(workerPool)
// Tool execution service — LLM function calling (tool_call loop)
toolExecutionService := service.NewToolExecutionService(captainCustomToolRepo, llmProvider)
captainConversationService.SetToolExecutionService(toolExecutionService)
copilotContextService := service.NewCopilotContextService(messageRepo, conversationRepo, contactRepo, llmProvider)
captainTaskService := service.NewCaptainTaskService(captainAssistantRepo, captainAssistantResponseRepo, captainCustomToolRepo, conversationRepo, messageRepo, llmProvider, copilotContextService, copilotSuggestionRepo)
conversationInsightService := service.NewConversationInsightService(conversationRepo, messageRepo, captainAssistantRepo, llmProvider)