Documentation
¶
Overview ¶
Package header provides header filtering for the tapes proxy.
This proxy sits between a client and an upstream LLM provider like so:
Client <--> Proxy <--> Upstream LLM Provider
and headers are handled accordingly as each leg negotiates compression, hops, encoding, etc. independently.
Index ¶
Constants ¶
const ( // CodexSessionID is the Codex harness's root session id, present on // every Codex call. CodexSessionID = "session-id" // CodexThreadID is the Codex harness's thread id for this call: equal to // session-id on root turns, a distinct id on sub-thread (spawned agent) // turns. CodexThreadID = "thread-id" )
Codex's native identity headers. Unlike Claude Code, Codex stamps thread-id on EVERY call — root turns carry thread-id == session-id, and only spawned sub-thread (child) turns carry a distinct thread-id. So presence alone doesn't mean "subagent"; the root guard in ThreadID compares the pair and resolves root turns to "". Getting this wrong is not cosmetic: a non-empty thread_id on a root turn misroutes the root spine into tapes derive's threadCall path and silently degrades the session's derived status (terminalMainSpan requires ThreadID=="").
const AgentNameHeader = "X-Tapes-Agent-Name"
AgentNameHeader is the optional header used to tag agent requests.
Variables ¶
var ThreadIDHeaders = []string{
"x-claude-code-agent-id",
}
ThreadIDHeaders maps each harness's native sub-thread header onto the capture-side thread id. A harness that runs subagents fires their API calls with a per-thread identifier — Claude Code stamps x-claude-code-agent-id on every call made from a subagent context (including its security-monitor checks) and omits it on the main thread. Capturing it makes thread attribution deterministic at capture time instead of recovered by content joins downstream.
The list is ordered; first present header wins. Add other harnesses' equivalents here as they are identified — the rest of the pipeline is harness-neutral and only sees the resolved thread id. Codex is NOT a member of this list: its sub-thread signal is a header *pair* (see the Codex constants below), resolved separately in ThreadID.
This must stay in step with extproc/headers' harnessThreadIDHeaders: the two are independent capture paths for the same traffic, and a header one records and the other doesn't is a fidelity gap that only shows up as subagent turns mis-attributed to the main thread. They stayed separate through the extproc fold because they read from different transports — a fiber.Ctx here, an ext_proc HeaderMap there — so only the list itself could ever be shared.
These headers are NOT stripped on the way upstream. They are the harness's own, addressed to the model provider; tapes only observes them.
Functions ¶
Types ¶
type Handler ¶
type Handler struct{}
Handler manages headers between proxy connections.
func (*Handler) SetClientResponseHeaders ¶
SetClientResponseHeaders copies response headers from the upstream API http.Response to the Fiber context, filtering headers that the proxy should not forward back down to the client.