feat(gateway): add X-Cagent-Session-Id header to models gateway requests#2631
Merged
dgageot merged 2 commits intodocker:mainfrom May 5, 2026
Merged
feat(gateway): add X-Cagent-Session-Id header to models gateway requests#2631dgageot merged 2 commits intodocker:mainfrom
X-Cagent-Session-Id header to models gateway requests#2631dgageot merged 2 commits intodocker:mainfrom
Conversation
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.
…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`.
X-Cagent-Session-Id header to models gateway requestsX-Cagent-Session-Id header to models gateway requests
dgageot
approved these changes
May 5, 2026
dgageot
approved these changes
May 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.IDand stamps it on events, telemetry, slog, and the OTelsession.idattribute, 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 asX-Cagent-Session-Idby the existinguserAgentTransport. Header injection is gated on the request already carryingX-Cagent-Forward— the markerWithProxiedBaseURLsets when--models-gatewayis 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.