Skip to content

feat(anthropic): expose per-request headers on send/stream (bearer auth, caller-controlled anthropic-beta, version) #592

Description

@VikashLoomba

Summary

Expose adk-anthropic's existing per-request header plumbing publicly, so callers can supply the full HeaderMap for a messages request — enabling Authorization: Bearer auth, caller-controlled anthropic-beta composition, and anthropic-version selection without forking the client.

Motivation

The client internally already treats headers as per-request values with replacement semantics: execute_post_request(url, body, headers: Option<HeaderMap>) replaces the defaults entirely when a map is supplied, and both send() and stream() build and mutate a per-request map (the streaming ACCEPT swap, the conditional beta joins). But none of that is reachable publicly — build_default_headers is fixed (x-api-key, anthropic-version: "2023-06-01"), cached_headers has no setter, and no public method accepts headers (as of df9ef83, adk-anthropic/src/client.rs:305-320, 481-505, 533-604, 625-715).

That closes off three real use cases we've hit while building an Anthropic integration:

  1. Bearer-token auth. Several Anthropic-compatible surfaces authenticate with Authorization: Bearer <token> instead of x-api-key — OAuth access tokens, and gateways such as GitHub Copilot's Anthropic endpoint. Today there is no way to send Authorization or to omit x-api-key.
  2. Caller-controlled anthropic-beta. The client composes betas for its own features (structured outputs, context management, fast mode), but callers cannot request other documented betas — e.g. fine-grained-tool-streaming-2025-05-14 or interleaved-thinking-2025-05-14 — or suppress betas for gateways that reject them.
  3. anthropic-version selection. Pinned to a const today.

Proposed Solution

Expose the existing internal parameter — smallest possible API surface, e.g.:

pub async fn send_with_headers(&self, params: MessageCreateParams, headers: HeaderMap) -> Result<Message>;
pub async fn stream_with_headers(&self, params: &MessageCreateParams, headers: HeaderMap) -> Result<impl Stream<Item = Result<MessageStreamEvent>>>;

with documented replacement semantics (the supplied map replaces the defaults, exactly like the internal parameter today). Replacement rather than merge is load-bearing: it lets a caller send Authorization: Bearer … without x-api-key, so no request ever carries two credentials. A convenience Anthropic::default_headers_for(&self) -> HeaderMap (or making the current private default_headers() public) would let callers start from the standard set and adjust.

Base-URL validation from #457/#458 is unaffected — this proposal changes no URL handling, and the https/loopback rule keeps guarding wherever the headers go.

An alternative shape (builder-level with_extra_headers(HeaderMap) merged into cached_headers) is workable for betas/version but cannot express "omit x-api-key" without additional delete semantics, which is why the per-request replacement form seems cleaner.

Affected Crate(s)

adk-anthropic

Alternatives Considered

  • Merge-style extra headers — cannot drop x-api-key for bearer auth without delete sentinels (see above).
  • Forking the client — works, but this is plumbing the crate already has; exposing it keeps downstream users on the shared implementation.
  • Env-var control — headers vary per request (per-model beta sets), so process-level configuration doesn't fit.

Additional Context

Following the ask-first convention (per #550): happy to send the PR — the change is exposing the existing Option<HeaderMap> parameter plus docs and tests for the replacement semantics and the bearer-without-x-api-key case. Related follow-up we'd also like to propose separately: a fallbacks field on MessageCreateParams for the server-side fallback beta.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions