You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add custom headers support across all 4 SDKs (Node.js, Python, Go, .NET):
- Add headers field to ProviderConfig for session-level custom headers
- Add HeaderMergeStrategy type (override, merge) for configurable merge behavior
- Add requestHeaders and headerMergeStrategy to MessageOptions/send()
- Add updateProvider/update_provider/UpdateProviderAsync method on Session
- Add comprehensive documentation in docs/auth/byok.md
- Update all SDK READMEs with custom headers examples
Closes#355
|`wireApi` / `wire_api`|`"completions"`\|`"responses"`| API format (default: `"completions"`) |
178
+
|`headers`|`Record<string, string>`| Custom HTTP headers for all outbound requests ([details](#custom-headers)) |
178
179
|`azure.apiVersion` / `azure.api_version`| string | Azure API version (default: `"2024-10-21"`) |
179
180
180
181
### Wire API Format
@@ -304,6 +305,327 @@ provider: {
304
305
305
306
> **Note:** The `bearerToken` option accepts a **static token string** only. The SDK does not refresh this token automatically. If your token expires, requests will fail and you'll need to create a new session with a fresh token.
306
307
308
+
## Custom Headers
309
+
310
+
Custom headers let you attach additional HTTP headers to every outbound model request. This is useful when your provider endpoint sits behind an API gateway or proxy that requires extra authentication or routing headers.
311
+
312
+
### Use Cases
313
+
314
+
| Scenario | Example Header |
315
+
|----------|---------------|
316
+
| Azure API Management / AI Gateway |`Ocp-Apim-Subscription-Key`|
Pass `requestHeaders` on `send()` to include headers for a **single turn** only. This is useful when headers change between requests (e.g., per-request trace IDs or rotating tokens).
When you provide both session-level `headers` and per-turn `requestHeaders`, the `headerMergeStrategy` controls how they combine.
484
+
485
+
| Strategy | Behavior |
486
+
|----------|----------|
487
+
|`"override"` (default) | Per-turn headers **completely replace** session-level headers. No session headers are sent for that turn. This is the safest default — no unexpected header leakage. |
488
+
|`"merge"`| Per-turn headers are **merged** with session-level headers. Per-turn values win on key conflicts. |
489
+
490
+
#### Override (Default)
491
+
492
+
```typescript
493
+
// Session created with headers: { "X-Team": "alpha", "X-Env": "prod" }
494
+
495
+
awaitsession.send({
496
+
prompt: "Hello",
497
+
requestHeaders: { "X-Request-Id": "abc-123" },
498
+
// headerMergeStrategy defaults to "override"
499
+
});
500
+
// Only "X-Request-Id" is sent — session headers are NOT included
501
+
```
502
+
503
+
#### Merge
504
+
505
+
```typescript
506
+
// Session created with headers: { "X-Team": "alpha", "X-Env": "prod" }
Use `updateProvider()` to change provider configuration — including headers — between turns without recreating the session. This is useful for rotating API keys, switching tenants, or adjusting gateway headers on the fly.
Header values support environment variable expansion at the runtime level. This lets you reference secrets without hardcoding them in your application code.
601
+
602
+
| Syntax | Behavior |
603
+
|--------|----------|
604
+
|`${VAR}`| Replaced with the value of `VAR`. Fails if `VAR` is not set. |
605
+
|`$VAR`| Same as `${VAR}`. |
606
+
|`${VAR:-default}`| Replaced with the value of `VAR`, or `default` if `VAR` is not set. |
607
+
608
+
```typescript
609
+
provider: {
610
+
type: "openai",
611
+
baseUrl: "https://my-gateway.example.com/v1",
612
+
headers: {
613
+
// Expanded at runtime from the APIM_KEY environment variable
614
+
"Ocp-Apim-Subscription-Key": "${APIM_KEY}",
615
+
// Falls back to "default-tenant" if X_TENANT is not set
616
+
"X-Tenant-Id": "${X_TENANT:-default-tenant}",
617
+
},
618
+
}
619
+
```
620
+
621
+
> **Note:** Expansion is performed by the CLI server, not the SDK client. The SDK passes header values as-is to the server, which resolves environment variables before sending requests to your provider.
622
+
623
+
### Security Considerations
624
+
625
+
-**Scoped to your endpoint** — Custom headers are sent only to the configured `baseUrl`. They are never sent to GitHub Copilot servers or other endpoints.
626
+
-**Prefer env var expansion** — Use `${VAR}` syntax for sensitive values like API keys and tokens rather than hardcoding them. This avoids secrets in source code and logs.
627
+
-**Override is the safe default** — The default `headerMergeStrategy` of `"override"` ensures per-turn headers completely replace session-level headers, preventing accidental leakage of session headers into turns that specify their own.
628
+
307
629
## Custom Model Listing
308
630
309
631
When using BYOK, the CLI server may not know which models your provider supports. You can supply a custom `onListModels` handler at the client level so that `client.listModels()` returns your provider's models in the standard `ModelInfo` format. This lets downstream consumers discover available models without querying the CLI.
Per-turn headers and merge strategies are also supported. See the [Custom Headers](docs/auth/byok.md#custom-headers) section in the BYOK guide for full details.
621
+
599
622
## Telemetry
600
623
601
624
The SDK supports OpenTelemetry for distributed tracing. Provide a `Telemetry` config to enable trace export and automatic W3C Trace Context propagation.
0 commit comments