@octocodeai/freellama-mcp-server 0.6.2 → 0.9.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/CONFIGURATION.md +11 -3
- package/DEVELOPING.md +6 -6
- package/README.md +224 -402
- package/dist/index.js +11714 -4251
- package/dist/research/bash-agent.js +1495 -71
- package/dist/research/coder-agent.js +4668 -0
- package/dist/research/github-agent.js +2923 -0
- package/dist/research/octocode-agent.js +1407 -116
- package/docs/ARCHITECTURE.md +101 -45
- package/docs/BUILD_AND_NOTES.md +31 -0
- package/docs/CLI.md +76 -27
- package/docs/COMPARISON.md +40 -0
- package/docs/CPU_GPU_ROUTING.md +127 -25
- package/docs/DEFERRED_JOBS.md +79 -0
- package/docs/FEATURES.md +303 -0
- package/docs/LOCAL_MODELS.md +190 -0
- package/docs/MODEL_FORMS_AND_RESULTS.md +55 -0
- package/docs/MODEL_INTROSPECTION.md +128 -0
- package/docs/MODEL_SELECTION.md +74 -22
- package/docs/MONITORING.md +115 -33
- package/docs/PRODUCTION.md +76 -13
- package/docs/README.md +11 -6
- package/docs/SCOPES_AND_WARMING.md +55 -7
- package/docs/TESTING.md +24 -2
- package/docs/TUNING.md +86 -0
- package/docs/cookbooks/README.md +22 -0
- package/docs/cookbooks/batch-text.md +19 -0
- package/docs/cookbooks/classify.md +25 -0
- package/docs/cookbooks/coding.md +17 -0
- package/docs/cookbooks/duplicates.md +17 -0
- package/docs/cookbooks/find-code.md +21 -0
- package/docs/cookbooks/image-recognition.md +15 -0
- package/docs/cookbooks/image-search.md +13 -0
- package/docs/cookbooks/jobs.md +60 -0
- package/docs/cookbooks/memory-and-caching.md +31 -0
- package/docs/cookbooks/ocr.md +17 -0
- package/docs/cookbooks/research-agent.md +27 -0
- package/docs/cookbooks/speech-to-text.md +19 -0
- package/docs/cookbooks/sweep.md +66 -0
- package/docs/cookbooks/text-to-speech.md +15 -0
- package/docs/octocode/GITHUB.md +30 -0
- package/docs/octocode/LOCAL.md +29 -0
- package/native/index.d.ts +1 -11
- package/native/index.js +18 -34
- package/package.json +13 -15
package/docs/MONITORING.md
CHANGED
|
@@ -31,8 +31,10 @@ token and keeps it only for the browser tab.
|
|
|
31
31
|
`status` answers "why is my task waiting?" in one call:
|
|
32
32
|
|
|
33
33
|
- **`backends.gpu` / `backends.cpu`**: admission (units in use, current limit, ceiling, queue depth,
|
|
34
|
-
oldest wait, refusal and timeout counters
|
|
35
|
-
|
|
34
|
+
oldest wait, refusal and timeout counters, and `affinity_promotions`: grants given ahead of older
|
|
35
|
+
same-priority work because the waiter's model was already running or admitted last), the
|
|
36
|
+
adaptive limiter state, and the circuit breaker (`closed`, `open` with seconds remaining, or
|
|
37
|
+
`half_open`).
|
|
36
38
|
- **`raw_proxy`**: active and waiting raw streams against their cap and wait budget.
|
|
37
39
|
- **`loaded_models`**: Ollama's `/api/ps` with total and VRAM bytes, context length, expiry, and
|
|
38
40
|
whether the model is pinned.
|
|
@@ -50,6 +52,16 @@ token and keeps it only for the browser tab.
|
|
|
50
52
|
deadlines, states, and waiting reasons. States cover discovery, admission, resources, runner
|
|
51
53
|
transitions, loading, execution, and completion. Metadata excludes the original payload.
|
|
52
54
|
|
|
55
|
+
A task receipt explains its own wait. `admission.mode` is `resident_shared` (the runner was
|
|
56
|
+
reused without the backend load lock) or `nonresident_transition_exclusive` (this task loaded the
|
|
57
|
+
runner under it). `admission.reason` says why a present runner could not be shared when its identity
|
|
58
|
+
was not established, for example `resident_identity_unobserved` when `/api/ps` reports no digest;
|
|
59
|
+
it is `null` for a plain match. `queue_wait_ms`, `transition_wait_ms` (waiting for the load lock) and
|
|
60
|
+
`resource_wait_ms` add up to `total_wait_ms`. Waiting for the lock is bounded by the task's queue
|
|
61
|
+
deadline; a raw load that waits too long gets 503 `proxy busy`, and a raw generation whose
|
|
62
|
+
allocation cannot be forecast gets 503 `model_forecast_unavailable`. See
|
|
63
|
+
[Load lock and use lease](CPU_GPU_ROUTING.md#load-lock-and-use-lease).
|
|
64
|
+
|
|
53
65
|
Use `run_task {defer:true}` in MCP or `task --defer` in the CLI to get a job handle. A list or
|
|
54
66
|
status request omits results; fetching one ID returns its retained result or structured failure.
|
|
55
67
|
Terminal states are `completed`, `failed`, `cancelled`, and `expired`. Cancellation is per task,
|
|
@@ -64,7 +76,10 @@ cancellation closes the upstream request; physical computation may continue on a
|
|
|
64
76
|
`ollama.config` describes the primary process; `ollama.cpu_config` describes the CPU process when
|
|
65
77
|
configured. Process attribution matches `OLLAMA_HOST` to the selected endpoint, so separate
|
|
66
78
|
parallelism and KV cache settings size each backend independently. Fallback sources remain visible
|
|
67
|
-
when process settings cannot be observed.
|
|
79
|
+
when process settings cannot be observed. Each config's `effective` block reports the resolved
|
|
80
|
+
`num_parallel`, `context_length`, `flash_attention` (`on`, `off`, or `auto` when unset) and the KV
|
|
81
|
+
cache it sizes for (`kv_cache_type`, `kv_cache_percent_of_f16`); see
|
|
82
|
+
[KV cache and flash attention](TUNING.md#kv-cache-and-flash-attention).
|
|
68
83
|
|
|
69
84
|
Process settings are cached for five seconds and refreshed on discovery or monitoring requests,
|
|
70
85
|
including after an Ollama restart. Each config receipt includes `observed_at` and
|
|
@@ -90,12 +105,28 @@ Each backend's admission `queue_depth` includes both `slot_waiters` and `resourc
|
|
|
90
105
|
A resource waiter returns its execution slot after two seconds but remains in the bounded queue
|
|
91
106
|
until capacity recovers, its deadline expires, or it is cancelled.
|
|
92
107
|
|
|
108
|
+
Model affinity is bounded: `affinity_max_skips` (4) and `affinity_max_wait_ms` (2000) in the same
|
|
109
|
+
receipt are how often, and how long, an older waiter can be passed over before its class is served
|
|
110
|
+
in arrival order again. A rising `affinity_promotions` with flat queue waits means fewer model
|
|
111
|
+
switches; see [the admission design](ARCHITECTURE.md#managed-task-execution).
|
|
112
|
+
|
|
113
|
+
`GET /health` reports `admission.request_body_budget` (`total_bytes`, `available_bytes`): the
|
|
114
|
+
process-wide memory for request bodies being read or held by running requests,
|
|
115
|
+
`FREELLAMA_MAX_BUFFERED_BYTES` (256 MiB by default). When it is full, a new upload waits up to the
|
|
116
|
+
queue wait and is then refused with 503 `request_body_budget_exhausted`; raise it, or lower
|
|
117
|
+
`FREELLAMA_MAX_REQUEST_BYTES`, when large uploads are normal.
|
|
118
|
+
|
|
93
119
|
## Record usage
|
|
94
120
|
|
|
95
|
-
Every managed task
|
|
96
|
-
The record contains time, model, backend,
|
|
97
|
-
|
|
98
|
-
|
|
121
|
+
Every managed task, and every raw Ollama or OpenAI-compatible generation, updates in-memory usage
|
|
122
|
+
totals and offers one record to a bounded writer queue. The record contains time, model, backend,
|
|
123
|
+
task kind (`raw` for passthrough, whose `priority` field holds the path), priority, outcome, HTTP
|
|
124
|
+
status, prompt, cached prompt and output tokens, duration, queue wait, load time, output tokens per
|
|
125
|
+
second and, with client keys, the client. It contains no prompt or response text. Raw counts are read
|
|
126
|
+
from the fields each response reports (`prompt_eval_count`, `prompt_eval_cached_count`, `eval_count`,
|
|
127
|
+
OpenAI `usage`, decision `usage`) as it streams through unchanged; a client that leaves early records
|
|
128
|
+
what arrived. `cached_prompt_tokens` totals show how much prompt work the runners' prompt caches
|
|
129
|
+
saved. One worker writes records in order; task completion does not wait for disk.
|
|
99
130
|
|
|
100
131
|
The writer queue defaults to 128 records. Configure its positive startup-only capacity through
|
|
101
132
|
`usage_queue_capacity` or `FREELLAMA_USAGE_QUEUE_CAPACITY`; runtime reload does not resize the worker.
|
|
@@ -105,13 +136,16 @@ failure records a failed write. Inspect `usage_ledger` in `status`, or `ledger`
|
|
|
105
136
|
`asynchronous_best_effort`: pending records can be lost on a crash, and in-memory totals can exceed
|
|
106
137
|
persisted totals. Error evidence remains visible after later successful writes.
|
|
107
138
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
139
|
+
The ledger is the `usage` table of the shared database (`~/.octocode/freellama/freellama.sqlite`). `serve`
|
|
140
|
+
keeps daily totals for the last 35 days in memory, computed in the database at startup, and never
|
|
141
|
+
deletes records. `usage --days N` past 35 days reads the older days from the database on request
|
|
142
|
+
(`retention.older_days: "ledger"`); with `--ephemeral` they are `"not_retained"`. Memory holds at
|
|
143
|
+
most 256 models per day, and the task counters at most 256 models: raw requests can name any
|
|
144
|
+
model, so further names are counted under `other`. Successful writes
|
|
145
|
+
contribute to restart totals; completion is not a zero-loss persistence promise. Embedded callers
|
|
146
|
+
can use the bounded `flush_ledger` barrier for orderly teardown; it confirms attempted writes, not
|
|
147
|
+
recovery of dropped/failed records. `--home` moves the database; `--ephemeral` keeps totals in
|
|
148
|
+
memory only.
|
|
115
149
|
|
|
116
150
|
## Scrape metrics
|
|
117
151
|
|
|
@@ -120,7 +154,7 @@ The ledger lives next to the feedback file in the platform data directory. Choos
|
|
|
120
154
|
`freellama_load_seconds_total`, `freellama_raw_requests_total`, `freellama_evictions_total`,
|
|
121
155
|
`freellama_circuit_open_total`, `freellama_concurrency_limit_changes_total`); task counters are
|
|
122
156
|
labelled by model, backend, task, and outcome, raw requests by kind and outcome, and the rest by
|
|
123
|
-
backend. Gauges cover admission, queues, the raw proxy, host and GPU memory,
|
|
157
|
+
backend. `freellama_admission_affinity_promotions_total` counts model-affinity grants per backend. Gauges cover admission, queues, the raw proxy, host and GPU memory,
|
|
124
158
|
loaded models, and `freellama_ollama_num_parallel`. Point Prometheus, Grafana Agent, or any
|
|
125
159
|
OpenMetrics-compatible scraper at it.
|
|
126
160
|
|
|
@@ -167,8 +201,8 @@ A task captures its cost when execution starts. Reload affects tasks that start
|
|
|
167
201
|
already queued or active tasks keep their captured cost. `config` reports effective values and
|
|
168
202
|
the runtime-file source; invalid keys, zero,
|
|
169
203
|
or overflow reject the reload and retain the last good configuration. Preview advice, health
|
|
170
|
-
costs, and execution receipts use the resolved policy. Health
|
|
171
|
-
|
|
204
|
+
costs, and execution receipts use the resolved policy. Health exposes the complete task-kind map
|
|
205
|
+
under `admission.costs.base_by_task` and the embedding batch formula. Task kinds remain
|
|
172
206
|
caller-declared; these weights are cooperative scheduling policy, not workload classification.
|
|
173
207
|
See the
|
|
174
208
|
[runtime example](https://github.com/bgauryy/FreeLlama/blob/main/freellama.runtime.example.toml) for the table syntax.
|
|
@@ -198,10 +232,8 @@ report verified placement and `feedback.accepted:true` while
|
|
|
198
232
|
`execution.throughput_learning.eligible:false`; it contributes no comparable speed sample.
|
|
199
233
|
|
|
200
234
|
Each backend retains at most one adaptive profile window per task kind. Status exposes
|
|
201
|
-
`adaptive.profile_windows` keyed by task
|
|
202
|
-
|
|
203
|
-
windows report their explicit input-rate kind separately. Use the task windows for learning
|
|
204
|
-
evidence. See [automatic feedback](CPU_GPU_ROUTING.md#understand-automatic-feedback) for
|
|
235
|
+
`adaptive.profile_windows` keyed by task. Embedding windows report their explicit input-rate kind
|
|
236
|
+
separately. Use the task windows for learning evidence. See [automatic feedback](CPU_GPU_ROUTING.md#understand-automatic-feedback) for
|
|
205
237
|
persisted routing windows.
|
|
206
238
|
|
|
207
239
|
The CPU backend is adaptive by default because oversubscribing it shows up as a throughput collapse
|
|
@@ -209,14 +241,24 @@ rather than an error. Every change is counted in metrics and shown in `status`.
|
|
|
209
241
|
|
|
210
242
|
## Model residency and eviction
|
|
211
243
|
|
|
212
|
-
Omitted managed `keep_alive` values use finite retention informed by measured reuse and loading
|
|
213
|
-
|
|
244
|
+
Omitted managed `keep_alive` values use finite retention informed by measured reuse and loading,
|
|
245
|
+
starting from `base_seconds` (300, Ollama's own default) and shortened by `pressure_factor` under a
|
|
246
|
+
host hold. Explicit values take precedence. The background pressure sweep releases, under
|
|
247
|
+
FreeLlama's own low-memory estimate, only runners idle longer than `base_seconds ×
|
|
248
|
+
pressure_factor` (75 s by default); swapping or OS memory pressure releases any idle runner. For governed prewarming, profile compatibility, and retention
|
|
214
249
|
settings, see [Scope history and model warming](SCOPES_AND_WARMING.md).
|
|
215
250
|
|
|
216
251
|
When a model about to load needs room, FreeLlama unloads idle runners itself (`keep_alive: 0`)
|
|
217
|
-
instead of letting the load wait, fail, or spill to CPU. It does this in
|
|
218
|
-
|
|
219
|
-
|
|
252
|
+
instead of letting the load wait, fail, or spill to CPU. It does this in four cases, checked in
|
|
253
|
+
this order: (discrete GPU) the model does not fit in free VRAM, where Ollama otherwise chooses its
|
|
254
|
+
own victim; the load would take the backend's loaded models past `model_memory_budget`; host RAM
|
|
255
|
+
can fall below the reserve; or the host is already holding for low memory. Raw passthrough loads
|
|
256
|
+
(an Ollama API call for a model that is not loaded) take the same steps, and raw calls in flight
|
|
257
|
+
count as busy, so their models are not unloaded under them.
|
|
258
|
+
|
|
259
|
+
`model_memory_budget` (runtime file, or `FREELLAMA_MODEL_MEMORY_BUDGET`) is `"75%"` of RAM by
|
|
260
|
+
default; set a size such as `"24GiB"`, another share, or `"off"`. It applies where the runners share
|
|
261
|
+
host memory: unified memory (Apple silicon) or a CPU backend.
|
|
220
262
|
|
|
221
263
|
Which runners go is a small optimisation, in the spirit of llama-swap's `evict_costs` and LocalAI's
|
|
222
264
|
busy-aware LRU:
|
|
@@ -226,7 +268,7 @@ busy-aware LRU:
|
|
|
226
268
|
- **Not for a model bigger than the GPU:** it spills to the CPU whatever is unloaded, so VRAM is
|
|
227
269
|
left alone.
|
|
228
270
|
- **Cost of unloading a runner** = its reload time (Ollama's measured `load_duration` from earlier
|
|
229
|
-
loads, or size ÷ 1.5 GB/s before the first one) × (1 + recent uses, decaying with a 30-minute
|
|
271
|
+
loads, kept in the shared database across restarts, or size ÷ 1.5 GB/s before the first one) × (1 + recent uses, decaying with a 30-minute
|
|
230
272
|
half-life; only tasks served count) × its `eviction_costs` weight (default 1).
|
|
231
273
|
- **Choice:** the set of runners with the lowest total cost that frees enough memory; ties go to
|
|
232
274
|
fewer runners, then less memory freed beyond what is needed. Only the memory that matters is
|
|
@@ -234,10 +276,43 @@ busy-aware LRU:
|
|
|
234
276
|
memory.
|
|
235
277
|
|
|
236
278
|
Every managed receipt that caused an eviction carries the plan under
|
|
237
|
-
`memory_reservation.eviction`: what was unloaded, its cost and reload estimate,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
279
|
+
`memory_reservation.eviction`: what was unloaded, its cost and reload estimate, what was kept and
|
|
280
|
+
why, the `trigger` (`gpu_memory`, `model_memory_budget` or `host_memory`) and `unload_ms`. `status`
|
|
281
|
+
and the page show the latest one that unloaded something. Eviction runs once per task, after
|
|
282
|
+
admission and before the memory wait, and is never cancelled halfway by a deadline. Set
|
|
283
|
+
`evict_idle_models = false` to leave residency entirely to Ollama.
|
|
284
|
+
|
|
285
|
+
`memory_reservation` names the `kv_cache_type` and `flash_attention` state it sized for. With a
|
|
286
|
+
quantized cache it also carries `ollama_f16_preflight_bytes`, the f16-cache size Ollama's own fit
|
|
287
|
+
check predicts. On a CPU or
|
|
288
|
+
unified-memory backend, `ollama_preflight_threshold_bytes` is 80% of the available memory the load
|
|
289
|
+
was admitted against; when the reserved estimate fits under it and the f16 figure does not, the
|
|
290
|
+
receipt adds `ollama_may_evict_or_offload: true` and a one-line `ollama_preflight_reason`: Ollama may
|
|
291
|
+
unload other runners or offload layers even though FreeLlama found room. Run previews carry the
|
|
292
|
+
same fields. The reservation itself is unchanged: measurements still take precedence over the
|
|
293
|
+
estimate.
|
|
294
|
+
|
|
295
|
+
### The residency audit
|
|
296
|
+
|
|
297
|
+
Every load, unload and eviction is recorded with its cause and duration in the shared database, so
|
|
298
|
+
the audit covers every FreeLlama process on the machine. `status` summarizes the last hour under
|
|
299
|
+
`residency`:
|
|
300
|
+
|
|
301
|
+
| Field | Meaning |
|
|
302
|
+
|---|---|
|
|
303
|
+
| `model_memory_budget` | The setting, its bytes, and per backend whether it applies, what its loaded models hold, and the share used |
|
|
304
|
+
| `audit.counts`, `audit.by_trigger` | Loads, unloads and evictions; causes such as `managed_task`, `raw_request`, `caller_unload`, `model_memory_budget`, `host_memory` |
|
|
305
|
+
| `audit.switch_ms` | Per model: measured loads, average, total and last load time (Ollama's `load_duration`) |
|
|
306
|
+
| `audit.thrashing` | Models loaded 3 or more times in 10 minutes: raise the budget, pin the model, or give it its own backend |
|
|
307
|
+
| `audit.recent` | The 20 newest events (the database keeps every event; counts cover the whole hour) |
|
|
308
|
+
|
|
309
|
+
A raw passthrough load is recorded when its response ends, with the `load_duration` Ollama
|
|
310
|
+
reported in it, and that time also teaches the eviction planner what reloading the model costs.
|
|
311
|
+
Preloads appear as `preload` or `preload_failed` events with trigger `startup` or
|
|
312
|
+
`predicted_after:<model>`.
|
|
313
|
+
|
|
314
|
+
A task refused because the host stayed under pressure says which signals held it:
|
|
315
|
+
`resource_admission.held_by` (such as `["thermal_throttling"]`), also named in the error text.
|
|
241
316
|
|
|
242
317
|
## Who decides what: FreeLlama and Ollama
|
|
243
318
|
|
|
@@ -253,8 +328,8 @@ Two schedulers that both guess at memory can disagree. The split is:
|
|
|
253
328
|
| Context size | Ollama by default | `num_ctx` is left to Ollama when its default covers the request |
|
|
254
329
|
|
|
255
330
|
To keep the estimates honest, FreeLlama learns from every runner Ollama reports as resident,
|
|
256
|
-
including ones loaded by raw clients, and saves those measurements
|
|
257
|
-
|
|
331
|
+
including ones loaded by raw clients, and saves those measurements in the shared database, keeping
|
|
332
|
+
the larger size when two processes measure the same runner. After a restart a model it has seen before is sized from Ollama's measurement, not a
|
|
258
333
|
formula. Each measurement records the `OLLAMA_NUM_PARALLEL` and KV-cache type it was taken under and
|
|
259
334
|
is used only while those match, so changing either setting falls back to the formula until Ollama
|
|
260
335
|
measures again. A larger context than any measured one is sized as the measurement plus exactly the extra
|
|
@@ -275,6 +350,13 @@ on a discrete GPU only) Ollama's VRAM tier, from total VRAM minus `OLLAMA_GPU_OV
|
|
|
275
350
|
Memory estimates always use the context Ollama can allocate. Use `"explicit"` to always
|
|
276
351
|
send `num_ctx`.
|
|
277
352
|
|
|
353
|
+
The context-shift setting is part of a runner's identity too: Ollama reloads a runner when a
|
|
354
|
+
request's `shift` differs from the one it was loaded with, and its default is on for most models.
|
|
355
|
+
`context_shift = "off"` (the default) sends `shift: false` on managed chat, so a generation that
|
|
356
|
+
reaches the context limit stops instead of discarding its earliest tokens, at the cost of a reload
|
|
357
|
+
when raw clients use the same model. `"ollama_default"` omits `shift` so raw and managed chat share
|
|
358
|
+
the runner. Both modes send `truncate: false`. `status` reports it under `ollama.context_shift`.
|
|
359
|
+
|
|
278
360
|
## Change settings without a restart
|
|
279
361
|
|
|
280
362
|
Put any of the settings above in a TOML file and start `serve --runtime-config <file>` (or set
|
package/docs/PRODUCTION.md
CHANGED
|
@@ -11,8 +11,8 @@ not provide tenant isolation or billing.
|
|
|
11
11
|
## Meet the prerequisites
|
|
12
12
|
|
|
13
13
|
- Install one Ollama CLI and server version. Run `freellama doctor` and resolve any mismatch.
|
|
14
|
-
- Install Node.js
|
|
15
|
-
- Use the release artifacts for your operating system, or build with Rust 1.
|
|
14
|
+
- Install Node.js 22 or later for MCP and npm distribution use.
|
|
15
|
+
- Use the release artifacts for your operating system, or build with Rust 1.89 or later.
|
|
16
16
|
- Preinstall and benchmark exact model tags. Discovery never authorizes a pull.
|
|
17
17
|
- Keep the primary and optional CPU Ollama processes on distinct loopback sockets.
|
|
18
18
|
- In a slim or distroless container, install the CA bundle (`ca-certificates`) or set
|
|
@@ -38,10 +38,19 @@ The repository has no CI or release workflows; they were removed (see git histor
|
|
|
38
38
|
clean checkout: `yarn release:version <version>`, `yarn release:build` (builds each target's
|
|
39
39
|
executable and addon into `release-artifacts/<target>/`), `node scripts/assemble-release.mjs
|
|
40
40
|
release-artifacts release`, then `yarn release:verify:publish`. The publish verifier checks that
|
|
41
|
-
`FREELLAMA_RELEASE_TAG`, when set, matches the workspace version.
|
|
41
|
+
`FREELLAMA_RELEASE_TAG`, when set, matches the workspace version. It also requires every addon and
|
|
42
|
+
executable to embed `freellama-source-commit=<sha>` (written by `packages/rust-core/build.rs`; also
|
|
43
|
+
shown by `freellama --version`) equal to `git rev-parse HEAD`, and a clean tracked tree; a stale or
|
|
44
|
+
`-dirty` artifact fails naming the file and the commit it was built from. CI checkouts without git
|
|
45
|
+
set `FREELLAMA_RELEASE_COMMIT` to the 40-character release SHA. Then run `yarn release:smoke`: it packs
|
|
46
|
+
`packages/cli`, `packages/mcp` and this host's `packages/native/<id>`, installs them into a fresh
|
|
47
|
+
project and checks `freellama --version`, that `freellama --help` lists every subcommand of
|
|
48
|
+
`target/release/freellama`, that the installed addon exports exactly the functions in
|
|
49
|
+
`packages/mcp/native/index.d.ts`, and that the installed MCP server answers `tools/list` (needs the
|
|
50
|
+
registry for the MCP dependencies). `yarn verify:production` runs both.
|
|
42
51
|
Live E2E and hardware qualification remain separate operator checks; verify those receipts before tagging.
|
|
43
52
|
|
|
44
|
-
Attach `release/SHA256SUMS` and binaries to the release. Publish
|
|
53
|
+
Attach `release/SHA256SUMS` and binaries to the release. Publish every `@octocodeai/freellama-native-*` package
|
|
45
54
|
first, followed by the exact-version `@octocodeai/freellama` and `@octocodeai/freellama-mcp-server` packages. Publish
|
|
46
55
|
the Rust crates from the same commit with `cargo publish --workspace` (it uploads `freellama-core`
|
|
47
56
|
before `freellama-cli`; run it with `--dry-run` first). Configure registry credentials (`npm login`,
|
|
@@ -127,16 +136,15 @@ and require the same visible values before admitting work.
|
|
|
127
136
|
Generate a token without placing the secret in shell history or the process list:
|
|
128
137
|
|
|
129
138
|
```bash
|
|
130
|
-
freellama auth-token --out ~/.
|
|
139
|
+
freellama auth-token --out ~/.octocode/freellama/auth.token
|
|
131
140
|
```
|
|
132
141
|
|
|
133
142
|
The command creates a new file with mode `0600` on Unix and refuses to overwrite an existing
|
|
134
|
-
token. Start the service with
|
|
143
|
+
token. Start the service with authentication:
|
|
135
144
|
|
|
136
145
|
```bash
|
|
137
146
|
freellama serve \
|
|
138
|
-
--
|
|
139
|
-
--auth-token-file ~/.local/share/freellama/auth.token \
|
|
147
|
+
--auth-token-file ~/.octocode/freellama/auth.token \
|
|
140
148
|
--upstream http://127.0.0.1:11434 \
|
|
141
149
|
--cpu-upstream http://127.0.0.1:11436 \
|
|
142
150
|
--cpu-model nomic-embed-text:latest
|
|
@@ -147,10 +155,65 @@ adapters. Authentication covers both `/_freellama/v1/*` and Ollama-compatible pa
|
|
|
147
155
|
Use `--allow-remote` only with an authentication token. The server refuses unauthenticated
|
|
148
156
|
nonloopback listeners.
|
|
149
157
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
158
|
+
### Client keys
|
|
159
|
+
|
|
160
|
+
Give each agent, team or tool its own key instead of sharing the operator token. Create one token
|
|
161
|
+
file per client with `freellama auth-token --out`, then list them in `clients.toml` in the home (or
|
|
162
|
+
pass `--client-keys` / `FREELLAMA_CLIENT_KEYS`):
|
|
163
|
+
|
|
164
|
+
```toml
|
|
165
|
+
[[client]]
|
|
166
|
+
name = "octocode"
|
|
167
|
+
token_file = "keys/octocode.token" # relative to this file; mode 0600
|
|
168
|
+
daily_tokens = 2000000 # optional; unmetered when absent
|
|
169
|
+
admin = false # optional; true allows model files and config reload
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
A key's usage is the tokens the backend processed for it per UTC day: output plus the prompt tokens
|
|
173
|
+
not reused from a prompt cache, for managed tasks and raw Ollama or OpenAI calls. The budget is
|
|
174
|
+
checked before each generating request, so the request that crosses it finishes; later ones get 429
|
|
175
|
+
with `code: "client_budget_exhausted"` and a `Retry-After` until the next UTC day. Reads still work.
|
|
176
|
+
Non-admin keys get 403 (`client_not_admin`) for pull, push, copy, create, delete, blob uploads and
|
|
177
|
+
`config/reload`. `usage` shows each key's `tokens_today`, `daily_tokens` and `remaining_today`; a
|
|
178
|
+
client key sees only its own row. Today's totals start from the shared database at startup and
|
|
179
|
+
then count this process's traffic. Point a client's `FREELLAMA_AUTH_TOKEN_FILE` at its own key. A
|
|
180
|
+
serve that the MCP server starts itself treats that file as the operator token, so run `serve`
|
|
181
|
+
yourself when you use client keys.
|
|
182
|
+
|
|
183
|
+
### Other OpenAI-compatible engines
|
|
184
|
+
|
|
185
|
+
`upstreams.toml` in the home (or `--upstreams` / `FREELLAMA_UPSTREAMS`) puts other engines behind
|
|
186
|
+
the same endpoint:
|
|
187
|
+
|
|
188
|
+
```toml
|
|
189
|
+
[[upstream]]
|
|
190
|
+
name = "lmstudio"
|
|
191
|
+
url = "http://127.0.0.1:1234/v1"
|
|
192
|
+
|
|
193
|
+
[[upstream]]
|
|
194
|
+
name = "cloud"
|
|
195
|
+
url = "https://api.example.com/v1"
|
|
196
|
+
api_key_file = "keys/cloud.key" # mode 0600; sent only over HTTPS or to this machine
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Only OpenAI-compatible paths (`/v1/...`) route by model: `name/model` goes to that engine as
|
|
200
|
+
`model`; a bare name goes to Ollama when Ollama has it, else to the first engine whose `/v1/models`
|
|
201
|
+
lists it. `GET /v1/models` merges every list and names unreachable engines. A request to an engine is
|
|
202
|
+
sent once (no retries), streams through unchanged, carries the `x-freellama-upstream` header and is
|
|
203
|
+
counted in usage. An engine on this machine waits out host holds as a loaded Ollama model would; a
|
|
204
|
+
remote one does not. Managed tasks, residency and the memory budget cover Ollama only, and there is no
|
|
205
|
+
automatic failover from one engine to another.
|
|
206
|
+
|
|
207
|
+
Everything the server learns lives in one `SQLite` database, `~/.octocode/freellama/freellama.sqlite`
|
|
208
|
+
(`--home` or `FREELLAMA_HOME` moves the home): measured runner sizes, placement feedback, the usage
|
|
209
|
+
ledger and the residency audit. It uses write-ahead logging, so several FreeLlama processes on one
|
|
210
|
+
machine share it safely and learn from each other. The feedback snapshot is versioned and bounded by
|
|
211
|
+
backend and task type; only physically verified warm samples are saved, and a schema-1 snapshot (0.7.x)
|
|
212
|
+
is migrated on load (aggregates kept as diagnostics, original kept as `placement_feedback_v1_backup`);
|
|
213
|
+
a corrupt or unknown-version snapshot starts empty with a stderr warning and `/health`
|
|
214
|
+
`feedback.persistence.last_error`, and is never overwritten. A database file with
|
|
215
|
+
another schema version is refused with its path; move or delete it to start a new one. Use
|
|
216
|
+
`--ephemeral` only for disposable tests.
|
|
154
217
|
|
|
155
218
|
## Bound conversation history and residency
|
|
156
219
|
|
|
@@ -193,7 +256,7 @@ longer resident before returning. Inspect both `execution.observation` and
|
|
|
193
256
|
|
|
194
257
|
Require these health contracts before admitting traffic:
|
|
195
258
|
|
|
196
|
-
- `placement_feedback_persistence:
|
|
259
|
+
- `placement_feedback_persistence: shared_database_snapshot_v2`
|
|
197
260
|
- `authentication: optional_bearer_all_routes`
|
|
198
261
|
- `immediate_unload_observation: observe_then_unload`
|
|
199
262
|
- `placement_observation: ollama_api_ps_after_execution`
|
package/docs/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
FreeLlama helps agents offload bounded work to local models through Ollama. The calling agent owns
|
|
4
4
|
the task and verifies the answer; FreeLlama manages model selection and resources around execution.
|
|
5
|
-
Start with the [repository
|
|
5
|
+
Start with the [repository README](https://github.com/bgauryy/FreeLlama/blob/main/README.md#install) to install and run one managed task.
|
|
6
6
|
|
|
7
7
|
## Choose a guide
|
|
8
8
|
|
|
@@ -11,8 +11,17 @@ Start with the [repository MCP setup](https://github.com/bgauryy/FreeLlama/blob/
|
|
|
11
11
|
| Connect an agent and choose a tool | [MCP server](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md) |
|
|
12
12
|
| Follow the agent's operating workflow | [FreeLlama skill](https://github.com/bgauryy/FreeLlama/blob/main/skills/freellama/SKILL.md) |
|
|
13
13
|
| Look up commands and task controls | [CLI reference](CLI.md) |
|
|
14
|
+
| Choose a model for a job | `models {view:"catalog"}`, `freellama catalog`, or the [local model catalog](LOCAL_MODELS.md) |
|
|
15
|
+
| Follow a recipe for one job | [Cookbooks](cookbooks/README.md) |
|
|
16
|
+
| Teach an agent the Octocode CLI in under 30 lines | [Local tools](octocode/LOCAL.md), [GitHub tools](octocode/GITHUB.md) |
|
|
14
17
|
| Understand task and resource ownership | [Architecture](ARCHITECTURE.md) |
|
|
18
|
+
| See every feature, routing and admission in depth, and why FreeLlama exists | [Features](FEATURES.md) |
|
|
19
|
+
| Compare FreeLlama with Ollama, llama.cpp, llama-swap and LocalAI | [Comparison](COMPARISON.md) |
|
|
20
|
+
| See supported model forms and dated measured results | [Model forms and results](MODEL_FORMS_AND_RESULTS.md) |
|
|
21
|
+
| Reduce reloads, prompt cost and memory; tune Ollama settings | [Tuning](TUNING.md) |
|
|
22
|
+
| Build from source; read operating notes (response store, port 11435, certificates) | [Build and notes](BUILD_AND_NOTES.md) |
|
|
15
23
|
| Choose a model and interpret its metadata | [Model selection](MODEL_SELECTION.md), [model metadata](MODEL_SELECTION.md#model-metadata) |
|
|
24
|
+
| Inspect quantization, placement, or neuron activations | [Model introspection](MODEL_INTROSPECTION.md) |
|
|
16
25
|
| Configure CPU helpers alongside GPU work | [CPU/GPU routing](CPU_GPU_ROUTING.md) |
|
|
17
26
|
| Inspect queues, memory, usage, and live settings | [Monitoring](MONITORING.md) |
|
|
18
27
|
| Retain history, affinity, or residency | [Scopes and warming](SCOPES_AND_WARMING.md) |
|
|
@@ -22,11 +31,7 @@ Start with the [repository MCP setup](https://github.com/bgauryy/FreeLlama/blob/
|
|
|
22
31
|
| Run development and release checks | [Testing](TESTING.md), [release packages](TESTING.md#verify-release-packages) |
|
|
23
32
|
| Embed the routing core | [Rust core](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/README.md) |
|
|
24
33
|
| Use the read-only status page | `/_freellama/ui` on a running `serve` (see [Monitoring](MONITORING.md)) |
|
|
25
|
-
|
|
26
|
-
## Evidence and design
|
|
27
|
-
|
|
28
|
-
| Goal | Source |
|
|
29
|
-
|---|---|
|
|
34
|
+
| Configure durable receipts, idempotency and bounded job retention | [Deferred jobs and recovery](DEFERRED_JOBS.md) |
|
|
30
35
|
|
|
31
36
|
Historical measurements describe one model, machine, and workload. Inspect current state and
|
|
32
37
|
repeat the relevant checks before using them to select models or set resource limits.
|
|
@@ -145,9 +145,14 @@ Expired entries are removed during store operations.
|
|
|
145
145
|
|
|
146
146
|
## Warm API
|
|
147
147
|
|
|
148
|
-
`POST /warm`, MCP `
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
`POST /warm`, MCP `ollama_manage {action:"warm"}`, and CLI `warm` load an exact installed model with a matching
|
|
149
|
+
task profile; `task: "embedding"` loads an embedding model with an empty `/api/embed` request. A
|
|
150
|
+
chat warm may carry `messages` (MCP: `systemPrompt` and/or `messages`): the runner evaluates them
|
|
151
|
+
into its prompt cache with `num_predict: 0` and generates nothing, so a later request that starts
|
|
152
|
+
with the same messages, at the same context, reuses that work (its receipt reports
|
|
153
|
+
`cached_prompt_tokens`). Warming never pulls a model or stores conversation history. The default task
|
|
154
|
+
profile is `completion`. Ollama has no load-only request for decision models: they load on their
|
|
155
|
+
first `/v1/systemone` call, and `keep_alive` on that call sets their residency.
|
|
151
156
|
|
|
152
157
|
| HTTP field | MCP field | Meaning |
|
|
153
158
|
|---|---|---|
|
|
@@ -161,6 +166,13 @@ history. The default task profile is `completion`.
|
|
|
161
166
|
| `max_wait_seconds` | `maxWaitSeconds` | Shorter admission/resource wait budget. |
|
|
162
167
|
| `timeout_seconds` | `timeoutSeconds` | Total request deadline, capped by server policy. |
|
|
163
168
|
| `defer` | `defer` | Return a job handle for the same managed operation. |
|
|
169
|
+
| `messages` | `systemPrompt`, `messages` | A prompt prefix to evaluate into the runner's prompt cache. |
|
|
170
|
+
|
|
171
|
+
A warm of a model that is not resident is a load. Like any load it takes the backend's load lock
|
|
172
|
+
(see [Load lock and use lease](CPU_GPU_ROUTING.md#load-lock-and-use-lease)) until its runner is
|
|
173
|
+
observed in `/api/ps`, so it queues behind another load on the same backend but never waits for
|
|
174
|
+
another model's decoding. It makes room only by unloading idle runners: a model with a running
|
|
175
|
+
task is never evicted for a warm.
|
|
164
176
|
|
|
165
177
|
Synchronous warming returns HTTP `200`; deferred warming returns HTTP `202`. Inspect deferred
|
|
166
178
|
work through `task_jobs` or `jobs` using its returned ID. Warming reuses ordinary routing,
|
|
@@ -177,9 +189,17 @@ chat requires Ollama's `done:true`; an absent or non-boolean completion marker i
|
|
|
177
189
|
These are separate observations in Ollama's [chat response](https://docs.ollama.com/api/chat) and
|
|
178
190
|
[running-model inventory](https://docs.ollama.com/api/ps).
|
|
179
191
|
|
|
180
|
-
With `keep_alive:"0"
|
|
181
|
-
residency after unload: `loaded:false` on verified unload,
|
|
182
|
-
`residency_source:"ollama_api_ps_after_unload"`.
|
|
192
|
+
With `keep_alive:"0"` on a model that is not resident, warming loads it, observes placement and then
|
|
193
|
+
unloads. The `warm` receipt describes residency after unload: `loaded:false` on verified unload,
|
|
194
|
+
with `residency_source:"ollama_api_ps_after_unload"`. On a model that is already resident,
|
|
195
|
+
`keep_alive:"0"` is a plain unload: it waits for that model's running tasks, unloads it and returns
|
|
196
|
+
`{"unloaded": true, "status": "unloaded", "unload_ms": …}` without loading or routing anything.
|
|
197
|
+
`POST /_freellama/v1/unload {"model": …}` (CLI `unload`) does the same and never loads a model that is
|
|
198
|
+
not resident (`status: "not_resident"`).
|
|
199
|
+
|
|
200
|
+
A warm without `task` loads an embedding-only model as an embedding task, so
|
|
201
|
+
`{"model":"nomic-embed-text:v1.5"}` works without `"task":"embedding"`. Warms and preloads teach
|
|
202
|
+
FreeLlama a model's load time but do not count as uses, so they never lengthen their own residency.
|
|
183
203
|
|
|
184
204
|
Warming uses the same truncation and context-shift policy as managed chat. This preserves a
|
|
185
205
|
compatible runner profile instead of forcing a transition solely because warming omitted those
|
|
@@ -187,6 +207,34 @@ controls. Use a context/task profile compatible with the following task. Warming
|
|
|
187
207
|
require another runner transition. Warm residency does not reserve a later execution slot. Cache reuse depends on the compatible
|
|
188
208
|
profile, unchanged prefix, and inference backend. See [Managed execution](ARCHITECTURE.md#managed-task-execution).
|
|
189
209
|
|
|
210
|
+
## Preload
|
|
211
|
+
|
|
212
|
+
The runtime file's `[preload]` table loads models without a caller asking:
|
|
213
|
+
|
|
214
|
+
- `startup`: tags, or tables with `model` and optional `context_tokens`, `keep_alive` (default: the
|
|
215
|
+
warming policy's `max_seconds`) and `messages`, loaded in order once the server is up and again
|
|
216
|
+
for entries a reloaded runtime file adds. `FREELLAMA_PRELOAD` sets a comma-separated list.
|
|
217
|
+
- `predictive` (on by default): every switch from one model to another within
|
|
218
|
+
`follow_window_seconds` (600) is counted in the shared database. Once at least `min_observations`
|
|
219
|
+
(3) switches away from a model happened and `min_probability` (0.5) of them went to one successor,
|
|
220
|
+
finishing a caller's work on the model loads that successor in the background, but only when it
|
|
221
|
+
is not loaded, fits without unloading anything (budget, GPU and host memory), the host is under no
|
|
222
|
+
pressure, and nothing is running or queued on the backend. Only the primary backend predicts.
|
|
223
|
+
`FREELLAMA_PREDICTIVE_PRELOAD=0` turns it off.
|
|
224
|
+
|
|
225
|
+
Predictive warm is refused on a discrete-GPU or remote backend. Vendor-wide free VRAM does not
|
|
226
|
+
say which devices that Ollama process may allocate on, and nothing in FreeLlama verifies it
|
|
227
|
+
(`gpu_capacity_scope` stays `host_aggregate_not_verified_for_backend`), so a speculative load
|
|
228
|
+
could displace work on a pool it cannot see. The skip reason is `GPU device eligibility for this
|
|
229
|
+
Ollama backend is unverified` (`opportunistic_warm_skipped`). Unified-memory hosts and the CPU
|
|
230
|
+
backend, where host memory is the budget, still predict. Explicit warms, startup preloads and
|
|
231
|
+
managed tasks on a discrete GPU run through ordinary admission.
|
|
232
|
+
|
|
233
|
+
Each preload is a background warm under the usual admission, memory and pressure rules, and the
|
|
234
|
+
residency audit records it as `preload` (or `preload_failed`) with trigger `startup` or
|
|
235
|
+
`predicted_after:<model>`. Switches are counted per process from the order requests finish, so
|
|
236
|
+
several agents interleaving models add noise that the probability threshold has to outweigh.
|
|
237
|
+
|
|
190
238
|
For a bounded warm operation, replace `MODEL_TAG` with an exact installed tag:
|
|
191
239
|
|
|
192
240
|
```bash
|
|
@@ -208,7 +256,7 @@ Matching environment values override `[warming]` file values.
|
|
|
208
256
|
|---|---|---:|---|
|
|
209
257
|
| `min_seconds` | `FREELLAMA_KEEP_ALIVE_MIN_SECONDS` | `15` | Minimum automatic duration. |
|
|
210
258
|
| `max_seconds` | `FREELLAMA_KEEP_ALIVE_MAX_SECONDS` | `900` | Maximum automatic duration. |
|
|
211
|
-
| `base_seconds` | `FREELLAMA_KEEP_ALIVE_BASE_SECONDS` | `
|
|
259
|
+
| `base_seconds` | `FREELLAMA_KEEP_ALIVE_BASE_SECONDS` | `300` | Base duration before measured reuse and load cost; matches Ollama's five-minute default. |
|
|
212
260
|
| `reuse_gain_seconds` | `FREELLAMA_KEEP_ALIVE_REUSE_GAIN_SECONDS` | `30` | Additional duration per recent use. |
|
|
213
261
|
| `load_multiplier` | `FREELLAMA_KEEP_ALIVE_LOAD_MULTIPLIER` | `2.0` | Multiplier for measured load seconds. |
|
|
214
262
|
| `pressure_factor` | `FREELLAMA_KEEP_ALIVE_PRESSURE_FACTOR` | `0.25` | Duration factor while observed resource pressure holds admission. |
|
package/docs/TESTING.md
CHANGED
|
@@ -80,6 +80,14 @@ cargo clippy --all-targets -- -D warnings
|
|
|
80
80
|
|
|
81
81
|
Routing regressions run in the default Rust suite; none are hidden behind `#[ignore]`. Add a
|
|
82
82
|
focused contract test for each repaired behavior and keep it enabled in ordinary release checks.
|
|
83
|
+
Completion-planning regressions cover payload fit before ranking, global quality gates across
|
|
84
|
+
backends, exact-profile history retention, idempotent snapshot merges, unknown phase
|
|
85
|
+
costs, prefill/decode tradeoffs and cached-token normalization. Runner tests reject mismatched
|
|
86
|
+
digests/contexts and distinguish reported setup duration from an observed load transition.
|
|
87
|
+
Resource tests require released forecasts to invalidate both cached and already-returned host
|
|
88
|
+
snapshots. Predictive warm fixtures use a mock Ollama to assert no queuing or eviction under
|
|
89
|
+
contention; they require permission to bind a loopback listener. MCP tests require accepted jobs
|
|
90
|
+
to retain their identity and fail without re-execution if result retention fails.
|
|
83
91
|
Resource contracts cover conservative full host-memory reservations when discrete-GPU telemetry is
|
|
84
92
|
missing, and immediate-unload cleanup after a failed inference response body. The latter also checks
|
|
85
93
|
that uncertain inference is never replayed and ordinary keep-alive requests retain their runner.
|
|
@@ -198,13 +206,27 @@ placement, shared-memory contention, or OCR quality.
|
|
|
198
206
|
The historical CPU/GPU observations above predate the corrected paired-run acceptance gate.
|
|
199
207
|
They remain records of those runs and do not qualify a release.
|
|
200
208
|
|
|
209
|
+
## Run live model harnesses
|
|
210
|
+
|
|
211
|
+
These scripts measure installed models through a running `serve`. They are not part of any test
|
|
212
|
+
tier, and each writes a dated report to the git-ignored `.octocode/local-test/`.
|
|
213
|
+
|
|
214
|
+
| Script | Measures |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `scripts/local-test/rivals.mjs` | The graded questions in `cases.mjs` on rival models per job, three rounds, resumable |
|
|
217
|
+
| `scripts/local-test/lifecycle.mjs` | Cold and warm calls, keep-alive, unload, switching, queue priorities, prompt caching, CPU vs GPU |
|
|
218
|
+
| `scripts/local-test/assist.mjs` | Issue to code, duplicates, triage and OCR on a real repository |
|
|
219
|
+
| `scripts/local-test/media.mjs` | Speech round trip, multimodal image search, embedding comparison through MCP |
|
|
220
|
+
| `scripts/local-test/octocode-agent.mjs` | A local model driving Octocode through `delegate_research` |
|
|
221
|
+
|
|
201
222
|
## Verify release packages
|
|
202
223
|
|
|
203
224
|
```bash
|
|
204
225
|
# Collect each target's `freellama` executable and `freellama.<target>.node`
|
|
205
|
-
# under release-artifacts/<target>/, then stage
|
|
226
|
+
# under release-artifacts/<target>/, then stage every platform package in scripts/release-platforms.mjs.
|
|
206
227
|
node scripts/assemble-release.mjs release-artifacts release
|
|
207
|
-
yarn release:verify:publish
|
|
228
|
+
yarn release:verify:publish # also requires each artifact's embedded commit == HEAD, clean tree
|
|
229
|
+
yarn release:smoke # packed-install smoke of the host platform package
|
|
208
230
|
```
|
|
209
231
|
|
|
210
232
|
Build every claimed CLI/native target in a clean environment, assemble `SHA256SUMS`, run the full
|