pi-lemonade-link 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,16 +10,19 @@ No hardcoded endpoints, no manual model lists. One extension, five capabilities:
10
10
  1. **Live model discovery** — every chat model your lemonade box advertises shows
11
11
  up in `/model` automatically, annotated with whether it's loaded right now.
12
12
  2. **Nine agent tools** — transcription, image generation/editing/upscaling,
13
- text-to-speech, music/SFX, 3D meshes, and text classification, all callable
13
+ text-to-speech (incl. voice cloning + voice design), music/SFX, 3D meshes,
14
+ and text classification (fixed-label + zero-shot), all callable
14
15
  by the LLM, all model-aware.
15
16
  3. **A setup menu** — `/lemonade-setup` opens a navigable TUI for status,
16
- discovery, configuration, model management (live-progress pulls, Hugging
17
- Face installs), and live log streaming.
17
+ discovery, configuration, a live model browser (inline status, type-to-
18
+ search, contextual actions, animated busy markers with Esc-to-detach),
19
+ download-job management, recipe-backend installs, model updates, Hugging
20
+ Face installs, and live log streaming.
18
21
  4. **A lemonade status bar** — while a lemonade model is active, an extra
19
22
  below-editor row appears (your footer is never touched): instance name,
20
23
  tok/s and prefix-cache hit % derived locally from the session's own
21
- messages, plus polled busy/queue, CPU/GPU/NPU and VRAM from the active
22
- instance.
24
+ messages, plus polled busy/queue, whole-box active requests + live tok/s,
25
+ CPU/GPU/NPU and VRAM from the active instance.
23
26
  Switching to a non-lemonade model removes the row.
24
27
  5. **Harness self-awareness** — every chat, including virgin ones, is told
25
28
  where its lemonade machinery lives, so the agent can operate it directly.
@@ -186,7 +189,7 @@ Per tool:
186
189
  | `upscale_image` | Image → 4x PNG | arg → `defaultUpscaleModel` (RealESRGAN-x4plus) | PNG on disk + path | needs an upscale model pulled on the server; `-anime` variant exists for art. Sends the image as base64 JSON, not multipart |
187
190
  | `text_to_speech` | Text → spoken audio | arg → first model labeled `tts` (OpenMOSS-TTS on current builds) | mp3/wav on disk + path | if the TTS model isn't pulled, the request can trigger a slow auto-pull that outlasts the request — pull it via the setup menu first. `voice`/`speed`/`response_format` supported |
188
191
  | `generate_audio` | Prompt → music / SFX | arg → first model labeled `music`/`sfx`/`audio` | wav on disk + path | ACE-Step for music (optional `lyrics` with `[verse]`/`[chorus]` tags = sung vocals; omit = instrumental), ThinkSound for SFX. Not downloaded by default — pull first |
189
- | `classify_text` | Text → ranked label confidences | arg → `defaultClassifierModel` → first catalog model with the `onnxruntime` recipe | inline text readout | encoder classifiers (phishing, PII, prompt-injection...) — millisecond inference in its own classification slot; scores returned highest-first, so the top line is the verdict. Pull classifiers via the setup menu or HF install |
192
+ | `classify_text` | Text → ranked label confidences | arg → `defaultClassifierModel` → first catalog model with the `onnxruntime` recipe (or a `zero-shot` decision model when `labels` is passed) | inline text readout | fixed-label encoder classifiers (phishing, PII, prompt-injection — their label set is baked in) and zero-shot decision models (labels sent per request); scores returned highest-first, so the top line is the verdict. Pull classifiers via the setup menu or HF install |
190
193
  | `generate_3d_model` | Image → textured `.glb` | arg → first model labeled `3d` (TRELLIS-3D) | .glb on disk + path | minutes per mesh; `resolution` 512/1024/1536; needs TRELLIS pulled. TUI cannot render it — open the file in a 3D viewer |
191
194
 
192
195
  **How `classify_text` handles multiple classifiers and modalities.** Each
@@ -278,8 +281,9 @@ and the normal menu takes over once the first instance exists.
278
281
  | Menu | What you can do |
279
282
  |---|---|
