on main help sign in
fix: tool calls break the converation if interrupted.
e76fd54Manolo Santos
internal/llm/provider/anthropic.go+3
@@ -151,6 +151,9 @@ func (a *anthropicClient) convertMessages(messages []message.Message) (anthropic
151 }
151 }
152
152
153 for _, toolCall := range msg.ToolCalls() {
153 for _, toolCall := range msg.ToolCalls() {
154+ if !toolCall.Finished {
155+ continue
156+ }
154 var inputMap map[string]any
157 var inputMap map[string]any
155 err := json.Unmarshal([]byte(toolCall.Input), &inputMap)
158 err := json.Unmarshal([]byte(toolCall.Input), &inputMap)
156 if err != nil {
159 if err != nil {
internal/llm/provider/gemini.go+3
@@ -81,6 +81,9 @@ func (g *geminiClient) convertMessages(messages []message.Message) []*genai.Cont
81
81
82 if len(msg.ToolCalls()) > 0 {
82 if len(msg.ToolCalls()) > 0 {
83 for _, call := range msg.ToolCalls() {
83 for _, call := range msg.ToolCalls() {
84+ if !call.Finished {
85+ continue
86+ }
84 args, _ := parseJSONToMap(call.Input)
87 args, _ := parseJSONToMap(call.Input)
85 assistantParts = append(assistantParts, &genai.Part{
88 assistantParts = append(assistantParts, &genai.Part{
86 FunctionCall: &genai.FunctionCall{
89 FunctionCall: &genai.FunctionCall{
internal/llm/provider/openai.go+23−9
@@ -125,16 +125,25 @@ func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessag
125 Role: "assistant",
125 Role: "assistant",
126 }
126 }
127
127
128+ // Only include finished tool calls; interrupted tool calls must not be resent.
128 if len(msg.ToolCalls()) > 0 {
129 if len(msg.ToolCalls()) > 0 {
129− assistantMsg.ToolCalls = make([]openai.ChatCompletionMessageToolCallParam, len(msg.ToolCalls()))
130+ finished := make([]message.ToolCall, 0, len(msg.ToolCalls()))
130− for i, call := range msg.ToolCalls() {
131+ for _, call := range msg.ToolCalls() {
132+ if call.Finished {
133+ finished = append(finished, call)
134+ }
135+ }
136+ if len(finished) > 0 {
137+ assistantMsg.ToolCalls = make([]openai.ChatCompletionMessageToolCallParam, len(finished))
138+ for i, call := range finished {
131− assistantMsg.ToolCalls[i] = openai.ChatCompletionMessageToolCallParam{
139+ assistantMsg.ToolCalls[i] = openai.ChatCompletionMessageToolCallParam{
132− ID: call.ID,
140+ ID: call.ID,
133− Type: "function",
141+ Type: "function",
134− Function: openai.ChatCompletionMessageToolCallFunctionParam{
142+ Function: openai.ChatCompletionMessageToolCallFunctionParam{
135− Name: call.Name,
143+ Name: call.Name,
136− Arguments: call.Input,
144+ Arguments: call.Input,
137− },
145+ },
146+ }
138 }
147 }
139 }
148 }
140 }
149 }
@@ -151,6 +160,11 @@ func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessag
151 },
160 },
152 })
161 })
153 }
162 }
163+ // Skip empty assistant messages (no content and no finished tool calls)
164+ if msg.Content().String() == "" && len(assistantMsg.ToolCalls) == 0 {
165+ continue
166+ }
167+
154 openaiMessages = append(openaiMessages, openai.ChatCompletionMessageParamUnion{
168 openaiMessages = append(openaiMessages, openai.ChatCompletionMessageParamUnion{
155 OfAssistant: &assistantMsg,
169 OfAssistant: &assistantMsg,
156 })
170 })