Files
serverAppConfigs/serverAppConfigs-docs/Agent/OMP Harness.md
T
Frank 87721ab0fe rename frank-small → frank-secondary (Dankclaw llama.cpp :7771)
Cross-cutting rename of the current llama.cpp endpoint on the RTX 3090
(port 7771) from frank-small to frank-secondary:

- Service trio: scripts/{frank-small.env,frank-small.service,
  serve-frank-small.sh,download-frank-small.sh} → frank-secondary.*
- Test: tests/frank_small_unit.bats → tests/frank_secondary_unit.bats
- Runbooks: serverAppConfigs-docs/LLM/frank-small-*.md →
  frank-secondary-*.md (9 files); the FreeToken runbook stays
  freetoken-frank-small.md (it documents the retired CUDA-era service)
- Identifiers: FRANK_SMALL→FRANK_SECONDARY, llm_small→llm_secondary,
  LLM_SMALL_*→LLM_SECONDARY_*, deploy_llm_small→deploy_llm_secondary
- Historical references to the OLD frank-small (FreeToken/CUDA on the
  3090, and the Dankserver service that became frank-medium) are
  preserved verbatim — they describe what the service was called
  at the time.
2026-10-06 15:37:13 -07:00

12 KiB
Raw Blame History

type, title, description, tags, timestamp
type title description tags timestamp
reference OMP Harness 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.
omp
harness
compaction
models-yml
context
samplers
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.

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-primary on the current shape)
  2. Output budget = capped at the target model's maxTokens (32,768 for frank-secondary; 36,864 frank-primary; 57,344 frank-large — 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-primary); 140,490 + 57,344 = 197,834 ≤ 200,700 (frank-large); 140,492 + 32,768 = 173,260 ≤ 200,704 (frank-secondary).

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.

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-large) 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-primary'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-large'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:
    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:
    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:
    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).