280
283
  | **Server status** | The complete state of the box, grouped by the endpoint each metric came from — every server metric flat on one **live** panel that re-fetches every `statusPollMs` (default 2 s) while open, with each snapshot timestamped in the header; a transient fetch failure keeps the last good snapshot. Scrollable (wrap-aware `↑↓/j/k/pgup/pgdn/home/end` scrolling + mouse wheel, `q`/`esc`/`enter` return; position indicator in the footer). With multiple instances configured, `n`/`p` cycles between boxes without leaving the view — the title names the instance shown, and the menu's active instance follows it on exit. Sections: `/v1/health` (loaded models with busy/streaming/backend-health/pid/slot-pool, per-type slot limits, pinned counts, telemetry state), `/v1/system-stats` (CPU/RAM used-total-%, GPU, VRAM, NPU), `/v1/stats` (last-request tok/s, TTFT, in/out tokens, prefix-cache hit rate, lifetime token/request counters, routing decisions), `/v1/system-info` (CPU cores/threads, OS, GPU/NPU inventory incl. NPU power mode and TOPS, model-storage drive usage), and `/metrics` (llama.cpp backend: request queue depth, busy slots per decode, peak sequence length). Each section degrades to an "(unreachable)" line independently — one dead endpoint never blanks the panel |
281
- | **Server settings** | Discover servers (UDP beacon + HTTP fallback), edit base URL, edit API key, test connection |
282
- | **Model management** | List catalog (including not-yet-downloaded registry entries), load / unload, pull (download) with live progress + esc-to-cancel, install from Hugging Face (search → pick variant → install as `user.*`), delete, change context size (unload → reload with `ctx_size`, saved), toggle chat-only filter, refresh provider |
284
+ | **Server settings** | Discover servers (UDP beacon + HTTP fallback), edit base URL, edit API key, edit admin key (for `/internal/*`: pin, bulk model sync), test connection |
285
+ | **Model management** | **Model browser**: one live list of every model — downloaded or not — with inline status (`●` loaded · `○` downloaded · `◌` not on disk · `↓` downloading % · `⤴` update available · `★` featured); **type to search** (substring over name + description, `⌫` edits, `esc` clears the filter first), `ctrl+t` toggles all ⇄ downloaded-only, and the list refreshes underneath you every ~2 s. Selecting a model opens its **contextual actions**: view details (checkpoints, launch command, load state), load (animated busy marker with live server-side load status, `esc` continues in background), unload, pin/unpin, pull / update (live progress + esc-cancel), recipe-options editor, delete (typed phrase). Plus: **Downloads** (server-owned job list — live, cancel/pause/remove/retry, bulk-clear stopped jobs; terminal jobs are auto-removed so they never linger), **Install from Hugging Face** (search → pick variant → install as `user.*`), **Check for model updates** (report, then bulk sync via the admin key or update one-by-one with plain pulls), chat-only filter toggle, refresh provider |
286
+ | **Backends** | The recipe × backend inventory from system-info (installed / installable / unsupported, tier, version) — install with dry-run preview + live download progress, uninstall, `ctrl`-free type-to-search across every recipe:backend. Guest-tier note: models whose recipe has only guest backends stay hidden from the catalog until one is installed |
283
287
  | **Transcription settings** | Default Whisper model, endpoint path, smoke-test a file |
284
288
  | **Live server logs** | WebSocket stream of the server's log: full snapshot backlog (up to 5000 entries) then live entries as they happen; Esc to close |
285
289
  | **Spec & version check** | The three drift tiers, interactive: docs-vs-upstream status (TUI-only), live per-instance server versions beside the verified build and the latest upstream release, re-check now, one-keystroke docs re-sync (re-downloads upstream docs into the extension's docs/ folder — the code is not updated), `specCheck` / `serverVersionCheck` / `upstreamVersionCheck` toggles |
@@ -289,9 +293,14 @@ Notes on the destructive and slow paths:
289
293
  - **Delete** requires two gates: a confirm dialog, then typing the exact phrase
290
294
  `i want to delete <model-id>` — three attempts allowed, each prompt shows
291
295
  chances remaining, and Esc aborts immediately.
292
- - **Change context size** prefills the model's *current* context (from live
293
- health), accepts `32k`, `1m`, or raw token counts, and warns that the model
294
- is unloaded and reloaded (the new `ctx_size` is saved for future loads).
296
+ - **Change context size / recipe options** is a per-model editor over
297
+ `GET/POST/DELETE /v1/models/{id}/options`: every option key with its
298
+ saved/effective/default values side by side; edits save immediately
299
+ (merge — untouched keys keep their values; empty/`auto` clears a key,
300
+ `ctx_size: -1` = auto-size, backend keys get a menu of what this system
301
+ supports), and a loaded model is offered a reload to apply. Works on
302
+ unloaded models too — the options take effect at the next load. The old
303
+ unload → reload-with-ctx hack is retired; this is strictly more capable.
295
304
  - **Pull** uses lemonade's server-owned download jobs: a live progress view
296
305
  (percent, bytes, per-file status, updated every second) with **Esc to cancel**
