Skip to content

feat(gateway): add X-Cagent-Session-Id header to models gateway requests#2631

Merged
dgageot merged 2 commits intodocker:mainfrom
cogvel:feat/session-id-header
May 5, 2026
Merged

feat(gateway): add X-Cagent-Session-Id header to models gateway requests#2631
dgageot merged 2 commits intodocker:mainfrom
cogvel:feat/session-id-header

Conversation

@tdabasinskas
Copy link
Copy Markdown
Contributor

Today the models gateway has no way to map an outbound LLM call back to the cagent session that triggered it: the run loop knows sess.ID and stamps it on events, telemetry, slog, and the OTel session.id attribute, but the value never reaches the wire. That gap rules out per-session billing, per-session rate limiting, and audit trails on the gateway side.

The session ID rides through context.Context (ContextWithSessionID / SessionIDFromContext) seeded once at the run-loop boundary, and is forwarded as X-Cagent-Session-Id by the existing userAgentTransport. Header injection is gated on the request already carrying X-Cagent-Forward — the marker WithProxiedBaseURL sets when --models-gateway is wired up — so direct provider calls and unrelated outbound HTTP made through this transport never carry the identifier even when the value is in context.

Same pattern and namespace as #1751 (X-Cagent-Model-Name); gateways that do not care can ignore the header.

Today the models gateway has no way to map an outbound LLM call back to the cagent session that triggered it: the run loop knows `sess.ID` and stamps it on events, telemetry, slog, and the OTel `session.id` attribute, but the value never reaches the wire. That gap rules out per-session billing, per-session rate limiting, and audit trails on the gateway side.

The session ID rides through context.Context (`ContextWithSessionID` / `SessionIDFromContext`) seeded once at the run-loop boundary, and is forwarded as `X-Cagent-Session-Id` by the existing `userAgentTransport`. Header injection is gated on the request already carrying `X-Cagent-Forward` — the marker `WithProxiedBaseURL` sets when `--models-gateway` is wired up — so direct provider calls and unrelated outbound HTTP made through this transport never carry the identifier even when the value is in context. Same pattern and namespace as docker#1751 (`X-Cagent-Model-Name`); gateways that do not care can ignore the header.
@tdabasinskas tdabasinskas requested a review from a team as a code owner May 5, 2026 05:55
…action

Title generation runs from `App.generateTitle` and `SessionManager.generateTitle` directly into `sessiontitle.Generator.Generate` → provider — never crossing `runStreamLoop`, so the session ID seeded there did not reach the gateway. Manual compaction has the same shape: `App` calls `runtime.Summarize` → `compactWithReason`, also outside the run loop.

Stamping at both entry points (using the explicit `sessionID` parameter in `Generator.Generate` and `sess.ID` in `compactWithReason`) keeps the seed close to where the session is known and is idempotent for internal compaction callers that already inherit a stamped ctx via `runStreamLoop`.
@tdabasinskas tdabasinskas changed the title feat: add X-Cagent-Session-Id header to models gateway requests feat(gateway): add X-Cagent-Session-Id header to models gateway requests May 5, 2026
@dgageot dgageot merged commit 3f3e7ff into docker:main May 5, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants