refactor(api): split monolithic handlers.go into focused modules
All checks were successful
Beta Release / beta (push) Successful in 44s
All checks were successful
Beta Release / beta (push) Successful in 44s
Break down the 627-line handlers.go into specialized modules: - handlers_chat.go: chat and streaming endpoints - handlers_config.go: configuration endpoints - handlers_common.go: shared utilities - handlers_info.go: info and status endpoints - handlers_terminal.go: terminal/shell endpoints - handlers_tools.go: tool-related endpoints Also includes config improvements, orchestrator enhancements, and web component updates. 💘 Generated with Crush Assisted-by: MiniMax-M2.7 via Crush <crush@charm.land>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package orchestrator
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -34,6 +35,9 @@ type ChatResponse struct {
|
||||
Message struct {
|
||||
Content string `json:"content"`
|
||||
} `json:"message"`
|
||||
Delta struct {
|
||||
Content string `json:"content"`
|
||||
} `json:"delta"`
|
||||
} `json:"choices"`
|
||||
Usage struct {
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
@@ -161,6 +165,104 @@ func (o *Orchestrator) Send(userMessage string) (string, error) {
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func (o *Orchestrator) SendStream(userMessage string, onChunk func(string)) (string, error) {
|
||||
o.histMu.Lock()
|
||||
o.history = append(o.history, Message{
|
||||
Role: "user",
|
||||
Content: userMessage,
|
||||
})
|
||||
|
||||
if len(o.history) > maxHistorySize {
|
||||
o.history = o.history[len(o.history)-maxHistorySize:]
|
||||
}
|
||||
|
||||
messages := make([]Message, 0, len(o.history)+1)
|
||||
if o.systemPrompt != "" {
|
||||
messages = append(messages, Message{Role: "system", Content: o.systemPrompt})
|
||||
}
|
||||
messages = append(messages, o.history...)
|
||||
|
||||
reqBody := ChatRequest{
|
||||
Model: o.provider.Model,
|
||||
Messages: messages,
|
||||
Stream: true,
|
||||
}
|
||||
o.histMu.Unlock()
|
||||
|
||||
body, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal request: %w", err)
|
||||
}
|
||||
|
||||
baseURL := o.provider.BaseURL
|
||||
if baseURL == "" {
|
||||
baseURL = getProviderBaseURL(o.provider.Name)
|
||||
}
|
||||
|
||||
url := strings.TrimRight(baseURL, "/") + "/chat/completions"
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+o.provider.APIKey)
|
||||
|
||||
resp, err := o.client.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("send request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
return "", fmt.Errorf("API error (%d): %s", resp.StatusCode, string(respBody))
|
||||
}
|
||||
|
||||
var fullContent strings.Builder
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.HasPrefix(line, "data: ") {
|
||||
continue
|
||||
}
|
||||
data := strings.TrimPrefix(line, "data: ")
|
||||
if data == "[DONE]" {
|
||||
break
|
||||
}
|
||||
|
||||
var chatResp ChatResponse
|
||||
if err := json.Unmarshal([]byte(data), &chatResp); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(chatResp.Choices) > 0 {
|
||||
chunk := chatResp.Choices[0].Delta.Content
|
||||
if chunk != "" {
|
||||
fullContent.WriteString(chunk)
|
||||
onChunk(chunk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return fullContent.String(), fmt.Errorf("read stream: %w", err)
|
||||
}
|
||||
|
||||
content := cleanAIResponse(fullContent.String())
|
||||
o.histMu.Lock()
|
||||
o.history = append(o.history, Message{
|
||||
Role: "assistant",
|
||||
Content: content,
|
||||
})
|
||||
o.histMu.Unlock()
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func cleanAIResponse(content string) string {
|
||||
content = thinkRegex.ReplaceAllString(content, "")
|
||||
lines := strings.Split(content, "\n")
|
||||
|
||||
Reference in New Issue
Block a user