# Warlock AI Anthropic — full skills

> Package: `@warlock.js/ai-anthropic`

> Generated artifact. Concatenates every SKILL.md and reference file under `@warlock.js/ai-anthropic/skills/`. Re-run `node scripts/generate-llms.mjs` after any change.

## setup-anthropic  `@warlock.js/ai-anthropic/setup-anthropic/SKILL.md`

---
name: setup-anthropic
description: 'Wire @warlock.js/ai-anthropic — new AnthropicSDK({apiKey, baseURL?, provider?}) for Claude, .model({name, vision?, structuredOutput?, maxTokens?}). System-prompt hoisting, max_tokens required (default 4096), no first-party embeddings. Triggers: `AnthropicSDK`, `anthropic.model`, `anthropic.count`, `maxTokens`, `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-opus-4-7`; "wire claude into warlock agent", "configure anthropic provider", "use claude sonnet", "anthropic gateway baseURL"; typical import `import { AnthropicSDK } from "@warlock.js/ai-anthropic"`. Skip: embeddings — `@warlock.js/ai-openai/setup-openai/SKILL.md`; sibling adapters `@warlock.js/ai-openai`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `@anthropic-ai/sdk`; Vercel `@ai-sdk/anthropic`.'
---

# `@warlock.js/ai-anthropic`

Provider adapter that turns Anthropic's Messages API into a vendor-neutral `ModelContract`. Mirrors `@warlock.js/ai-openai` — same shape, Claude-specific wire mapping.

## Construction

```ts
import { AnthropicSDK } from "@warlock.js/ai-anthropic";

const anthropic = new AnthropicSDK({ apiKey: process.env.ANTHROPIC_API_KEY! });

// Proxied / gateway endpoints speaking the Anthropic protocol:
const proxied = new AnthropicSDK({
  apiKey: process.env.GATEWAY_KEY!,
  baseURL: "https://gateway.internal/anthropic",
  provider: "anthropic-proxy",
});
```

`AnthropicSDK` is a class with a long-lived `Anthropic` client. `provider` defaults to `"anthropic"`.

## Producing a model

```ts
anthropic.model({ name: "claude-sonnet-4-6" })                  // common case
anthropic.model({ name: "claude-haiku-4-5", temperature: 0.2 }) // sampling controls
anthropic.model({ name: "claude-opus-4-7", maxTokens: 8192 })   // raise the cap
```

## Capabilities — what's auto-set

