@@ -125,16 +125,25 @@ func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessag
125 Role: "assistant",
125 Role: "assistant",
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() {
133+ finished = append(finished, call)
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,
@@ -151,6 +160,11 @@ func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessag
163+ // Skip empty assistant messages (no content and no finished tool calls)
164+ if msg.Content().String() == "" && len(assistantMsg.ToolCalls) == 0 {
154 openaiMessages = append(openaiMessages, openai.ChatCompletionMessageParamUnion{
168 openaiMessages = append(openaiMessages, openai.ChatCompletionMessageParamUnion{
155 OfAssistant: &assistantMsg,
169 OfAssistant: &assistantMsg,