mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(executors): forward X-Session-ID/X-Title agent metadata headers (#7104)
* fix(executors): forward X-Session-ID/X-Title agent metadata headers (port from 9router#2413) Custom agent clients (e.g. non-OpenCode providers) commonly send X-Session-ID and X-Title headers for upstream request tracking/attribution, but forwardOpencodeClientHeaders() only forwarded x-opencode-* keys plus User-Agent, silently dropping these for every client. Extends the existing case-insensitive allowlist forwarding path with x-session-id/x-title. Reported-by: Atikur Rahman Chitholian (@chitholian) (https://github.com/decolua/9router/issues/2413) * chore(changelog): move #2413 entry to changelog.d fragment Consistency with the repo's canonical changelog.d/fixes/ workflow (avoids merge-storm re-conflicts from editing CHANGELOG.md directly).
This commit is contained in:
committed by
GitHub
parent
39222525ea
commit
60448d4f31
1
changelog.d/fixes/2413-preserve-agent-headers.md
Normal file
1
changelog.d/fixes/2413-preserve-agent-headers.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(executors):** forward agent-supplied `X-Session-ID`/`X-Title` metadata headers to upstream providers — previously dropped for every client outside the `x-opencode-*` allowlist. (thanks @chitholian) (#7104)
|
||||
@@ -12,6 +12,15 @@ const OPENCODE_HEADER_KEYS = [
|
||||
"x-opencode-client",
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* Common agent-metadata headers used by non-OpenCode clients (custom agents/
|
||||
* providers) for upstream request tracking and attribution. Forwarded the same
|
||||
* way as the x-opencode-* set: case-insensitive lookup, client value wins.
|
||||
* Added for 9router#2413 — these were previously dropped for every client
|
||||
* outside the OpenCode allowlist.
|
||||
*/
|
||||
const AGENT_METADATA_HEADER_KEYS = ["x-session-id", "x-title"] as const;
|
||||
|
||||
/**
|
||||
* Case-insensitive lookup for a header in a headers record.
|
||||
*/
|
||||
@@ -26,6 +35,8 @@ function findHeader(headers: Record<string, string>, name: string): string | und
|
||||
* 1. Forwards User-Agent from clientHeaders via `setUserAgentHeader()`
|
||||
* 2. Forwards x-opencode-session, x-opencode-request, x-opencode-project,
|
||||
* x-opencode-client headers (case-insensitive match)
|
||||
* 3. Forwards x-session-id, x-title agent-metadata headers (case-insensitive
|
||||
* match) — common conventions used by non-OpenCode agent clients (9router#2413)
|
||||
*
|
||||
* @param headers - The outbound headers record to mutate
|
||||
* @param clientHeaders - The client-provided headers to forward from
|
||||
@@ -60,6 +71,14 @@ export function forwardOpencodeClientHeaders(
|
||||
}
|
||||
}
|
||||
|
||||
// 2b. Forward agent-metadata headers (x-session-id, x-title) — 9router#2413
|
||||
for (const headerName of AGENT_METADATA_HEADER_KEYS) {
|
||||
const value = findHeader(clientHeaders, headerName);
|
||||
if (value) {
|
||||
headers[headerName] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. OpencodeExecutor-only: synthesize session/request id from fallback headers
|
||||
if (options?.synthesizeRequestId && !headers["x-opencode-session"]) {
|
||||
const sessionAffinity =
|
||||
|
||||
@@ -116,6 +116,43 @@ describe("forwardOpencodeClientHeaders – x-opencode-* headers", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ── agent metadata headers (X-Session-ID / X-Title) — 9router#2413 ─────────
|
||||
// Non-OpenCode agent clients (e.g. custom providers) commonly send X-Session-ID
|
||||
// and X-Title for upstream request tracking/attribution. These were previously
|
||||
// dropped for every client outside the x-opencode-* allowlist.
|
||||
|
||||
describe("forwardOpencodeClientHeaders – X-Session-ID / X-Title", () => {
|
||||
it("forwards X-Session-ID from client headers", () => {
|
||||
const headers = h();
|
||||
const clientHeaders = { "X-Session-ID": "sess-xyz" };
|
||||
forwardOpencodeClientHeaders(headers, clientHeaders);
|
||||
assert.equal(headers["x-session-id"], "sess-xyz");
|
||||
});
|
||||
|
||||
it("forwards X-Title from client headers", () => {
|
||||
const headers = h();
|
||||
const clientHeaders = { "X-Title": "My Agent" };
|
||||
forwardOpencodeClientHeaders(headers, clientHeaders);
|
||||
assert.equal(headers["x-title"], "My Agent");
|
||||
});
|
||||
|
||||
it("matches X-Session-ID / X-Title case-insensitively", () => {
|
||||
const headers = h();
|
||||
const clientHeaders = { "x-session-id": "sess-lower", "x-title": "lower title" };
|
||||
forwardOpencodeClientHeaders(headers, clientHeaders);
|
||||
assert.equal(headers["x-session-id"], "sess-lower");
|
||||
assert.equal(headers["x-title"], "lower title");
|
||||
});
|
||||
|
||||
it("still does NOT forward unrelated unknown headers", () => {
|
||||
const headers = h();
|
||||
const clientHeaders = { "X-Session-ID": "sess-1", "X-Random-Other": "nope" };
|
||||
forwardOpencodeClientHeaders(headers, clientHeaders);
|
||||
assert.equal(headers["x-session-id"], "sess-1");
|
||||
assert.equal(headers["X-Random-Other"], undefined);
|
||||
});
|
||||
});
|
||||
|
||||
// ── synthesizeRequestId ─────────────────────────────────────────────────────
|
||||
|
||||
describe("forwardOpencodeClientHeaders – synthesizeRequestId", () => {
|
||||
|
||||
Reference in New Issue
Block a user