fix(sdk): preserve request header forms and overrides
PR Checklist
- The commit message follows the contribution guidelines.
Bugs / Features
- Related issue linked: #1516; the issue records the reproduction and work plan before implementation.
- Tests added through the public SDK against a real local HTTP server.
- Docs added / updated: N/A, restores existing
RequestInit.headersand configured-header override behavior; no public API additions. - Patch changeset for
@voltagent/sdkincluded.
What is the current behavior?
sendRequest object-spreads RequestInit.headers. A Headers instance loses its fields, a tuple array produces numeric headers, and differently cased overrides concatenate with defaults. Constructor headers have the same case collision on typed eval requests. Reproduced on SDK 2.0.3 / main e9fc599f6059afcd88b34f2bfc50d0d1d6a0877c; #1516 includes a runnable snippet.
What is the new behavior?
Normalize with the native Headers implementation and apply caller fields using set, consistently at construction and both request paths. Records, Headers and tuples now send equivalent overrides regardless of casing. Unrelated defaults and public/secret-key fields are retained, and caller header containers are not mutated. Existing signatures and exports are unchanged.
Fixes #1516.
Notes for reviewers
- New real-HTTP regression file: 4 failures / 1 passing control on the original implementation, then 5 passes after the fix. Checks the actual received fields and absence of numeric header names.
- Full SDK suite: 22 passed across three files, including the five new cases.
- Independent probe of the built public SDK, native fetch and local HTTP server: changes from 4 failures in 5 cases to 5/5 passes.
- Frozen pnpm 8.10.5 dependencies; existing build scripts for internal/logger/core/SDK all pass on the baseline, and SDK CJS/ESM/declaration build passes after the fix.
- Full
pnpm lint:ci: passed, 1731 files, five existing complexity warnings. Targeted Biome formatting/check andgit diff --checkpass; normal pre-commit and commit-msg hooks ran successfully. - Standalone SDK
tsc --noEmitstill reports four diagnostics in the unchangedsrc/evals/index.spec.ts. Restoring the exact base client and excluding the new test reproduces all four diagnostics identically; the fixed source/test bytes were restored and verified. No additional diagnostic is introduced. This check is not reported as passing. - #1444 changes the same client file's abort/timeout logic. Its actual patch does not normalize headers, and
git apply --checkof that client patch succeeds against this fixed working tree. This change does not editfetchWithTimeoutand does not implement cancellation.
Node 24.13.0/macOS arm64 only. The local server substitutes for VoltOps and returns a minimal dataset-list response; actual client, native fetch and header serialization are exercised. No real cloud/provider credentials, model, browser, or production integration is tested. Full monorepo tests/build and Node 20 were not run.
AI assistance: OpenAI Codex discovered, implemented and locally reviewed this change, and ran the checks above using the contributor's authorized account. Automated verification does not represent human or maintainer approval.
Summary by cubic
Fix request header handling in @voltagent/sdk so Headers instances, tuple arrays, and records all work as request headers, and caller overrides merge case-insensitively with configured defaults.
Previously, RequestInit.headers was object-spread, which stripped fields from Headers instances, turned tuple arrays into numeric header names, and left differently cased overrides duplicating defaults instead of replacing them. Headers are now normalized with the native Headers implementation and caller fields are applied with set, consistently at construction and across both request paths. Caller header containers are not mutated.
Fixes #1516.
Summary by CodeRabbit
- Bug Fixes
- Improved HTTP header handling across SDK requests. Headers supplied as records,
Headersobjects, or tuple arrays are preserved, and caller-provided values override configured defaults regardless of capitalization. - Configured and authentication headers are retained when request-specific headers are applied.
- Improved HTTP header handling across SDK requests. Headers supplied as records,