Skip to content

api-proxy: stream_options.include_usage injected into OpenAI Responses API requests #3804

Description

@lpcox

Problem

The api-proxy injectStreamOptions() function in containers/api-proxy/body-transform.js is injecting stream_options: { include_usage: true } into OpenAI Responses API (/responses) requests. The OpenAI Responses API does not support this parameter and rejects the request with:

{
  "error": {
    "message": "Unknown parameter: 'stream_options.include_usage'.",
    "type": "invalid_request_error",
    "param": "stream_options.include_usage",
    "code": "unknown_parameter"
  }
}

This causes Codex CLI to crash immediately (exit code 1, duration=0s) on every attempt, making all Codex workflows non-functional when using the api-proxy.

Evidence

From CI run 26415291484:

Turn error: "Unknown parameter: 'stream_options.include_usage'"
[codex-harness] attempt 1: process closed exitCode=1 duration=0s stderr=227762B

All 4 retry attempts fail identically.

Root Cause

body-transform.js:148 has a guard to skip Responses API paths:

if (/^\/(?:v\d+\/)?responses(?:\/|$)/.test(pathOnly)) return null;

However, this regex requires a leading /. The Codex client (v0.133.0) appears to send requests where req.url does not match the expected pattern — either because:

  1. The path arrives without a leading / (Codex logs show api.path="responses")
  2. The proxy routes requests in a way that req.url at the injection point differs from the final upstream path

Proposed Solution

  1. Make the regex more permissive — handle paths with or without leading slash:

    if (/^(?:\/)?(?:v\d+\/)?responses(?:\/|$)/.test(pathOnly)) return null;
  2. Also check the parsed body for Responses API request shape (presence of input field, absence of messages field) as a secondary guard.

  3. For token usage tracking on the Responses API: The Responses API automatically includes usage in the response.completed event during streaming and in the response body for non-streaming. The token tracker should parse usage from response.completed events rather than relying on stream_options.include_usage. This is important for billing/OTEL — we need accurate token counts for all OpenAI APIs including Responses.

Impact

Files

  • containers/api-proxy/body-transform.js:141-162injectStreamOptions() function
  • containers/api-proxy/proxy-request.js:690-696 — injection call site
  • containers/api-proxy/body-transform.test.js:13-18 — tests (need case without leading slash)

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions