-
Notifications
You must be signed in to change notification settings - Fork 132
fix: moonshot reasoning_content on tool_calls #2022
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3755,34 +3755,20 @@ chat.openapi(completions, async (c) => { | |
| } | ||
| } | ||
|
|
||
| // For Moonshot provider, enrich assistant messages with cached reasoning_content | ||
| // This is needed for multi-turn tool call conversations with thinking models | ||
| // Moonshot requires reasoning_content in assistant messages with tool_calls | ||
| // Moonshot's thinking models reject assistant tool_call messages that lack | ||
| // reasoning_content. If the client echoes `reasoning` (OpenAI-style) we map | ||
| // it across; otherwise fall back to an empty string so multi-turn tool | ||
| // conversations don't 400. | ||
| if (usedProvider === "moonshot") { | ||
| const { redisClient } = await import("@llmgateway/cache"); | ||
| for (const message of messages) { | ||
| if ( | ||
| message.role === "assistant" && | ||
| message.tool_calls && | ||
| Array.isArray(message.tool_calls) && | ||
| message.tool_calls.length > 0 && | ||
| !(message as any).reasoning_content // Only add if not already present | ||
| !(message as any).reasoning_content | ||
| ) { | ||
| // Get reasoning_content from the first tool call (all tool calls share the same reasoning) | ||
| const firstToolCall = message.tool_calls[0]; | ||
| if (firstToolCall?.id) { | ||
| try { | ||
| const cachedReasoningContent = await redisClient.get( | ||
| `reasoning_content:${firstToolCall.id}`, | ||
| ); | ||
| if (cachedReasoningContent) { | ||
| // Add reasoning_content to the message for Moonshot | ||
| (message as any).reasoning_content = cachedReasoningContent; | ||
| } | ||
| } catch { | ||
| // Silently fail - reasoning_content caching is optional | ||
| } | ||
| } | ||
| (message as any).reasoning_content = (message as any).reasoning ?? ""; | ||
|
Comment on lines
+3816
to
+3818
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify whether BaseMessage (or adjacent message types) already define reasoning/reasoning_content
# so we can avoid local casting entirely.
rg -n -C3 --type=ts '\b(type|interface)\s+BaseMessage\b|reasoning_content|reasoning'Repository: theopenco/llmgateway Length of output: 50377 🏁 Script executed: #!/bin/bash
# Verify the exact code at lines 3758-3771 in apps/gateway/src/chat/chat.ts
sed -n '3758,3771p' apps/gateway/src/chat/chat.ts | cat -nRepository: theopenco/llmgateway Length of output: 760 Remove Lines 3769 and 3771 use 💡 Proposed fix if (usedProvider === "moonshot") {
+ type MoonshotAssistantMessage = BaseMessage & {
+ tool_calls?: unknown[];
+ reasoning?: string | null;
+ reasoning_content?: string;
+ };
for (const message of messages) {
+ const moonshotMessage = message as MoonshotAssistantMessage;
if (
- message.role === "assistant" &&
- message.tool_calls &&
- Array.isArray(message.tool_calls) &&
- message.tool_calls.length > 0 &&
- !(message as any).reasoning_content
+ moonshotMessage.role === "assistant" &&
+ moonshotMessage.tool_calls &&
+ Array.isArray(moonshotMessage.tool_calls) &&
+ moonshotMessage.tool_calls.length > 0 &&
+ moonshotMessage.reasoning_content == null
) {
- (message as any).reasoning_content = (message as any).reasoning ?? "";
+ moonshotMessage.reasoning_content = moonshotMessage.reasoning ?? "";
}
}
}🤖 Prompt for AI Agents |
||
| } | ||
|
Comment on lines
3812
to
3819
|
||
| } | ||
| } | ||
|
Comment on lines
+3805
to
3821
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The guard
!(message as any).reasoning_contenttreats an empty string as “missing”. Since this code can setreasoning_contentto "" intentionally, subsequent passes will still enter the block and may overwrite an explicit emptyreasoning_content(or redo work unnecessarily). Use an explicit undefined/null check (e.g.,message.reasoning_content == nullortypeof ... === "undefined") to mean “not present”.