mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 03:13:12 +00:00
Merge pull request #1574 from ReWiG/fix/stream-options-include-usage
fix(proxy): forward stream_options.include_usage to OpenAI-compatible upstreams
This commit is contained in:
2 files changed
+45
No files matched your search
@@ -101,6 +101,9 @@ interface OpenAIMessage {
|
||||
export interface ProxyOpenAIRequest {
|
||||
model?: string;
|
||||
stream: boolean;
|
||||
stream_options?: {
|
||||
include_usage: boolean;
|
||||
};
|
||||
reasoning_effort?: string;
|
||||
reasoning?: {
|
||||
enabled: boolean;
|
||||
@@ -728,6 +731,16 @@ export class ProxyRequestTransformer {
|
||||
? source.model.trim()
|
||||
: undefined,
|
||||
stream: source.stream === true,
|
||||
// Ask the upstream provider to emit a final SSE chunk with token usage.
|
||||
// OpenAI-compatible endpoints (and most proxies that follow the spec,
|
||||
// including LiteLLM) only include `usage` in the streamed response when
|
||||
// `stream_options.include_usage` is set on the request. Without this
|
||||
// flag the proxy's stream parser still writes Anthropic-shaped events
|
||||
// with `usage: { input_tokens: 0, output_tokens: 0 }`, so Claude Code's
|
||||
// status line and the session log show 0 tokens even though the call
|
||||
// was billed. See:
|
||||
// https://platform.openai.com/docs/api-reference/chat-streaming
|
||||
...(source.stream === true ? { stream_options: { include_usage: true } } : {}),
|
||||
messages: coalesceMessages(allMessages),
|
||||
max_tokens: asNumber(source.max_tokens),
|
||||
temperature: asNumber(source.temperature),
|
||||
|
||||
@@ -115,4 +115,36 @@ describe('ProxyRequestTransformer', () => {
|
||||
expect(result.stop).toEqual(['A']);
|
||||
expect(result.metadata).toBeUndefined();
|
||||
});
|
||||
|
||||
it('sets stream_options.include_usage for streaming requests so upstreams return token usage', () => {
|
||||
const transformer = new ProxyRequestTransformer();
|
||||
const result = transformer.transform({
|
||||
stream: true,
|
||||
messages: [{ role: 'user', content: 'ping' }],
|
||||
});
|
||||
|
||||
expect(result.stream).toBe(true);
|
||||
expect(result.stream_options).toEqual({ include_usage: true });
|
||||
});
|
||||
|
||||
it('omits stream_options for non-streaming requests', () => {
|
||||
const transformer = new ProxyRequestTransformer();
|
||||
const result = transformer.transform({
|
||||
stream: false,
|
||||
messages: [{ role: 'user', content: 'ping' }],
|
||||
});
|
||||
|
||||
expect(result.stream).toBe(false);
|
||||
expect(result.stream_options).toBeUndefined();
|
||||
});
|
||||
|
||||
it('omits stream_options when the upstream flag is absent', () => {
|
||||
const transformer = new ProxyRequestTransformer();
|
||||
const result = transformer.transform({
|
||||
messages: [{ role: 'user', content: 'ping' }],
|
||||
});
|
||||
|
||||
expect(result.stream).toBe(false);
|
||||
expect(result.stream_options).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user