(question string, writer io.Writer, history []*RawMessage, prompt string, knowledgeMessages []*RawMessage, toolSession *ToolSession, lang string)
| 65 | } |
| 66 | |
| 67 | func (p *OpenCodeProvider) QueryText(question string, writer io.Writer, history []*RawMessage, prompt string, knowledgeMessages []*RawMessage, toolSession *ToolSession, lang string) (*ModelResult, error) { |
| 68 | flusher, ok := writer.(http.Flusher) |
| 69 | if !ok { |
| 70 | return nil, fmt.Errorf(i18n.Translate(lang, "model:writer does not implement http.Flusher")) |
| 71 | } |
| 72 | |
| 73 | if strings.HasPrefix(question, "$OpenAgentDryRun$") { |
| 74 | return &ModelResult{}, nil |
| 75 | } |
| 76 | |
| 77 | // NOTE: OpenCode is a self-contained agent that executes tools internally |
| 78 | // on the server side. It does not expose a "function calling" API where |
| 79 | // the LLM returns tool calls for the client to execute. This means |
| 80 | // OpenAgent's MCP tools cannot be mapped to OpenCode's execution model. |
| 81 | // When toolSession is non-nil, tools are silently unavailable and the |
| 82 | // LLM will produce a text-only response. |
| 83 | _ = toolSession |
| 84 | |
| 85 | sessionID, err := p.createSession() |
| 86 | if err != nil { |
| 87 | return nil, fmt.Errorf("OpenCode: failed to create session at %s: %v.\n\nMake sure 'opencode serve' is running. You can change the server URL in provider settings.", p.serverUrl, err) |
| 88 | } |
| 89 | defer p.deleteSession(sessionID) |
| 90 | |
| 91 | var messageText strings.Builder |
| 92 | for _, msg := range history { |
| 93 | if msg.Text == "" { |
| 94 | continue |
| 95 | } |
| 96 | switch msg.Author { |
| 97 | case "AI": |
| 98 | messageText.WriteString("Assistant: ") |
| 99 | case "User": |
| 100 | messageText.WriteString("User: ") |
| 101 | } |
| 102 | messageText.WriteString(msg.Text) |
| 103 | messageText.WriteString("\n") |
| 104 | } |
| 105 | if len(knowledgeMessages) > 0 { |
| 106 | messageText.WriteString("\n--- Context ---\n") |
| 107 | for _, msg := range knowledgeMessages { |
| 108 | messageText.WriteString(msg.Text) |
| 109 | messageText.WriteString("\n") |
| 110 | } |
| 111 | messageText.WriteString("--- End Context ---\n\n") |
| 112 | } |
| 113 | messageText.WriteString(question) |
| 114 | |
| 115 | // Shared context so SSE goroutine can be cancelled if sendMessageAsync fails |
| 116 | ctx, cancel := context.WithCancel(context.Background()) |
| 117 | defer cancel() |
| 118 | |
| 119 | type sseResult struct { |
| 120 | result *ModelResult |
| 121 | err error |
| 122 | } |
| 123 | resultCh := make(chan sseResult, 1) |
| 124 | readyCh := make(chan struct{}) |
nothing calls this directly
no test coverage detected