pi-lemonade-link 1.1.0 → 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 +54 -21
- package/docs/README.md +23 -0
- package/docs/anthropic.md +183 -6
- package/docs/internal.md +1080 -0
- package/docs/lemonade.md +2453 -1665
- package/docs/llamacpp.md +385 -252
- package/docs/mcp.md +232 -128
- package/docs/ollama.md +967 -15
- package/docs/openai.md +1734 -634
- package/docs/router.md +201 -0
- package/index.ts +1543 -227
- package/lemonade.example.json +16 -2
- package/package.json +3 -3
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,
|
|
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
|
|
17
|
-
|
|
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,
|
|
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
|
|
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** |
|
|
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**
|
|
293
|
-
|
|
294
|
-
|
|
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
|
|
@@ -402,17 +411,18 @@ The full shape (values shown are the built-in defaults):
|
|
|
402
411
|
|---|---|
|
|
403
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. |
|
|
404
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). |
|
|
405
|
-
|
|
|
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). |
|
|
406
416
|
| `chatOnly` | Filter the provider down to chat-capable models. |
|
|
407
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*. |
|
|
408
|
-
| `defaultTranscriptionModel` / `defaultImageModel` / `defaultUpscaleModel` / `defaultClassifierModel` | Fixed model ids for the tools. Empty = auto-pick from the live catalog (by label, or
|
|
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). |
|
|
409
419
|
| `outputDir` | Where generated files (images, audio, meshes) are saved. Empty = agent's working directory. |
|
|
410
420
|
| `*TimeoutMs` | Per-operation timeouts. `pullTimeoutMs` only caps the *blocking* pull fallback — normal pulls use download jobs with live progress. |
|
|
411
421
|
| `statusPollMs` | How often the setup-menu status panel re-fetches while open (live refresh). `0` = static snapshot. |
|
|
412
422
|
| `statusBar` | Show the below-editor lemonade status bar while a lemonade model is active (see *Lemonade status bar*). |
|
|
413
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 %). |
|
|
414
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). |
|
|
415
|
-
| `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 (`
|
|
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. |
|
|
416
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. |
|
|
417
427
|
|
|
418
428
|
## Offline & unreachable networks
|
|
@@ -545,6 +555,8 @@ uses:
|
|
|
545
555
|
| [`docs/README.md`](./docs/README.md) | Spec index and design philosophy |
|
|
546
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 |
|
|
547
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 |
|
|
548
560
|
| [`docs/mcp.md`](./docs/mcp.md) | The MCP gateway (lemonade as an MCP server) |
|
|
549
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.) |
|
|
550
562
|
|
|
@@ -562,7 +574,7 @@ Drift is watched **in tiers, ordered by what actually matters at runtime**:
|
|
|
562
574
|
|
|
563
575
|
1. **Extension ↔ server sync (startup warning).** Every registration and
|
|
564
576
|
refresh compares each instance's live `/v1/health` version against the
|
|
565
|
-
build this extension was verified against (`
|
|
577
|
+
build this extension was verified against (`v2026.46.2` — a constant in the
|
|
566
578
|
extension code, **not a user setting**: it is a property of the code,
|
|
567
579
|
updated with each extension release). A mismatch is the one signal that
|
|
568
580
|
means *endpoints may have changed for this pairing*, so it warns —
|
|
@@ -573,7 +585,7 @@ Drift is watched **in tiers, ordered by what actually matters at runtime**:
|
|
|
573
585
|
default, separately toggleable).** The latest published lemonade release
|
|
574
586
|
is probed via GitHub (throttled, durable, silent on network failure); any
|
|
575
587
|
server older than it gets a single info line — *"instance 'x' runs
|
|
576
|
-
lemonade
|
|
588
|
+
lemonade v2026.44.1; the latest published release is v2026.46.2 — a server
|
|
577
589
|
update is available."* Much lower tier: an older server isn't broken,
|
|
578
590
|
it's just behind. The notice is **deduplicated to once per (instance,
|
|
579
591
|
release)** — it fires when a new upstream release first appears, never
|
|
@@ -599,7 +611,7 @@ release.
|
|
|
599
611
|
## Extension version & provider API
|
|
600
612
|
|
|
601
613
|
This extension's version (`version` in `package.json`) and the lemonade
|
|
602
|
-
server build it was verified against (`
|
|
614
|
+
server build it was verified against (`2026.46.2`) are recorded together in
|
|
603
615
|
the `provider` block of `package.json` and in the
|
|
604
616
|
`EXTENSION_CONFIRMED_SERVER_VERSION` constant in `index.ts` (which drives
|
|
605
617
|
the startup version-drift warning). The server status panel and the
|
|
@@ -623,8 +635,10 @@ and server-version checks (see *Keeping the specs honest*) are what catch
|
|
|
623
635
|
|
|
624
636
|
## Lemonade behavior reference
|
|
625
637
|
|
|
626
|
-
Empirically confirmed against lemonade
|
|
627
|
-
[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):
|
|
628
642
|
|
|
629
643
|
- **Auto-loading.** A request for an unloaded model triggers an automatic load
|
|
630
644
|
attempt. If the model's slot is free or holds an unpinned model, lemonade
|
|
@@ -634,8 +648,27 @@ Empirically confirmed against lemonade 11.7.0 (cross-checked with the
|
|
|
634
648
|
- **Per-type slots.** The server holds one slot per model type (llm,
|
|
635
649
|
transcription, image, embedding, …), so Whisper can be loaded alongside your
|
|
636
650
|
chat model.
|
|
637
|
-
- **change-ctx
|
|
638
|
-
|
|
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.
|
|
639
672
|
- **Status panel sources.** All five metric endpoints are live-confirmed:
|
|
640
673
|
`/v1/health` (incl. per-model `is_busy`/`is_streaming`/`backend_health`/
|
|
641
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
|
|
3
|
+
Lemonade serves the Anthropic Messages API for applications that call Claude-style APIs.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
11
|
+
<!-- BEGIN GENERATED: anthropic.messages -->
|
|
12
|
+
## `POST /v1/messages`
|
|
13
|
+
<sub></sub>
|
|
10
14
|
|
|
11
|
-
|
|
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></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></sub> |
|
|
25
|
+
| `system` | No | System prompt, as a string or an array of `text` blocks. | <sub></sub> |
|
|
26
|
+
| `max_tokens` | No | Upper bound on generated tokens. | <sub></sub> |
|
|
27
|
+
| `temperature` | No | Sampling temperature. | <sub></sub> |
|
|
28
|
+
| `top_p` | No | Cumulative probability of the top tokens to consider during nucleus sampling, from `0.0` to `1.0`. | <sub></sub> |
|
|
29
|
+
| `top_k` | No | Number of top tokens to consider during sampling. | <sub></sub> |
|
|
30
|
+
| `stop_sequences` | No | Sequences where generation stops. | <sub></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></sub> |
|
|
32
|
+
| `tools` | No | Tools the model may call, each with a `name`, `description` and `input_schema`. | <sub></sub> |
|
|
33
|
+
| `tool_choice` | No | `{"type": "auto"}`, `any`, `none`, or `tool` with a `name`. | <sub></sub> |
|
|
34
|
+
| `output_config` | No | `format` of type `json_schema` (with a `schema`) or `json_object` constrains the reply. | <sub></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></sub> |
|
|
36
|
+
| `metadata` | No | Ignored for local models, with a warning. | <sub></sub> |
|
|
37
|
+
| `context_management` | No | Ignored for local models, with a warning. | <sub></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></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></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 -->
|