297
306
  (via `/v1/downloads/control`). Blocking pull is kept only as a fallback for
@@ -375,6 +384,7 @@ The full shape (values shown are the built-in defaults):
375
384
  "classifyPath": "/v1/classify",
376
385
  "beaconPort": 13305,
377
386
  "chatOnly": true,
387
+ "cacheOnOutage": false,
378
388
  "defaultTranscriptionModel": "Whisper-Large-v3",
379
389
  "defaultImageModel": "",
380
390
  "defaultUpscaleModel": "RealESRGAN-x4plus",
@@ -401,16 +411,18 @@ The full shape (values shown are the built-in defaults):
401
411
  |---|---|
402
412
  | `servers` | **Required** — the only instance store: `[{ "name", "baseUrl", "apiKey"?, "description"? }]`. May be empty on a fresh install (the first `/lemonade-setup` run offers a wizard); the FIRST entry is the default instance (targeted when tools' `server` argument is omitted); reordering changes the default. Each registers as a `lemonade-<name>` provider. |
403
413
  | `apiKey` | Shared fallback `Authorization: Bearer …` for instances without their own. A dummy value works for auth-less servers (pi requires non-empty auth to list models). |
404
- | `*Path` | API endpoint paths, in case a future lemonade changes them. |
414
+ | `adminApiKey` | Key for `/internal/*` endpoints (pin/unpin, bulk model sync) on servers that set `LEMONADE_ADMIN_API_KEY`. Empty = fall back to `apiKey`. Per-instance override lives on the server entry, same fallback chain. |
415
+ | `*Path` | API endpoint paths, in case a future lemonade changes them (incl. `modelOptionsPath` with its `{id}` placeholder). |
405
416
  | `chatOnly` | Filter the provider down to chat-capable models. |
406
- | `defaultTranscriptionModel` / `defaultImageModel` / `defaultUpscaleModel` / `defaultClassifierModel` | Fixed model ids for the tools. Empty = auto-pick from the live catalog (by label, or by `onnxruntime` recipe for classifiers). |
417
+ | `cacheOnOutage` | **Outage cache**: when a probe can't reach an instance, `/model` lists its last good catalog — persisted on every successful probe, provenance-marked `(cached <time>)`, warned at session start, and re-synced automatically (prompt submits, model selections, session starts, plus the status bar's own health poll) with a `+new −gone` diff notice once the box answers. Once an instance is known down (durable flag from the last failed probe), the next startup serves the cached listing **instantly — no probe wait** and reconciles in the background, so the down-box stall only ever bites once per outage, at the transition into it. `false` (default) keeps the fully-honest empty listing. Manage via `/lemonade-setup` → *Catalog cache*; force a re-probe with *Refresh connection*. |
418
+ | `defaultTranscriptionModel` / `defaultImageModel` / `defaultUpscaleModel` / `defaultClassifierModel` | Fixed model ids for the tools. Empty = auto-pick from the live catalog (by label; classifiers prefer `onnxruntime` encoders, or `zero-shot`-labeled decision models when `labels` is passed). |
407
419
  | `outputDir` | Where generated files (images, audio, meshes) are saved. Empty = agent's working directory. |
408
420
  | `*TimeoutMs` | Per-operation timeouts. `pullTimeoutMs` only caps the *blocking* pull fallback — normal pulls use download jobs with live progress. |
409
421
  | `statusPollMs` | How often the setup-menu status panel re-fetches while open (live refresh). `0` = static snapshot. |
410
422
  | `statusBar` | Show the below-editor lemonade status bar while a lemonade model is active (see *Lemonade status bar*). |
411
423
  | `barPollMs` | Server-poll cadence for the status bar's busy/queue + CPU/GPU/NPU/VRAM segments. `0` = local metrics only (instance, tok/s, cache-hit %). |
412
424
  | `specCheck` / `specCheckCooldownMs` / `specCheckTimeoutMs` | Docs-freshness check: the `docs/` snapshot is compared against upstream `lemonade-sdk/lemonade` by git blob SHA — **TUI-only status, no startup warning** (extension ↔ server agreement is what matters; see *Keeping the specs honest*); the verdict is durable for `specCheckCooldownMs` (default 24 h, also the upstream-release probe's throttle). |
413
- | `serverVersionCheck` | **Tier 1, startup warning**: `/v1/health` self-reports the server version; any instance reporting a version other than the build this extension was verified against (`v11.7.0` — a constant in the extension code, not a setting) warns **with direction**: server newer → check for an extension update; server older → update the server. |
425
+ | `serverVersionCheck` | **Tier 1, startup warning**: `/v1/health` self-reports the server version; any instance reporting a version other than the build this extension was verified against (`v2026.46.2` — a constant in the extension code, not a setting; dev builds like `2026.46.2~1719.034d3f52` count as their release) warns **with direction**: server newer → check for an extension update; server older → update the server. |
414
426
  | `upstreamVersionCheck` | **Tier 2, info notice**: servers older than the latest published lemonade release (probed via GitHub, throttled) get a one-line "a server update is available" notice — **deduplicated to once per (instance, release)**, so it never re-fires on every session for the same release; the TUI always shows current state. Default on; separately toggleable. |
415
427
 
416
428
  ## Offline & unreachable networks
@@ -432,6 +444,18 @@ WAN, VPN down, box asleep):
432
444
  (`Error: Model "lemonade/<id>" not found`), and resume working once the box
