Documentation

Anthropic integration

Same two paths as OpenAI: a drop-in client wrapper for TypeScript, and the language-agnostic gateway proxy.

SDK wrapper (TypeScript)

ts
import Anthropic from "@anthropic-ai/sdk";
import { AuditTrailClient, wrapAnthropic } from "@audittrail/sdk";
 
const audit = new AuditTrailClient({
  baseUrl: "https://your-audittrail-host",
  apiKey: process.env.AUDITTRAIL_API_KEY,
});
 
const anthropic = wrapAnthropic(new Anthropic(), audit);
 
const msg = await anthropic.messages.create({
  model: "claude-sonnet-4-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "hello" }],
});

The wrapper proxies messages.create, maps Anthropic's input_tokens/output_tokens usage onto the AuditTrail span schema, and is structurally typed — the SDK has no runtime dependency on @anthropic-ai/sdk. Spans join the active trace context, so wrapping your handler in traceable() nests them properly.

SDK wrapper (Go & Rust)

Go installs an http.RoundTripper on the official anthropic-sdk-go client; Rust wraps any Serialize request/response pair. Both map input_tokens/output_tokens and emit one span per messages call.

go
audit, _ := audittrail.New(audittrail.Config{APIKey: apiKey})
client := anthropic.NewClient(
    option.WithHTTPClient(audittrail.AnthropicHTTPClient(audit)),
)
rust
let response: serde_json::Value = audit
    .wrap_anthropic(&request, || async { /* call anthropic */ Ok::<_, MyErr>(resp) })
    .await?;

See the SDK parity matrix for the full language grid.

Gateway proxy (any language)

The gateway speaks the OpenAI-compatible /chat/completions envelope and routes by model name — claude-* (and anthropic/*) models forward to the Anthropic API using the upstream key configured on the server (AUDITTRAIL_GATEWAY_ANTHROPIC_KEY, or a per-request stored secret via the X-AuditTrail-Secret header):

bash
export OPENAI_BASE_URL="https://your-audittrail-host/api/v1/gateway/proxy/v1"
export OPENAI_API_KEY="at-gw-..."   # AuditTrail virtual key
python
from openai import OpenAI
 
client = OpenAI()
resp = client.chat.completions.create(
    model="claude-sonnet-4-5",   # routed to Anthropic by the gateway
    messages=[{"role": "user", "content": "hello"}],
)

Every proxied call becomes a fully-attributed span with constitutional rules evaluated server-side. Configure the upstream Anthropic key via the AUDITTRAIL_GATEWAY_ANTHROPIC_KEY env var (Gateway proxy) or a stored agent secret; envelope and error semantics live in Gateway proxy. (BYOK keys back the Operations Assistant only — the gateway never reads them.)

Gotchas

  • Anthropic requires max_tokens on messages.create — the wrapper passes your params through untouched, so the usual client-side validation still applies.
  • Through the gateway you use the OpenAI message shape even for Claude models (the gateway translates); through the wrapper you use Anthropic's native shape.
  • A claude-* request with no Anthropic key configured server-side is rejected with 400 unsupported_model — the gateway never fabricates a response when a real key is expected.