| Flag | Default |
| --- | --- |
| `structuredOutput` | `true` (via Anthropic's native `output_config.format`) |
| `vision` | Inferred from model name. `true` for Claude 3 / 3.5 / 3.7 / 4 family; `false` for pre-3 and unknown. |

Explicit config always wins.

## Pricing & cost

Pricing is opt-in. Supply USD-per-million-token rates and every report this SDK's models produce carries `Usage.cost`; omit them and `cost` stays `undefined` (honest absence, never a false zero). Two declaration sites:

```ts
// SDK-level registry — one source of truth, keyed by model name:
const anthropic = new AnthropicSDK({
  apiKey,
  pricing: {
    "claude-haiku-4-5":  { input: 1, output: 5,  cachedInput: 0.1 },
    "claude-sonnet-4-6": { input: 3, output: 15, cachedInput: 0.3 },
  },
});

// Per-model override (multi-tenant / contract-specific rates):
anthropic.model({ name: "claude-sonnet-4-6", pricing: { input: 3, output: 15 } });
```

Resolution at `model()` time: per-model `pricing` > SDK registry entry for that name > `undefined`. `ModelPricing` is `{ input, output, cachedInput?, cachedOutput? }`. Anthropic meters cache **reads** — when present they surface as `usage.cachedTokens` and bill at the `cachedInput` rate (falling back to `input` when unset).

## `max_tokens` is required

Unlike OpenAI, Anthropic **requires** `max_tokens` on every request. Resolution: per-call `options.maxTokens` > `config.maxTokens` > **default `4096`**. A caller who never sets a cap still gets a complete answer instead of a 400.

## System prompt

Anthropic has no `"system"` role inside `messages`. The adapter hoists every neutral `role: "system"` message into the top-level `system` parameter (multiple system messages join with a blank line). Transparent to the agent.

## Tool calls

- Outgoing: vendor-neutral tools → Anthropic `tools` with `input_schema` (non-object schemas degrade to a parameterless object so registration never fails).
- Assistant tool calls in history → `assistant` message with an optional leading `text` block + one `tool_use` block per call.
- Tool results (`role: "tool"`) → a `user` turn carrying a single `tool_result` block keyed by `tool_use_id`.
- Response `tool_use` blocks → neutral `toolCalls`; `stop_reason: "tool_use"` → `finishReason: "tool_calls"`.

## Structured output

When the agent passes `responseSchema` and the model is `structuredOutput`-capable, an **object-root** schema is forwarded as `output_config: { format: { type: "json_schema", schema } }` (Anthropic native). Non-object schemas or `structuredOutput: false` omit it; the agent's soft system-prompt hint + client-side `validate()` still enforce shape.

## Multipart messages (vision)

`ContentPart[]` user content maps to Anthropic content blocks:

- `{ type: "text", text }` → `{ type: "text", text }`
- `{ type: "image", source: { url } }` → `{ type: "image", source: { type: "url", url } }`
- `{ type: "image", source: { base64, mediaType } }` → `{ type: "image", source: { type: "base64", media_type, data } }`

## Streaming

`model.stream()` drains `messages.create({ stream: true })`:

- `content_block_delta` text → `{ type: "delta", content }`
- `tool_use` blocks accumulate `input_json_delta` fragments and emit one consolidated `{ type: "tool-call", ... }` at `content_block_stop` (no partial-arg `{}` artifact — input is parsed once, whole)
- terminal `{ type: "done", finishReason, usage }` — `usage.input` from `message_start`, `usage.output` from `message_delta`, `total` computed

## Finish-reason mapping

`end_turn` / `stop_sequence` → `stop` · `max_tokens` → `length` · `tool_use` → `tool_calls` · `refusal` / `pause_turn` / unknown / null → `error`.

## Errors

Raw SDK errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy. Dispatch keys on `error.type` (Anthropic has no per-error machine `code`), falling back to HTTP status:

- `authentication_error` / `permission_error` / 401 / 403 → `ProviderAuthError`
- `rate_limit_error` / 429 → `ProviderRateLimitError` (+`retryAfter` from `retry-after`)
- `billing_error` → `QuotaExceededError`
- `invalid_request_error` with "prompt is too long" → `ContextLengthExceededError`, else `InvalidRequestError`
- 5xx / overloaded → `ProviderError`
- Connection timeouts → `ProviderTimeoutError`

## Token counting

```ts
await anthropic.count("some text")  // approximate heuristic, offline
```

## No embeddings

Anthropic ships no first-party embeddings API, so `AnthropicSDK` intentionally does **not** implement `embedder()` (the `SDKAdapterContract.embedder` slot is optional). Use [`@warlock.js/ai-openai`](@warlock.js/ai-openai/setup-openai/SKILL.md) (or another embeddings-capable adapter) for vectors.

## When NOT to use this skill

- Direct calls to `@anthropic-ai/sdk` without going through `@warlock.js/ai` agents.
- OpenAI / Bedrock / Gemini / Ollama models — those have their own adapter packages.

## See also

- [`@warlock.js/ai/run-ai-agent/SKILL.md`](@warlock.js/ai/run-ai-agent/SKILL.md)
- [`@warlock.js/ai/pick-ai-provider/SKILL.md`](@warlock.js/ai/pick-ai-provider/SKILL.md)
- [`@warlock.js/ai/handle-ai-errors/SKILL.md`](@warlock.js/ai/handle-ai-errors/SKILL.md)


