@octocodeai/freellama-mcp-server 0.5.0 → 0.6.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 +108 -0
- package/DEVELOPING.md +109 -0
- package/README.md +130 -282
- package/dist/index.js +1509 -1411
- package/dist/research/bash-agent.js +2435 -0
- package/dist/research/octocode-agent.js +1639 -0
- package/docs/ARCHITECTURE.md +145 -81
- package/docs/CLI.md +83 -55
- package/docs/CPU_GPU_ROUTING.md +4 -3
- package/docs/MODEL_SELECTION.md +115 -5
- package/docs/MONITORING.md +19 -11
- package/docs/PRODUCTION.md +10 -13
- package/docs/README.md +9 -13
- package/docs/SCOPES_AND_WARMING.md +8 -9
- package/docs/TESTING.md +18 -30
- package/native/index.d.ts +179 -174
- package/native/index.js +3 -3
- package/package.json +11 -10
- package/adapters/agent_context.py +0 -850
- package/adapters/agent_transport.py +0 -215
- package/adapters/bash_agent.py +0 -345
- package/adapters/octocode_agent.py +0 -404
- package/adapters/shell_sandbox.py +0 -487
- package/docs/ECONOMICS.md +0 -110
- package/docs/INDEX.md +0 -21
- package/docs/MODEL_METADATA.md +0 -106
- package/docs/OLLAMA_SIDECAR.md +0 -78
- package/docs/PRODUCT_POSITIONING.md +0 -121
- package/docs/dev/ADR_RESOURCE_AWARE_BACKEND_ROUTING.md +0 -55
- package/docs/dev/FINDINGS_AND_POSITIONING.md +0 -290
- package/docs/dev/LOCAL_PERFORMANCE_TESTING.md +0 -298
- package/docs/dev/OLLAMA_SYSTEM_OPTIMIZATION.md +0 -255
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -11,10 +11,14 @@ the operating system and drivers schedule physical work.
|
|
|
11
11
|
|
|
12
12
|
## Responsibility boundary
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
This is the canonical ownership rule; other guides link here.
|
|
15
15
|
|
|
16
16
|
| Responsibility | Owner |
|
|
17
17
|
|---|---|
|
|
18
|
+
| Goal decomposition, prompts, system messages, task dependencies, and answer verification | Calling agent |
|
|
19
|
+
| Ollama processes and endpoints, exact `--cpu-model` assignments, runtime settings, and approval of pulls, stops, and deletes | Operator |
|
|
20
|
+
| Prompt templates and model defaults | Ollama model metadata or a `Modelfile` |
|
|
21
|
+
| Physical CPU/GPU scheduling and memory | OS, drivers, and accelerator runtime |
|
|
18
22
|
| Model files, runners, Metal, MLX, llama.cpp, and token generation | Ollama |
|
|
19
23
|
| Native `/api/*` and OpenAI-compatible `/v1/*` semantics | Ollama |
|
|
20
24
|
| Installed-model discovery and capability normalization | FreeLlama |
|
|
@@ -23,9 +27,33 @@ The following table defines the ownership boundary:
|
|
|
23
27
|
| Forecast memory reservations, host-pressure holds, and requests to unload idle unpinned models | FreeLlama managed execution |
|
|
24
28
|
| Explicit per-model CPU/GPU backend assignment | FreeLlama and separate Ollama processes |
|
|
25
29
|
| Grounded research adapters, citations, and verification verdicts | FreeLlama MCP server |
|
|
30
|
+
| Bearer authentication of every route | FreeLlama; external ingress owns TLS and tenant authorization |
|
|
26
31
|
|
|
27
|
-
FreeLlama
|
|
28
|
-
|
|
32
|
+
FreeLlama is a governed router, not an unrestricted hardware scheduler: a CPU preference cannot move
|
|
33
|
+
an arbitrary tag, and one managed call contains one task. Only the calling agent knows which tasks
|
|
34
|
+
are independent.
|
|
35
|
+
|
|
36
|
+
### Ollama sidecar
|
|
37
|
+
|
|
38
|
+
FreeLlama is a loopback sidecar, not an Ollama fork. It talks to Ollama over its documented HTTP
|
|
39
|
+
contract, which also makes a second, process-isolated CPU backend possible without changing client
|
|
40
|
+
payloads:
|
|
41
|
+
|
|
42
|
+
```mermaid
|
|
43
|
+
flowchart LR
|
|
44
|
+
C["Ollama-compatible client"] --> F["FreeLlama loopback sidecar"]
|
|
45
|
+
F -->|"raw /api and /v1"| G["Primary Ollama"]
|
|
46
|
+
F -->|"managed primary task"| G
|
|
47
|
+
F -->|"managed assigned task"| U["Optional CPU Ollama"]
|
|
48
|
+
G --> E["Metal, MLX, CUDA, ROCm, Vulkan, or CPU runner"]
|
|
49
|
+
U --> E2["CPU runner"]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
FreeLlama does not make an individual model decode faster. It can improve workload completion by
|
|
53
|
+
avoiding unsuitable routes, reducing avoidable transitions, refusing unsupported work early, and
|
|
54
|
+
overlapping independent CPU and GPU model requests when the machine benefits from that layout.
|
|
55
|
+
Sources: [Ollama API](https://docs.ollama.com/api/introduction),
|
|
56
|
+
[streaming](https://docs.ollama.com/api/streaming), [usage](https://docs.ollama.com/api/usage).
|
|
29
57
|
|
|
30
58
|
## System topology
|
|
31
59
|
|
|
@@ -79,8 +107,7 @@ flowchart TD
|
|
|
79
107
|
RAW --> PRIMARY["Primary Ollama"]
|
|
80
108
|
P -->|"Yes"| C{"Control endpoint"}
|
|
81
109
|
C -->|"health, machine, models"| READ["Read local and Ollama state"]
|
|
82
|
-
C -->|"
|
|
83
|
-
C -->|"natural-routes"| INTENT["Run intent model, then route"]
|
|
110
|
+
C -->|"routes"| DECIDE["Decide without inference"]
|
|
84
111
|
C -->|"tasks"| RUN["Route, admit, and execute"]
|
|
85
112
|
C -->|"sessions"| SESSION["Create in-memory affinity id"]
|
|
86
113
|
C -->|"scopes"| SCOPES["Retain revision-protected messages"]
|
|
@@ -94,9 +121,7 @@ The control API exposes these endpoints:
|
|
|
94
121
|
| `GET /_freellama/v1/health` | Health, admission capacity, and configured backends | No |
|
|
95
122
|
| `GET /_freellama/v1/machine` | Machine profile | No |
|
|
96
123
|
| `GET /_freellama/v1/models` | Normalized installed catalog, evidence, residency, and execution backend | No |
|
|
97
|
-
| `POST /_freellama/v1/recommendations` | Installed route or reviewed installation plan | No |
|
|
98
124
|
| `POST /_freellama/v1/routes` | Deterministic route decision | No |
|
|
99
|
-
| `POST /_freellama/v1/natural-routes` | Schema-bound intent interpretation followed by deterministic routing | Intent model only |
|
|
100
125
|
| `POST /_freellama/v1/sessions` | New model-affinity session | No |
|
|
101
126
|
| `DELETE /_freellama/v1/sessions/:session_id` | Release model-affinity session | No |
|
|
102
127
|
| `POST /_freellama/v1/scopes` | Create bounded message history | No |
|
|
@@ -104,12 +129,49 @@ The control API exposes these endpoints:
|
|
|
104
129
|
| `POST /_freellama/v1/scopes/:id/fork` | Fork history at an expected revision | No |
|
|
105
130
|
| `DELETE /_freellama/v1/scopes/:id` | Delete retained history | No |
|
|
106
131
|
| `POST /_freellama/v1/warm` | Admitted load of an exact installed runner profile | Load only |
|
|
107
|
-
| `POST /_freellama/v1/tasks` | Managed chat, vision, tools, or embedding task | Yes |
|
|
132
|
+
| `POST /_freellama/v1/tasks` | Managed chat, vision, tools, or embedding task (body shape under [Request shapes](#request-shapes)) | Yes |
|
|
108
133
|
| `GET /_freellama/v1/jobs` | Deferred job metadata without prompts or results | No |
|
|
109
134
|
| `GET /_freellama/v1/jobs/:id` | One deferred receipt and retained result | No |
|
|
110
135
|
| `POST /_freellama/v1/jobs/:id/cancel` | Cancel one deferred task and release its local permits | No new inference |
|
|
111
136
|
| `DELETE /_freellama/v1/jobs/:id` | Cancel active work, release local permits, and remove its retained record | No new inference |
|
|
112
137
|
|
|
138
|
+
### Request shapes
|
|
139
|
+
|
|
140
|
+
The control API uses snake_case JSON. A managed task body is the routing fields plus the payload:
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"task": "vision", "objective": "fastest", "model": "my-vision-model",
|
|
145
|
+
"session_id": "<uuid from POST /sessions>", "required_capabilities": ["vision"],
|
|
146
|
+
"prompt": "Text Recognition:", "images": ["<base64, no data-URI prefix>"],
|
|
147
|
+
"priority": "background", "keep_alive": "5m", "max_wait_seconds": 30, "timeout_seconds": 120,
|
|
148
|
+
"stop_on_repetition": true,
|
|
149
|
+
"request_options": { "options": { "temperature": 0, "num_predict": 600 }, "format": "json", "think": false }
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`model` is read the way Ollama reads it: an exact installed tag, else `name:latest`, else the one
|
|
154
|
+
installed tag of that family; an unknown or ambiguous name is refused with the installed candidates.
|
|
155
|
+
`messages` (Ollama message objects, images included) replaces `prompt`; `input` serves embeddings;
|
|
156
|
+
`context_tokens` owns `num_ctx` and placement owns `num_gpu`, so neither is accepted inside
|
|
157
|
+
`request_options.options`. `stop_on_repetition: true` streams the chat from Ollama and stops as soon
|
|
158
|
+
as the output repeats its unit twice after the first copy over 96+ characters: the connection
|
|
159
|
+
closes, which cancels generation upstream, and everything generated is kept with
|
|
160
|
+
`done_reason: "repetition"`. An Ollama "token repeat limit" abort is kept the same way
|
|
161
|
+
(`done_reason: "repeat_limit"`). A stopped stream has no Ollama timing fields, so it trains no
|
|
162
|
+
throughput feedback. The receipt holds `route`, `admission` (`queue_wait_ms`,
|
|
163
|
+
`resource_wait_ms`, `transition_wait_ms`, `total_wait_ms`), `execution` (placement, observation,
|
|
164
|
+
`resource_admission`, `context_sizing`, `memory_reservation`), `metrics`, `feedback` and
|
|
165
|
+
`response`, which is Ollama's own answer (`message.content`, `eval_count`, durations).
|
|
166
|
+
|
|
167
|
+
A batch nests whole task bodies:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{ "max_parallelism": 2, "tasks": [ { "id": "item-1", "independent": true, "task": { "task": "vision", "model": "my-vision-model", "prompt": "...", "images": ["..."] } } ] }
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`POST /sessions` with an empty object returns `session_id`; `POST /warm` takes `{"model": "<tag>"}`.
|
|
174
|
+
|
|
113
175
|
The machine profile is host-derived rather than model-name-derived. It reports total physical
|
|
114
176
|
memory on macOS (`sysctl`), Linux (`/proc`), and Windows (system APIs), along with CPU, OS,
|
|
115
177
|
architecture, and disk. `memory_bytes` is portable host RAM. `unified_memory_bytes` is populated
|
|
@@ -117,7 +179,10 @@ only when host and accelerator memory are known to share a pool; it must not be
|
|
|
117
179
|
GPU VRAM. Ollama's `/api/ps` remains the placement authority.
|
|
118
180
|
|
|
119
181
|
All other paths use the compatibility proxy. It buffers request bodies up to 64 MB so a retry can
|
|
120
|
-
resend identical bytes, then streams the upstream response. It
|
|
182
|
+
resend identical bytes, then streams the upstream response. It removes hop-by-hop headers, adds
|
|
183
|
+
`x-freellama-proxy: 1`, always targets the primary upstream, and does not apply CPU model
|
|
184
|
+
assignment. Existing Ollama clients keep predictable compatibility; clients that opt into the
|
|
185
|
+
managed API receive routing and policy behavior.
|
|
121
186
|
|
|
122
187
|
## Model discovery
|
|
123
188
|
|
|
@@ -131,12 +196,26 @@ flowchart LR
|
|
|
131
196
|
BENCH["Local benchmark report"] --> CAT
|
|
132
197
|
POLICY["Task policy"] --> CAT
|
|
133
198
|
ASSIGN["CPU model assignments"] --> CAT
|
|
134
|
-
|
|
199
|
+
LOOPS["Observed repetition loops"] --> CAT
|
|
200
|
+
CAT --> MODEL["CatalogModel<br/>capabilities · context · residency<br/>benchmark · policy rank · backend · loops"]
|
|
135
201
|
```
|
|
136
202
|
|
|
137
203
|
FreeLlama fetches tags and residency from each configured backend. Models assigned to CPU are
|
|
138
204
|
removed from the primary catalog view and included only from the secondary backend. Static catalog
|
|
139
|
-
metadata is cached for 30 seconds; residency
|
|
205
|
+
metadata is cached for 30 seconds; residency and observed loops are refreshed before routing.
|
|
206
|
+
|
|
207
|
+
Every field comes from the model's own metadata and from what FreeLlama observed, never from its
|
|
208
|
+
name. `GET /_freellama/v1/models` adds, per model:
|
|
209
|
+
|
|
210
|
+
- `context_default`: the context Ollama gives a request that leaves `num_ctx` unset (`source` is
|
|
211
|
+
`modelfile`, `config`, `ollama_context_length`, `vram_tier`, or `resident_runner`). A managed
|
|
212
|
+
task that sends a different `num_ctx` reloads the runner.
|
|
213
|
+
- `resident_context`: the `context_length` of the loaded runner from `/api/ps`.
|
|
214
|
+
- `observed_loops`: per task kind, managed runs since start and how many ended in a repetition
|
|
215
|
+
loop (`{runs, loops}`); process-local, not persisted.
|
|
216
|
+
- `kv_cache_bytes_per_token_f16`: estimated from the declared architecture's block count, KV head
|
|
217
|
+
count and key/value lengths, for any architecture; `null` when the metadata declares recurrent,
|
|
218
|
+
state-space, sliding-window, shared or cross-attention caches, which the dense formula misstates.
|
|
140
219
|
|
|
141
220
|
A failed `/api/show` response skips that model instead of failing the entire catalog. An unreachable
|
|
142
221
|
configured backend fails catalog discovery closed because FreeLlama cannot prove the assigned model's
|
|
@@ -150,7 +229,7 @@ matches exact tags and digest prefixes, preserves local supported features, and
|
|
|
150
229
|
source excerpts and usage notes. Its bounded in-memory cache expires successes after one hour and
|
|
151
230
|
failures after one minute. Failed or unmatched lookups leave local inventory and evidence intact.
|
|
152
231
|
Public claims do not enter the Rust catalog, task policy, quality confidence, or routing decisions.
|
|
153
|
-
See [
|
|
232
|
+
See [Model metadata](MODEL_SELECTION.md#model-metadata) for the public contract and request bounds.
|
|
154
233
|
|
|
155
234
|
## Deterministic routing
|
|
156
235
|
|
|
@@ -176,8 +255,17 @@ flowchart TD
|
|
|
176
255
|
G -->|"Yes or unset"| D["RouteDecision"]
|
|
177
256
|
```
|
|
178
257
|
|
|
179
|
-
Explicit model selection never substitutes another model.
|
|
180
|
-
|
|
258
|
+
Explicit model selection never substitutes another model. An explicit `model` is read the way
|
|
259
|
+
Ollama reads it: the exact tag, else `name:latest`, else the one installed tag of that family; an
|
|
260
|
+
unknown or ambiguous name is refused with the installed candidates. Every rejected candidate
|
|
261
|
+
includes a reason so callers can distinguish capability, context, policy, and installation failures.
|
|
262
|
+
|
|
263
|
+
Routing never ranks by a model's name or architecture. Automatic selection (fallback ranking and
|
|
264
|
+
session affinity) ranks a model last for a task kind when it has looped on that kind at least twice
|
|
265
|
+
in at most twice as many managed runs; the decision then carries
|
|
266
|
+
`repeats_on_this_task_last_resort`. An operator policy naming the model for the task, or an explicit
|
|
267
|
+
`model`, always wins. No request option is added because of which model was chosen: stop sequences
|
|
268
|
+
and decoding settings belong to the caller.
|
|
181
269
|
|
|
182
270
|
`context_window_fit` means only that requested `num_ctx` fits the model's advertised context
|
|
183
271
|
window. It is not a live-memory, free-VRAM, K/V-cache, thermal, or runner-admission verdict.
|
|
@@ -198,37 +286,12 @@ Confidence is a grade derived from independent evidence dimensions:
|
|
|
198
286
|
`minConfidence: "medium"` refuses before generation when either input is missing. The gate lives in
|
|
199
287
|
`select_route`, so the HTTP API, CLI, MCP server, and embedded core share the same behavior.
|
|
200
288
|
|
|
201
|
-
## Natural-language routing
|
|
202
|
-
|
|
203
|
-
Natural-language routing cannot select a model directly:
|
|
204
|
-
|
|
205
|
-
```mermaid
|
|
206
|
-
sequenceDiagram
|
|
207
|
-
participant C as Client
|
|
208
|
-
participant F as FreeLlama
|
|
209
|
-
participant I as Intent model
|
|
210
|
-
participant R as Deterministic router
|
|
211
|
-
|
|
212
|
-
C->>F: Natural-language request
|
|
213
|
-
F->>I: Strict JSON schema and bounded profile
|
|
214
|
-
I-->>F: Task, objective, context, tool, and vision fields
|
|
215
|
-
F->>F: Apply deterministic guards
|
|
216
|
-
F->>R: Normalized RouteInput
|
|
217
|
-
R-->>F: RouteDecision
|
|
218
|
-
F-->>C: Intent, adjustments, and route
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
Word-boundary guards prevent incidental substrings such as `photosynthesis` from creating a vision
|
|
222
|
-
requirement. Explicit requirements in the original text override weak or unsupported inferred fields.
|
|
223
|
-
|
|
224
|
-
The natural route endpoint does not run the selected task. Submit a managed task to execute it.
|
|
225
|
-
|
|
226
289
|
## Managed task execution
|
|
227
290
|
|
|
228
|
-
The implementation separates [admission scheduling](
|
|
229
|
-
[execution coordination](
|
|
230
|
-
[read-only readiness](
|
|
231
|
-
[typed errors](
|
|
291
|
+
The implementation separates [admission scheduling](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/admission.rs),
|
|
292
|
+
[execution coordination](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/execution/mod.rs),
|
|
293
|
+
[read-only readiness](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/readiness.rs), and
|
|
294
|
+
[typed errors](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/error.rs). The platform module wires HTTP endpoints,
|
|
232
295
|
configuration, discovery, and shared state; extracting these owners preserves the public routing API.
|
|
233
296
|
|
|
234
297
|
Managed tasks combine routing with admission and backend-aware transition coordination. With
|
|
@@ -322,16 +385,26 @@ Process observations refresh on requests after five seconds; measurements made u
|
|
|
322
385
|
settings cannot supply an exact-fit estimate. Ollama remains the live loader and final memory
|
|
323
386
|
authority. Configured settings alone do not prove physical processor placement.
|
|
324
387
|
|
|
325
|
-
The shared [resource governor](
|
|
388
|
+
The shared [resource governor](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/resources/mod.rs) samples local
|
|
326
389
|
available-memory estimates, load per logical CPU, OS memory pressure, active swap-out growth, and
|
|
327
|
-
thermal throttling when reported.
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
390
|
+
thermal throttling when reported. OS memory pressure holds every local demand; active swap-out
|
|
391
|
+
growth holds new loads; CPU-load and thermal holds apply to CPU-assigned work and to cold loads
|
|
392
|
+
(decoding weights is CPU work and a new heat source) but not to a bounded request on a runner
|
|
393
|
+
already resident on the GPU, which neither waits for the cores nor cools the package by waiting (`ResourceDemand::is_held_by`; the assessment's
|
|
394
|
+
`held_by` lists the holds that applied). Low available RAM (below the larger of 15% or 1 GiB, clearing after two
|
|
395
|
+
healthy samples above the larger of 20% or 2 GiB) depends on the platform (`ResourcePolicy::low_memory`).
|
|
396
|
+
On macOS (`advisory`) the estimate undercounts what the OS can reclaim, so a load that does not cover
|
|
397
|
+
it first unloads idle runners and then dispatches with a `memory_advisory`. On Linux, Windows, and
|
|
398
|
+
other platforms (`refuse`) a new load that does not fit first unloads idle runners and then waits
|
|
399
|
+
with `held_insufficient_capacity` until a permit release or a fresh sample frees capacity, or refuses
|
|
400
|
+
with 503 at its deadline: Linux `MemAvailable` already includes reclaimable cache and is the hard cap
|
|
401
|
+
in a container, so over-admitting invites the OOM killer. Already-resident runners add no memory and
|
|
402
|
+
are admitted in both modes, also during an active-swapping hold, so a large load never locks out
|
|
403
|
+
reuse of its own runner; swapping still holds new loads. Historical swap occupancy alone is not pressure. Samples are cached for two
|
|
404
|
+
seconds; unavailable signals stay unknown. Remote backends bypass this host gate.
|
|
331
405
|
|
|
332
406
|
Each pressure signal recovers independently after two fresh samples that meet its recovery
|
|
333
|
-
threshold. A recovered CPU-load signal therefore clears even while RAM remains low.
|
|
334
|
-
unchanged resident runners eligible under a memory-only hold while cold loads continue waiting.
|
|
407
|
+
threshold. A recovered CPU-load signal therefore clears even while RAM remains low.
|
|
335
408
|
|
|
336
409
|
The default `require_memory` telemetry policy holds local inference when available RAM is missing,
|
|
337
410
|
even when a raw request has no model-footprint estimate. `best_effort` is an explicit opt-in;
|
|
@@ -339,15 +412,15 @@ even when a raw request has no model-footprint estimate. `best_effort` is an exp
|
|
|
339
412
|
Unsupported Linux collector signals remain explicitly unavailable rather than being fabricated.
|
|
340
413
|
The pure `ResourceSnapshot::assess_capacity` calculation is shared by admission and previews.
|
|
341
414
|
Previews use the same footprint lookup, subtract existing reservations, and expose both queue and
|
|
342
|
-
resource readiness.
|
|
343
|
-
|
|
415
|
+
resource readiness. Insufficient model headroom reports `runnable_low_memory_estimate` and admits
|
|
416
|
+
no siblings on macOS; elsewhere it reports `held_insufficient_capacity`. Preview capacity is advisory and conservative, never a reservation.
|
|
344
417
|
|
|
345
418
|
Managed CPU/unified-memory tasks reserve estimated additional model-file and known F16 KV bytes
|
|
346
419
|
across both backends. Verified runner footprints replace that estimate only for the same backend,
|
|
347
420
|
immutable model digest, and equal-or-larger observed context. Exact resident digest/context matches
|
|
348
|
-
avoid double-counting existing allocations. The reservation is rechecked after transition locking
|
|
349
|
-
an increased requirement that no longer fits
|
|
350
|
-
|
|
421
|
+
avoid double-counting existing allocations. The reservation is rechecked after transition locking
|
|
422
|
+
without waiting while holding the backend lock; an increased requirement that no longer fits the
|
|
423
|
+
estimate dispatches with a `memory_advisory`, and a pressure hold refuses with 503. Permits release on completion or cancellation. On discrete-GPU hosts, observed free
|
|
351
424
|
VRAM discounts the estimated host-memory requirement by the bytes the GPU can hold. Missing VRAM
|
|
352
425
|
telemetry reserves the full estimated footprint in host RAM. The governor cannot constrain external
|
|
353
426
|
allocations or preempt an already-running model.
|
|
@@ -418,35 +491,18 @@ cold-load cost do not poison the comparison. It requires more than a 10% advanta
|
|
|
418
491
|
break a tie before the sample threshold. Quality routing, explicit model selection, and session
|
|
419
492
|
affinity do not follow the latency loop.
|
|
420
493
|
|
|
421
|
-
The same selection function supplies preview
|
|
422
|
-
managed task execution. This keeps advertised placement and actual request routing aligned.
|
|
494
|
+
The same selection function supplies preview receipts and managed task execution. This keeps advertised placement and actual request routing aligned.
|
|
423
495
|
|
|
424
496
|
Raw proxy traffic always uses the primary upstream. For setup and runtime verification, see
|
|
425
497
|
[Run models on CPU and GPU](CPU_GPU_ROUTING.md).
|
|
426
498
|
|
|
427
499
|
## MCP tool flow
|
|
428
500
|
|
|
429
|
-
The MCP server keeps general model work
|
|
430
|
-
operations
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
MC["MCP client"] --> TOOL{"Tool"}
|
|
435
|
-
TOOL -->|"doctor"| NAPI["Native core diagnostics"]
|
|
436
|
-
TOOL -->|"models"| MIX["Control API or direct Ollama/library HTTP"]
|
|
437
|
-
TOOL -->|"run_task"| TASK["Control API route or task"]
|
|
438
|
-
TOOL -->|"task_jobs"| JOB["Deferred receipts and per-task cancellation"]
|
|
439
|
-
TOOL -->|"ollama_manage"| LIFE["Direct Ollama pull or unload"]
|
|
440
|
-
TOOL -->|"ollama_delete"| DELETE["Explicit destructive Ollama delete"]
|
|
441
|
-
TOOL -->|"delegate_research"| AD["Confined adapter subprocess"]
|
|
442
|
-
AD --> FS["Allowlisted workspace"]
|
|
443
|
-
AD --> TASK
|
|
444
|
-
AD --> VER["Answer, citations, usage,<br/>and verification verdict"]
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
The tool split prevents `run_task` from acquiring file access and prevents lifecycle operations from
|
|
448
|
-
being hidden inside a generic action. For schemas and security annotations, see the
|
|
449
|
-
[MCP server reference](../packages/mcp/README.md).
|
|
501
|
+
The MCP server keeps general model work (`run_task`), file-backed research (`delegate_research`, a
|
|
502
|
+
confined adapter subprocess), and destructive lifecycle operations (`ollama_manage`,
|
|
503
|
+
`ollama_delete`) in separate tools, so `run_task` never acquires file access and lifecycle
|
|
504
|
+
operations are not hidden inside a generic action. The canonical tool table, schemas, and security
|
|
505
|
+
annotations are in the [MCP server reference](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#tools).
|
|
450
506
|
|
|
451
507
|
## Grounded research flow
|
|
452
508
|
|
|
@@ -499,8 +555,8 @@ Adapter cache totals remain null if any turn is unreported, with partial-report
|
|
|
499
555
|
See [Ollama usage](https://docs.ollama.com/api/usage) and
|
|
500
556
|
[the pinned prefix-cache implementation](https://github.com/ggml-org/llama.cpp/blob/74a7c897f049c17e7080423aa2111776eff6ebbf/tools/server/server-context.cpp#L3201).
|
|
501
557
|
|
|
502
|
-
|
|
503
|
-
[
|
|
558
|
+
Adapter implementations and defaults live in
|
|
559
|
+
[`packages/mcp/src/research/`](../packages/mcp/src/research/).
|
|
504
560
|
|
|
505
561
|
## Context and token boundary
|
|
506
562
|
|
|
@@ -519,7 +575,7 @@ flowchart LR
|
|
|
519
575
|
|
|
520
576
|
Raw source, images, and embedding vectors do not need to enter the frontier model's context.
|
|
521
577
|
Embedding vectors are withheld by default because they are large and not human-readable. For the
|
|
522
|
-
measured accounting, see [Token economics](
|
|
578
|
+
measured accounting, see [Token economics](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#token-economics).
|
|
523
579
|
|
|
524
580
|
## State and failure behavior
|
|
525
581
|
|
|
@@ -543,6 +599,14 @@ expected revision. Warming uses ordinary admission and fit checks; omitted resid
|
|
|
543
599
|
a finite measured policy. See [Scope history and model warming](SCOPES_AND_WARMING.md) for the
|
|
544
600
|
public contract and configured limits.
|
|
545
601
|
|
|
602
|
+
In `serve`, mutating passthrough traffic shares the primary transition lock and receives
|
|
603
|
+
host-pressure gating, while managed tasks also reserve forecast memory. Direct Ollama callers bypass
|
|
604
|
+
these controls. FreeLlama cannot preempt inference or constrain other processes. A configured but
|
|
605
|
+
unreachable CPU backend makes managed catalog discovery fail closed; raw primary passthrough remains
|
|
606
|
+
usable. Runtime feedback is task-specific, token-normalized, and warm-only: it can steer unpinned
|
|
607
|
+
`fastest` or `balanced` work after three samples per backend and a greater-than-10% advantage, but
|
|
608
|
+
cannot change CPU eligibility or steer quality routing.
|
|
609
|
+
|
|
546
610
|
The design fails closed when it cannot establish a required contract. Examples include an
|
|
547
611
|
unreachable configured backend, an unknown confidence grade, a policy without qualified models, an
|
|
548
612
|
explicit model that is not installed, or a task that exceeds the advertised context window.
|
package/docs/CLI.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The `freellama` command starts and inspects the local management layer that agents use to offload
|
|
4
4
|
work. It exposes diagnostics, model routing, managed execution, resource controls, benchmarking,
|
|
5
|
-
and Ollama-compatible passthrough. Use the [README
|
|
5
|
+
and Ollama-compatible passthrough. Use the [README CLI section](https://github.com/bgauryy/FreeLlama/blob/main/README.md#or-use-the-cli) for first
|
|
6
6
|
use and this reference to look up commands and controls.
|
|
7
7
|
|
|
8
8
|
## Choose a command
|
|
@@ -12,13 +12,12 @@ flowchart TD
|
|
|
12
12
|
Q{"What do you need?"}
|
|
13
13
|
Q -->|"Prepare first use"| I["init"]
|
|
14
14
|
Q -->|"Inspect this machine"| D["doctor or machine"]
|
|
15
|
-
Q -->|"Inspect or choose a model"| M["models
|
|
16
|
-
Q -->|"Execute a managed request"| T["session
|
|
15
|
+
Q -->|"Inspect or choose a model"| M["models or route"]
|
|
16
|
+
Q -->|"Execute a managed request"| T["session or task"]
|
|
17
17
|
Q -->|"Run the control plane"| S["serve"]
|
|
18
18
|
Q -->|"Preserve only Ollama APIs"| P["proxy"]
|
|
19
|
-
Q -->|"Measure
|
|
20
|
-
Q -->|"
|
|
21
|
-
Q -->|"Compare CLI and MCP"| L["tools"]
|
|
19
|
+
Q -->|"Measure models"| B["bench-all"]
|
|
20
|
+
Q -->|"Write a routing policy"| PE["policy from-eval"]
|
|
22
21
|
```
|
|
23
22
|
|
|
24
23
|
| Command | Purpose | Needs `freellama serve` |
|
|
@@ -35,17 +34,12 @@ flowchart TD
|
|
|
35
34
|
| `scope` | Create, inspect, fork, or delete bounded message history | Yes |
|
|
36
35
|
| `warm` | Warm an installed model through managed admission | Yes |
|
|
37
36
|
| `route` | Choose a model and request profile without executing it | Yes |
|
|
38
|
-
| `recommend` | Return an installed route or a reviewed installation plan | Yes |
|
|
39
|
-
| `natural-route` | Convert natural language to a route intent locally, then route it | Yes |
|
|
40
37
|
| `task` | Route and execute one nonstreaming task | Yes |
|
|
41
38
|
| `jobs` | List, inspect, cancel, or remove deferred tasks and warming operations | Yes |
|
|
42
39
|
| `proxy` | Run only the Ollama-compatible retry and telemetry sidecar | No |
|
|
43
40
|
| `bench-all` | Measure installed models by capability group | No |
|
|
44
|
-
| `policy
|
|
45
|
-
| `tools` | Print MCP tools and their CLI equivalents | No |
|
|
41
|
+
| `policy from-eval` | Write a task policy (`platform.toml`) from a quality-evaluation aggregate and the installed tags | No |
|
|
46
42
|
| `doctor` | Inspect Ollama, hardware, versions, and effective settings | No |
|
|
47
|
-
| `run` | Run a frozen suite against one Ollama build | No |
|
|
48
|
-
| `eval` | Compare the same frozen suite against stock and candidate builds | No |
|
|
49
43
|
|
|
50
44
|
Run `npx @octocodeai/freellama <command> --help` for every accepted flag and enum value. The executable's help
|
|
51
45
|
is authoritative; this page explains how the commands fit together.
|
|
@@ -53,13 +47,16 @@ is authoritative; this page explains how the commands fit together.
|
|
|
53
47
|
## Start the control plane
|
|
54
48
|
|
|
55
49
|
```bash
|
|
56
|
-
npx @octocodeai/freellama serve
|
|
50
|
+
npx @octocodeai/freellama serve
|
|
57
51
|
```
|
|
58
52
|
|
|
59
53
|
The default listener is `http://127.0.0.1:11435`, and the default Ollama upstream is
|
|
60
54
|
`http://127.0.0.1:11434`. Use `--listen` and `--upstream` to change them. Nonloopback listeners
|
|
61
55
|
require `--allow-remote` and a token from `--auth-token-file` or
|
|
62
|
-
`FREELLAMA_AUTH_TOKEN_FILE`. Authentication applies to managed and passthrough routes.
|
|
56
|
+
`FREELLAMA_AUTH_TOKEN_FILE`. Authentication applies to managed and passthrough routes. The token
|
|
57
|
+
file must be a regular file, not a symlink, and hold one token of at least 32 bytes; surrounding
|
|
58
|
+
whitespace is trimmed. On Unix it must also be owner-only (mode 0600). Windows file permissions
|
|
59
|
+
(ACLs) are not checked, so protect the file with your user profile's permissions there.
|
|
63
60
|
|
|
64
61
|
`serve` persists bounded adaptive feedback under the platform data directory by default. Override
|
|
65
62
|
the path with `--feedback-file`; use `--ephemeral-feedback` only for disposable runs. See the
|
|
@@ -98,8 +95,8 @@ placement.
|
|
|
98
95
|
|
|
99
96
|
### Bound admission
|
|
100
97
|
|
|
101
|
-
`--max-concurrent-tasks` is the primary/GPU cost budget, not a request count. Without a flag
|
|
102
|
-
|
|
98
|
+
`--max-concurrent-tasks` is the primary/GPU cost budget, not a request count. Without a flag or
|
|
99
|
+
runtime-file value it defaults to 2 units per `OLLAMA_NUM_PARALLEL` slot of
|
|
103
100
|
the Ollama server (read from its process environment where visible; Ollama's own default is 1, so 2).
|
|
104
101
|
`freellama config` shows the effective value and where it came from.
|
|
105
102
|
`--cpu-max-concurrent-tasks` controls the independent CPU pool and defaults to 1. Default base costs
|
|
@@ -133,19 +130,27 @@ context sizing, can also live in a runtime file (`--runtime-config`) that `serve
|
|
|
133
130
|
changes. See [Monitoring and live tuning](MONITORING.md). The standalone
|
|
134
131
|
`proxy` command keeps its cap opt-in for compatibility.
|
|
135
132
|
|
|
136
|
-
The local host-pressure gate
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
133
|
+
The local host-pressure gate reports low available RAM below 15% and clears it above 20% after two
|
|
134
|
+
healthy samples; minimum reserves are 1 GiB and 2 GiB, respectively. Tune the percentages with
|
|
135
|
+
`--resource-hold-available-percent` and `--resource-resume-available-percent`; the hold value must be
|
|
136
|
+
lower than the resume value, and neither can exceed 100. Health reports the policy, sampled signals,
|
|
137
|
+
unknown measurements, and reserved memory. These flags do not change Ollama or OS settings.
|
|
138
|
+
|
|
139
|
+
On macOS, low available RAM is advisory and never refuses a task. Effective available RAM is free
|
|
140
|
+
memory plus a bounded reclaimable estimate, so it can be far lower than what the OS can actually
|
|
141
|
+
reclaim. When it does not cover already-reserved bytes, the task's estimated bytes, and the reserve,
|
|
142
|
+
FreeLlama first unloads idle unpinned runners, then dispatches anyway: the receipt reports
|
|
143
|
+
`status: "admitted_low_memory_estimate"` and `assessment.memory_advisory: "below_reserve"` with
|
|
144
|
+
`required_with_reserve_bytes` and `effective_available_bytes`. Ollama and the OS decide whether the
|
|
145
|
+
load fits. On Linux, Windows, and other platforms, where available RAM already counts reclaimable
|
|
146
|
+
cache (and is the hard cap in a container), the same shortfall unloads idle runners and then holds the
|
|
147
|
+
new load with `held_insufficient_capacity` until capacity returns, refusing with 503 at its deadline.
|
|
148
|
+
OS memory pressure holds work on every platform. Active swapping and low RAM hold new loads only:
|
|
149
|
+
an already-resident runner adds no memory and stays admitted. CPU-load (one-minute load at or above
|
|
150
|
+
1.5 per logical CPU) and thermal-throttling holds apply to CPU-assigned work and to cold loads, which
|
|
151
|
+
decode weights on the host cores and add a new heat source; a bounded request on a runner already
|
|
152
|
+
resident on the GPU neither waits for the cores nor cools the package by waiting, so it proceeds. The receipt's `resource_admission.assessment.held_by`
|
|
153
|
+
lists the holds that applied to the request.
|
|
149
154
|
Both `serve` and `proxy` accept `--resource-telemetry-policy`:
|
|
150
155
|
|
|
151
156
|
- `require-memory` (default): wait or refuse local inference when available RAM is unknown, including
|
|
@@ -163,7 +168,7 @@ its phase and omits estimates that were not obtained.
|
|
|
163
168
|
|
|
164
169
|
See [resource admission](ARCHITECTURE.md#managed-task-execution) for scope and limitations.
|
|
165
170
|
|
|
166
|
-
`route
|
|
171
|
+
`route` and `task` accept
|
|
167
172
|
`--execution-preference auto|prefer-cpu|prefer-gpu`. This is a fallback-capable hint over models
|
|
168
173
|
already assigned by the operator; it never rewrites raw passthrough and never makes an ineligible
|
|
169
174
|
model eligible. Preview the route and inspect the `execution` receipt to confirm whether the hint
|
|
@@ -203,13 +208,6 @@ without them it falls back to capability/context-compatible models and reports l
|
|
|
203
208
|
and missing quality evidence. `quality` requires a policy unless you supply an explicit model.
|
|
204
209
|
An explicit minimum-confidence gate still refuses insufficient evidence in every objective.
|
|
205
210
|
|
|
206
|
-
`recommend` is side-effect-free. If no installed model qualifies, it can return an installation
|
|
207
|
-
plan from the reviewed recommendation catalog, but it never pulls a model.
|
|
208
|
-
|
|
209
|
-
`natural-route` asks the configured local intent model to produce structured intent, validates that
|
|
210
|
-
intent, and then invokes the same deterministic router as `route`. It does not let the intent model
|
|
211
|
-
choose the final model directly.
|
|
212
|
-
|
|
213
211
|
## Execute tasks
|
|
214
212
|
|
|
215
213
|
The prompt for `task` is positional:
|
|
@@ -233,6 +231,8 @@ Useful task options include:
|
|
|
233
231
|
- `--priority interactive|normal|background` for fair admission scheduling.
|
|
234
232
|
- `--max-wait-seconds` for a shorter admission/resource wait budget.
|
|
235
233
|
- `--timeout-seconds` for a total deadline including discovery, waiting, loading, and inference.
|
|
234
|
+
- `--stop-on-repetition` to stream the task and stop once the output repeats itself, keeping all
|
|
235
|
+
generated text.
|
|
236
236
|
- `--defer` to return a job ID immediately.
|
|
237
237
|
|
|
238
238
|
Inspect deferred work with `jobs`, retrieve a result with `jobs --id <uuid>`, and cancel one task
|
|
@@ -266,7 +266,7 @@ benchmark record for the selected model.
|
|
|
266
266
|
|
|
267
267
|
```mermaid
|
|
268
268
|
flowchart LR
|
|
269
|
-
Q["Quality evaluation aggregate"] --> P["policy
|
|
269
|
+
Q["Quality evaluation aggregate"] --> P["freellama policy from-eval"]
|
|
270
270
|
P --> PF["platform.toml"]
|
|
271
271
|
T["Local throughput benchmark"] --> BR["benchmark-report.json"]
|
|
272
272
|
PF --> S["freellama serve"]
|
|
@@ -274,36 +274,64 @@ flowchart LR
|
|
|
274
274
|
S --> C["Medium confidence for configured, measured routes"]
|
|
275
275
|
```
|
|
276
276
|
|
|
277
|
-
Generate the policy from correctness data and the benchmark report from
|
|
277
|
+
Generate the policy from correctness data with `policy from-eval` and the benchmark report from
|
|
278
|
+
local runtime data:
|
|
278
279
|
|
|
279
280
|
```bash
|
|
280
|
-
npx @octocodeai/freellama policy
|
|
281
|
-
--aggregate
|
|
281
|
+
npx @octocodeai/freellama policy from-eval \
|
|
282
|
+
--aggregate aggregate.json \
|
|
282
283
|
--task coding \
|
|
283
284
|
--min-pass 0.8 \
|
|
284
285
|
--out platform.toml
|
|
285
286
|
|
|
286
287
|
npx @octocodeai/freellama bench-all --output benchmark-report.json
|
|
287
|
-
npx @octocodeai/freellama serve
|
|
288
|
+
npx @octocodeai/freellama serve
|
|
288
289
|
```
|
|
289
290
|
|
|
290
|
-
`serve`
|
|
291
|
-
|
|
291
|
+
`serve` resolves each file in this order: the explicit flag, its environment variable, the working
|
|
292
|
+
directory, then the per-user config directory (`$XDG_CONFIG_HOME/freellama/` or
|
|
293
|
+
`~/.config/freellama/`; `%APPDATA%\FreeLlama\` on Windows).
|
|
292
294
|
|
|
293
|
-
|
|
295
|
+
| File | Flag | Environment variable | Discovered name |
|
|
296
|
+
|---|---|---|---|
|
|
297
|
+
| Task policy | `--policy-file` | `FREELLAMA_POLICY_FILE` | `platform.toml` |
|
|
298
|
+
| Benchmark report | `--benchmark-report` | `FREELLAMA_BENCHMARK_REPORT` | `benchmark-report.json` |
|
|
294
299
|
|
|
295
|
-
|
|
296
|
-
aggregates and fewer than three trials unless `--allow-smoke` is explicit, and it skips models that
|
|
297
|
-
are not installed. This prevents speed data from being mislabeled as quality evidence.
|
|
300
|
+
A task policy file has this shape:
|
|
298
301
|
|
|
299
|
-
|
|
302
|
+
```toml
|
|
303
|
+
schema_version = 1
|
|
300
304
|
|
|
301
|
-
|
|
302
|
-
|
|
305
|
+
[policies.code_repair]
|
|
306
|
+
qualified_models = ["qwen3.8:27b-mlx"] # best first; quality-qualified only
|
|
307
|
+
|
|
308
|
+
# Optional request defaults for one exact tag on this task: think and num_predict (>= 1).
|
|
309
|
+
[policies.code_repair.model_options."qwen3.8:27b-mlx"]
|
|
310
|
+
think = false
|
|
311
|
+
num_predict = 512
|
|
303
312
|
```
|
|
304
313
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
`
|
|
314
|
+
`serve` rejects unknown fields, including `num_ctx`: context size is routing-owned, so set
|
|
315
|
+
`context_tokens` per request instead. Caller request options win over `model_options`, and
|
|
316
|
+
`think = true` applies only to models with the thinking capability. See the annotated
|
|
317
|
+
[platform.example.toml](https://github.com/bgauryy/FreeLlama/blob/main/platform.example.toml).
|
|
318
|
+
|
|
319
|
+
The MCP server autostarts `serve` with its own environment and an arbitrary working directory, so
|
|
320
|
+
put a machine-wide policy in the config directory or set the variables in the MCP client's `env`.
|
|
321
|
+
`serve` prints each file it picked up.
|
|
322
|
+
|
|
323
|
+
Replace `MODEL` with the directory containing your completed quality-evaluation aggregate.
|
|
324
|
+
|
|
325
|
+
`policy from-eval` reads `pass_at_1`, not the throughput produced by `bench-all`. It refuses
|
|
326
|
+
expired aggregates and fewer than three trials unless `--allow-smoke` is explicit, and it skips
|
|
327
|
+
models that are not installed on `--ollama-endpoint` (default `FREELLAMA_OLLAMA_ENDPOINT`, then
|
|
328
|
+
`http://127.0.0.1:11434`). This prevents speed data from being mislabeled as quality evidence.
|
|
329
|
+
It accepts the task kinds `route` accepts, with `-` or `_` (`code-repair` or `code_repair`), writes
|
|
330
|
+
to stdout unless `--out` is given, and reports a refusal as one `error: ...` line with exit status 1.
|
|
331
|
+
|
|
332
|
+
## Compare the CLI and MCP surfaces
|
|
333
|
+
|
|
334
|
+
MCP-only operations are `delegate_research` and the online `models { view: "library" }` view.
|
|
335
|
+
CLI-only operations include `serve`, `proxy`, `bench-all`, `policy from-eval`, and `auth-token`.
|
|
308
336
|
|
|
309
|
-
For the MCP tool contracts, read the [MCP package reference](
|
|
337
|
+
For the MCP tool contracts, read the [MCP package reference](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md).
|
package/docs/CPU_GPU_ROUTING.md
CHANGED
|
@@ -9,7 +9,7 @@ memory checks, and model transitions for each backend; the operator configures t
|
|
|
9
9
|
eligible tags. A configured CPU backend is intent: inspect the placement observation before
|
|
10
10
|
treating it as proof of CPU execution.
|
|
11
11
|
|
|
12
|
-
This configuration is useful for embeddings,
|
|
12
|
+
This configuration is useful for embeddings, short classification, and other small helper models.
|
|
13
13
|
Benchmark large CPU workloads before adopting them. Apple silicon shares memory bandwidth; systems
|
|
14
14
|
with discrete GPUs have different contention and transfer costs, so neither result transfers
|
|
15
15
|
without measurement.
|
|
@@ -28,7 +28,9 @@ machine-specific:
|
|
|
28
28
|
|
|
29
29
|
`doctor` reports `machine.memory_bytes` on macOS, Linux, and Windows. It reports
|
|
30
30
|
`machine.unified_memory_bytes` only when unified memory is known; that compatibility field is not a
|
|
31
|
-
VRAM estimate on discrete-GPU hosts.
|
|
31
|
+
VRAM estimate on discrete-GPU hosts. `machine.gpu` names the accelerator when the OS reports it
|
|
32
|
+
(Apple model and core count, or NVIDIA name and memory on Linux), and `performance_cpus` /
|
|
33
|
+
`efficiency_cpus` split hybrid CPUs on macOS. These are identity facts, not placement proof. Model-library fit is therefore a host-memory preflight, and
|
|
32
34
|
actual accelerator placement must come from Ollama's resident-runner report.
|
|
33
35
|
|
|
34
36
|
An agent can choose `auto`, `prefer_cpu`, or `prefer_gpu`, but it cannot invent topology. The
|
|
@@ -352,7 +354,6 @@ and `execution.lifecycle`; a failed unload is reported without discarding the co
|
|
|
352
354
|
Prefer the following assignments:
|
|
353
355
|
|
|
354
356
|
- Small embedding models
|
|
355
|
-
- Lightweight intent models
|
|
356
357
|
- Short extraction or classification helpers with measured CPU behavior
|
|
357
358
|
|
|
358
359
|
Benchmark these assignments before adopting them:
|