Skip to content

fix(providers): centralize stream request headers#59542

Merged
vincentkoc merged 3 commits into
mainfrom
fix/provider-stream-request-headers
Apr 2, 2026
Merged

fix(providers): centralize stream request headers#59542
vincentkoc merged 3 commits into
mainfrom
fix/provider-stream-request-headers

Conversation

@vincentkoc

Copy link
Copy Markdown
Member

Summary

  • Problem: stream and websocket request-header mutation still lived in three separate paths with different merge rules for attribution/default headers versus caller headers.
  • Why it matters: phase 1 centralized request policy, phase 2 centralized model and provider HTTP request shaping, but stream/websocket paths were still a duplication hotspot that could silently drift.
  • What changed: added resolveProviderRequestHeaders in src/agents/provider-request-config.ts and migrated OpenAI stream attribution, OpenRouter stream attribution, Kilocode stream defaults, and OpenAI websocket headers onto that shared seam.
  • What did NOT change (scope boundary): payload mutation logic, provider routing policy, and provider HTTP request shaping were left unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause / Regression History (if applicable)

  • Root cause: stream and websocket paths accumulated separate header merge implementations after request policy and HTTP request shaping were centralized, so precedence behavior was encoded ad hoc per call site.
  • Missing detection / guardrail: there was no shared seam test for caller-wins versus defaults-win header precedence across non-HTTP request paths.
  • Prior context (git blame, prior PR, issue, or refactor if known): this continues the provider request-policy/request-config work from refactor(providers): add internal request config seam #59454 and the shared HTTP seam from fix(providers): centralize media request shaping #59469.
  • Why this regressed now: older duplication became the main remaining drift point after HTTP paths moved onto the shared helper.
  • If unknown, what was ruled out: N/A

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/provider-request-config.test.ts, src/agents/openai-ws-connection.test.ts, src/agents/pi-embedded-runner/extra-params.openai.test.ts, src/agents/pi-embedded-runner/proxy-stream-wrappers.test.ts, src/agents/pi-embedded-runner/extra-params.kilocode.test.ts
  • Scenario the test should lock in: OpenAI defaults can override spoofed caller attribution, OpenRouter caller headers still win over documented attribution defaults, Kilocode runtime headers remain non-overridable, and websocket headers use the same centralized merge path.
  • Why this is the smallest reliable guardrail: the new helper is now the merge point, and the existing transport tests prove the migrated call sites preserve their prior behavior.
  • Existing test that already covers this (if any): the transport tests already covered each behavior separately but not through one shared seam.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • None intended. This PR centralizes stream/websocket request-header shaping while preserving current OpenAI, OpenRouter, Kilocode, and OpenAI websocket behavior.

Diagram (if applicable)

Before:
[OpenAI stream] -> [manual merge A]
[OpenRouter stream] -> [manual merge B]
[OpenAI websocket] -> [manual merge C]

After:
[stream/websocket path] -> [resolveProviderRequestHeaders] -> [transport call]

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node 22 / pnpm
  • Model/provider: OpenAI, OpenAI Codex, OpenRouter, Kilocode
  • Integration/channel (if any): N/A
  • Relevant config (redacted): default provider config plus transport test fixtures

Steps

  1. Run the stream/websocket wrapper tests that exercise OpenAI, OpenRouter, Kilocode, and websocket header injection.
  2. Verify caller header precedence stays provider-specific where intended.
  3. Verify the shared helper tests cover both precedence modes directly.

Expected

  • Stream/websocket paths share one request-header seam while preserving existing transport behavior.

Actual

  • The migrated paths use resolveProviderRequestHeaders(...), and targeted tests/build/check all pass.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: OpenAI stream attribution override behavior, OpenRouter caller-header precedence, Kilocode non-overridable runtime header behavior, OpenAI websocket default header injection, and shared precedence tests.
  • Edge cases checked: native OpenAI attribution on verified endpoints, custom websocket endpoints without hidden attribution, explicit caller spoofing versus OpenAI defaults, caller override versus OpenRouter defaults.
  • What you did not verify: full pnpm test and live provider traffic.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: a future caller could assume one universal precedence rule across all providers and transports.
    • Mitigation: the helper makes precedence explicit, and tests lock both defaults-win and caller-wins behavior.
  • Risk: more provider families may eventually need different request-header semantics.
    • Mitigation: this PR centralizes only the merge mechanism; provider policy and payload behavior remain separate.

@openclaw-barnacle openclaw-barnacle Bot added the agents Agent runtime and tooling label Apr 2, 2026
@vincentkoc vincentkoc self-assigned this Apr 2, 2026
@openclaw-barnacle openclaw-barnacle Bot added size: S maintainer Maintainer-authored PR labels Apr 2, 2026
@vincentkoc
vincentkoc marked this pull request as ready for review April 2, 2026 08:12
@greptile-apps

greptile-apps Bot commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR centralizes stream/websocket request-header merging into a new resolveProviderRequestHeaders helper, migrating four call sites (OpenAI stream, OpenRouter stream, Kilocode stream, OpenAI websocket) off their hand-rolled merge patterns. The behavioral semantics at each call site — defaults-win for OpenAI/Kilocode/websocket and caller-wins for OpenRouter — are correctly preserved, and the new seam tests confirm both precedence modes directly.

Confidence Score: 5/5

  • Safe to merge; all behavioral changes are intentional refactors with matching test coverage.
  • The header merge logic is correct and equivalent to what it replaces at every call site. The only finding is a P2 documentation gap on the implicit defaults-win default when precedence is omitted — no current caller is affected.
  • No files require special attention.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/provider-request-config.ts
Line: 114-116

Comment:
**Implicit `defaults-win` when `precedence` is omitted**

When `precedence` is `undefined`, the ternary falls through to the `defaults-win` branch silently. All current call sites explicitly pass the parameter, so there's no current bug, but this undocumented default could surprise a future caller who omits it expecting a neutral merge. A short JSDoc comment (or an explicit default in the parameter list) would lock in the intent.

```suggestion
  // When precedence is omitted, defaults-win is the conservative choice:
  // attribution/default headers cannot be silently overridden by callers.
  return params.precedence === "caller-wins"
    ? mergeProviderRequestHeaders(mergedDefaults, params.callerHeaders)
    : mergeProviderRequestHeaders(params.callerHeaders, mergedDefaults);
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Merge branch 'main' into fix/provider-st..." | Re-trigger Greptile

Comment thread src/agents/provider-request-config.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@vincentkoc
vincentkoc merged commit 331e835 into main Apr 2, 2026
10 checks passed
@vincentkoc
vincentkoc deleted the fix/provider-stream-request-headers branch April 2, 2026 08:21
ngutman pushed a commit that referenced this pull request Apr 3, 2026
* fix(providers): centralize stream request headers

* Update src/agents/provider-request-config.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
steipete pushed a commit to duncanita/openclaw that referenced this pull request Apr 4, 2026
* fix(providers): centralize stream request headers

* Update src/agents/provider-request-config.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
* fix(providers): centralize stream request headers

* Update src/agents/provider-request-config.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
* fix(providers): centralize stream request headers

* Update src/agents/provider-request-config.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
* fix(providers): centralize stream request headers

* Update src/agents/provider-request-config.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
* fix(providers): centralize stream request headers

* Update src/agents/provider-request-config.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Nachx639 pushed a commit to Nachx639/clawdbot that referenced this pull request Jun 17, 2026
* fix(providers): centralize stream request headers

* Update src/agents/provider-request-config.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant