SPB Git

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%
9.7 KB

# Anthropic — API Research (Phase 0)

Researched: 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).

# 1. Base URL & endpoints

  • Base URL: https://api.anthropic.com/v1
  • Messages (chat): POST /v1/messagesNOT OpenAI-compatible; native client required
  • Model listing: GET /v1/models (and GET /v1/models/{id})
  • Token counting: POST /v1/messages/count_tokens (useful for cost estimates)
  • Batches/Files exist but are out of scope for the chat client.

# 2. Authentication

  • Header: x-api-key: <ANTHROPIC_API_KEY> (NOT Authorization: Bearer)
  • Required version header: anthropic-version: 2023-06-01 (this exact value — it is the current stable version string)
  • Content-Type: application/json
  • Optional anthropic-beta: <flag> for beta features (not needed for the app's core flows).

# 3. Chat model catalog

All 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 ✅.

Model ID Display name Context Max output $/1M in/out Thinking mode Effort param Status
claude-opus-5 Claude Opus 5 1M 128K 5.00 / 25.00 adaptive (on by default) low…max (all 5) Recommended default
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
claude-fable-5 Claude Fable 5 1M 128K 10.00 / 50.00 always on (omit param; disabled → 400) low…max Most capable; premium
claude-opus-4-8 Claude Opus 4.8 1M 128K 5.00 / 25.00 adaptive (off unless set) low…max Current-gen
claude-opus-4-7 Claude Opus 4.7 1M 128K 5.00 / 25.00 adaptive (off unless set) low…max Previous-gen
claude-opus-4-6 Claude Opus 4.6 1M 128K 5.00 / 25.00 adaptive or enabled+budget (deprecated) low/med/high/max Older
claude-sonnet-4-6 Claude Sonnet 4.6 1M 128K 3.00 / 15.00 adaptive or enabled+budget (deprecated) low/med/high/max Older
claude-opus-4-5-20251101 Claude Opus 4.5 200K 64K 5.00 / 25.00 (unverified) enabled + budget_tokens low/med/high Legacy
claude-sonnet-4-5-20250929 Claude Sonnet 4.5 1M 64K 3.00 / 15.00 enabled + budget_tokens Legacy
claude-haiku-4-5-20251001 Claude Haiku 4.5 200K 64K 1.00 / 5.00 enabled + budget_tokens Fast/cheap
claude-opus-4-1-20250805 Claude Opus 4.1 200K 32K 15.00 / 75.00 enabled + budget_tokens Deprecated (retires 2026-08-05)

Notes: 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.

# 4. Request/response format (Messages API — native, not OpenAI-compatible)

Key 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.

json
POST /v1/messages
{
  "model": "claude-opus-5",
  "max_tokens": 4096,
  "system": "You are a helpful assistant.",
  "messages": [
    {"role": "user", "content": [
      {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "<base64, no newlines>"}},
      {"type": "text", "text": "What is in this image?"}
    ]}
  ],
  "stream": true
}
  • 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"}}
  • 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.
  • 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.
  • Multi-turn: resend full history; pass assistant thinking blocks back unchanged on the same model.

# 5. Streaming (SSE) — named events, no [DONE]

"stream": true. Each SSE frame has an event: name AND a data: JSON whose type matches:

Event Payload
message_start {"message": {id, model, role, usage: {input_tokens, ...}}} — input token count arrives here
content_block_start `{"index", "content_block": {"type": "text"
content_block_delta `{"index", "delta": {"type": "text_delta", "text"}
content_block_stop {"index"}
message_delta {"delta": {"stop_reason", "stop_sequence"}, "usage": {"output_tokens"}}final output token count here
message_stop {} — end of stream (no [DONE] sentinel)
ping keepalive — ignore
error mid-stream error, e.g. {"error": {"type": "overloaded_error", ...}} — handle

Route thinking_delta into the collapsible "Thinking…" section; text_delta into the message body. Track block index to separate blocks.

# 6. Special parameters (per-model gating is critical)

  • Thinking config matrix (send exactly this or get 400s):
    • claude-fable-5: OMIT thinking entirely (always on) or {"type":"adaptive"}; disabled/budget_tokens → 400.
    • claude-opus-5: default adaptive; {"type":"adaptive"} or {"type":"disabled"} (disabled only allowed at effort ≤ high); budget_tokens → 400.
    • claude-sonnet-5: default adaptive; {"type":"adaptive"} or {"type":"disabled"}; budget_tokens → 400.
    • claude-opus-4-8 / -4-7: off unless {"type":"adaptive"} set; budget_tokens → 400.
    • claude-opus-4-6 / claude-sonnet-4-6: {"type":"adaptive"} recommended; {"type":"enabled","budget_tokens":N} deprecated but works.
    • Older (4.5 / haiku-4-5 / 4.1): {"type":"enabled","budget_tokens":N} required for thinking; N ≥ 1024 and < max_tokens.
    • To see thinking text on 4.7+/Sonnet 5/Opus 5/Fable 5, set "thinking": {"type":"adaptive","display":"summarized"} — default "omitted" streams empty thinking.
  • 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.
  • 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.
  • max_tokens required on every request; large values (>~16K) should always be streamed.
  • No assistant prefill on 4.6+ (400).
  • Prompt caching available via cache_control blocks (optional optimization; min cacheable prefix 512–4096 tokens depending on model).

# 7. Rate limits & errors

  • 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_..."}
  • HTTP: 400, 401, 403, 404, 413, 429 (retry-after header), 500, 529 overloaded (Anthropic-specific — retry with backoff).
  • 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-limits
  • Retry 429/500/529 with exponential backoff; never retry 4xx (except 408/429).

# 8. /models listing

  • 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).
  • 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.

# Catalog guidance for ModelCatalog / AnthropicClient

  • Default model: claude-sonnet-5 (balanced) with claude-opus-5 as the flagship option.
  • The client must gate: thinking config shape, effort support, and sampling params per model (matrix in §6) — encode these as capability flags in AIModel.
  • Auto-title generation: use claude-haiku-4-5-20251001.