Skip to content

fix: guarantee usage rows for streamed /v1/responses#141

Merged
SantiagoDePolonia merged 1 commit intomainfrom
fix/guarantee-one-usage-row-for-streamed-responses
Mar 12, 2026
Merged

fix: guarantee usage rows for streamed /v1/responses#141
SantiagoDePolonia merged 1 commit intomainfrom
fix/guarantee-one-usage-row-for-streamed-responses

Conversation

@SantiagoDePolonia
Copy link
Copy Markdown
Contributor

@SantiagoDePolonia SantiagoDePolonia commented Mar 12, 2026

Summary

  • move streamed /v1/responses usage enforcement into the chat-backed responses adapter
  • force include_usage=true when ENFORCE_RETURNING_USAGE_DATA is enabled without mutating the canonical request
  • preserve the policy on the noop usage logger path and add regression coverage for chat-backed, native, and end-to-end streamed usage persistence

Validation

  • go test ./config ./internal/usage ./internal/providers ./internal/server
  • direct Gemini curl check confirmed streamed chat usage is returned only when stream_options.include_usage=true
  • end-to-end GOModel + Gemini run wrote exactly one /v1/responses usage row to SQLite

Refs GOM-89

Summary by CodeRabbit

  • New Features

    • Added support for requesting usage data in streaming responses from compatible providers based on configuration policy.
  • Bug Fixes

    • Improved stream options handling to prevent unintended mutation of original requests during streaming operations.
  • Tests

    • Added comprehensive tests covering conditional usage data injection and stream options cloning behavior.
  • Refactor

    • Enhanced internal streaming logic to centralize and conditionally apply usage data enforcement.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 12, 2026

📝 Walkthrough

Walkthrough

This PR introduces context-based enforcement for returning usage data in streaming responses. It adds a context key to control usage data injection, implements stream options cloning to prevent mutation, and updates handler logic to conditionally inject IncludeUsage when enforcement is enabled. Changes span context management, provider adapters, server handlers, and usage logging.

Changes

Cohort / File(s) Summary
Configuration & Usage Policy
config/config.go, internal/usage/usage.go
Updated documentation comments for EnforceReturningUsageData field to clarify that stream_options are added when possible for supporting providers.
Context Management
internal/core/context.go
Added new context key enforce-returning-usage-data with getter GetEnforceReturningUsageData() and setter WithEnforceReturningUsageData() to propagate the usage enforcement policy through request context.
Provider Adapter
internal/providers/responses_adapter.go
Introduced cloneStreamOptions() helper and conditionally enabled IncludeUsage in StreamOptions when converting ResponsesRequest to ChatRequest and enforcement is active.
Provider Adapter Tests
internal/providers/responses_adapter_test.go
Added in-test capturingChatProvider and comprehensive tests verifying StreamOptions cloning behavior and conditional usage injection in streaming flows.
Server Handlers
internal/server/handlers.go
Introduced shouldEnforceReturningUsageData() and cloneChatRequestForStreamUsage() helpers; refactored ChatCompletion and Responses streaming paths to clone requests and conditionally inject IncludeUsage when enforcement is enabled.
Server Handler Tests
internal/server/handlers_test.go
Added chatBackedResponsesProvider type and tests verifying usage data injection behavior for chat-backed providers and unchanged behavior for native providers.
Usage Logger
internal/usage/factory.go, internal/usage/logger.go, internal/usage/usage_test.go
Updated NoopLogger from empty struct to configured struct with constructor NewNoopLogger(), added Close() method, and tests validating configuration preservation and disabled state.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler as Server Handler
    participant Context as Context Ctx
    participant Adapter as Provider Adapter
    participant Provider as Chat Provider

    Client->>Handler: Stream Chat Request
    Handler->>Handler: Check shouldEnforceReturningUsageData()
    alt Enforcement Enabled
        Handler->>Handler: cloneChatRequestForStreamUsage(req)
        Handler->>Handler: Set IncludeUsage: true in StreamOptions
        Handler->>Context: WithEnforceReturningUsageData(ctx, true)
    end
    Handler->>Provider: Call with enforced context & cloned request

    alt Responses Stream Path
        Provider->>Adapter: ConvertResponsesRequestToChat()
        Adapter->>Adapter: cloneStreamOptions()
        Adapter->>Context: GetEnforceReturningUsageData()
        alt Enforcement Active
            Adapter->>Adapter: Set IncludeUsage: true
        end
        Adapter->>Provider: ChatRequest with usage enabled
    end

    Provider-->>Handler: Stream response with usage
    Handler-->>Client: Usage data in stream
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A context hops through handlers bright,
With cloned requests held just right,
Stream options dance when told to play,
Usage data flows the modern way!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the changeset: ensuring usage data is guaranteed for streamed /v1/responses requests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/guarantee-one-usage-row-for-streamed-responses
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SantiagoDePolonia
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@SantiagoDePolonia SantiagoDePolonia self-assigned this Mar 12, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/providers/responses_adapter.go (1)

