Summary
LLMClient.call_model_stream_raw in fipsagents.baseagent.llm does not set stream_options={\"include_usage\": True} when issuing streaming chat completions. vLLM (and other OpenAI-compat servers) only emit a usage chunk on streaming responses when this flag is explicitly opted into. Without the flag, StreamMetrics.prompt_tokens / completion_tokens stay None for the entire stream, and OpenAIChatServer._persist_cost_data (added in #117 / #116) returns early — meaning cost tracking is a no-op in real deployments.
The unit tests in tests/test_server_openai.py synthesise StreamMetrics with populated prompt_tokens / completion_tokens, so they exercise the persistence path correctly but bypass the gap in the LLM client.
Reproduction
Cluster smoke against fipsagents 0.14.0 + fipsagents-platform 0.2.0, gpt-oss-20b on RHPDS:
- POST two
/v1/chat/completions with the same session_id.
- Both calls return content correctly; the response's
usage block is {prompt_tokens: null, completion_tokens: null, total_tokens: null}.
- Inspect the platform's session row:
messages populated (204 bytes), cost_data empty {}.
Direct curl against the same vLLM endpoint with stream_options.include_usage=true confirms the model happily emits a final usage chunk: {prompt_tokens:70, total_tokens:75, completion_tokens:5, prompt_tokens_details:{cached_tokens:64}}. The endpoint isn't broken — the client never asks.
Fix
In LLMClient.call_model_stream_raw, after call_kwargs[\"stream\"] = True:
call_kwargs.setdefault(\"stream_options\", {\"include_usage\": True})
setdefault so callers can opt out by passing stream_options={\"include_usage\": False} (or pass other stream options).
Tests
- Regression: assert
_client.chat.completions.create is called with stream_options={\"include_usage\": True} when streaming. Mock the OpenAI client; check the kwargs.
- E2E coverage already exists for the persistence path; once the flag is forwarded, the existing usage-driven tests prove the loop closes.
Impact
- Affects every fipsagents 0.14.0 deployment that depends on
cost_data accumulation.
- No data loss — sessions persistence is unaffected; only the cost accumulator is empty.
- Patch-level fix: cut 0.14.1.
Related
Summary
LLMClient.call_model_stream_rawinfipsagents.baseagent.llmdoes not setstream_options={\"include_usage\": True}when issuing streaming chat completions. vLLM (and other OpenAI-compat servers) only emit a usage chunk on streaming responses when this flag is explicitly opted into. Without the flag,StreamMetrics.prompt_tokens/completion_tokensstayNonefor the entire stream, andOpenAIChatServer._persist_cost_data(added in #117 / #116) returns early — meaning cost tracking is a no-op in real deployments.The unit tests in
tests/test_server_openai.pysynthesiseStreamMetricswith populatedprompt_tokens/completion_tokens, so they exercise the persistence path correctly but bypass the gap in the LLM client.Reproduction
Cluster smoke against fipsagents 0.14.0 + fipsagents-platform 0.2.0, gpt-oss-20b on RHPDS:
/v1/chat/completionswith the samesession_id.usageblock is{prompt_tokens: null, completion_tokens: null, total_tokens: null}.messagespopulated (204 bytes),cost_dataempty{}.Direct curl against the same vLLM endpoint with
stream_options.include_usage=trueconfirms the model happily emits a final usage chunk:{prompt_tokens:70, total_tokens:75, completion_tokens:5, prompt_tokens_details:{cached_tokens:64}}. The endpoint isn't broken — the client never asks.Fix
In
LLMClient.call_model_stream_raw, aftercall_kwargs[\"stream\"] = True:setdefaultso callers can opt out by passingstream_options={\"include_usage\": False}(or pass other stream options).Tests
_client.chat.completions.createis called withstream_options={\"include_usage\": True}when streaming. Mock the OpenAI client; check the kwargs.Impact
cost_dataaccumulation.Related