@octocodeai/freellama-mcp-server 0.5.0 → 0.6.1
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 +106 -0
- package/DEVELOPING.md +112 -0
- package/LICENSE-MIT +1 -1
- package/README.md +133 -284
- package/dist/index.js +1514 -1409
- package/dist/research/bash-agent.js +2435 -0
- package/dist/research/octocode-agent.js +1639 -0
- package/docs/ARCHITECTURE.md +176 -101
- package/docs/CLI.md +94 -63
- package/docs/CPU_GPU_ROUTING.md +15 -14
- package/docs/MODEL_SELECTION.md +116 -5
- package/docs/MONITORING.md +26 -16
- package/docs/PRODUCTION.md +33 -26
- package/docs/README.md +9 -17
- package/docs/SCOPES_AND_WARMING.md +8 -9
- package/docs/TESTING.md +22 -35
- package/native/index.d.ts +179 -174
- package/native/index.js +3 -3
- package/package.json +12 -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/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#from-the-terminal) 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
|
|
@@ -81,8 +78,9 @@ npx @octocodeai/freellama serve \
|
|
|
81
78
|
--cpu-model nomic-embed-text:latest
|
|
82
79
|
```
|
|
83
80
|
|
|
84
|
-
FreeLlama rejects a CPU upstream with no assignments,
|
|
85
|
-
|
|
81
|
+
FreeLlama rejects a CPU upstream with no assignments, `--cpu-model` without `--cpu-upstream`, and a
|
|
82
|
+
CPU upstream that is the same Ollama endpoint as `--upstream`, including loopback aliases on one port.
|
|
83
|
+
It also sets `options.num_gpu=0` on CPU-assigned managed requests.
|
|
86
84
|
Read [CPU and GPU model routing](CPU_GPU_ROUTING.md) before deploying this layout.
|
|
87
85
|
|
|
88
86
|
After startup, require `contracts.placement_observation` and `placement_evidence_gate`, then inspect
|
|
@@ -98,8 +96,8 @@ placement.
|
|
|
98
96
|
|
|
99
97
|
### Bound admission
|
|
100
98
|
|
|
101
|
-
`--max-concurrent-tasks` is the primary/GPU cost budget, not a request count. Without a flag
|
|
102
|
-
|
|
99
|
+
`--max-concurrent-tasks` is the primary/GPU cost budget, not a request count. Without a flag or
|
|
100
|
+
runtime-file value it defaults to 2 units per `OLLAMA_NUM_PARALLEL` slot of
|
|
103
101
|
the Ollama server (read from its process environment where visible; Ollama's own default is 1, so 2).
|
|
104
102
|
`freellama config` shows the effective value and where it came from.
|
|
105
103
|
`--cpu-max-concurrent-tasks` controls the independent CPU pool and defaults to 1. Default base costs
|
|
@@ -133,27 +131,39 @@ context sizing, can also live in a runtime file (`--runtime-config`) that `serve
|
|
|
133
131
|
changes. See [Monitoring and live tuning](MONITORING.md). The standalone
|
|
134
132
|
`proxy` command keeps its cap opt-in for compatibility.
|
|
135
133
|
|
|
136
|
-
The local host-pressure gate
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
134
|
+
The local host-pressure gate reports low available RAM below 15% and clears it above 20% after two
|
|
135
|
+
healthy samples; minimum reserves are 1 GiB and 2 GiB, respectively. Tune the percentages with
|
|
136
|
+
`--resource-hold-available-percent` and `--resource-resume-available-percent`; the hold value must be
|
|
137
|
+
lower than the resume value, and neither can exceed 100. Health reports the policy, sampled signals,
|
|
138
|
+
unknown measurements, and reserved memory. These flags do not change Ollama or OS settings.
|
|
139
|
+
|
|
140
|
+
On macOS, low available RAM is advisory and never refuses a task. Effective available RAM is free
|
|
141
|
+
memory plus a bounded reclaimable estimate, so it can be far lower than what the OS can actually
|
|
142
|
+
reclaim. When it does not cover already-reserved bytes, the task's estimated bytes, and the reserve,
|
|
143
|
+
FreeLlama first unloads idle unpinned runners, then dispatches anyway: the receipt reports
|
|
144
|
+
`status: "admitted_low_memory_estimate"` and `assessment.memory_advisory: "below_reserve"` with
|
|
145
|
+
`required_with_reserve_bytes` and `effective_available_bytes`. Ollama and the OS decide whether the
|
|
146
|
+
load fits. On Linux, Windows, and other platforms, where available RAM already counts reclaimable
|
|
147
|
+
cache (and is the hard cap in a container), the same shortfall unloads idle runners and then holds the
|
|
148
|
+
new load with `held_insufficient_capacity` until capacity returns, refusing with 503 at its deadline.
|
|
149
|
+
OS memory pressure holds all work where the OS reports it (macOS, and Linux when the kernel
|
|
150
|
+
exposes `/proc/pressure/memory`; Windows has no host collector yet). Active swapping and low RAM hold new loads only:
|
|
151
|
+
an already-resident runner adds no memory and stays admitted. CPU-load (one-minute load at or above
|
|
152
|
+
1.5 per logical CPU) and thermal-throttling holds apply to CPU-assigned work and to cold loads, which
|
|
153
|
+
decode weights on the host cores and add a new heat source; a bounded request on a runner already
|
|
154
|
+
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`
|
|
155
|
+
lists the holds that applied to the request.
|
|
149
156
|
Both `serve` and `proxy` accept `--resource-telemetry-policy`:
|
|
150
157
|
|
|
151
|
-
- `require-memory` (default): wait or refuse local inference when available RAM is
|
|
152
|
-
raw requests with zero forecast bytes. Missing thermal data alone does not block
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
- `require-memory` (default on Linux and macOS): wait or refuse local inference when available RAM is
|
|
159
|
+
unknown, including raw requests with zero forecast bytes. Missing thermal data alone does not block
|
|
160
|
+
this policy.
|
|
161
|
+
- `require-all`: require all signals applicable to the collector. The built-in Linux collector reads
|
|
162
|
+
OS memory pressure from `/proc/pressure/memory` when the kernel provides it, but has no thermal
|
|
163
|
+
signal and marks it as unsupported; custom collectors must provide it. Unsupported signals are not
|
|
164
|
+
evidence of healthy hardware.
|
|
165
|
+
- `best-effort`: explicitly permit unknown telemetry unless an observed pressure hold is active. This
|
|
166
|
+
is the default on Windows, which has no built-in memory collector.
|
|
157
167
|
|
|
158
168
|
Remote upstreams bypass local host policy. Raw metadata and empty unload requests remain available
|
|
159
169
|
during a hold. Route receipts separate `queue_readiness` from `resource_readiness`, and include
|
|
@@ -163,7 +173,7 @@ its phase and omits estimates that were not obtained.
|
|
|
163
173
|
|
|
164
174
|
See [resource admission](ARCHITECTURE.md#managed-task-execution) for scope and limitations.
|
|
165
175
|
|
|
166
|
-
`route
|
|
176
|
+
`route` and `task` accept
|
|
167
177
|
`--execution-preference auto|prefer-cpu|prefer-gpu`. This is a fallback-capable hint over models
|
|
168
178
|
already assigned by the operator; it never rewrites raw passthrough and never makes an ineligible
|
|
169
179
|
model eligible. Preview the route and inspect the `execution` receipt to confirm whether the hint
|
|
@@ -203,13 +213,6 @@ without them it falls back to capability/context-compatible models and reports l
|
|
|
203
213
|
and missing quality evidence. `quality` requires a policy unless you supply an explicit model.
|
|
204
214
|
An explicit minimum-confidence gate still refuses insufficient evidence in every objective.
|
|
205
215
|
|
|
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
216
|
## Execute tasks
|
|
214
217
|
|
|
215
218
|
The prompt for `task` is positional:
|
|
@@ -233,6 +236,8 @@ Useful task options include:
|
|
|
233
236
|
- `--priority interactive|normal|background` for fair admission scheduling.
|
|
234
237
|
- `--max-wait-seconds` for a shorter admission/resource wait budget.
|
|
235
238
|
- `--timeout-seconds` for a total deadline including discovery, waiting, loading, and inference.
|
|
239
|
+
- `--stop-on-repetition` to stream the task and stop once the output repeats itself, keeping all
|
|
240
|
+
generated text.
|
|
236
241
|
- `--defer` to return a job ID immediately.
|
|
237
242
|
|
|
238
243
|
Inspect deferred work with `jobs`, retrieve a result with `jobs --id <uuid>`, and cancel one task
|
|
@@ -266,7 +271,7 @@ benchmark record for the selected model.
|
|
|
266
271
|
|
|
267
272
|
```mermaid
|
|
268
273
|
flowchart LR
|
|
269
|
-
Q["Quality evaluation aggregate"] --> P["policy
|
|
274
|
+
Q["Quality evaluation aggregate"] --> P["freellama policy from-eval"]
|
|
270
275
|
P --> PF["platform.toml"]
|
|
271
276
|
T["Local throughput benchmark"] --> BR["benchmark-report.json"]
|
|
272
277
|
PF --> S["freellama serve"]
|
|
@@ -274,36 +279,62 @@ flowchart LR
|
|
|
274
279
|
S --> C["Medium confidence for configured, measured routes"]
|
|
275
280
|
```
|
|
276
281
|
|
|
277
|
-
Generate the policy from correctness data and the benchmark report from
|
|
282
|
+
Generate the policy from correctness data with `policy from-eval` and the benchmark report from
|
|
283
|
+
local runtime data:
|
|
278
284
|
|
|
279
285
|
```bash
|
|
280
|
-
npx @octocodeai/freellama policy
|
|
281
|
-
--aggregate
|
|
286
|
+
npx @octocodeai/freellama policy from-eval \
|
|
287
|
+
--aggregate aggregate.json \
|
|
282
288
|
--task coding \
|
|
283
289
|
--min-pass 0.8 \
|
|
284
290
|
--out platform.toml
|
|
285
291
|
|
|
286
292
|
npx @octocodeai/freellama bench-all --output benchmark-report.json
|
|
287
|
-
npx @octocodeai/freellama serve
|
|
293
|
+
npx @octocodeai/freellama serve
|
|
288
294
|
```
|
|
289
295
|
|
|
290
|
-
`serve`
|
|
291
|
-
|
|
296
|
+
`serve` resolves each file in this order: the explicit flag, its environment variable, the working
|
|
297
|
+
directory, then the per-user config directory (`$XDG_CONFIG_HOME/freellama/` or
|
|
298
|
+
`~/.config/freellama/`; `%APPDATA%\FreeLlama\` on Windows).
|
|
292
299
|
|
|
293
|
-
|
|
300
|
+
| File | Flag | Environment variable | Discovered name |
|
|
301
|
+
|---|---|---|---|
|
|
302
|
+
| Task policy | `--policy-file` | `FREELLAMA_POLICY_FILE` | `platform.toml` |
|
|
303
|
+
| Benchmark report | `--benchmark-report` | `FREELLAMA_BENCHMARK_REPORT` | `benchmark-report.json` |
|
|
294
304
|
|
|
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.
|
|
305
|
+
A task policy file has this shape:
|
|
298
306
|
|
|
299
|
-
|
|
307
|
+
```toml
|
|
308
|
+
schema_version = 1
|
|
300
309
|
|
|
301
|
-
|
|
302
|
-
|
|
310
|
+
[policies.code_repair]
|
|
311
|
+
qualified_models = ["qwen3.8:27b-mlx"] # best first; quality-qualified only
|
|
312
|
+
|
|
313
|
+
# Optional request defaults for one exact tag on this task: think and num_predict (>= 1).
|
|
314
|
+
[policies.code_repair.model_options."qwen3.8:27b-mlx"]
|
|
315
|
+
think = false
|
|
316
|
+
num_predict = 512
|
|
303
317
|
```
|
|
304
318
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
`
|
|
319
|
+
`serve` rejects unknown fields, including `num_ctx`: context size is routing-owned, so set
|
|
320
|
+
`context_tokens` per request instead. Caller request options win over `model_options`, and
|
|
321
|
+
`think = true` applies only to models with the thinking capability. See the annotated
|
|
322
|
+
[platform.example.toml](https://github.com/bgauryy/FreeLlama/blob/main/platform.example.toml).
|
|
323
|
+
|
|
324
|
+
The MCP server autostarts `serve` with its own environment and an arbitrary working directory, so
|
|
325
|
+
put a machine-wide policy in the config directory or set the variables in the MCP client's `env`.
|
|
326
|
+
`serve` prints each file it picked up.
|
|
327
|
+
|
|
328
|
+
`policy from-eval` reads `pass_at_1`, not the throughput produced by `bench-all`. It refuses
|
|
329
|
+
expired aggregates and fewer than three trials unless `--allow-smoke` is explicit, and it skips
|
|
330
|
+
models that are not installed on `--ollama-endpoint` (default `FREELLAMA_OLLAMA_ENDPOINT`, then
|
|
331
|
+
`http://127.0.0.1:11434`). This prevents speed data from being mislabeled as quality evidence.
|
|
332
|
+
It accepts the task kinds `route` accepts, with `-` or `_` (`code-repair` or `code_repair`), writes
|
|
333
|
+
to stdout unless `--out` is given, and reports a refusal as one `error: ...` line with exit status 1.
|
|
334
|
+
|
|
335
|
+
## Compare the CLI and MCP surfaces
|
|
336
|
+
|
|
337
|
+
MCP-only operations are `delegate_research` and the online `models { view: "library" }` view.
|
|
338
|
+
CLI-only operations include `serve`, `proxy`, `bench-all`, `policy from-eval`, and `auth-token`.
|
|
308
339
|
|
|
309
|
-
For the MCP tool contracts, read the [MCP package reference](
|
|
340
|
+
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
|
|
@@ -54,7 +56,7 @@ flowchart TB
|
|
|
54
56
|
CP --> CPU["CPU runner"]
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
FreeLlama does not
|
|
59
|
+
FreeLlama does not rewrite raw passthrough request bodies or route them by model. A direct Ollama client that
|
|
58
60
|
needs model-aware CPU placement must use the managed task endpoint instead.
|
|
59
61
|
|
|
60
62
|
## Start the backends
|
|
@@ -115,7 +117,7 @@ unsafe or ambiguous configurations:
|
|
|
115
117
|
- A CPU model assignment without `--cpu-upstream`
|
|
116
118
|
- Empty model names
|
|
117
119
|
- The same socket expressed through aliases such as `localhost:11434` and `127.0.0.1:11434`
|
|
118
|
-
-
|
|
120
|
+
- An upstream that points back to the FreeLlama listener, or an unspecified host such as `0.0.0.0`
|
|
119
121
|
|
|
120
122
|
A nonloopback FreeLlama listener requires `--allow-remote` and bearer-token authentication.
|
|
121
123
|
See the [production runbook](PRODUCTION.md) for remote ingress requirements.
|
|
@@ -214,7 +216,7 @@ curl --silent http://127.0.0.1:11436/api/ps | jq '.models[] | {name, size, size_
|
|
|
214
216
|
A fully CPU-loaded model reports `size_vram:0`; a fully GPU-loaded model reports positive VRAM
|
|
215
217
|
covering its resident `size`. Compare both values from the same `/api/ps` entry. Installed `/api/tags`
|
|
216
218
|
file bytes can differ from resident memory and cannot prove a mixed placement. Positive VRAM without
|
|
217
|
-
total resident size stays unknown. `observation.status` is `verified`, `mismatch`, or unavailable
|
|
219
|
+
total resident size stays unknown. `observation.status` is `verified`, `mismatch`, `not_resident`, or `unavailable`. Unknown, mixed, and mismatched
|
|
218
220
|
samples are reported but excluded from adaptive feedback.
|
|
219
221
|
|
|
220
222
|
## Understand concurrency
|
|
@@ -250,17 +252,18 @@ FreeLlama can overlap requests across the two servers even when each Ollama proc
|
|
|
250
252
|
`OLLAMA_NUM_PARALLEL=1`. Raising `OLLAMA_NUM_PARALLEL` affects parallel requests within one server
|
|
251
253
|
and multiplies K/V-cache memory; it is a separate tuning decision. `OLLAMA_MAX_QUEUE` likewise
|
|
252
254
|
bounds each Ollama process after FreeLlama admission. It does not replace either backend's weighted
|
|
253
|
-
FreeLlama budget, bounded waiter count, or queue-wait deadline. Raw passthrough uses a
|
|
254
|
-
one-stream default cap in `serve`; its permit is held until the streamed response ends or is dropped.
|
|
255
|
+
FreeLlama budget, bounded waiter count, or queue-wait deadline. Raw generation passthrough uses a
|
|
256
|
+
separate one-stream default cap in `serve`; its permit is held until the streamed response ends or is dropped.
|
|
255
257
|
|
|
256
258
|
The runtime file's `[task_costs]` table can tune individual task-kind weights without increasing
|
|
257
259
|
the entire pool's ceiling. Default vision weight four can serialize two vision requests under a
|
|
258
260
|
four-unit budget even when Ollama has two slots. A lower weight requires a qualified workload;
|
|
259
261
|
it does not add engine slots or relax memory checks. See
|
|
260
262
|
[monitoring controls](MONITORING.md#adaptive-concurrency).
|
|
261
|
-
|
|
262
|
-
lock and receive 503
|
|
263
|
-
|
|
263
|
+
Raw generation requests also require exclusive access to the primary backend's managed transition
|
|
264
|
+
lock and receive 503 if it stays busy past the raw queue wait. Metadata GET/HEAD, `/api/show`,
|
|
265
|
+
model-store calls (pull, push, copy, delete), and empty `keep_alive:0` unloads remain available.
|
|
266
|
+
This prevents raw inference from overlapping a managed generation on that backend.
|
|
264
267
|
|
|
265
268
|
## Understand automatic feedback
|
|
266
269
|
|
|
@@ -352,7 +355,6 @@ and `execution.lifecycle`; a failed unload is reported without discarding the co
|
|
|
352
355
|
Prefer the following assignments:
|
|
353
356
|
|
|
354
357
|
- Small embedding models
|
|
355
|
-
- Lightweight intent models
|
|
356
358
|
- Short extraction or classification helpers with measured CPU behavior
|
|
357
359
|
|
|
358
360
|
Benchmark these assignments before adopting them:
|
|
@@ -381,9 +383,8 @@ A configured but unreachable CPU backend causes model discovery to fail closed.
|
|
|
381
383
|
can also be unavailable until the secondary server returns. Raw passthrough to the primary server
|
|
382
384
|
continues to work because it does not depend on catalog discovery.
|
|
383
385
|
|
|
384
|
-
For the surrounding
|
|
385
|
-
|
|
386
|
-
[CLI reference](CLI.md).
|
|
386
|
+
For the surrounding Ollama settings, see [Production](PRODUCTION.md#configure-ollama-explicitly). For
|
|
387
|
+
all `serve` flags, see the [CLI reference](CLI.md).
|
|
387
388
|
|
|
388
389
|
## Upstream sources
|
|
389
390
|
|
package/docs/MODEL_SELECTION.md
CHANGED
|
@@ -10,8 +10,7 @@ are not compiled into routing. Re-run
|
|
|
10
10
|
`doctor.machine.memory_bytes` is host RAM; a discrete GPU's usable VRAM must be observed separately.
|
|
11
11
|
|
|
12
12
|
For supported features and sourced publisher use-case guidance, inspect
|
|
13
|
-
`models {view:"installed", includeLibrary:true}` through MCP.
|
|
14
|
-
[Ollama metadata reference](MODEL_METADATA.md) explains digest matching, variant capabilities,
|
|
13
|
+
`models {view:"installed", includeLibrary:true}` through MCP. [Model metadata](#model-metadata) explains digest matching, variant capabilities,
|
|
15
14
|
custom-model fallbacks, and how to read family claims without treating them as quality measurements.
|
|
16
15
|
|
|
17
16
|
```mermaid
|
|
@@ -33,10 +32,16 @@ flowchart TD
|
|
|
33
32
|
grounded research, image description, OCR, and summarization. Using one large multimodal model also
|
|
34
33
|
avoided contention between separate heavy text and vision runners.
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
and
|
|
35
|
+
In those evaluations it was strong at grounded lookup, long-context retrieval and strict instruction
|
|
36
|
+
following, needed `think:true` and a generous output budget for multi-step reasoning, and about a
|
|
37
|
+
third of its unsupervised code-review findings were false or context-limited.
|
|
38
38
|
These examples do not establish that a tag is installed or suitable on your host.
|
|
39
39
|
|
|
40
|
+
Dedicated OCR models answer best to the prompts their model card documents; send them with base64
|
|
41
|
+
`images` in `run_task`. A model that repeats its answer until the output cap can run with
|
|
42
|
+
`stopOnRepetition:true`. See [Route images](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#route-images)
|
|
43
|
+
for the early stop and the `output_check` receipt.
|
|
44
|
+
|
|
40
45
|
`muse-glimmer:30b-mlx` was a credible alternative and answered 29 of 30 questions correctly
|
|
41
46
|
(96.7%) with the Bash adapter, but it was slower and did not add a required capability in this
|
|
42
47
|
workload.
|
|
@@ -61,7 +66,7 @@ keywords, repository search was both faster and more accurate in the measured sa
|
|
|
61
66
|
|
|
62
67
|
## Place helper models on CPU when useful
|
|
63
68
|
|
|
64
|
-
A small embedding or
|
|
69
|
+
A small embedding or helper model can be assigned to a second CPU Ollama process while a large
|
|
65
70
|
generation model remains resident on the primary GPU-capable process. This can overlap independent
|
|
66
71
|
work, but it does not make CPU inference fast. Apple silicon shares memory bandwidth; discrete-GPU
|
|
67
72
|
systems have different transfer and contention costs and need their own benchmark.
|
|
@@ -76,3 +81,109 @@ this machine and workload, not a universal model-placement rule. Follow
|
|
|
76
81
|
`bench-all` measures local performance. A quality benchmark measures correctness. FreeLlama needs
|
|
77
82
|
both the generated task policy and local benchmark data before grading a route medium confidence.
|
|
78
83
|
See the [CLI reference](CLI.md#earn-medium-routing-confidence) for the commands.
|
|
84
|
+
|
|
85
|
+
## Model metadata
|
|
86
|
+
|
|
87
|
+
The MCP `models` tool reads your Ollama instance and can enrich results with Ollama's public model
|
|
88
|
+
library. Supported features and advertised use cases are metadata: they do not change routing
|
|
89
|
+
confidence, and exact-model benchmarks and policy remain the quality evidence. The CLI's `models`
|
|
90
|
+
command reports the core catalog and does not expose these enrichment flags.
|
|
91
|
+
|
|
92
|
+
| Request | Result | External access |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `models {view:"installed"}` | Managed inventory with a `knowledge` object for each model | Local backend data only |
|
|
95
|
+
| `models {view:"installed", includeLibrary:true}` | Inventory enriched with public guidance for verified local tags | Fetches model family and tag pages from ollama.com |
|
|
96
|
+
| `models {view:"detail", model:"gemma3:1b"}` | Ollama details, maximum context, and supported-use explanations | Selected Ollama endpoint only |
|
|
97
|
+
| `models {view:"detail", model:"gemma3:1b", includeLibrary:true}` | Details plus public guidance after a tag and digest check | Selected Ollama endpoint and ollama.com |
|
|
98
|
+
| `models {view:"library", query:"coding"}` | Public family search with descriptions and advertised feature chips | ollama.com and optional local inventory/profile reads |
|
|
99
|
+
| `models {view:"library", model:"gemma3"}` | All public tags with size, digest prefix, context, modalities, and cloud status | ollama.com and optional local inventory/profile reads |
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
| Option | Valid views | Default | Meaning |
|
|
103
|
+
|---|---|---|---|
|
|
104
|
+
| `includeLibrary` | `installed`, `detail` | `false` | Requests public metadata; the default makes no website calls |
|
|
105
|
+
| `includeReadme` | Library step 2, or `detail` with `includeLibrary:true` | `false` | Returns README text, capped at 65,536 characters, with its format and truncation flag |
|
|
106
|
+
| `includeVerbose` | `detail` | `false` | Returns Ollama's license and Modelfile fields independently of README enrichment |
|
|
107
|
+
| `limit`, `cursor` | `raw`, library tag listings; `limit` also applies to library search | Tag/raw page size 20; search limit 10 | Pages large lists; the tag cursor rejects a changed tag list |
|
|
108
|
+
| `ollamaEndpoint` | Direct Ollama views and library inventory reads | Configured Ollama endpoint | Chooses the Ollama instance; enriched managed inventory uses each model's assigned backend |
|
|
109
|
+
|
|
110
|
+
An incompatible option returns an error before any lookup. Installed enrichment omits full READMEs;
|
|
111
|
+
request one model's detail to read its README.
|
|
112
|
+
|
|
113
|
+
### Supported features
|
|
114
|
+
|
|
115
|
+
`knowledge.supportedFeatures` preserves the feature strings from the selected source
|
|
116
|
+
(`supportedFeaturesSource`: `ollama_api` or `freellama_catalog`). Unknown future strings stay visible
|
|
117
|
+
but do not create routing requirements. `knowledge.supportedUseCases` explains each recognized
|
|
118
|
+
feature with `capability`, `use`, `reason`, and `basis:"supported_feature"`;
|
|
119
|
+
`knowledge.quality` stays `"metadata_only"`.
|
|
120
|
+
|
|
121
|
+
| Feature | Supported workflow | What to evaluate separately |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| `completion` | Text generation | Coding, summarization, reasoning, and instruction-following accuracy |
|
|
124
|
+
| `tools` | Tool calls | Argument correctness, tool selection, and agent-loop reliability |
|
|
125
|
+
| `vision` | Image input | OCR and visual understanding accuracy |
|
|
126
|
+
| `audio` | Audio workflows advertised by the model | Supported audio task and accuracy |
|
|
127
|
+
| `embedding` | Retrieval and similarity vectors | Retrieval quality on your documents |
|
|
128
|
+
| `thinking` | A thinking mode | Reasoning accuracy, latency, and token cost |
|
|
129
|
+
| `insert` | Suffix-based text insertion | Completion accuracy in the target code or text |
|
|
130
|
+
| `image` | Image generation | Output quality and supported controls |
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
### Public guidance and provenance
|
|
134
|
+
|
|
135
|
+
For a verified installed model, `knowledge.library` contains the source page, tag-page URL,
|
|
136
|
+
`fetchedAt`, `expiresAt`, `cached`, exact public tag metadata, and:
|
|
137
|
+
|
|
138
|
+
| Field | Meaning |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `description` | The public family description |
|
|
141
|
+
| `advertisedFamilyCapabilities` | Family feature chips; these do not extend the local tag's capabilities |
|
|
142
|
+
| `advertisedUseCases` | Recognized coding, tool-calling, image-understanding/OCR, reasoning, embedding, summarization, question-answering, translation, and long-context claims |
|
|
143
|
+
| `advertisedUseCases[].evidence` | A bounded source excerpt, source URL, and fetch timestamp |
|
|
144
|
+
| `usageNotes` | Bounded excerpts about requirements, restrictions, context, memory, languages, or query prefixes |
|
|
145
|
+
| `readmeAvailable` | Whether a README was extracted |
|
|
146
|
+
| `readme` | Requested text with `format` (`markdown` or `text`) and `truncated` |
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
Advertised uses have `basis:"advertised"`, `scope:"family"`, and `quality:"unmeasured"`. Extraction
|
|
150
|
+
skips fenced code and negative statements; an omitted use means no recognized claim, not absence.
|
|
151
|
+
These labels are not the `run_task` task enum. Local capabilities filter advertised uses: a family
|
|
152
|
+
vision chip cannot make `gemma3:1b` a vision candidate.
|
|
153
|
+
|
|
154
|
+
Installed enrichment requires the exact public tag and a digest-prefix match of at least 12 hex
|
|
155
|
+
characters. Custom names are never mapped by architecture or guessed base model; without a verified
|
|
156
|
+
match, public guidance is withheld. Library step 2 describes public models before installation, so
|
|
157
|
+
its guidance stays family-scoped; each `tags[]` entry carries its own modalities, context, digest
|
|
158
|
+
prefix, and `cloud` flag. Search's `cloudAvailable` badge does not prove local downloads are absent.
|
|
159
|
+
|
|
160
|
+
### Lookup states
|
|
161
|
+
|
|
162
|
+
| `library.status` | Meaning | Next action |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| `not_requested` | Website enrichment was not requested | Set `includeLibrary:true` if external lookup is useful |
|
|
165
|
+
| `matched` | Installed tag and public digest prefix match | Read the sourced guidance, then evaluate the exact tag |
|
|
166
|
+
| `available` | Public family and tag pages were parsed in library step 2 | Inspect the exact tag before recommending a download |
|
|
167
|
+
| `unverified` | Digest or current backend inventory could not be verified | Recheck local inventory; retain local feature information |
|
|
168
|
+
| `digest_mismatch` | The public tag differs from the installed digest | Treat public guidance as unavailable for this installed model |
|
|
169
|
+
| `tag_not_found` | The parsed public tag list has no exact matching tag | Check the source and custom-model provenance |
|
|
170
|
+
| `unmatched` | The name cannot resolve to an exact public Ollama name | Keep use-case suitability unknown until provenance is verified |
|
|
171
|
+
| `not_found` | A requested public page returned HTTP 404 | Check the source URL or custom name |
|
|
172
|
+
| `unavailable` | Transport, timeout, HTTP refusal, or page-size limit prevented lookup | Retry later; local results remain available |
|
|
173
|
+
| `parse_error` | HTML content or tag rows were not recognized | Inspect the source; do not conclude the model is absent |
|
|
174
|
+
| `remote_model`, `remote_tag` | Remote Ollama fields or a hosted tag identify cloud execution | Select a local download tag for local execution |
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
`localModel:false` flags detected remote entries; cloud tags never become local trial
|
|
178
|
+
recommendations. This metadata is not processor-placement evidence.
|
|
179
|
+
|
|
180
|
+
### Cache and request bounds
|
|
181
|
+
|
|
182
|
+
Each MCP process caches at most 128 families: successes for one hour, failures for one minute;
|
|
183
|
+
concurrent requests share one lookup and a restart clears the cache. Installed enrichment runs at
|
|
184
|
+
most four family lookups concurrently. Requests use GET, refuse redirects, cap each page at 2 MiB,
|
|
185
|
+
and time out after the smaller of 10 seconds and `FREELLAMA_MCP_FETCH_TIMEOUT_SECONDS`. They disclose
|
|
186
|
+
the requested public family name to ollama.com. Download size does not establish runtime memory
|
|
187
|
+
fit, placement, or quality, and model discovery never authorizes a pull. Sources:
|
|
188
|
+
[model details API](https://docs.ollama.com/api-reference/show-model-details),
|
|
189
|
+
[model-list API](https://docs.ollama.com/api/tags).
|
package/docs/MONITORING.md
CHANGED
|
@@ -38,7 +38,9 @@ token and keeps it only for the browser tab.
|
|
|
38
38
|
whether the model is pinned.
|
|
39
39
|
- **`host`**: available and reserved RAM, whether the pressure gate is holding, and discrete-GPU
|
|
40
40
|
total and free memory (`nvidia-smi` or amdgpu sysfs) when available. Optional `gpu_activity`
|
|
41
|
-
reports driver counters separately from resident memory.
|
|
41
|
+
reports driver counters separately from resident memory. On macOS, `thermal_pressure` is the
|
|
42
|
+
system thermal pressure level (`nominal`, `moderate`, `heavy`, `trapping`, `sleeping`); `heavy`
|
|
43
|
+
or worse holds CPU-assigned work and cold loads. Other platforms report `null`.
|
|
42
44
|
- **`ollama`**: the Ollama server's effective `OLLAMA_*` settings with a source for each — the
|
|
43
45
|
running process's environment (Linux `/proc/<pid>/environ`, macOS `ps eww` for a same-user
|
|
44
46
|
process), `launchctl getenv` for the macOS app, FreeLlama's own environment, or Ollama's default.
|
|
@@ -72,7 +74,8 @@ FreeLlama admission limits remain governed by its runtime configuration.
|
|
|
72
74
|
|
|
73
75
|
`host.gpu_activity` is nullable. When available, it identifies its `source`,
|
|
74
76
|
`scope: "observed_devices_all_processes"`, `window: "driver_defined"`, and individual `devices`.
|
|
75
|
-
Each device has an identity, nullable `busy_percent`, and nullable `memory_busy_percent`.
|
|
77
|
+
Each device has an identity, nullable `busy_percent`, and nullable `memory_busy_percent`. Apple
|
|
78
|
+
devices may add `allocated_memory_bytes`, the driver's allocated memory across all processes.
|
|
76
79
|
An observed zero means the driver reported zero; a missing or malformed counter remains unknown.
|
|
77
80
|
Use `host.sample_age_ms` to check freshness.
|
|
78
81
|
|
|
@@ -115,8 +118,9 @@ The ledger lives next to the feedback file in the platform data directory. Choos
|
|
|
115
118
|
`/metrics` exposes counters (`freellama_tasks_total`, `freellama_prompt_tokens_total`,
|
|
116
119
|
`freellama_output_tokens_total`, `freellama_task_seconds_total`, `freellama_queue_wait_seconds_total`,
|
|
117
120
|
`freellama_load_seconds_total`, `freellama_raw_requests_total`, `freellama_evictions_total`,
|
|
118
|
-
`freellama_circuit_open_total`, `freellama_concurrency_limit_changes_total`)
|
|
119
|
-
backend, task, and outcome,
|
|
121
|
+
`freellama_circuit_open_total`, `freellama_concurrency_limit_changes_total`); task counters are
|
|
122
|
+
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,
|
|
120
124
|
loaded models, and `freellama_ollama_num_parallel`. Point Prometheus, Grafana Agent, or any
|
|
121
125
|
OpenMetrics-compatible scraper at it.
|
|
122
126
|
|
|
@@ -129,12 +133,13 @@ FreeLlama waits for safe capacity within a deadline and bounds the retained back
|
|
|
129
133
|
| Managed queue full | `429` | `admission_queue_full` |
|
|
130
134
|
| Raw proxy over its cap after `raw_queue_wait_seconds` | `429` | |
|
|
131
135
|
| Managed wait exceeded `max_queue_wait_seconds` (or the task's `max_wait_seconds`) | `503` | `admission_timeout` |
|
|
132
|
-
|
|
|
136
|
+
| OS pressure, swapping, CPU, thermal, or required telemetry still holds when the waiting budget expires (low available RAM alone only warns on macOS; low RAM and swapping never hold an already-resident runner, and CPU load and thermal never hold one on the GPU) | `503` | `resource_admission_unavailable` |
|
|
133
137
|
| Backend circuit open | `503` | `upstream_circuit_open` |
|
|
134
138
|
|
|
135
139
|
These capacity refusals carry a `Retry-After` header and `retry_after_seconds` in the body. For a queue it
|
|
136
|
-
is estimated from the queue depth, the
|
|
137
|
-
|
|
140
|
+
is estimated from the queue depth, the lanes that can run at once (current limit divided by the
|
|
141
|
+
task's cost), and the backend's recent average service time, which excludes queue wait (1 to 120
|
|
142
|
+
seconds). A task can ask for a shorter wait with `max_wait_seconds` (`maxWaitSeconds`
|
|
138
143
|
in MCP); the server caps it at the configured maximum.
|
|
139
144
|
|
|
140
145
|
## Circuit breaker
|
|
@@ -166,7 +171,7 @@ costs, and execution receipts use the resolved policy. Health retains its summar
|
|
|
166
171
|
exposes the complete task-kind map under `admission.costs.base_by_task`. Task kinds remain
|
|
167
172
|
caller-declared; these weights are cooperative scheduling policy, not workload classification.
|
|
168
173
|
See the
|
|
169
|
-
[runtime example](
|
|
174
|
+
[runtime example](https://github.com/bgauryy/FreeLlama/blob/main/freellama.runtime.example.toml) for the table syntax.
|
|
170
175
|
|
|
171
176
|
With `adaptive_concurrency = "cpu"` (the default) or `"all"`, each pool's limit moves between 1 and
|
|
172
177
|
its configured ceiling:
|
|
@@ -263,9 +268,10 @@ out-of-memory shrink-and-retry only applies when the context was not requested e
|
|
|
263
268
|
|
|
264
269
|
With `context_mode = "ollama_default"` (the default), FreeLlama sizes the context as before but
|
|
265
270
|
omits `num_ctx` when Ollama's own default for the model is known, covers the request, and is at most
|
|
266
|
-
`auto_context_max` (32768). The default is
|
|
267
|
-
then `OLLAMA_CONTEXT_LENGTH`, then (
|
|
268
|
-
|
|
271
|
+
`auto_context_max` (32768). The default is the Modelfile's `num_ctx`, then the
|
|
272
|
+
runtime file's `ollama_default_context`, then `OLLAMA_CONTEXT_LENGTH`, then (primary backend
|
|
273
|
+
on a discrete GPU only) Ollama's VRAM tier, from total VRAM minus `OLLAMA_GPU_OVERHEAD` — 4096 below
|
|
274
|
+
23 GiB, 32768 below 47 GiB, 262144 from 47 GiB. Receipts show `context_sizing.num_ctx_sent` and the default used.
|
|
269
275
|
Memory estimates always use the context Ollama can allocate. Use `"explicit"` to always
|
|
270
276
|
send `num_ctx`.
|
|
271
277
|
|
|
@@ -273,13 +279,17 @@ send `num_ctx`.
|
|
|
273
279
|
|
|
274
280
|
Put any of the settings above in a TOML file and start `serve --runtime-config <file>` (or set
|
|
275
281
|
`FREELLAMA_RUNTIME_CONFIG`). Start from
|
|
276
|
-
[`freellama.runtime.example.toml`](
|
|
282
|
+
[`freellama.runtime.example.toml`](https://github.com/bgauryy/FreeLlama/blob/main/freellama.runtime.example.toml). `serve` checks the file every
|
|
277
283
|
two seconds and applies changes to live admission pools; a waiting task sees the new limit at once.
|
|
278
284
|
|
|
279
|
-
Precedence for every setting, strongest first: CLI flag,
|
|
280
|
-
runtime file, the built-in default.
|
|
281
|
-
|
|
282
|
-
|
|
285
|
+
Precedence for every setting, strongest first: CLI flag, environment variable (where one exists),
|
|
286
|
+
the runtime file, the built-in default. Only these settings have an environment variable:
|
|
287
|
+
`FREELLAMA_MAX_QUEUE_WAIT_SECONDS`, `FREELLAMA_EVICT_IDLE_MODELS`, `FREELLAMA_USAGE_QUEUE_CAPACITY`,
|
|
288
|
+
and the individual `FREELLAMA_SCOPE_*` and `FREELLAMA_KEEP_ALIVE_*` limits. Set every other key in
|
|
289
|
+
the runtime file or with its CLI flag. A flag or variable pins a value, so editing the file cannot
|
|
290
|
+
override it; `freellama config` shows which source won: `cli`, `env`, `file`, a default source
|
|
291
|
+
such as `default` or `ollama_num_parallel`, or `env_invalid` when a set variable failed validation.
|
|
292
|
+
A malformed file or an unknown key is rejected at reload and the previous values stay in force.
|
|
283
293
|
|
|
284
294
|
The default GPU budget follows the Ollama server: 2 units per `OLLAMA_NUM_PARALLEL` slot (one chat
|
|
285
295
|
per decoding slot), read from the running Ollama process where visible.
|