diff --git a/internal/llm/provider/anthropic.go b/internal/llm/provider/anthropic.go index 4448cd79d52782e2ec8a2410e03aa6f59e6ed16c..3fffd6b35fe6ee8b6a765e2e5b815ad36a5b6a55 100644 --- a/internal/llm/provider/anthropic.go +++ b/internal/llm/provider/anthropic.go @@ -151,6 +151,9 @@ func (a *anthropicClient) convertMessages(messages []message.Message) (anthropic } for _, toolCall := range msg.ToolCalls() { + if !toolCall.Finished { + continue + } var inputMap map[string]any err := json.Unmarshal([]byte(toolCall.Input), &inputMap) if err != nil { diff --git a/internal/llm/provider/gemini.go b/internal/llm/provider/gemini.go index 21f4e65dfb400d449d3da050fe4c2436ffa66c0e..2e02bd088b57c9434d1d534204b664f3ef7443ed 100644 --- a/internal/llm/provider/gemini.go +++ b/internal/llm/provider/gemini.go @@ -81,6 +81,9 @@ func (g *geminiClient) convertMessages(messages []message.Message) []*genai.Cont if len(msg.ToolCalls()) > 0 { for _, call := range msg.ToolCalls() { + if !call.Finished { + continue + } args, _ := parseJSONToMap(call.Input) assistantParts = append(assistantParts, &genai.Part{ FunctionCall: &genai.FunctionCall{ diff --git a/internal/llm/provider/openai.go b/internal/llm/provider/openai.go index 4e88aea895120db101ae67ff95139fc28fdaf3a6..eb5a84867aecf0a76b30a7c022ccb14bf6a2139a 100644 --- a/internal/llm/provider/openai.go +++ b/internal/llm/provider/openai.go @@ -125,16 +125,25 @@ func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessag Role: "assistant", } + // Only include finished tool calls; interrupted tool calls must not be resent. if len(msg.ToolCalls()) > 0 { - assistantMsg.ToolCalls = make([]openai.ChatCompletionMessageToolCallParam, len(msg.ToolCalls())) - for i, call := range msg.ToolCalls() { - assistantMsg.ToolCalls[i] = openai.ChatCompletionMessageToolCallParam{ - ID: call.ID, - Type: "function", - Function: openai.ChatCompletionMessageToolCallFunctionParam{ - Name: call.Name, - Arguments: call.Input, - }, + finished := make([]message.ToolCall, 0, len(msg.ToolCalls())) + for _, call := range msg.ToolCalls() { + if call.Finished { + finished = append(finished, call) + } + } + if len(finished) > 0 { + assistantMsg.ToolCalls = make([]openai.ChatCompletionMessageToolCallParam, len(finished)) + for i, call := range finished { + assistantMsg.ToolCalls[i] = openai.ChatCompletionMessageToolCallParam{ + ID: call.ID, + Type: "function", + Function: openai.ChatCompletionMessageToolCallFunctionParam{ + Name: call.Name, + Arguments: call.Input, + }, + } } } } @@ -151,6 +160,11 @@ func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessag }, }) } + // Skip empty assistant messages (no content and no finished tool calls) + if msg.Content().String() == "" && len(assistantMsg.ToolCalls) == 0 { + continue + } + openaiMessages = append(openaiMessages, openai.ChatCompletionMessageParamUnion{ OfAssistant: &assistantMsg, })