988-998: ⚠️ Potential issue | 🟠 Major

Gate include_usage injection to providers that actually support it; the unused providerName parameter suggests this is incomplete.

StreamResponsesViaChat unconditionally forces stream_options.include_usage = true when the context flag is on, but sends the request directly through each provider's native StreamChatCompletion without any field filtering. The providerName parameter is available but never used—leaving no way to conditionally apply this field only to providers that support it. This violates the coding guideline to "be conservative in what you send to AI model providers."

Check which of Groq, Ollama, and Gemini support stream_options.include_usage in their upstream APIs, then either condition the injection or strip the field before sending to unsupported providers.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/server/handlers_test.go`:
- Around line 2998-3016: The test after calling handler.Responses(c) currently
only verifies a usage entry was persisted but not that the HTTP response was
successful; update the test to assert the response status is 200 (OK)
immediately after the call to handler.Responses(c) by checking the response
recorder/status on the test context (the same context variable used for the
call, e.g., c or the response recorder tied to it) so the test fails if
/v1/responses returns an error status; keep the existing usageLog.entries and
entry checks (RequestID, Provider, Endpoint, and token counts) after this new
status assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b67a04f3-3322-4037-b434-78ece2926ffa

📥 Commits

Reviewing files that changed from the base of the PR and between 6a3b490 and f279252.

📒 Files selected for processing (10)
  • config/config.go
  • internal/core/context.go
  • internal/providers/responses_adapter.go
  • internal/providers/responses_adapter_test.go
  • internal/server/handlers.go
  • internal/server/handlers_test.go
  • internal/usage/factory.go
  • internal/usage/logger.go
  • internal/usage/usage.go
  • internal/usage/usage_test.go

@SantiagoDePolonia SantiagoDePolonia merged commit f5a9e75 into main Mar 12, 2026
13 checks passed
@SantiagoDePolonia
Copy link
Copy Markdown
Contributor Author

@coderabbitai feedback: The review comment is based on incorrect premises. providerName is
used, and all providers that flow through this code path use OpenAI-compatible
endpoints that support stream_options.include_usage. No change is needed.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 12, 2026

Tip

For best results, initiate chat on the files or code changes.

@SantiagoDePolonia: Thank you for the clarification! I understand — providerName is indeed used, and all providers that flow through the chatBackedResponsesProvider / StreamResponsesViaChat path use OpenAI-compatible endpoints that fully support stream_options.include_usage. The concern was unfounded, and no change is needed.


✏️ Learnings added
Learnt from: SantiagoDePolonia
URL: https://github.com/ENTERPILOT/GOModel/pull/141

Timestamp: 2026-03-12T22:39:09.713Z
Learning: In the GOModel repository (github.com/ENTERPILOT/GOModel), all providers that flow through the chat-backed responses adapter (`StreamResponsesViaChat` / `chatBackedResponsesProvider`) use OpenAI-compatible endpoints that support `stream_options.include_usage`. The `providerName` field is used in this code path. Do not flag concerns about provider compatibility with `stream_options.include_usage` for this path.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@SantiagoDePolonia SantiagoDePolonia deleted the fix/guarantee-one-usage-row-for-streamed-responses branch March 22, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant