spb/zyquo-cloud Public MIT
Native macOS AI chat client for 12 cloud providers — your keys, every cloud model, one beautiful chat.
Swift 97.4%
Shell 1.7%
Makefile 1%
1<!--2 anthropic.md3 Zyquo Cloud4 Author: Simon-Pierre Boucher5 Mail: contact@spboucher.ai6-->78# Anthropic — API Research (Phase 0)910Researched: 2026-07-30. Sources: https://platform.claude.com/docs/en/about-claude/models/overview.md , https://platform.claude.com/docs/en/pricing.md , https://platform.claude.com/docs/en/build-with-claude/streaming.md , https://platform.claude.com/docs/en/build-with-claude/adaptive-thinking.md , https://platform.claude.com/docs/en/api/errors.md , https://platform.claude.com/docs/en/api/rate-limits.md . Live model list verified against `GET /v1/models` with a real key on 2026-07-30 (`/tmp/zyquo-probe/anthropic.json`) — the live response includes `max_input_tokens`, `max_tokens`, and a full `capabilities` tree per model (authoritative below).1112## 1. Base URL & endpoints1314- Base URL: `https://api.anthropic.com/v1`15- Messages (chat): `POST /v1/messages` — **NOT OpenAI-compatible**; native client required16- Model listing: `GET /v1/models` (and `GET /v1/models/{id}`)17- Token counting: `POST /v1/messages/count_tokens` (useful for cost estimates)18- Batches/Files exist but are out of scope for the chat client.1920## 2. Authentication2122- Header: `x-api-key: <ANTHROPIC_API_KEY>` (NOT `Authorization: Bearer`)23- Required version header: `anthropic-version: 2023-06-01` (this exact value — it is the current stable version string)24- `Content-Type: application/json`25- Optional `anthropic-beta: <flag>` for beta features (not needed for the app's core flows).2627## 3. Chat model catalog2829All IDs verified live 2026-07-30. Context / max output come from the live `/v1/models` response. Pricing in USD per 1M tokens (input/output). All models: streaming ✅, tools/function calling ✅, vision (image input) ✅, PDF input ✅, structured outputs ✅.3031| Model ID | Display name | Context | Max output | $/1M in/out | Thinking mode | Effort param | Status |32|---|---|---|---|---|---|---|---|33| `claude-opus-5` | Claude Opus 5 | 1M | 128K | 5.00 / 25.00 | adaptive (on by default) | low…max (all 5) | **Recommended default** |34| `claude-sonnet-5` | Claude Sonnet 5 | 1M | 128K | 3.00 / 15.00 (intro 2.00/10.00 through 2026-08-31) | adaptive (on by default) | low…max | **Recommended balanced** |35| `claude-fable-5` | Claude Fable 5 | 1M | 128K | 10.00 / 50.00 | always on (omit param; `disabled` → 400) | low…max | Most capable; premium |36| `claude-opus-4-8` | Claude Opus 4.8 | 1M | 128K | 5.00 / 25.00 | adaptive (off unless set) | low…max | Current-gen |37| `claude-opus-4-7` | Claude Opus 4.7 | 1M | 128K | 5.00 / 25.00 | adaptive (off unless set) | low…max | Previous-gen |38| `claude-opus-4-6` | Claude Opus 4.6 | 1M | 128K | 5.00 / 25.00 | adaptive or `enabled`+budget (deprecated) | low/med/high/max | Older |39| `claude-sonnet-4-6` | Claude Sonnet 4.6 | 1M | 128K | 3.00 / 15.00 | adaptive or `enabled`+budget (deprecated) | low/med/high/max | Older |40| `claude-opus-4-5-20251101` | Claude Opus 4.5 | 200K | 64K | 5.00 / 25.00 (unverified) | `enabled` + `budget_tokens` | low/med/high | Legacy |41| `claude-sonnet-4-5-20250929` | Claude Sonnet 4.5 | 1M | 64K | 3.00 / 15.00 | `enabled` + `budget_tokens` | ❌ | Legacy |42| `claude-haiku-4-5-20251001` | Claude Haiku 4.5 | 200K | 64K | 1.00 / 5.00 | `enabled` + `budget_tokens` | ❌ | Fast/cheap |43| `claude-opus-4-1-20250805` | Claude Opus 4.1 | 200K | 32K | 15.00 / 75.00 | `enabled` + `budget_tokens` | ❌ | Deprecated (retires 2026-08-05) |4445Notes: date-suffixed aliases exist for the dated models (`claude-opus-4-5`, `claude-sonnet-4-5`, `claude-haiku-4-5` resolve); the 4.6+ IDs have **no** date suffix — never append one. `claude-mythos-5` exists but is invite-only (Project Glasswing) — exclude from catalog.4647## 4. Request/response format (Messages API — native, not OpenAI-compatible)4849Key differences from OpenAI: `system` is a **top-level parameter** (not a message role, though 4.8+/Opus 5/Fable 5 also accept mid-conversation `role:"system"` messages); `max_tokens` is **required**; message content is an array of typed content blocks; roles strictly alternate user/assistant.5051```json52POST /v1/messages53{54 "model": "claude-opus-5",55 "max_tokens": 4096,56 "system": "You are a helpful assistant.",57 "messages": [58 {"role": "user", "content": [59 {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "<base64, no newlines>"}},60 {"type": "text", "text": "What is in this image?"}61 ]}62 ],63 "stream": true64}65```6667- Response: `{"id", "type": "message", "role": "assistant", "model", "content": [{"type": "text", "text": "..."} | {"type": "thinking", "thinking": "...", "signature": "..."} | {"type": "tool_use", ...}], "stop_reason", "usage": {"input_tokens", "output_tokens", "cache_creation_input_tokens", "cache_read_input_tokens"}}`68- Vision block: `{"type": "image", "source": {"type": "base64", "media_type": "image/jpeg|image/png|image/gif|image/webp", "data": "<b64>"}}` (also `{"type": "url", "url": ...}`). Image block goes **before** the text block.69- `stop_reason` values: `end_turn`, `max_tokens`, `stop_sequence`, `tool_use`, `pause_turn`, `refusal` (check before reading content — Fable 5/Opus 5 classifiers can refuse with HTTP 200), `model_context_window_exceeded`.70- Multi-turn: resend full history; pass assistant `thinking` blocks back **unchanged** on the same model.7172## 5. Streaming (SSE) — named events, no [DONE]7374`"stream": true`. Each SSE frame has an `event:` name AND a `data:` JSON whose `type` matches:7576| Event | Payload |77|---|---|78| `message_start` | `{"message": {id, model, role, usage: {input_tokens, ...}}}` — input token count arrives here |79| `content_block_start` | `{"index", "content_block": {"type": "text"|"thinking"|"tool_use", ...}}` |80| `content_block_delta` | `{"index", "delta": {"type": "text_delta", "text"} | {"type": "thinking_delta", "thinking"} | {"type": "input_json_delta", "partial_json"} | {"type": "signature_delta", ...}}` |81| `content_block_stop` | `{"index"}` |82| `message_delta` | `{"delta": {"stop_reason", "stop_sequence"}, "usage": {"output_tokens"}}` — **final output token count here** |83| `message_stop` | `{}` — end of stream (no `[DONE]` sentinel) |84| `ping` | keepalive — ignore |85| `error` | mid-stream error, e.g. `{"error": {"type": "overloaded_error", ...}}` — handle |8687Route `thinking_delta` into the collapsible "Thinking…" section; `text_delta` into the message body. Track block `index` to separate blocks.8889## 6. Special parameters (per-model gating is critical)9091- **Thinking config matrix** (send exactly this or get 400s):92 - `claude-fable-5`: OMIT `thinking` entirely (always on) or `{"type":"adaptive"}`; `disabled`/`budget_tokens` → 400.93 - `claude-opus-5`: default adaptive; `{"type":"adaptive"}` or `{"type":"disabled"}` (disabled only allowed at effort ≤ high); `budget_tokens` → 400.94 - `claude-sonnet-5`: default adaptive; `{"type":"adaptive"}` or `{"type":"disabled"}`; `budget_tokens` → 400.95 - `claude-opus-4-8` / `-4-7`: off unless `{"type":"adaptive"}` set; `budget_tokens` → 400.96 - `claude-opus-4-6` / `claude-sonnet-4-6`: `{"type":"adaptive"}` recommended; `{"type":"enabled","budget_tokens":N}` deprecated but works.97 - Older (4.5 / haiku-4-5 / 4.1): `{"type":"enabled","budget_tokens":N}` required for thinking; N ≥ 1024 and < `max_tokens`.98 - To see thinking text on 4.7+/Sonnet 5/Opus 5/Fable 5, set `"thinking": {"type":"adaptive","display":"summarized"}` — default `"omitted"` streams empty thinking.99- **Effort**: `"output_config": {"effort": "low|medium|high|xhigh|max"}` (default high). Supported per the table in §3; errors on Sonnet 4.5/Haiku 4.5.100- **Sampling restrictions**: `temperature`/`top_p`/`top_k` are **removed (400)** on Opus 5, Fable 5, Opus 4.8, Opus 4.7; Sonnet 5 rejects non-default values; allowed on 4.6 and older (never send temperature AND top_p together on Claude 4+). Zyquo Cloud must hide these sliders for 4.7+ models.101- `max_tokens` required on every request; large values (>~16K) should always be streamed.102- No assistant prefill on 4.6+ (400).103- Prompt caching available via `cache_control` blocks (optional optimization; min cacheable prefix 512–4096 tokens depending on model).104105## 7. Rate limits & errors106107- Error body: `{"type": "error", "error": {"type": "invalid_request_error|authentication_error|permission_error|not_found_error|request_too_large|rate_limit_error|api_error|overloaded_error", "message": "..."}, "request_id": "req_..."}`108- HTTP: 400, 401, 403, 404, 413, 429 (retry-after header), 500, **529 overloaded** (Anthropic-specific — retry with backoff).109- Rate limits are tier-based per model: RPM + input-tokens/min (ITPM) + output-tokens/min (OTPM). Headers: `retry-after`, `anthropic-ratelimit-requests-remaining`, `anthropic-ratelimit-*-tokens-remaining/reset`. Docs: https://platform.claude.com/docs/en/api/rate-limits110- Retry 429/500/529 with exponential backoff; never retry 4xx (except 408/429).111112## 8. /models listing113114- `GET /v1/models` exists and is **rich**: `{"data": [{"type": "model", "id", "display_name", "created_at", "max_input_tokens", "max_tokens", "capabilities": {"image_input": {...}, "thinking": {"types": {"enabled", "adaptive"}}, "effort": {"low"…"max"}, "structured_outputs", "pdf_input", ...}], "has_more", "first_id", "last_id"}` — paginated (`after_id`).115- Use it for dynamic refresh: context window, output cap, thinking mode, and effort support can all be read live per model. 11 models returned on 2026-07-30.116117### Catalog guidance for ModelCatalog / AnthropicClient118119- Default model: `claude-sonnet-5` (balanced) with `claude-opus-5` as the flagship option.120- The client must gate: thinking config shape, effort support, and sampling params per model (matrix in §6) — encode these as capability flags in `AIModel`.121- Auto-title generation: use `claude-haiku-4-5-20251001`.122