fix: remove stream_options from xAI handler to fix Grok-4 API error

- Remove stream_options parameter from xAI streaming requests as the xAI API does not support it
- Add comment explaining why stream_options is not included
- Update tests to not expect stream_options in xAI API calls
- Add specific test case for Grok-4 streaming

Fixes #6702
This commit is contained in:
Roo Code 2025-08-05 08:50:54 +00:00
parent d90bab71ff
commit 9eb5925175
2 changed files with 37 additions and 6 deletions

View file

@ -276,8 +276,35 @@ describe("XAIHandler", () => {
temperature: 0,
messages: expect.arrayContaining([{ role: "system", content: systemPrompt }]),
stream: true,
stream_options: { include_usage: true },
// xAI API doesn't support stream_options
}),
)
})
it("should not include stream_options for Grok-4 model", async () => {
// Create handler with Grok-4 model
const grok4Handler = new XAIHandler({ apiModelId: "grok-4" })
// Setup mock for streaming response
mockCreate.mockImplementationOnce(() => {
return {
[Symbol.asyncIterator]: () => ({
async next() {
return { done: true }
},
}),
}
})
// Start generating a message
const messageGenerator = grok4Handler.createMessage("test prompt", [])
await messageGenerator.next()
// Verify that stream_options was NOT included
const calls = mockCreate.mock.calls
const lastCall = calls[calls.length - 1][0]
expect(lastCall).not.toHaveProperty("stream_options")
expect(lastCall.stream).toBe(true)
expect(lastCall.model).toBe("grok-4")
})
})

View file

@ -54,7 +54,7 @@ export class XAIHandler extends BaseProvider implements SingleCompletionHandler
temperature: this.options.modelTemperature ?? XAI_DEFAULT_TEMPERATURE,
messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)],
stream: true,
stream_options: { include_usage: true },
// xAI API doesn't support stream_options parameter
...(reasoning && reasoning),
})
@ -75,15 +75,19 @@ export class XAIHandler extends BaseProvider implements SingleCompletionHandler
}
}
// Note: xAI API doesn't support stream_options, so usage data might not be available in streaming responses
if (chunk.usage) {
// Extract detailed token information if available
// First check for prompt_tokens_details structure (real API response)
const promptDetails = "prompt_tokens_details" in chunk.usage ? chunk.usage.prompt_tokens_details : null;
const cachedTokens = promptDetails && "cached_tokens" in promptDetails ? promptDetails.cached_tokens : 0;
const promptDetails = "prompt_tokens_details" in chunk.usage ? chunk.usage.prompt_tokens_details : null
const cachedTokens = promptDetails && "cached_tokens" in promptDetails ? promptDetails.cached_tokens : 0
// Fall back to direct fields in usage (used in test mocks)
const readTokens = cachedTokens || ("cache_read_input_tokens" in chunk.usage ? (chunk.usage as any).cache_read_input_tokens : 0);
const writeTokens = "cache_creation_input_tokens" in chunk.usage ? (chunk.usage as any).cache_creation_input_tokens : 0;
const readTokens =
cachedTokens ||
("cache_read_input_tokens" in chunk.usage ? (chunk.usage as any).cache_read_input_tokens : 0)
const writeTokens =
"cache_creation_input_tokens" in chunk.usage ? (chunk.usage as any).cache_creation_input_tokens : 0
yield {
type: "usage",