Problem
When embedding docker-agent programmatically (via anthropic.NewClient, teamloader.Load, etc.), there is currently no way to inject custom HTTP middleware into the transport chain used by provider clients — neither in direct mode nor in gateway/proxy mode.
Both the Anthropic and OpenAI provider clients build their HTTP client internally:
// direct path (anthropic/client.go)
option.WithHTTPClient(httpclient.NewHTTPClient(ctx))
// gateway path (anthropic/client.go)
option.WithHTTPClient(httpclient.NewHTTPClient(ctx, httpOptions...))
The options.ModelOptions struct and config.RuntimeConfig carry no transport field, so there is no place to hook in.
Use cases
- Bearer-token injection for a private LLM proxy: a private reverse proxy requires
Authorization: Bearer <token> on every request. The token is known at client-construction time but must be injected regardless of whether the provider is in direct or gateway mode.
- Custom observability / tracing: adding spans or metrics around every LLM HTTP call, beyond what OTel wrapping already provides.
- Request/response logging and debugging: inspect raw HTTP traffic during development.
- Retry/circuit-breaker policies: wrap the transport with custom retry logic specific to the deployment.
All of these share the same shape: wrap whatever transport docker-agent would build, apply some middleware, and delegate to the original.
Proposed API
Add a new Opt to the options package:
// WithHTTPTransportWrapper registers a function that wraps the HTTP transport
// used by all provider clients. The function receives the transport that
// docker-agent built (including OTel instrumentation, SSE decompression fix,
// and Desktop proxy support) and must return a new RoundTripper that delegates
// to it. The wrapper is applied in both direct mode and gateway/proxy mode.
//
// Example — inject a bearer token on every outbound LLM request:
//
// options.WithHTTPTransportWrapper(func(base http.RoundTripper) http.RoundTripper {
// return &bearerTransport{token: myToken, base: base}
// })
func WithHTTPTransportWrapper(fn func(base http.RoundTripper) http.RoundTripper) Opt {
return func(cfg *ModelOptions) {
cfg.transportWrapper = fn
}
}
And surface it via ModelOptions:
func (o *ModelOptions) TransportWrapper() func(http.RoundTripper) http.RoundTripper {
return o.transportWrapper
}
Implementation sketch (Anthropic provider, direct path)
httpClient := httpclient.NewHTTPClient(ctx)
if wrapper := globalOptions.TransportWrapper(); wrapper != nil {
httpClient.Transport = wrapper(httpClient.Transport)
}
requestOptions := []option.RequestOption{
option.WithHTTPClient(httpClient),
...
}
Same two-liner applied to the gateway path. The same pattern applies symmetrically to the OpenAI provider (and any future providers that use httpclient.NewHTTPClient).
Notes
- The wrapper function receives the already-built transport (post-OTel, post-SSE-filter, post-Desktop-proxy), so callers compose on top of docker-agent's chain rather than replacing it.
- A single
WithHTTPTransportWrapper call is the common case; stacking multiple wrappers is possible by chaining the functions before passing them in.
- This is intentionally lower-level than
WithGateway — it targets use cases where callers manage their own transport-level concerns that docker-agent has no opinion on.
Problem
When embedding docker-agent programmatically (via
anthropic.NewClient,teamloader.Load, etc.), there is currently no way to inject custom HTTP middleware into the transport chain used by provider clients — neither in direct mode nor in gateway/proxy mode.Both the Anthropic and OpenAI provider clients build their HTTP client internally:
The
options.ModelOptionsstruct andconfig.RuntimeConfigcarry no transport field, so there is no place to hook in.Use cases
Authorization: Bearer <token>on every request. The token is known at client-construction time but must be injected regardless of whether the provider is in direct or gateway mode.All of these share the same shape: wrap whatever transport docker-agent would build, apply some middleware, and delegate to the original.
Proposed API
Add a new
Optto theoptionspackage:And surface it via
ModelOptions:Implementation sketch (Anthropic provider, direct path)
Same two-liner applied to the gateway path. The same pattern applies symmetrically to the OpenAI provider (and any future providers that use
httpclient.NewHTTPClient).Notes
WithHTTPTransportWrappercall is the common case; stacking multiple wrappers is possible by chaining the functions before passing them in.WithGateway— it targets use cases where callers manage their own transport-level concerns that docker-agent has no opinion on.