433
445
  is back and a Refresh has re-registered it. Non-reachable chat requests are
434
446
  the honest outcome; phantom listings are never shown.
447
+ - **`cacheOnOutage: true` softens the offline cliff**: instead of the empty
448
+ listing, `/model` shows the instance's last good catalog — provenance-marked
449
+ `(cached <time>)` in the model name, warned once per session start, and
450
+ automatically re-synced (with a `+new −gone` diff notice) on prompt submits,
451
+ model selections, session starts, and the status bar's own health poll.
452
+ Pinned sessions then resolve and soft-fail at send time instead of
453
+ hard-failing model resolution. `/lemonade-setup` → *Refresh connection*
454
+ forces an immediate re-probe; *Catalog cache* shows/clears the snapshots.
455
+ Once an instance is known down, the flag makes the next startup **instant**:
456
+ the cached listing is served with zero probe wait and reconciled by a
457
+ background probe — the `discoveryTimeoutMs` stall only happens at the
458
+ transition into an outage, never on startups after it.
435
459
  - **Tools fail with actionable text, not cryptic errors**: every tool detects
436
460
  the unreachable server and returns the same message — *where* it tried to
437
461
  connect and *what to do about it* (reconnect, or point the extension at a
@@ -531,6 +555,8 @@ uses:
531
555
  | [`docs/README.md`](./docs/README.md) | Spec index and design philosophy |
532
556
  | [`docs/openai.md`](./docs/openai.md) | OpenAI-compatible surface: chat/completions, embeddings, audio (transcription, speech, generations), images (generation/edit/variation/upscale), realtime, `/v1/models` + labels taxonomy |
533
557
  | [`docs/lemonade.md`](./docs/lemonade.md) | Lemonade-specific surface: load/unload/pull/delete, download jobs + control, registry search + pull variants, health/stats/system-stats/system-info, classify, audio/3D generation, log streaming, job engine, install/uninstall |
558
+ | [`docs/router.md`](./docs/router.md) | Router API: `collection.router` models and routing policies |
559
+ | [`docs/internal.md`](./docs/internal.md) | Internal API: aliases, model sync, telemetry — used by the desktop app; versioned separately from the public surface |
534
560
  | [`docs/mcp.md`](./docs/mcp.md) | The MCP gateway (lemonade as an MCP server) |
535
561
  | [`docs/ollama.md`](./docs/ollama.md), [`docs/anthropic.md`](./docs/anthropic.md), [`docs/llamacpp.md`](./docs/llamacpp.md) | Other compatibility surfaces (rerank, slots, etc.) |
536
562
 
@@ -548,7 +574,7 @@ Drift is watched **in tiers, ordered by what actually matters at runtime**:
548
574
 
549
575
  1. **Extension ↔ server sync (startup warning).** Every registration and
550
576
  refresh compares each instance's live `/v1/health` version against the
551
- build this extension was verified against (`v11.7.0` — a constant in the
577
+ build this extension was verified against (`v2026.46.2` — a constant in the
552
578
  extension code, **not a user setting**: it is a property of the code,
553
579
  updated with each extension release). A mismatch is the one signal that
554
580
  means *endpoints may have changed for this pairing*, so it warns —
@@ -559,7 +585,7 @@ Drift is watched **in tiers, ordered by what actually matters at runtime**:
559
585
  default, separately toggleable).** The latest published lemonade release
560
586
  is probed via GitHub (throttled, durable, silent on network failure); any
561
587
  server older than it gets a single info line — *"instance 'x' runs
562
- lemonade v11.7.0; the latest published release is v11.9.0 — a server
588
+ lemonade v2026.44.1; the latest published release is v2026.46.2 — a server
563
589
  update is available."* Much lower tier: an older server isn't broken,
564
590
  it's just behind. The notice is **deduplicated to once per (instance,
565
591
  release)** — it fires when a new upstream release first appears, never
