fix(stream): inject stream_options.include_usage for OpenAI-compatible streaming - #3081
thatssoheil wants to merge 2 commits into
Conversation
Streaming requests to OpenAI-compatible providers (e.g. opencode combo -> deepseek-free) recorded IN 0 OUT 0 because the upstream never sent a usage chunk: the client's stream request lacked stream_options.include_usage. Ask for usage in the final chunk (same approach as the iflow executor) so usageHistory and the dashboard reflect real token counts for streams. Closes #3017
Cherry-picked from open upstream PRs (none merged upstream as of 2026-08-09): decolua#3078 /api/pxpipe -> LOCAL_ONLY_PATHS (defense in depth) decolua#3085 enforce requireApiKey on GET /v1/models decolua#3063 SSRF guard on search baseUrl + block default-password remote login decolua#3081 inject stream_options.include_usage for OpenAI-compatible upstreams decolua#3083 read cached_tokens from nested prompt_tokens_details Verified: no test regressions vs v0.5.50 baseline (88 pre-existing failures unchanged); +21 new passing tests.
29 PR upstream di-cherry-pick (semua masih open upstream per 2026-08-09). Rincian lengkap + link per PR ada di FORK-CHANGES.md. P1 skala 2475 koneksi : decolua#2798 decolua#410 decolua#2879 decolua#879 decolua#2997 P2 akurasi token/usage: decolua#2422 decolua#2658 decolua#2762 decolua#2453 decolua#2668 decolua#2361 P3 provider & combo : decolua#2526 decolua#3125 decolua#1434 decolua#2689 decolua#2439 decolua#2724 decolua#2647 decolua#1805 decolua#2909 decolua#2853 decolua#2508 decolua#2928 decolua#2345 decolua#2112 decolua#2786 P4 keamanan : decolua#1666 decolua#2776 Revert decolua#664: menambah transformRequest kedua di DefaultExecutor sehingga menimpa yang pertama dan mematikan stream_options/text.format/ injectReasoningContent/stripUnsupportedParams — termasuk PR decolua#3081 yang sudah dipakai produksi. Test: 88 gagal / 1783 lulus — nol regresi vs baseline v0.5.50 (88/1656).
Port of DurinDoor decolua#401: the generic stream_options.include_usage injection (from decolua#3081) leaked into Claude Messages requests, which reject the OpenAI-only field with 400 'stream_options: Extra inputs are not permitted'. Gate on the effective transport format being OpenAI (runtimeTransport.format, falling back to provider config), stripping the -apikey suffix.
The decolua#3081 injection added stream_options to the responses->chat translated body, but the translation doesn't carry the stream field. OpenAI-compatible upstreams (deepseek) reject with 'stream_options should be set along with stream = true'. Set stream:true since the executor streams upstream regardless.
|
heads up, on the responses to chat path the translated body has no stream field, so just injecting stream_options makes openai compatible upstreams (deepseek) 400 with "stream_options should be set along with stream = true". we set transformed.stream = true alongside the injection, probably worth doing here too so responses clients dont break. |
Review feedback (#3081): the executor-level stream flag can be true while the translated body omits stream (Responses->chat conversion, Accept: text/event-stream clients). Injecting stream_options into such a body makes strict OpenAI-compatible upstreams (deepseek) 400 with "stream_options should be set along with stream = true". Gate injection on the body's own stream === true, matching what the upstream actually receives.
|
Good catch, thanks. The executor-level Fixed in becd573: injection is now gated on |
What
Injects
stream_options: { include_usage: true }into upstream OpenAI-compatible requests when streaming, so usage chunks are actually returned by upstreams that require the opt-in (fixes streaming usage showing 0).Closes #3017