fix: preserve tool result follow-up text
This commit is contained in:
parent
6e004b8eff
commit
1ecb921068
2 changed files with 44 additions and 1 deletions
|
|
@ -534,6 +534,13 @@ func cachedReasoningContent(calls []OAIToolCall) string {
|
|||
return reasoning
|
||||
}
|
||||
}
|
||||
if len(calls) > 0 {
|
||||
// Moonshot/Kimi rejects follow-up assistant tool-call messages when
|
||||
// thinking is enabled unless reasoning_content is present. Some
|
||||
// OpenAI-compatible streams omit reasoning_content on the initial tool
|
||||
// call, so provide a minimal placeholder for replayed tool-call history.
|
||||
return "Tool call requested."
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
|
@ -615,7 +622,14 @@ func contentToOpenAI(m AMessage) []OAIMessage {
|
|||
return []OAIMessage{msg}
|
||||
}
|
||||
if len(toolMsgs) > 0 {
|
||||
return toolMsgs
|
||||
out := append([]OAIMessage{}, toolMsgs...)
|
||||
if userText := strings.TrimSpace(text.String()); userText != "" {
|
||||
// Anthropic can send a user's next text in the same content array as
|
||||
// tool_result blocks. Preserve that text as the next user message;
|
||||
// dropping it makes the model answer the previous tool result again.
|
||||
out = append(out, OAIMessage{Role: m.Role, Content: userText})
|
||||
}
|
||||
return out
|
||||
}
|
||||
return []OAIMessage{{Role: m.Role, Content: text.String()}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,11 +112,40 @@ func TestResponsesInputFunctionCallUsesCallID(t *testing.T) {
|
|||
if messages[0].ToolCalls[0].ID != "call_123" {
|
||||
t.Fatalf("tool call ID should match call_id for follow-up tool output: %+v", messages[0].ToolCalls[0])
|
||||
}
|
||||
if messages[0].ReasoningContent == "" {
|
||||
t.Fatalf("assistant tool call history should include fallback reasoning_content: %+v", messages[0])
|
||||
}
|
||||
if messages[1].ToolCallID != "call_123" {
|
||||
t.Fatalf("bad tool output ID: %+v", messages[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnthropicToolUseHistoryIncludesFallbackReasoning(t *testing.T) {
|
||||
messages := contentToOpenAI(AMessage{Role: "assistant", Content: []byte(`[{"type":"tool_use","id":"call_123","name":"Bash","input":{"command":"pwd"}}]`)})
|
||||
if len(messages) != 1 {
|
||||
t.Fatalf("got %d messages", len(messages))
|
||||
}
|
||||
if messages[0].Role != "assistant" || len(messages[0].ToolCalls) != 1 {
|
||||
t.Fatalf("bad tool call conversion: %+v", messages[0])
|
||||
}
|
||||
if messages[0].ReasoningContent == "" {
|
||||
t.Fatalf("assistant tool call history should include fallback reasoning_content: %+v", messages[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnthropicToolResultPreservesFollowingUserText(t *testing.T) {
|
||||
messages := contentToOpenAI(AMessage{Role: "user", Content: []byte(`[{"type":"tool_result","tool_use_id":"call_123","content":"09:33:16"},{"type":"text","text":"https://figma.example/design what's going on here?"}]`)})
|
||||
if len(messages) != 2 {
|
||||
t.Fatalf("got %d messages: %+v", len(messages), messages)
|
||||
}
|
||||
if messages[0].Role != "tool" || messages[0].ToolCallID != "call_123" || messages[0].Content != "09:33:16" {
|
||||
t.Fatalf("bad tool result conversion: %+v", messages[0])
|
||||
}
|
||||
if messages[1].Role != "user" || !strings.Contains(messages[1].Content, "figma.example") {
|
||||
t.Fatalf("following user text was not preserved: %+v", messages[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestStreamAnthropicForwardsToolCalls(t *testing.T) {
|
||||
reasoningContentCache.Lock()
|
||||
reasoningContentCache.byCallID = map[string]string{}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue