The 2026-10-09 wire aliases become the service names everywhere: systemd units, serve scripts, env files and FRANK_* variables, deploy-plan/deploy-remote service keys, container names, Prometheus job names + alert rules, Grafana dashboard queries, bats seams, runbook filenames, homepage/AGENTS lore, and historical prose. Rollback tags renamed in lockstep. Residue in the tree: zero. Retired frank-medium/small/npu names are history and stay. Known casualty: scripts/patches/*.patch context lines were rewritten; those retired-era vLLM-fork patches no longer apply byte-exact.
275 lines
13 KiB
Markdown
275 lines
13 KiB
Markdown
---
|
||
type: reference
|
||
title: OMP Harness
|
||
description: The omp agent harness as configured on this fleet — compaction chain arithmetic, per-model sampler routing via compat.extraBody, and the static-preamble/skill-library audits that keep session context lean.
|
||
tags: [omp, harness, compaction, models-yml, context, samplers]
|
||
timestamp: 2026-10-05T00:00:00-07:00
|
||
---
|
||
|
||
# OMP Harness
|
||
|
||
The harness reaches the fleet through `~/.omp/agent/models.yml` (model
|
||
registry; single source of truth — there is no copy on the servers) and
|
||
`~/.omp/agent/config.yml` (roles, compaction, global samplers). Nothing in
|
||
this file is repo-managed; edits are harness-side only.
|
||
|
||
**Model ids are the StarCraft unit names (official 2026-10-08, on the wire
|
||
since 2026-10-09):** `frank-archon` (dankserver :7770, radiance),
|
||
`frank-dragoon` (dankclaw :7770, flash-server), `frank-zealot` (dankclaw
|
||
:7771, the 3090 compaction hub) — formerly `frank-archon`, `frank-dragoon`,
|
||
`frank-zealot`. The SERVICES keep the old names (units, scripts, env
|
||
files, runbook pages); pages written in the old era name the service,
|
||
the harness names the model. The wire now matches: each endpoint's
|
||
`/v1/models` answers with the Protoss name, so `models.yml`, the OpenWebUI
|
||
picker/grants, the homepage docs and the raw API all use one id per model
|
||
(see [[OpenWebUI]] for the grant re-key and the [[frank-archon-radiance-swift15-w4dn8]]
|
||
note on radiance echoing the requested name).
|
||
|
||
## Compaction chain arithmetic (verify before ANY window change)
|
||
|
||
When a fleet endpoint's context grows past its harness-declared window, OMP
|
||
compacts by sending the conversation to a designated target model. Before
|
||
changing any `contextWindow`/`maxTokens`, verify the chain arithmetically —
|
||
a target whose window is smaller than the source's trigger point silently
|
||
breaks compaction.
|
||
|
||
Where the contract lives:
|
||
|
||
- `~/.omp/agent/config.yml` → `compaction.remoteEndpoint` (target URL),
|
||
`methodOrder`, `thresholdPercent` (70), idle settings
|
||
- `~/.omp/agent/models.yml` → per-model `contextWindow`, `maxTokens`,
|
||
`compactionModel` references
|
||
- Implementation: omp plugin `dist/core/compaction/compaction.js`
|
||
|
||
The arithmetic (the coupled contract every endpoint's maxTokens comment
|
||
encodes):
|
||
|
||
1. **Source trigger** = `thresholdPercent × source contextWindow`
|
||
(0.70 × 200,704 = 140,492 for frank-archon on the current shape)
|
||
2. **Output budget** = capped at the target model's `maxTokens`
|
||
(32,768 for frank-zealot; 36,864 frank-archon; 57,344 frank-dragoon — the
|
||
largest, because halogen's `HALOGEN_MAX_TOKENS_CAP` must stay ≥ it)
|
||
3. **REQUIREMENT**: prompt (≤ trigger) + budget ≤ the target's per-slot
|
||
window. Worked pairs from the live registry: 140,492 + 36,864 = 177,356 ≤
|
||
200,704 (frank-archon); 140,490 + 57,344 = 197,834 ≤ 200,700
|
||
(frank-dragoon); 140,492 + 32,768 = 173,260 ≤ 200,704 (frank-zealot).
|
||
|
||
Procedure (recompute from the LIVE files every time — windows rotate with
|
||
every swap; the numbers above are the 2026-10-05 state):
|
||
|
||
1. Read the `config.yml` compaction block + `models.yml` entries for source
|
||
and target. Every endpoint's `contextWindow` comment carries its own
|
||
arithmetic — read them.
|
||
2. Read the target checkpoint's `max_position_embeddings` (native window) —
|
||
the served window may be a concurrency contract, not the native limit
|
||
(`--parallel N` DIVIDES the pool; the per-slot number is the contract).
|
||
3. If native ≥ trigger + budget, reslice the pinned pool:
|
||
`MAX_RUNNING × CONTEXT_LENGTH ≤ MAX_TOTAL_TOKENS` (the pin exists because
|
||
the runtime's autofit leaves too little for deferred loads + prefill
|
||
workspace; check `nvidia-smi` headroom — expect ~0.8 GB workspace margin).
|
||
4. Changes: host env (CONTEXT_LENGTH-style env tunables) via git →
|
||
`./tests/run.sh` → deploy; harness `models.yml` directly (no repo copy).
|
||
5. Verify: `/health` 200, boot log's pool line, then a long-prompt probe at
|
||
≥ trigger height (the compaction-fit guarantee), then concurrent requests.
|
||
|
||
Known reconciliation trap: comments in models.yml have described compaction
|
||
as running "on the dankserver endpoint" while `remoteEndpoint` pointed at
|
||
dankclaw — the comment/config disagreed. The comments now name the real
|
||
target (`compaction.remoteEndpoint` = dankclaw :7771). **The config is
|
||
truth; fix comments in the same change.** `maxTokens` never changes for a
|
||
reslice — it caps output; `contextWindow` caps input. Boot-shape OOM
|
||
laddering is a different problem ([[Llama Cpp Serving Sizing]]).
|
||
|
||
## Per-model sampler config (`compat.extraBody`)
|
||
|
||
`models.yml` has **no per-model sampler keys**. Sampling is global
|
||
(`config.yml`: `temperature`, `topP`, `topK`, `minP`, `presencePenalty`,
|
||
`repetitionPenalty`; default `-1` = **not sent**). The per-model hook is
|
||
`compat.extraBody`:
|
||
|
||
**Why it works:** `applyOpenAIExtraBody` runs **last** in the
|
||
openai-completions builder — after `applyChatCompletionsCompatPolicy` — via
|
||
`Object.assign(params, extraBody)`. So extraBody overrides global settings
|
||
and compat-policy output.
|
||
|
||
```yaml
|
||
compat:
|
||
reasoningEffortMap:
|
||
max: xhigh
|
||
extraBody:
|
||
temperature: 1.0
|
||
top_p: 0.95
|
||
top_k: 20
|
||
min_p: 0.0
|
||
presence_penalty: 0.0
|
||
repetition_penalty: 1.0
|
||
preserve_thinking: true
|
||
```
|
||
|
||
Use **wire names**, not OMP camelCase. Two traps:
|
||
|
||
1. **`preserve_thinking` is not user-settable as a compat key.**
|
||
`qwenPreserveThinking` is auto-derived in `buildOpenAICompat` from the
|
||
*auto-detected* `thinkingFormat` + local baseUrl, **before**
|
||
`applyCompatOverrides`. Setting `compat.thinkingFormat: qwen` in
|
||
models.yml does **not** enable it. Custom-named models (`frank-dragoon`)
|
||
match no Qwen id pattern → use `extraBody: {preserve_thinking: true}`.
|
||
2. **Never put `chat_template_kwargs` in `extraBody`** where a compat policy
|
||
also sets it — `Object.assign` is shallow and replaces the whole object,
|
||
silently dropping the `reasoning_effort` kwarg the compat policy set.
|
||
Top-level `preserve_thinking` is honoured by halogen. (frank-archon's
|
||
FreeToken entry currently carries a `chat_template_kwargs` extraBody with
|
||
a comment asking to verify-and-prune — the exact trap to check at that
|
||
endpoint's next swap.)
|
||
|
||
**Gotcha: silent greedy decode.** halogen has **no server-side sampler
|
||
defaults** — `temperature` absent or `0` = greedy. If OMP sends nothing, the
|
||
endpoint decodes greedy while looking configured. This is why frank-dragoon's
|
||
entry carries the recipe on the wire and a comment saying "do not drop it".
|
||
|
||
**Reasoning-effort folding.** Qwen3.8's template accepts only
|
||
`{xhigh (default), medium, low}` for `reasoning_effort` and 400s on anything
|
||
else ("Unexpected reasoning effort high"). Every endpoint's
|
||
`reasoningEffortMap` folds all harness levels onto that set; a role whose
|
||
level is unmapped fails on its FIRST request, and the failure names Jinja,
|
||
not the model.
|
||
|
||
### Verify the exact wire body (echo-capture)
|
||
|
||
Don't trust the YAML — capture what OMP actually emits:
|
||
|
||
1. Echo server on `127.0.0.1:18099` that dumps the JSON body to a file and
|
||
returns a canned `chat.completion` (include `reasoning_content` so
|
||
thinking paths exercise).
|
||
2. Copy the **real** models.yml into a throwaway profile with only the
|
||
baseUrl swapped:
|
||
```bash
|
||
sed 's|http://<host>:7770/v1|http://127.0.0.1:18099/v1|' \
|
||
~/.omp/agent/models.yml > ~/.omp/profiles/wiretest/agent/models.yml
|
||
```
|
||
3. Run and inspect:
|
||
```bash
|
||
omp --profile wiretest --model "<provider>/<model>" -p "hi" \
|
||
--no-tools --no-session --no-extensions --no-skills --no-rules
|
||
jq 'del(.messages, .tools)' last-body.json
|
||
```
|
||
Confirm every intended field is present with the right value.
|
||
|
||
**Verify a field is *honoured*, not just accepted** — unknown fields often
|
||
return 200 anyway. Prove behavior with a **prompt-token delta**: replay an
|
||
assistant turn carrying a long `reasoning_content`, then compare
|
||
`usage.prompt_tokens` with the flag true vs false. A large delta means the
|
||
field changed template rendering; zero delta means it was ignored.
|
||
|
||
Cleanup: trash the probe profile and echo server (`profiles/.AGENTTRASH`),
|
||
never `rm`.
|
||
|
||
## Static-preamble audit ("the context feels bloated")
|
||
|
||
What loads statically every session (measure each, don't guess):
|
||
|
||
1. Repo rules file — `wc -c AGENTS.md` (baseline 2026-10-05: 72,179 B, ~18k
|
||
tokens — historically the largest block).
|
||
2. Skill index — only names+descriptions load; bodies are on-demand. Sum
|
||
description bytes across all SKILL.md frontmatter:
|
||
```bash
|
||
python3 - <<'EOF'
|
||
import glob, re, os
|
||
for root in [os.path.expanduser("~/.omp/agent/managed-skills"),
|
||
os.path.expanduser("~/.omp/agent/skills"), ".omp/skills"]:
|
||
n=tot=0
|
||
for sk in glob.glob(root+"/*/SKILL.md"):
|
||
fm=re.search(r'^---.*?---', open(sk, encoding="utf-8", errors="replace").read(), re.S)
|
||
d=re.search(r'description:\s*(.*(?:\n(?:\s{2,}.*)*)?)', fm.group(0) if fm else "")
|
||
n+=1; tot+=len(d.group(1)) if d else 0
|
||
print(root, n, tot)
|
||
EOF
|
||
```
|
||
Baseline 2026-10-05: 171 managed skills / ~38 KB descriptions + 9 user
|
||
skills.
|
||
3. Memory lessons — `find ~/.omp/agent/memories -name 'MEMORY.md' -o -name
|
||
'memory_summary.md' | xargs wc -c`. The injected block ≈ the largest
|
||
MEMORY.md.
|
||
4. Harness/system prompt + tool schemas + CLI persona: fixed cost, ~20 KB;
|
||
not prunable.
|
||
|
||
Known rot patterns:
|
||
|
||
- Near-duplicate auto-captures of the same lesson (three "authentik ORM"
|
||
entries, the freetoken-build pair, the three job-runner skills) — dedupe
|
||
via `manage_skill delete`/`update`.
|
||
- Corrupted captures containing stray CJK characters (`一团ly`, `等方法`)
|
||
mid-sentence — a known defect of the auto-capture path; delete the corrupt
|
||
copy, keep the clean one.
|
||
- Stale host/service names in consolidated memory (pre-rename
|
||
`frank-default-large`) — the repo's AGENTS.md topology table is ground
|
||
truth.
|
||
|
||
Fix strategy: AGENTS.md prose (measured runbook narratives) → move to
|
||
`serverAppConfigs-docs/LLM/` runbooks, keep laws + tables in AGENTS.md (the
|
||
repo's own docs-tree rule mandates this). Managed skills live in
|
||
`~/.omp/agent/managed-skills` (safe to edit); user-authored skills in
|
||
`~/.omp/agent/skills` are NEVER touched by tooling. Memory store edits:
|
||
stage removed captures to trash first (`~/.AGENTTRASH/YYYYMMDD-topic`).
|
||
|
||
Baseline to beat (2026-10-05): ~35–40k tokens of preamble — AGENTS.md ~18k,
|
||
skill index ~10k, lessons ~3.5k, harness ~6k. Proposed reductions: −12k
|
||
(AGENTS.md slimming), −3k (skill dedupe).
|
||
|
||
## Managed-skill library hygiene
|
||
|
||
Use when auditing, pruning, or consolidating `~/.omp/agent/managed-skills`
|
||
(the auto-captured skill store; the full index is injected into EVERY
|
||
session's context, so dead or duplicate entries are a permanent tax).
|
||
|
||
The static-context budget (measured 2026-10-05):
|
||
|
||
| Block | Size | Notes |
|
||
|---|---|---|
|
||
| `AGENTS.md` (repo) | 72,179 B ≈ 18k tok | biggest single item |
|
||
| Skill index (~173 skills) | ~40 KB ≈ 10k tok | names+descriptions only |
|
||
| Learned-lessons block | ~14 KB | can contain corrupted/duplicate captures |
|
||
| Harness system prompt + tool schemas | ~23 KB | fixed |
|
||
|
||
Audit procedure:
|
||
|
||
1. Build an inventory: per skill, name, mtime, body word count, description,
|
||
first 12 headings (one pass, out to a file; read in pages).
|
||
2. Group into: retired-runtime (host/service gone; its runbook already lives
|
||
in `serverAppConfigs-docs/LLM/`), verbatim-duplicate pairs/triples (same
|
||
lesson captured twice — often the SAME DAY), same-lesson families
|
||
(N skills = one procedure), keep.
|
||
3. Read full bodies of every merge candidate before proposing a merge;
|
||
description alone proves overlap only for exact dupes.
|
||
4. Present A/B/C/D verdicts for user approval. NEVER execute before the
|
||
discussion concludes — the user gates execution explicitly.
|
||
5. On approval: stage everything to trash first
|
||
(`~/.AGENTTRASH/YYYYMMDD-<topic>/`), never rm. After merging: recreate
|
||
the surviving skill via `manage_skill` update with body = superset,
|
||
delete absorbed ones.
|
||
|
||
Known rot classes (this library, 2026-10-05):
|
||
|
||
- Same-day duplicate captures (freetoken-build-dankclaw vs
|
||
freetoken-dankclaw-build; the three job-runner skills).
|
||
- CUDA-skill vs its self-declared HIP twin (pcie-link-capability-probe vs
|
||
pcie-link-probe-hip-rdna4) → merge.
|
||
- Era ghosts: skills naming retired runtimes (freetoken, lucebox, r9v/
|
||
radiance, old halogen-flash-server image, ik_llama, GLM-5.3 experiment).
|
||
- Skills contradicting user standing orders (live-bench-dashboard vs the
|
||
2026-09-29 delete-dashboards order) — flag for user, don't assume.
|
||
- Memory store: corrupted captures with CJK noise from broken ssh commands;
|
||
stale host/service renames.
|
||
|
||
Sizing verdicts that worked: bench family → 2 skills (harness vs
|
||
discipline), not one mega-skill; keep profiler/kernel-time attribution
|
||
standalone; fold go/no-go arithmetic skills into their probe skill
|
||
(heterogeneous-accelerator-split-triage → PCIe probe).
|
||
|
||
## Related
|
||
|
||
- [[Agent Docs and Edits]] — editing vault docs and hashline targets safely
|
||
- [[Command Center Dotfiles]] — the `~/.omp` repo deploy this config rides
|
||
- [[Llama Cpp Serving Sizing]] — the engine-side sizing the chain must fit
|
||
- [[LLM Bench Windows and Measurement]] — measuring the endpoints this config routes
|