feat: update providers and agent loop

This commit is contained in:
mxrain 2026-02-13 00:42:38 +08:00
parent 7e2050345f
commit 1d0e9b7b29
4 changed files with 80 additions and 23 deletions

View file

@ -380,6 +380,7 @@ func (al *AgentLoop) runLLMIteration(ctx context.Context, messages []providers.M
assistantMsg := providers.Message{
Role: "assistant",
Content: response.Content,
ThinkingContent: response.ThinkingContent,
}
for _, tc := range response.ToolCalls {
argumentsJSON, _ := json.Marshal(tc.Arguments)

View file

@ -77,6 +77,14 @@ func buildClaudeParams(messages []Message, tools []ToolDefinition, model string,
case "assistant":
if len(msg.ToolCalls) > 0 {
var blocks []anthropic.ContentBlockParamUnion
// Add thinking block if present (required for extended thinking mode)
if msg.ThinkingContent != "" {
blocks = append(blocks, anthropic.ContentBlockParamUnion{
OfThinking: &anthropic.ThinkingBlockParam{
Thinking: msg.ThinkingContent,
},
})
}
if msg.Content != "" {
blocks = append(blocks, anthropic.NewTextBlock(msg.Content))
}
@ -85,9 +93,16 @@ func buildClaudeParams(messages []Message, tools []ToolDefinition, model string,
}
anthropicMessages = append(anthropicMessages, anthropic.NewAssistantMessage(blocks...))
} else {
anthropicMessages = append(anthropicMessages,
anthropic.NewAssistantMessage(anthropic.NewTextBlock(msg.Content)),
)
var blocks []anthropic.ContentBlockParamUnion
if msg.ThinkingContent != "" {
blocks = append(blocks, anthropic.ContentBlockParamUnion{
OfThinking: &anthropic.ThinkingBlockParam{
Thinking: msg.ThinkingContent,
},
})
}
blocks = append(blocks, anthropic.NewTextBlock(msg.Content))
anthropicMessages = append(anthropicMessages, anthropic.NewAssistantMessage(blocks...))
}
case "tool":
anthropicMessages = append(anthropicMessages,
@ -150,10 +165,14 @@ func translateToolsForClaude(tools []ToolDefinition) []anthropic.ToolUnionParam
func parseClaudeResponse(resp *anthropic.Message) *LLMResponse {
var content string
var thinkingContent string
var toolCalls []ToolCall
for _, block := range resp.Content {
switch block.Type {
case "thinking":
tb := block.AsThinking()
thinkingContent += tb.Thinking
case "text":
tb := block.AsText()
content += tb.Text
@ -183,6 +202,7 @@ func parseClaudeResponse(resp *anthropic.Message) *LLMResponse {
return &LLMResponse{
Content: content,
ThinkingContent: thinkingContent,
ToolCalls: toolCalls,
FinishReason: finishReason,
Usage: &UsageInfo{

View file

@ -60,9 +60,41 @@ func (p *HTTPProvider) Chat(ctx context.Context, messages []Message, tools []Too
}
}
// Convert messages to API format, including reasoning_content for thinking models
apiMessages := make([]map[string]interface{}, 0, len(messages))
for _, msg := range messages {
apiMsg := map[string]interface{}{
"role": msg.Role,
"content": msg.Content,
}
// Include reasoning_content for assistant messages with thinking content
if msg.Role == "assistant" && msg.ThinkingContent != "" {
apiMsg["reasoning_content"] = msg.ThinkingContent
}
if len(msg.ToolCalls) > 0 {
toolCalls := make([]map[string]interface{}, 0, len(msg.ToolCalls))
for _, tc := range msg.ToolCalls {
argsJSON, _ := json.Marshal(tc.Arguments)
toolCalls = append(toolCalls, map[string]interface{}{
"id": tc.ID,
"type": "function",
"function": map[string]interface{}{
"name": tc.Name,
"arguments": string(argsJSON),
},
})
}
apiMsg["tool_calls"] = toolCalls
}
if msg.ToolCallID != "" {
apiMsg["tool_call_id"] = msg.ToolCallID
}
apiMessages = append(apiMessages, apiMsg)
}
requestBody := map[string]interface{}{
"model": model,
"messages": messages,
"messages": apiMessages,
}
if len(tools) > 0 {
@ -127,6 +159,7 @@ func (p *HTTPProvider) parseResponse(body []byte) (*LLMResponse, error) {
Choices []struct {
Message struct {
Content string `json:"content"`
ReasoningContent string `json:"reasoning_content"`
ToolCalls []struct {
ID string `json:"id"`
Type string `json:"type"`
@ -186,6 +219,7 @@ func (p *HTTPProvider) parseResponse(body []byte) (*LLMResponse, error) {
return &LLMResponse{
Content: choice.Message.Content,
ThinkingContent: choice.Message.ReasoningContent,
ToolCalls: toolCalls,
FinishReason: choice.FinishReason,
Usage: apiResponse.Usage,

View file

@ -20,6 +20,7 @@ type LLMResponse struct {
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
FinishReason string `json:"finish_reason"`
Usage *UsageInfo `json:"usage,omitempty"`
ThinkingContent string `json:"thinking_content,omitempty"` // For Claude extended thinking
}
type UsageInfo struct {
@ -33,6 +34,7 @@ type Message struct {
Content string `json:"content"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
ThinkingContent string `json:"thinking_content,omitempty"` // For Claude extended thinking
}
type LLMProvider interface {