@@ -585,7 +611,7 @@ release.
585
611
  ## Extension version & provider API
586
612
 
587
613
  This extension's version (`version` in `package.json`) and the lemonade
588
- server build it was verified against (`11.7.0`) are recorded together in
614
+ server build it was verified against (`2026.46.2`) are recorded together in
589
615
  the `provider` block of `package.json` and in the
590
616
  `EXTENSION_CONFIRMED_SERVER_VERSION` constant in `index.ts` (which drives
591
617
  the startup version-drift warning). The server status panel and the
@@ -609,8 +635,10 @@ and server-version checks (see *Keeping the specs honest*) are what catch
609
635
 
610
636
  ## Lemonade behavior reference
611
637
 
612
- Empirically confirmed against lemonade 11.7.0 (cross-checked with the
613
- [official endpoint spec](https://lemonade-server.ai/docs/api/)):
638
+ Empirically confirmed against lemonade 2026.46.2 (cross-checked with the
639
+ [official endpoint spec](https://lemonade-server.ai/docs/api/) — which the
640
+ server now also serves itself at `GET /v1/docs`, so the running build's
641
+ reference is always one curl away):
614
642
 
615
643
  - **Auto-loading.** A request for an unloaded model triggers an automatic load
616
644
  attempt. If the model's slot is free or holds an unpinned model, lemonade
@@ -620,8 +648,27 @@ Empirically confirmed against lemonade 11.7.0 (cross-checked with the
620
648
  - **Per-type slots.** The server holds one slot per model type (llm,
621
649
  transcription, image, embedding, …), so Whisper can be loaded alongside your
622
650
  chat model.
623
- - **change-ctx.** Implemented as unload → reload with `ctx_size` +
624
- `save_options: true`, which persists the choice for future loads.
651
+ - **change-ctx & friends.** Per-model recipe options (ctx size, backend,
652
+ args, evict timeouts) are edited through `/v1/models/{id}/options` — saved
653
+ without loading, merged per key, applied to a loaded model by a plain
654
+ reload (`POST /v1/load` reloads a model whose load-time options changed).
655
+ - **Pinning.** `POST /internal/pin` flips a loaded model's pinned flag in
656
+ place (no reload); it demands `LEMONADE_ADMIN_API_KEY` when the server sets
657
+ one — configure `adminApiKey` or every pin attempt fails with an actionable
658
+ admin-key message.
659
+ - **Model updates.** `POST /v1/models/check-updates` reports newer upstream
660
+ commits (plain key); updating is either a bulk `/internal/models/sync`
661
+ (admin key) or plain per-model re-pulls. Re-pulling a model with a stale
662
+ errored job RESUMES the job (status flips back to `downloading`) — verified
663
+ live.
664
+ - **Download-job hygiene.** The server keeps errored/cancelled jobs in
665
+ `GET /v1/downloads` until a client removes them; this extension now removes
666
+ the ones it drove to a terminal outcome (and offers bulk-clear in the
667
+ Downloads view), so dead jobs no longer linger forever.
668
+ - **Backends.** `GET /v1/system-info` reports the full recipe × backend matrix
669
+ (state: installed/installable/unsupported, tier, version, format);
670
+ `POST /v1/install` (+`/dry-run`) and `/v1/uninstall` manage them, and
671
+ installs flow through the same `/v1/downloads` job machinery as pulls.
625
672
  - **Status panel sources.** All five metric endpoints are live-confirmed:
626
673
  `/v1/health` (incl. per-model `is_busy`/`is_streaming`/`backend_health`/
627
674
  `slot_pool`/`residency_class`/`last_use`/`pid` and `pinned_models` counters),
package/docs/README.md CHANGED
@@ -18,5 +18,28 @@ This spec details all supported endpoints. It is organized into pages that corre
18
18
  | [MCP Gateway](./mcp.md) | Use this to expose Lemonade as a Model Context Protocol server (POST /mcp). |
19
19
  | [llama.cpp-Specific API](./llamacpp.md) | Reference for llama.cpp-specific compatibility and conventions. |
20
20
  | [Lemonade-Specific API](./lemonade.md) | Local-first API for managing lifecycle, configuration, backends, etc. |
21
+ | [Router API](./router.md) | How `collection.router` models route requests, and how to test a routing policy. |
22
+ | [Internal API](./internal.md) | Control endpoints for clients bundled with the server, secured by `LEMONADE_ADMIN_API_KEY`. |
21
23
 
22
24
  A running server also serves these pages itself: [`GET /v1/docs`](./lemonade.md#get-v1docs) lists what it has and [`GET /v1/docs/{page}`](./lemonade.md#get-v1docspage) returns one, so the reference always matches the installed version and stays available offline.
25
+
26
+ ## Authentication
27
+
28
+ When `LEMONADE_API_KEY` is set, clients send it in the `Authorization` header as a Bearer token:
29
+
30
+ ```bash
31
+ curl http://localhost:13305/v1/models -H "Authorization: Bearer $LEMONADE_API_KEY"
32
+ ```
33
+
34
+ Each route says whether it needs a key. The internal routes take `LEMONADE_ADMIN_API_KEY` when it is set, and `LEMONADE_API_KEY` otherwise; the admin key also works on every other route. Lemonade reads no other header, so an Anthropic SDK client passes the key as `auth_token`, not `api_key`. The WebSocket APIs take the key as an `api_key` query parameter instead. See [API Key and Security](../guide/configuration/README.md#api-key-and-security) for every combination of the two keys.
35
+
36
+ ## Errors
37
+
38
+ Each route lists the errors it answers with in its Errors table. These come from the server before a request reaches a route, so no route lists them:
39
+
40
+ | Status | Body | When |
41
+ |--------|------|------|
42
+ | `401` | `{"error": "Invalid or missing API key"}`, or `"Invalid or missing admin API key"` for an internal route | The request lacks the key its route needs |
43
+ | `403` | `{"error": "Origin not allowed"}` | The `Origin` header names an origin that [`allowed_origins`](../guide/configuration/README.md) does not allow |
44
+ | `404` | `{"error": {"message": "The requested endpoint does not exist", "type": "not_found", "path"}}` | No route matches the path |
45
+ | `405` | `{"error": "Method Not Allowed. Use POST for this endpoint"}` | A `GET` reaches a `POST`-only route under `/v0/`, `/v1/`, `/api/v0/` or `/api/v1/` |
package/docs/anthropic.md CHANGED
@@ -1,11 +1,188 @@
1
1
  # Anthropic-Compatible API
2
2
 
3
- Lemonade supports an initial Anthropic Messages compatibility endpoint for applications that call Claude-style APIs.
3
+ Lemonade serves the Anthropic Messages API for applications that call Claude-style APIs.
4
4
 
5
- | Endpoint | Status | Notes |
6
- |----------|--------|-------|
7
- | `POST /v1/messages` | Supported | Supports both streaming and non-streaming. Query params like `?beta=true` are accepted. |
5
+ <!-- BEGIN GENERATED: anthropic.summary -->
6
+ | Method | Endpoint | Description |
7
+ |--------|----------|-------------|
8
+ | `POST` | [`/v1/messages`](#post-v1messages) | Generate the next assistant message |
9
+ <!-- END GENERATED: anthropic.summary -->
8
10
 
9
- Current scope focuses on message generation parity for common fields (`model`, `messages`, `system`, `max_tokens`, `temperature`, `stream`, and basic `tools`). Unsupported or unimplemented Anthropic-specific fields are ignored and surfaced via warning logs/headers.
11
+ <!-- BEGIN GENERATED: anthropic.messages -->
12
+ ## `POST /v1/messages`
13
+ <sub>![Status](https://img.shields.io/badge/status-partially_available-yellow)</sub>
10
14
 
11
- Those limits apply only where Lemonade converts to and from the OpenAI shape. A cloud provider registered with `--wire-format anthropic` is relayed unconverted, so no field is dropped — see [Cloud Offload](../guide/configuration/cloud.md#providers-that-speak-the-anthropic-messages-format).
15
+ Generates the next assistant message for a conversation in the Anthropic Messages format.
16
+
17
+ Requires `LEMONADE_API_KEY` when it is set.
18
+
19
+ ### Parameters
20
+
21
+ | Parameter | Required | Description | Status |
22
+ |-----------|----------|-------------|--------|
23
+ | `model` | Yes | The model to run; loaded on first use. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
24
+ | `messages` | Yes | Conversation so far, as `user` and `assistant` messages. `content` is a string or an array of `text`, `image` (base64 source), `tool_use` and `tool_result` blocks. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
25
+ | `system` | No | System prompt, as a string or an array of `text` blocks. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
26
+ | `max_tokens` | No | Upper bound on generated tokens. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
27
+ | `temperature` | No | Sampling temperature. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
28
+ | `top_p` | No | Cumulative probability of the top tokens to consider during nucleus sampling, from `0.0` to `1.0`. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
29
+ | `top_k` | No | Number of top tokens to consider during sampling. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
30
+ | `stop_sequences` | No | Sequences where generation stops. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
31
+ | `stream` | No | `true` sends the response as server-sent events as it progresses; `false` sends one response once complete. Defaults to `false`. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
32
+ | `tools` | No | Tools the model may call, each with a `name`, `description` and `input_schema`. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
33
+ | `tool_choice` | No | `{"type": "auto"}`, `any`, `none`, or `tool` with a `name`. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
34
+ | `output_config` | No | `format` of type `json_schema` (with a `schema`) or `json_object` constrains the reply. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
35
+ | `thinking` | No | Not applied to local models: reasoning models think regardless. Qwen3 models skip their reasoning when the prompt ends with `/no_think`. | <sub>![Status](https://img.shields.io/badge/not_available-red)</sub> |
36
+ | `metadata` | No | Ignored for local models, with a warning. | <sub>![Status](https://img.shields.io/badge/not_available-red)</sub> |
37
+ | `context_management` | No | Ignored for local models, with a warning. | <sub>![Status](https://img.shields.io/badge/not_available-red)</sub> |
38
+ | `ctx_size` | No | Lemonade extension: context size to load the model with, when this request loads it. Ignored when the model is already loaded. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
39
+ | `beta` (query) | No | Accepted for Anthropic SDK compatibility. Values other than `true` add a warning; `true` is passed on to providers that are relayed. | <sub>![Status](https://img.shields.io/badge/available-green)</sub> |
40
+
41
+ Lemonade runs the request as an OpenAI chat completion and converts both ways. Some values it cannot convert, such as an unsupported content block type or `metadata`, are ignored and reported in the `X-Lemonade-Warning` header (joined with ` | `) and in a `warnings` array. Unknown fields are ignored without a warning. A cloud provider registered with `--wire-format anthropic` is relayed unconverted, so nothing is dropped; see [Cloud Offload](../guide/configuration/cloud.md#providers-that-speak-the-anthropic-messages-format).
42
+
43
+ Errors use Anthropic's shape, `{"type": "error", "error": {"type", "message"}}`.
44
+
45
+ ### Examples
46
+
47
+ #### Non-streaming
48
+
49
+ === "PowerShell"
50
+
51
+ ```powershell
52
+ Invoke-WebRequest `
53
+ -Uri "http://localhost:13305/v1/messages" `
54
+ -Method POST `
55
+ -Headers @{ "Content-Type" = "application/json" } `
56
+ -Body '{
57
+ "model": "Qwen3-0.6B-GGUF",
58
+ "max_tokens": 64,
59
+ "temperature": 0,
60
+ "messages": [{"role": "user", "content": "What is the capital of France? /no_think"}]
61
+ }'
62
+ ```
63
+
64
+ === "Bash"
65
+
66
+ ```bash
67
+ curl http://localhost:13305/v1/messages \
68
+ -H "Content-Type: application/json" \
69
+ -d '{
70
+ "model": "Qwen3-0.6B-GGUF",
71
+ "max_tokens": 64,
72
+ "temperature": 0,
73
+ "messages": [{"role": "user", "content": "What is the capital of France? /no_think"}]
74
+ }'
75
+ ```
76
+
77
+ **Response:** `200 OK`
78
+
79
+ ```json
80
+ {
81
+ "id": "chatcmpl-e1cbsIyQh8RNvDa8IFa7hUsiL7xxgEmv",
82
+ "type": "message",
83
+ "role": "assistant",
84
+ "model": "Qwen3-0.6B-GGUF",
85
+ "content": [{"type": "text", "text": "The capital of France is **Paris**."}],
86
+ "stop_reason": "end_turn",
87
+ "stop_sequence": null,
88
+ "usage": {"input_tokens": 19, "output_tokens": 14}
89
+ }
90
+ ```
91
+
92
+ #### Streaming
93
+
94
+ === "PowerShell"
95
+
96
+ ```powershell
97
+ Invoke-WebRequest `
98
+ -Uri "http://localhost:13305/v1/messages" `
99
+ -Method POST `
100
+ -Headers @{ "Content-Type" = "application/json" } `
101
+ -Body '{
102
+ "model": "Qwen3-0.6B-GGUF",
103
+ "max_tokens": 64,
104
+ "temperature": 0,
105
+ "messages": [{"role": "user", "content": "What is the capital of France? /no_think"}],
106
+ "stream": true
107
+ }'
108
+ ```
109
+
110
+ === "Bash"
111
+
112
+ ```bash
113
+ curl http://localhost:13305/v1/messages \
114
+ -H "Content-Type: application/json" \
115
+ -d '{
116
+ "model": "Qwen3-0.6B-GGUF",
117
+ "max_tokens": 64,
118
+ "temperature": 0,
119
+ "messages": [{"role": "user", "content": "What is the capital of France? /no_think"}],
120
+ "stream": true
121
+ }'
122
+ ```
123
+
124
+ **Response:** `200 OK`
125
+
126
+ ```text
127
+ event: message_start
128
+ data: {"type": "message_start", "message": {"content": [], "id": "chatcmpl-VoeIi1EHhQg4HDI3S7ehBxKOoUCjX2DI", "model": "Qwen3-0.6B-GGUF", "role": "assistant", "stop_reason": null, "stop_sequence": null, "type": "message", "usage": {"input_tokens": 0, "output_tokens": 0}}}
129
+ event: content_block_start
130
+ data: {"type": "content_block_start", "index": 0, "content_block": {"text": "", "type": "text"}}
131
+ event: content_block_delta
132
+ data: {"type": "content_block_delta", "index": 0, "delta": {"text": "The", "type": "text_delta"}}
133
+ ...
134
+ event: message_delta
135
+ data: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence": null}, "usage": {"input_tokens": 0, "output_tokens": 0}}
136
+ event: message_stop
137
+ data: {"type": "message_stop"}
138
+ ```
139
+
140
+ ### Response format
141
+
142
+ #### JSON
143
+
144
+ - `id` - The message's ID.
145
+ - `type` - Always `message`.
146
+ - `role` - Always `assistant`.
147
+ - `model` - The model that generated the message.
148
+ - `content` - The message's content blocks.
149
+ - `type` - `text` or `tool_use`. A relayed provider can add its own block types, such as `thinking`.
150
+ - `text` - In a `text` block: the text.
151
+ - `id` - In a `tool_use` block: the tool call's ID.
152
+ - `name` - In a `tool_use` block: the tool's name.
153
+ - `input` - In a `tool_use` block: the call's arguments.
154
+ - `stop_reason` - `end_turn`, `max_tokens` or `tool_use`.
155
+ - `stop_sequence` - The stop sequence that ended the message; always `null` for local models.
156
+ - `usage` - Token counts.
157
+ - `input_tokens` - Prompt tokens.
158
+ - `output_tokens` - Generated tokens.
159
+ - `warnings` - What Lemonade ignored or changed while converting; present only when there is something to report.
160
+
161
+ #### Event stream
162
+
163
+ - `type` - Matches the event's name: `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta`, `message_stop` or `error`. A relayed provider can also send `ping`.
164
+ - `message` - In `message_start`: the message, with empty `content` and zero `usage`.
165
+ - `index` - In `content_block_start`, `content_block_delta` and `content_block_stop`: the block's position in the message's `content`.
166
+ - `content_block` - In `content_block_start`: the block, with empty `text` or `input`.
167
+ - `delta` - In `content_block_delta`: the block's next `text_delta` text or `input_json_delta` partial JSON. In `message_delta`: the `stop_reason` and `stop_sequence`.
168
+ - `usage` - In `message_delta`: token counts. Both are `0` when the backend's stream carries no usage, as with llama.cpp.
169
+ - `warnings` - In `message_delta`: what Lemonade ignored while converting; present only when there is something to report.
170
+ - `error` - In `error`, sent when the backend or provider fails after the stream started: the error's `type` and `message`.
171
+
172
+ ### Errors
173
+
174
+ | Status | Code | When |
175
+ |--------|------|------|
176
+ | `400` | `invalid_json` | The body is not a JSON object |
177
+ | `400` | `missing_argument` | A required argument is missing |
178
+ | `400` | `invalid_argument` | An argument or a value nested in it has the wrong JSON type, or a value its schema does not list |
179
+ | `400` | | `model` is a cloud model whose `--wire-format anthropic` provider has an `http://` base URL and was not installed with `--allow-insecure-http` |
180
+ | `401` | | `model` is a cloud model whose `--wire-format anthropic` provider has no API key |
181
+ | `404` | | `model` fails to load for any reason other than a residency conflict, such as naming no model or a failed download |
182
+ | `409` | `router_residency_conflict` | Loading the requested model would evict a model that a `collection.router` model needs resident on the same NPU |
183
+ | `500` | | `model` is a cloud model whose `--wire-format anthropic` provider has no base URL |
184
+ | `500` | | `model` is a `--wire-format anthropic` cloud model with no `checkpoint` |
185
+ | `500` | | The backend reports an error; the backend's own status replaces this one when it sends one |
186
+ | `500` | | The request fails unexpectedly |
187
+ | `502` | | Without `stream`, the relayed cloud request fails or the provider answers with an error; the provider's own status and body replace this one when it answers |
188
+ <!-- END GENERATED: anthropic.messages -->