Skip to content

[Feature] expose usage/timing for streaming responses in onResponse ctx #9571

Description

@amaleta

Problem / Use Case

For streaming requests the plugin onResponse hook receives
{ status, streamed: true } — no response body and no token usage / timing
data (per #8711 the SSE body is not materialised). Non-streaming responses
pass the full JSON body including usage.

Any observability plugin (metrics, trace exporters, cost accounting) is
therefore structurally blind to streaming requests — typically the majority
of chat traffic.

Current behavior (v3.8.49), open-sse/handlers/chatCore/pluginOnResponse.ts:

export type PluginOnResponsePayload = {
  status: number;
  data?: unknown;      // non-streaming only
  streamed?: boolean;  // streaming: no data, no usage
};

Proposed Solution

The gateway computes usage for streaming responses anyway (it is surfaced to
the client via the final SSE chunk / call logs). Expose a bounded summary in
the onResponse payload for streaming paths instead of materialising the
SSE body, e.g. usage: { prompt_tokens, completion_tokens, total_tokens }
plus durationMs, alongside the existing streamed: true.

This keeps #8711's constraint (no body materialisation) intact while giving
plugins the minimal data needed to account for streaming generations.

Alternatives Considered

  • Guessing usage from the request body alone — unreliable; actual streaming
    usage is only known at stream end.
  • Materialising the full SSE body for plugins — exactly what fix(backend): Plugin system never sends response #8711 avoided
    (memory pressure on large streams).
  • Reading usage out-of-band from call logs — works, but is not a plugin API
    and requires file access from the plugin.

Acceptance Criteria

  • onResponse payload for streaming requests includes usage
    (prompt/completion/total tokens) and durationMs when available;
    streamed: true remains.
  • Non-streaming payload unchanged (data with the full body incl. usage).
  • No SSE body materialisation added to the streaming path (memory behaviour
    unchanged).
  • Existing plugins that ignore the new fields behave identically.

Area

Analytics / Usage Tracking

Related Provider(s)

No response

Additional Context

Companion to the headers-in-plugin-ctx feature request (вставь номер первого
issue после создания). Both are additive extensions of the plugin hook
contract introduced in #3221.

Expected Test Plan

  • Unit tests: extend tests/unit/plugins-hooks.test.ts — streaming
    onResponse payload carries usage/durationMs when available, omits them
    when not.
  • Unit test: non-streaming payload shape unchanged.
  • Keep npm run test:coverage at the current threshold.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions