local-lemonade 1.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 +520 -0
- package/docs/README.md +22 -0
- package/docs/anthropic.md +11 -0
- package/docs/lemonade.md +2537 -0
- package/docs/llamacpp.md +442 -0
- package/docs/mcp.md +199 -0
- package/docs/ollama.md +21 -0
- package/docs/openai.md +1192 -0
- package/index.ts +2374 -0
- package/lemonade.example.json +71 -0
- package/package.json +24 -0
package/docs/llamacpp.md
ADDED
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
# llama.cpp-Specific API
|
|
2
|
+
|
|
3
|
+
This page documents Lemonade's llama.cpp-specific compatibility surface.
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
| Method | Endpoint | Description | Modality |
|
|
8
|
+
|--------|----------|-------------|----------|
|
|
9
|
+
| `POST` | [`/v1/rerank`](#post-v1rerank) | Reranking | query + documents -> relevance-scored documents |
|
|
10
|
+
| `GET` | [`/v1/slots`](#get-v1slots) | Returns the current slots processing state | slots state |
|
|
11
|
+
| `POST` | [`/v1/slots/{id}?action=save`](#post-v1slotsidactionsave) | Save the prompt cache of the specified slot to a file | prompt cache |
|
|
12
|
+
| `POST` | [`/v1/slots/{id}?action=restore`](#post-v1slotsidactionrestore) | Restore the prompt cache of the specified slot from a file | prompt cache |
|
|
13
|
+
| `POST` | [`/v1/slots/{id}?action=erase`](#post-v1slotsidactionerase) | Erase the prompt cache of the specified slot | prompt cache |
|
|
14
|
+
| `POST` | [`/v1/tokenize`](#post-v1tokenize) | Tokenize a given text | tokenization |
|
|
15
|
+
|
|
16
|
+
## `POST /v1/rerank`
|
|
17
|
+
<sub></sub>
|
|
18
|
+
|
|
19
|
+
Reranking API for llama.cpp-compatible reranker models. You provide a query and a list of documents, and receive relevance scores for each document. Lemonade will load the requested model automatically if it is not already loaded.
|
|
20
|
+
|
|
21
|
+
> **Note:** This endpoint is part of Lemonade's llama.cpp compatibility layer. Internally, Lemonade forwards the request to llama.cpp's `/v1/rerank` endpoint.
|
|
22
|
+
|
|
23
|
+
> **Note:** Lemonade also accepts `/reranking` and `/reranker` as aliases — all three route to the same handler and behave identically.
|
|
24
|
+
|
|
25
|
+
> **Note:** The endpoint is available under all four path prefixes: `/api/v0/`, `/api/v1/`, `/v0/`, and `/v1/`.
|
|
26
|
+
|
|
27
|
+
> **Note:** This endpoint is only available for reranker-specific models using the `llamacpp` recipe, such as `bge-reranker-v2-m3-GGUF`.
|
|
28
|
+
|
|
29
|
+
### Parameters
|
|
30
|
+
|
|
31
|
+
| Parameter | Required | Description | Status |
|
|
32
|
+
|-----------|----------|-------------|--------|
|
|
33
|
+
| `query` | Yes | The search query text. | <sub></sub> |
|
|
34
|
+
| `documents` | Yes | Array of document strings to score against the query. | <sub></sub> |
|
|
35
|
+
| `model` | Yes | The reranking model to use. If not already loaded, Lemonade loads it before forwarding the request. | <sub></sub> |
|
|
36
|
+
|
|
37
|
+
### Example request
|
|
38
|
+
|
|
39
|
+
=== "PowerShell"
|
|
40
|
+
|
|
41
|
+
```powershell
|
|
42
|
+
Invoke-WebRequest `
|
|
43
|
+
-Uri "http://localhost:13305/v1/rerank" `
|
|
44
|
+
-Method POST `
|
|
45
|
+
-Headers @{ "Content-Type" = "application/json" } `
|
|
46
|
+
-Body '{
|
|
47
|
+
"model": "bge-reranker-v2-m3-GGUF",
|
|
48
|
+
"query": "What is the capital of France?",
|
|
49
|
+
"documents": [
|
|
50
|
+
"Paris is the capital of France.",
|
|
51
|
+
"Berlin is the capital of Germany.",
|
|
52
|
+
"Madrid is the capital of Spain."
|
|
53
|
+
]
|
|
54
|
+
}' -UseBasicParsing
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
=== "Bash"
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
curl -X POST http://localhost:13305/v1/rerank \
|
|
61
|
+
-H "Content-Type: application/json" \
|
|
62
|
+
-d '{
|
|
63
|
+
"model": "bge-reranker-v2-m3-GGUF",
|
|
64
|
+
"query": "What is the capital of France?",
|
|
65
|
+
"documents": [
|
|
66
|
+
"Paris is the capital of France.",
|
|
67
|
+
"Berlin is the capital of Germany.",
|
|
68
|
+
"Madrid is the capital of Spain."
|
|
69
|
+
]
|
|
70
|
+
}'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Response format
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"model": "bge-reranker-v2-m3-GGUF",
|
|
78
|
+
"object": "list",
|
|
79
|
+
"results": [
|
|
80
|
+
{
|
|
81
|
+
"index": 0,
|
|
82
|
+
"relevance_score": 8.60673713684082
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"index": 1,
|
|
86
|
+
"relevance_score": -5.3886260986328125
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"index": 2,
|
|
90
|
+
"relevance_score": -3.555561065673828
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"usage": {
|
|
94
|
+
"prompt_tokens": 51,
|
|
95
|
+
"total_tokens": 51
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Field Descriptions:**
|
|
101
|
+
|
|
102
|
+
- `model` - Model identifier used for reranking
|
|
103
|
+
- `object` - Type of response object, always `"list"`
|
|
104
|
+
- `results` - Array of all input documents with relevance scores
|
|
105
|
+
- `index` - Original index of the document in the input array
|
|
106
|
+
- `relevance_score` - Relevance score assigned by the model; higher means more relevant
|
|
107
|
+
- `usage` - Token usage statistics
|
|
108
|
+
- `prompt_tokens` - Number of tokens in the input
|
|
109
|
+
- `total_tokens` - Total tokens processed
|
|
110
|
+
|
|
111
|
+
> **Note:** Results are returned in input order. To rank documents by relevance, sort `results` by `relevance_score` in descending order on the client side.
|
|
112
|
+
|
|
113
|
+
## `GET /v1/slots`
|
|
114
|
+
<sub></sub>
|
|
115
|
+
|
|
116
|
+
Returns the current state of all processing slots in the llama.cpp server. Slots are parallel processing contexts that can handle multiple requests concurrently.
|
|
117
|
+
|
|
118
|
+
> **Note:** This endpoint is part of Lemonade's llama.cpp compatibility layer. Internally, Lemonade forwards the request to llama.cpp's `/slots` endpoint.
|
|
119
|
+
|
|
120
|
+
> **Note:** This endpoint is only available when a llama.cpp model is loaded.
|
|
121
|
+
|
|
122
|
+
> **Note:** This endpoint supports all four path prefixes: `/api/v0/slots`, `/api/v1/slots`, `/v0/slots`, and `/v1/slots`.
|
|
123
|
+
|
|
124
|
+
### Parameters
|
|
125
|
+
|
|
126
|
+
This endpoint accepts no parameters.
|
|
127
|
+
|
|
128
|
+
### Example request
|
|
129
|
+
|
|
130
|
+
=== "PowerShell"
|
|
131
|
+
|
|
132
|
+
```powershell
|
|
133
|
+
Invoke-WebRequest `
|
|
134
|
+
-Uri "http://localhost:13305/v1/slots" `
|
|
135
|
+
-Method GET -UseBasicParsing
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
=== "Bash"
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
curl http://localhost:13305/v1/slots
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Response format
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
[
|
|
148
|
+
{
|
|
149
|
+
"id": 0,
|
|
150
|
+
"state": "idle",
|
|
151
|
+
"next_token": {
|
|
152
|
+
"has_next_token": false,
|
|
153
|
+
"n_remain": 0,
|
|
154
|
+
"n_decoded": 0
|
|
155
|
+
},
|
|
156
|
+
"task_id": -1,
|
|
157
|
+
"cache_tokens": 1024
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"id": 1,
|
|
161
|
+
"state": "processing",
|
|
162
|
+
"next_token": {
|
|
163
|
+
"has_next_token": true,
|
|
164
|
+
"n_remain": 42,
|
|
165
|
+
"n_decoded": 15
|
|
166
|
+
},
|
|
167
|
+
"task_id": 123,
|
|
168
|
+
"cache_tokens": 512
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Field Descriptions:**
|
|
174
|
+
|
|
175
|
+
- `id` - Unique identifier for the slot
|
|
176
|
+
- `state` - Current processing state ("idle", "processing", etc.)
|
|
177
|
+
- `next_token` - Information about token generation state
|
|
178
|
+
- `has_next_token` - Whether more tokens are expected
|
|
179
|
+
- `n_remain` - Number of tokens remaining to generate
|
|
180
|
+
- `n_decoded` - Number of tokens already decoded
|
|
181
|
+
- `task_id` - Identifier of the current task being processed (-1 if idle)
|
|
182
|
+
- `cache_tokens` - Number of cached tokens in the slot's prompt cache
|
|
183
|
+
|
|
184
|
+
## `POST /v1/slots/{id}?action=save`
|
|
185
|
+
<sub></sub>
|
|
186
|
+
|
|
187
|
+
Save the prompt cache of a specific slot to a file. This allows you to persist the current context state for later restoration.
|
|
188
|
+
|
|
189
|
+
> **Note:** This endpoint is part of Lemonade's llama.cpp compatibility layer. Internally, Lemonade forwards the request to llama.cpp's `/slots/{id}?action=save` endpoint.
|
|
190
|
+
|
|
191
|
+
> **Note:** The llama.cpp server must be started with the `--slot-save-path` argument for save operations to work. See [Server Configuration](../guide/configuration/README.md) for details on configuring backend arguments.
|
|
192
|
+
>
|
|
193
|
+
> Example configuration:
|
|
194
|
+
> ```bash
|
|
195
|
+
> lemonade config set llamacpp.args="--slot-save-path /path/to/slot/saves"
|
|
196
|
+
> ```
|
|
197
|
+
|
|
198
|
+
> **Note:** This endpoint supports all four path prefixes: `/api/v0/slots/{id}`, `/api/v1/slots/{id}`, `/v0/slots/{id}`, and `/v1/slots/{id}`.
|
|
199
|
+
|
|
200
|
+
### Parameters
|
|
201
|
+
|
|
202
|
+
| Parameter | Required | Description | Status |
|
|
203
|
+
|-----------|----------|-------------|--------|
|
|
204
|
+
| `id` | Yes | The slot ID to save (path parameter). | <sub></sub> |
|
|
205
|
+
| `filename` | Yes | The filename where the slot cache should be saved (JSON body). | <sub></sub> |
|
|
206
|
+
|
|
207
|
+
### Example request
|
|
208
|
+
|
|
209
|
+
=== "PowerShell"
|
|
210
|
+
|
|
211
|
+
```powershell
|
|
212
|
+
Invoke-WebRequest `
|
|
213
|
+
-Uri "http://localhost:13305/v1/slots/0?action=save" `
|
|
214
|
+
-Method POST `
|
|
215
|
+
-Headers @{ "Content-Type" = "application/json" } `
|
|
216
|
+
-Body '{"filename": "my_conversation_cache.bin"}' -UseBasicParsing
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
=== "PowerShell (/api/v1)"
|
|
220
|
+
|
|
221
|
+
```powershell
|
|
222
|
+
Invoke-WebRequest `
|
|
223
|
+
-Uri "http://localhost:13305/api/v1/slots/0?action=save" `
|
|
224
|
+
-Method POST `
|
|
225
|
+
-Headers @{ "Content-Type" = "application/json" } `
|
|
226
|
+
-Body '{"filename": "my_conversation_cache.bin"}' -UseBasicParsing
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
=== "Bash"
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
curl -X POST "http://localhost:13305/v1/slots/0?action=save" \
|
|
233
|
+
-H "Content-Type: application/json" \
|
|
234
|
+
-d '{"filename": "my_conversation_cache.bin"}'
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Response format
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"id_slot": 0,
|
|
242
|
+
"filename": "my_conversation_cache.bin",
|
|
243
|
+
"n_saved": 1024
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Field Descriptions:**
|
|
248
|
+
|
|
249
|
+
- `id_slot` - The slot ID that was saved
|
|
250
|
+
- `filename` - The filename where the cache was saved
|
|
251
|
+
- `n_saved` - Number of tokens saved to the cache file
|
|
252
|
+
|
|
253
|
+
## `POST /v1/slots/{id}?action=restore`
|
|
254
|
+
<sub></sub>
|
|
255
|
+
|
|
256
|
+
Restore the prompt cache of a specific slot from a previously saved file. This allows you to resume a conversation or context from where you left off.
|
|
257
|
+
|
|
258
|
+
> **Note:** This endpoint is part of Lemonade's llama.cpp compatibility layer. Internally, Lemonade forwards the request to llama.cpp's `/slots/{id}?action=restore` endpoint.
|
|
259
|
+
|
|
260
|
+
> **Note:** The llama.cpp server must be started with the `--slot-save-path` argument for restore operations to work.
|
|
261
|
+
|
|
262
|
+
> **Note:** This endpoint supports all four path prefixes: `/api/v0/slots/{id}`, `/api/v1/slots/{id}`, `/v0/slots/{id}`, and `/v1/slots/{id}`.
|
|
263
|
+
|
|
264
|
+
### Parameters
|
|
265
|
+
|
|
266
|
+
| Parameter | Required | Description | Status |
|
|
267
|
+
|-----------|----------|-------------|--------|
|
|
268
|
+
| `id` | Yes | The slot ID to restore to (path parameter). | <sub></sub> |
|
|
269
|
+
| `filename` | Yes | The filename from which to restore the slot cache (JSON body). | <sub></sub> |
|
|
270
|
+
|
|
271
|
+
### Example request
|
|
272
|
+
|
|
273
|
+
=== "PowerShell"
|
|
274
|
+
|
|
275
|
+
```powershell
|
|
276
|
+
Invoke-WebRequest `
|
|
277
|
+
-Uri "http://localhost:13305/v1/slots/0?action=restore" `
|
|
278
|
+
-Method POST `
|
|
279
|
+
-Headers @{ "Content-Type" = "application/json" } `
|
|
280
|
+
-Body '{"filename": "my_conversation_cache.bin"}' -UseBasicParsing
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
=== "PowerShell (/api/v1)"
|
|
284
|
+
|
|
285
|
+
```powershell
|
|
286
|
+
Invoke-WebRequest `
|
|
287
|
+
-Uri "http://localhost:13305/api/v1/slots/0?action=restore" `
|
|
288
|
+
-Method POST `
|
|
289
|
+
-Headers @{ "Content-Type" = "application/json" } `
|
|
290
|
+
-Body '{"filename": "my_conversation_cache.bin"}' -UseBasicParsing
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
=== "Bash"
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
curl -X POST "http://localhost:13305/v1/slots/0?action=restore" \
|
|
297
|
+
-H "Content-Type: application/json" \
|
|
298
|
+
-d '{"filename": "my_conversation_cache.bin"}'
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Response format
|
|
302
|
+
|
|
303
|
+
```json
|
|
304
|
+
{
|
|
305
|
+
"id_slot": 0,
|
|
306
|
+
"filename": "my_conversation_cache.bin",
|
|
307
|
+
"n_restored": 1024
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Field Descriptions:**
|
|
312
|
+
|
|
313
|
+
- `id_slot` - The slot ID that was restored
|
|
314
|
+
- `filename` - The filename from which the cache was restored
|
|
315
|
+
- `n_restored` - Number of tokens restored from the cache file
|
|
316
|
+
|
|
317
|
+
## `POST /v1/slots/{id}?action=erase`
|
|
318
|
+
<sub></sub>
|
|
319
|
+
|
|
320
|
+
Erase (clear) the prompt cache of a specific slot. This removes all cached context from the slot, resetting it to an empty state.
|
|
321
|
+
|
|
322
|
+
> **Note:** This endpoint is part of Lemonade's llama.cpp compatibility layer. Internally, Lemonade forwards the request to llama.cpp's `/slots/{id}?action=erase` endpoint.
|
|
323
|
+
|
|
324
|
+
> **Note:** This endpoint supports all four path prefixes: `/api/v0/slots/{id}`, `/api/v1/slots/{id}`, `/v0/slots/{id}`, and `/v1/slots/{id}`.
|
|
325
|
+
|
|
326
|
+
### Parameters
|
|
327
|
+
|
|
328
|
+
| Parameter | Required | Description | Status |
|
|
329
|
+
|-----------|----------|-------------|--------|
|
|
330
|
+
| `id` | Yes | The slot ID to erase (path parameter). | <sub></sub> |
|
|
331
|
+
|
|
332
|
+
### Example request
|
|
333
|
+
|
|
334
|
+
=== "PowerShell"
|
|
335
|
+
|
|
336
|
+
```powershell
|
|
337
|
+
Invoke-WebRequest `
|
|
338
|
+
-Uri "http://localhost:13305/v1/slots/0?action=erase" `
|
|
339
|
+
-Method POST -UseBasicParsing
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
=== "PowerShell (/api/v1)"
|
|
343
|
+
|
|
344
|
+
```powershell
|
|
345
|
+
Invoke-WebRequest `
|
|
346
|
+
-Uri "http://localhost:13305/api/v1/slots/0?action=erase" `
|
|
347
|
+
-Method POST -UseBasicParsing
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
=== "Bash"
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
curl -X POST "http://localhost:13305/v1/slots/0?action=erase"
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Response format
|
|
357
|
+
|
|
358
|
+
```json
|
|
359
|
+
{
|
|
360
|
+
"id_slot": 0
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Field Descriptions:**
|
|
365
|
+
|
|
366
|
+
- `id_slot` - The slot ID that was erased
|
|
367
|
+
|
|
368
|
+
> **Note:** If the server returns an error, it may indicate that the slot was not found or that the operation failed.
|
|
369
|
+
|
|
370
|
+
## `POST /v1/tokenize`
|
|
371
|
+
<sub></sub>
|
|
372
|
+
|
|
373
|
+
Tokenize a given text. Does not count towards the current model's context window.
|
|
374
|
+
|
|
375
|
+
> **Note:** This endpoint is part of Lemonade's llama.cpp compatibility layer. Internally, Lemonade forwards the request to llama.cpp's `/tokenize` endpoint.
|
|
376
|
+
|
|
377
|
+
> **Note:** This endpoint supports all four path prefixes: `/api/v0/tokenize`, `/api/v1/tokenize`, `/v0/tokenize`, and `/v1/tokenize`.
|
|
378
|
+
|
|
379
|
+
> **Note:** Actual response values may vary for the same string across different models if the models do not share the same tokenizer.
|
|
380
|
+
|
|
381
|
+
### Parameters
|
|
382
|
+
|
|
383
|
+
| Parameter | Required | Description | Status |
|
|
384
|
+
|-----------|----------|-------------|--------|
|
|
385
|
+
| `content` | Yes | The text to tokenize. | <sub></sub> |
|
|
386
|
+
| `add_special` | No | Boolean indicating if special tokens, i.e. `BOS`, should be inserted. Default: `false` | <sub></sub> |
|
|
387
|
+
| `parse_special` | No | Boolean indicating if special tokens should be tokenized. When `false` special tokens are treated as plaintext. Default: `true` | <sub></sub> |
|
|
388
|
+
| `with_pieces` | No | Boolean indicating whether to return token pieces along with IDs. Default: `false` | <sub></sub> |
|
|
389
|
+
|
|
390
|
+
### Example request
|
|
391
|
+
|
|
392
|
+
=== "PowerShell"
|
|
393
|
+
|
|
394
|
+
```powershell
|
|
395
|
+
Invoke-WebRequest `
|
|
396
|
+
-Uri "http://localhost:13305/v1/tokenize" `
|
|
397
|
+
-Method POST `
|
|
398
|
+
-Headers @{ "Content-Type" = "application/json" } `
|
|
399
|
+
-Body '{"content": "This is a string to tokenize"}' -UseBasicParsing
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
=== "PowerShell (/api/v1)"
|
|
403
|
+
|
|
404
|
+
```powershell
|
|
405
|
+
Invoke-WebRequest `
|
|
406
|
+
-Uri "http://localhost:13305/api/v1/tokenize" `
|
|
407
|
+
-Method POST `
|
|
408
|
+
-Headers @{ "Content-Type" = "application/json" } `
|
|
409
|
+
-Body '{"content": "This is a string to tokenize"}' -UseBasicParsing
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
=== "Bash"
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
curl -X POST "http://localhost:13305/v1/tokenize" \
|
|
416
|
+
-H "Content-Type: application/json" \
|
|
417
|
+
-d '{"content": "This is a string to tokenize"}'
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Response format
|
|
421
|
+
|
|
422
|
+
```json
|
|
423
|
+
{
|
|
424
|
+
"tokens": [1919,369,264,886,310,74995]
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
If `with_pieces` is `true`:
|
|
429
|
+
|
|
430
|
+
```json
|
|
431
|
+
{
|
|
432
|
+
"tokens": [
|
|
433
|
+
{"id": 123, "piece": "Hello"},
|
|
434
|
+
{"id": 456, "piece": " world"},
|
|
435
|
+
{"id": 789, "piece": "!"}
|
|
436
|
+
]
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Field Descriptions:**
|
|
441
|
+
|
|
442
|
+
- `tokens` - Array of token IDs
|
package/docs/mcp.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# MCP Gateway
|
|
2
|
+
|
|
3
|
+
Lemonade exposes its inference capabilities as a Model Context Protocol (MCP) server, so any MCP-compatible client (GitHub Copilot, Claude Desktop, MCP Inspector, Cursor, the `mcp` Python client, etc.) can call your locally running models as tools.
|
|
4
|
+
|
|
5
|
+
The gateway implements the **MCP "Streamable HTTP" transport** (spec version `2025-06-18`) with the `tools` capability only. All traffic flows through a single endpoint:
|
|
6
|
+
|
|
7
|
+
| Endpoint | Status | Notes |
|
|
8
|
+
|----------|--------|-------|
|
|
9
|
+
| `POST /mcp` | Supported | JSON-RPC 2.0 envelope. Accepts a single message or a batch array. |
|
|
10
|
+
| `GET /mcp` | `405 Method Not Allowed` | Server-initiated SSE channel is not supported. |
|
|
11
|
+
|
|
12
|
+
> **Why a single path?** The MCP specification mandates one endpoint URL per server, so `/mcp` is an intentional exception to Lemonade's quad-prefix convention.
|
|
13
|
+
|
|
14
|
+
## Authentication
|
|
15
|
+
|
|
16
|
+
`/mcp` is treated as a regular API route, so it honors `LEMONADE_API_KEY` exactly like `/api/v1/chat/completions`:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
curl -s http://localhost:13305/mcp \
|
|
20
|
+
-H "Authorization: Bearer $LEMONADE_API_KEY" \
|
|
21
|
+
-H "Content-Type: application/json" \
|
|
22
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"ping"}'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Supported methods
|
|
26
|
+
|
|
27
|
+
| Method | Purpose |
|
|
28
|
+
|--------|---------|
|
|
29
|
+
| `initialize` | Negotiate protocol version, return server identity and capabilities. |
|
|
30
|
+
| `notifications/initialized` | Client acknowledgement; silently accepted. |
|
|
31
|
+
| `tools/list` | Return the catalogue of callable tools (with JSON Schemas). |
|
|
32
|
+
| `tools/call` | Invoke one of the tools below. |
|
|
33
|
+
| `ping` | Liveness probe; returns `{}`. |
|
|
34
|
+
|
|
35
|
+
## Tools
|
|
36
|
+
|
|
37
|
+
All tools auto-load (and download, if missing) the requested model on first call, exactly like `POST /v1/chat/completions`. Errors are returned as MCP results with `"isError": true` rather than JSON-RPC errors, matching the spec's guidance for tool failures.
|
|
38
|
+
|
|
39
|
+
### `lemonade_list_models`
|
|
40
|
+
|
|
41
|
+
Discover what's loaded, what's downloaded, and what's recommended. Call this first if you don't already know the exact model name to pass to the other tools — passing a wrong name may trigger a multi-GB download.
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"name": "lemonade_list_models",
|
|
46
|
+
"arguments": {
|
|
47
|
+
"include_available": true,
|
|
48
|
+
"include_suggested": true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Returns a summary text block plus a JSON-stringified text block with `{loaded, available, suggested_to_pull, recommended_chat_model}`.
|
|
54
|
+
|
|
55
|
+
### `lemonade_chat`
|
|
56
|
+
|
|
57
|
+
Chat completion against any LLM in the registry.
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"name": "lemonade_chat",
|
|
62
|
+
"arguments": {
|
|
63
|
+
"model": "Qwen3-1.7B-GGUF",
|
|
64
|
+
"messages": [
|
|
65
|
+
{"role": "system", "content": "You are concise."},
|
|
66
|
+
{"role": "user", "content": "Summarize MCP in one line."}
|
|
67
|
+
],
|
|
68
|
+
"max_tokens": 64,
|
|
69
|
+
"temperature": 0.2
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Returns one text block with the assistant content. If the model emits tool calls, a second text block containing `tool_calls: <json>` is appended.
|
|
75
|
+
|
|
76
|
+
Reasoning models (Qwen3, DeepSeek-R1, ...) have the `<think>` block disabled by default to keep small `max_tokens` budgets from being consumed by reasoning. Pass `"chat_template_kwargs": {"enable_thinking": true}` to opt back in.
|
|
77
|
+
|
|
78
|
+
> **Picking a portable model.** The example above uses `Qwen3-1.7B-GGUF` because GGUF (llama.cpp) runs everywhere lemonade does — Windows, Linux/Docker, macOS, CPU and Vulkan/ROCm/Metal GPUs. Hybrid/NPU variants such as `*-Hybrid` (recipe `ryzenai-llm`, **Windows + AMD RyzenAI** only) or `*-FLM` (recipe `flm`, **AMD Ryzen AI NPU** only) are faster on supported hardware but unavailable on others. If your client picks one that isn't supported, the tool returns a structured error suggesting a portable alternative — prefer `lemonade_list_models` to discover what's actually available on the running server.
|
|
79
|
+
|
|
80
|
+
### `lemonade_transcribe_audio`
|
|
81
|
+
|
|
82
|
+
Transcribe a local audio file with a Whisper-class model. Prefer `audio_path` (the server runs on the same machine as the caller); use `audio_base64` only when you genuinely have bytes in memory.
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"name": "lemonade_transcribe_audio",
|
|
87
|
+
"arguments": {
|
|
88
|
+
"model": "Whisper-Large-v3-Turbo",
|
|
89
|
+
"audio_path": "C:/clips/meeting.wav",
|
|
90
|
+
"response_format": "verbose_json"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Returns two text blocks: the bare transcript, followed by the full OpenAI-shaped response (for callers that need timestamps or segments).
|
|
96
|
+
|
|
97
|
+
### `lemonade_generate_image`
|
|
98
|
+
|
|
99
|
+
Generate one or more PNGs from a prompt. **Prefer writing to disk** via `output_path` (single image) or `output_dir` (one or more) — base64 image content blocks cost tens of thousands of tokens per image and some clients surface them as opaque resource URIs.
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"name": "lemonade_generate_image",
|
|
104
|
+
"arguments": {
|
|
105
|
+
"model": "SDXL-Turbo",
|
|
106
|
+
"prompt": "a lemon-shaped car driving across the moon",
|
|
107
|
+
"size": "512x512",
|
|
108
|
+
"output_path": "lemon-car.png"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
When disk paths are provided, returns text block(s) with the absolute path(s). Otherwise, returns one inline image content block per image (`{"type":"image", "data":"<base64>", "mimeType":"image/png"}`).
|
|
114
|
+
|
|
115
|
+
**Sandboxed disk writes.** To prevent a cross-origin or unauthenticated caller from overwriting arbitrary files, `output_path` and `output_dir` are confined to a sandbox directory:
|
|
116
|
+
|
|
117
|
+
- Default: `<cache_dir>/mcp-images`.
|
|
118
|
+
- Override with the `LEMONADE_MCP_IMAGE_DIR` environment variable (absolute path).
|
|
119
|
+
- Relative paths resolve against the sandbox root; absolute paths must stay within it. Paths that escape the sandbox (via `..` or symlinks) are rejected.
|
|
120
|
+
- `output_dir` writes use auto-generated, unique filenames (`image_<token>_<i>.png`), so concurrent callers never clobber one another's images — the returned `paths` tell you the exact names. Use `output_path` when you need an exact, caller-chosen filename (it is written as named, replacing any existing file at that path).
|
|
121
|
+
|
|
122
|
+
### `lemonade_omni`
|
|
123
|
+
|
|
124
|
+
One-shot multimodal turn against a **Lemonade Omni collection** (a model bundle that pairs a planner LLM with an image model, an image-edit model, and a TTS voice under a single `collection.omni` recipe — see [the Omni docs](../dev/lemonade-omni.md)). The server runs the orchestrator's internal tool-calling loop, executes the collection's `generate_image` / `edit_image` / `text_to_speech` tools by routing to the bundled components, and returns the result as a text block plus native MCP `image` / `audio` content blocks — one per artifact, in the order they were produced.
|
|
125
|
+
|
|
126
|
+
`model` is **optional** and defaults to `LMX-Omni-5.5B-Lite` (smaller and faster). Pass `model` explicitly to opt into a larger collection (e.g. `LMX-Omni-52B-Halo` on capable hardware) or any other `collection.omni` model surfaced by `lemonade_list_models`. The collection is downloaded on first use and may be multi-GB.
|
|
127
|
+
|
|
128
|
+
Use `lemonade_chat` instead when you only need plain-text LLM output and don't want the planner-loop overhead.
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"name": "lemonade_omni",
|
|
133
|
+
"arguments": {
|
|
134
|
+
"messages": [
|
|
135
|
+
{"role": "user", "content": "Generate an image of a lemon car, then read out a one-line description."}
|
|
136
|
+
],
|
|
137
|
+
"output_dir": "omni"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Disk vs. inline output.** A single Omni turn can produce both images and audio in arbitrary order. Pass an `output_dir` to write each artifact to disk under a unique auto-generated name (`omni_<token>_<i>.<ext>`) — the tool returns one text block per artifact with its absolute path, plus a JSON-stringified `paths` array. This is strongly preferred over inline base64 for the same reasons documented under `lemonade_generate_image` — and is the **only** way to get audio out on clients that don't render `audio` content blocks. Like `lemonade_generate_image`, `output_dir` is confined to the MCP image sandbox (see **Sandboxed disk writes** above): relative paths resolve against the sandbox root, paths escaping it are rejected, and unique filenames mean concurrent callers never clobber each other.
|
|
143
|
+
|
|
144
|
+
When `output_dir` is omitted, artifacts are inlined as MCP content blocks: `{"type":"image", "data":"<base64>", "mimeType":"image/png"}` and `{"type":"audio", "data":"<base64>", "mimeType":"audio/mpeg"}`.
|
|
145
|
+
|
|
146
|
+
If the planner emits app-defined tool calls (those you passed in via `tools`/`tool_choice`), an extra text block `tool_calls: <json>` is appended, matching `lemonade_chat`'s passthrough semantics.
|
|
147
|
+
|
|
148
|
+
Passing a non-collection model (e.g. a plain LLM) returns `isError: true` with a hint to use `lemonade_chat`.
|
|
149
|
+
|
|
150
|
+
### `lemonade_docs`
|
|
151
|
+
|
|
152
|
+
Read the server's own API reference. Call with no arguments to list the pages this server ships, then pass `page` to read one as markdown. The pages are bundled with the server, so they match the running version and work offline.
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"name": "lemonade_docs",
|
|
157
|
+
"arguments": {
|
|
158
|
+
"page": "api/lemonade"
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The listing returns a summary text block plus a JSON-stringified block with `{pages: [{id, title, bytes}]}`. `page` takes an `id` from that listing; unknown pages return `"isError": true`. The same content is available over HTTP at [`GET /v1/docs`](./lemonade.md#get-v1docs).
|
|
164
|
+
|
|
165
|
+
## Error model
|
|
166
|
+
|
|
167
|
+
| Code | Meaning |
|
|
168
|
+
|------|---------|
|
|
169
|
+
| `-32700` | Body was not valid JSON. |
|
|
170
|
+
| `-32600` | Request was not a JSON-RPC object (or batch was empty / missing `method`). |
|
|
171
|
+
| `-32601` | Unknown JSON-RPC method (e.g. `resources/list`). |
|
|
172
|
+
| `-32602` | Invalid `params` for a known method. |
|
|
173
|
+
| `-32603` | Internal server error (an exception escaped a handler). |
|
|
174
|
+
|
|
175
|
+
Tool-level failures (bad arguments, model load errors, backend exceptions) are returned as **successful** JSON-RPC results with `"isError": true` and a text content block describing the failure, so MCP-aware models can self-correct.
|
|
176
|
+
|
|
177
|
+
## Limitations (MVP)
|
|
178
|
+
|
|
179
|
+
- No server-initiated SSE (GET /mcp returns 405). Tools return their full result in the POST response.
|
|
180
|
+
- No session resumption (`Mcp-Session-Id` header is not issued).
|
|
181
|
+
- `resources/*` and `prompts/*` capabilities are not implemented.
|
|
182
|
+
- Streaming chat output is not exposed via MCP — `stream=true` is ignored. Use `POST /v1/chat/completions` directly for streamed tokens.
|
|
183
|
+
- Embeddings and text-to-speech are not currently exposed as MCP tools; use the OpenAI-compatible endpoints (`/v1/embeddings`, `/v1/audio/speech`) for those.
|
|
184
|
+
|
|
185
|
+
## Quick test with curl
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# 1. Initialize
|
|
189
|
+
curl -s http://localhost:13305/mcp -H "Content-Type: application/json" \
|
|
190
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{}}}'
|
|
191
|
+
|
|
192
|
+
# 2. List tools
|
|
193
|
+
curl -s http://localhost:13305/mcp -H "Content-Type: application/json" \
|
|
194
|
+
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
|
|
195
|
+
|
|
196
|
+
# 3. Call lemonade_chat
|
|
197
|
+
curl -s http://localhost:13305/mcp -H "Content-Type: application/json" \
|
|
198
|
+
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"lemonade_chat","arguments":{"model":"Qwen3-1.7B-GGUF","messages":[{"role":"user","content":"hi"}],"max_tokens":16}}}'
|
|
199
|
+
```
|
package/docs/ollama.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Ollama-Compatible API
|
|
2
|
+
|
|
3
|
+
Lemonade supports the [Ollama API](https://github.com/ollama/ollama/blob/main/docs/api.md), allowing applications built for Ollama to work with Lemonade without modification.
|
|
4
|
+
|
|
5
|
+
To enable auto-detection by Ollama-integrated apps, configure the server to use the Ollama default port `11434`. See [Server Configuration](../guide/configuration/README.md#settings-reference) for how to change the port.
|
|
6
|
+
|
|
7
|
+
| Endpoint | Status | Notes |
|
|
8
|
+
|----------|--------|-------|
|
|
9
|
+
| `POST /api/chat` | Supported | Streaming and non-streaming |
|
|
10
|
+
| `POST /api/generate` | Supported | Text completion + image generation |
|
|
11
|
+
| `GET /api/tags` | Supported | Lists downloaded models |
|
|
12
|
+
| `POST /api/show` | Supported | Model details |
|
|
13
|
+
| `DELETE /api/delete` | Supported | |
|
|
14
|
+
| `POST /api/pull` | Supported | Download with progress |
|
|
15
|
+
| `POST /api/embed` | Supported | New embeddings format |
|
|
16
|
+
| `POST /api/embeddings` | Supported | Legacy embeddings |
|
|
17
|
+
| `GET /api/ps` | Supported | Running models |
|
|
18
|
+
| `GET /api/version` | Supported | |
|
|
19
|
+
| `POST /api/create` | Not supported | Returns 501 |
|
|
20
|
+
| `POST /api/copy` | Not supported | Returns 501 |
|
|
21
|
+
| `POST /api/push` | Not supported | Returns 501 |
|