Commit Graph

379 Commits

Author SHA1 Message Date
vh 5a3a75b73d docs(backups): harden + live-activate /mnt/compose automount on ana-docker 2026-06-20 16:21:05 -07:00
vh 76b317ce3e feat(backups): freshness check + daily alert timer; record rest-server-ana recovery, fstab hardening, esh-pve-nas gap, worldtree admin-key provisioning 2026-06-20 16:13:13 -07:00
vh a7b4a82dec docs(backups): add backup architecture + freshness runbook; record rest-server-ana recovery + correct ana-docker sudo path 2026-06-20 15:56:41 -07:00
vh 8f15f6bb0d memory: capture 2026-06-20 session — Worldtree v0.37.7 demo fix, gitea notifier recovery, backup diagnosis 2026-06-20 15:46:14 -07:00
vh 58ec80d58a memory: snapshot — 2026-06-20
WT capability-gateway migration (aliases + swap-transparency rule + wildcard
removal + gen-frontier + v0.37.5 staged/triggered), OmniVoice streaming /tts
(diffusion TTFA floor), arbo v0.14.9, ratatoskr :8392 + admin.events.read
brokered, claude-bot admin on vh/Worldtree. Disk incident root-caused to a
94GB unrotated langfuse-clickhouse log (+ secondary image bloat) → fixed,
image/buildx prune cron added, Langfuse retired. Backup gap: rest-server-ana
is the ACTIVE ana-side restic target down ~months on a failed ana-nas NFS
mount (NOT decommissioned — docs corrected) → recovery deferred to clean
context, along with the docker-daemon log cap. Archived the [2026-06-16]
cluster (13 Recent + 8 Tried) to archival-memory.md.
2026-06-20 13:36:54 -07:00
vh f8eda1c333 chore(litellm): retire Langfuse — drop success/failure callbacks (redundant + crash-prone)
Langfuse's ClickHouse member spewed ~94 GB of unrotated logs and filled ana-docker's
root disk (took the fleet host to 100%, 28/48 containers unhealthy). Its trace UI was
redundant with LiteLLM's native logging — store_prompts_in_spend_logs:true already
captures full prompts/responses/tokens/cost/latency at :4000/ui — and nothing used its
unique trace-grouping/eval features (it only received flat gateway success_callbacks).
Removed the callbacks (gateway observability stays fully native) and tore down the
6-container langfuse stack + volumes on ana-docker. Re-add the callbacks if it returns.
2026-06-20 13:21:31 -07:00
vh 7819f96003 feat(litellm): add gen-frontier / gen-frontier-reasoning aliases (→ GLM 5.2)
Capability aliases for the PAID frontier tier, mirroring glm-5.2 / glm-5.2-
reasoning (thinking off / on) → openai/glm-5.2 @ z.ai. Worldtree binds these for
a frontier-grade generation/reasoning capability so the backing frontier model
can be swapped gateway-side (operator jump-started WT's request). PAID: only
all-proxy-models / explicitly-scoped keys reach them; the free all-agents-local
key stays fenced off z.ai spend. Verified both resolve + route to GLM 5.2.
2026-06-20 10:14:28 -07:00
vh d0eb09cac1 fix(litellm): remove the * → llama-swap wildcard (decommissioned backend)
llama-swap (ana-ml2:9292) is decommissioned (:9292 confirmed down), so the
catch-all wildcard routed every unmatched / typo'd / stale model name to a DEAD
backend, surfacing a misleading "Connection error" instead of a clean
"model not found". This is the exact footgun that silently swallowed Worldtree's
defunct model names (mistral-small-4 etc.) instead of erroring. Removed (operator
call) so unknown models now 404 loudly. Verified: gateway healthy post-restart,
a bogus model name now returns a clean not-found error, real aliases (gen) still
serve. Re-add explicit per-model entries if a swappable zoo ever returns.
2026-06-20 10:08:20 -07:00
vh d3721034c1 feat(litellm): Worldtree capability aliases (chat-judge, reranker, scalar-judge)
Stand up the gateway-side capability aliases for the role→capability model
indirection (worldtree-dev's transparent-swap direction; operator: no wt-
prefix, reuse the existing summarizer/classifier/gen alias convention).

- chat-judge  -> selene-1-mini-8b (mode chat)  — WT selene-judgment role.
- reranker    -> qwen3-reranker (mode rerank)  — generic name for the cap.
- scalar-judge -> Skywork-Reward-V2 via a pass_through_endpoint to ana-ml2:8003
  (LiteLLM has no reward/pooling MODE, so it's a passthrough, gateway-key-gated;
  consumers hit /scalar-judge/<route> e.g. /score|/pooling|/classify).

Deliberately NO generic `embedding` alias: embedding vectors are model-specific
(not swap-transparent), so that capability stays `qwen3-embedding` — the model-
specific name is the guardrail against treating it as freely swappable. Verified
all three live (chat-judge 200, reranker present, scalar-judge passthrough 200
returning a Skywork reward). Deployed + gateway health-gated.
2026-06-20 09:53:09 -07:00
vh cd92b85157 feat(omnivoice): tune streaming defaults (16-step + aggressive packing)
Empirical follow-up to the streaming /tts smoke test on the 3090. OmniVoice
is diffusion: a ~fixed per-call overhead (~1.5s at 32 steps, ~0.7s at 16)
dominates regardless of chunk length, so the upstream-claimed 40x RTF does
NOT hold here (measured ~2.8x/32-step, ~5.6x/16-step) and the chatterbox-
tuned scheduler over-chunks and starves.

- Streaming /tts defaults to num_step=16 (TTFA ~1.5s -> ~0.7s); batch
  /v1/audio/speech stays num_step=32 for quality. Per-request override intact.
- Scheduler prior raised to rtf_prior=20 (env OMNIVOICE_STREAM_RTF_PRIOR,
  wired through compose + .env.example) so it packs whole-text-minus-first-
  sentence into a few chunks: validated ~3 chunks, no starvation, total wall
  ~= one-shot, less per-chunk silence padding.
- Docs corrected: the "sub-second / 40x" claims were wrong; streaming has a
  diffusion TTFA floor (~0.7s) and wins mainly on long replies. chatterbox-
  fast (autoregressive, ~0.5s TTFA) stays the lowest-latency front-end;
  OmniVoice is the multilingual / voice-design complement.
2026-06-19 22:58:55 -07:00
vh 288d085236 feat(omnivoice): streaming /tts + language-safe sanitizer
Add a live-consumer streaming path and text sanitation to the OmniVoice
wrapper, so it can front speech-to-speech chat engines (not just the
asset-engine's batch WAV use).

- POST /tts: chunked 24 kHz mono s16le PCM (or open-ended WAV), driven by
  the adaptive buffer-ratchet scheduler. Emits the first sentence
  immediately, then ratchets chunk size up on OmniVoice's ~40x realtime
  headroom -> sub-second time-to-first-audio. Wire-compatible with
  chatterbox-fast /tts (both 24 kHz mono PCM). Batch /v1/audio/speech is
  unchanged for asset/file callers.

- scheduler.py: VENDORED byte-faithful copy of chatterbox-fast's pure-
  Python (torch-free) scheduler, pinned to commit 7631462 (v0.1.0/v0.1.1).
  Vendor-copy over a shared package (operator call 2026-06-19): the module
  has no GPU deps, so reuse it without dragging chatterbox-fast's torch
  tree into this image. Promote to a shared package only on a 3rd consumer
  or real drift.

- sanitize.py: language-safe TTS sanitizer run on both endpoints. Strips
  markdown, <think> blocks, HTML, and model control tokens; deliberately
  SKIPS the fork's English-only number/phone normalization that would
  corrupt OmniVoice's 600-language input. Preserves [laughter]-style tags.

- Refactor: shared GenParams base for SpeechRequest + TTSStreamRequest;
  single GEN_LOCK serializes generation (single-stream interactive).

- Dockerfile/playbook: copy + upload the two new modules; build-time
  `import app` smoke; correct stale "Gradio demo / no FastAPI" comments.
2026-06-19 22:47:15 -07:00
vh 826c2a6a64 memory: archive 15 pre-2026-06-16 entries to archival-memory.md
9 Recent decisions + 6 Tried-and-abandoned (dates [2026-06-14]/[2026-06-15]) moved
non-destructively to archival-memory.md, each stamped _Archived 2026-06-19._. Kept
the active [2026-06-14] 'migrate ALL infra access to Claude-specific credentials'
standing directive. Back-ref counts: Recent decisions 79->88, Tried-and-abandoned
70->76. persistent-memory.md 397->363 lines.
2026-06-19 21:54:45 -07:00
vh dfda60fac7 memory: snapshot — 2026-06-19 (pt2) litellm task-aliases (classifier->granite, summarizer-large->gen; gen-nt/gen-reasoning-nt added-then-removed as redundant with strip_empty_tools) + gateway-chat model-smoking web chat enhanced (auto-discover /v1/models + image upload) and stood up as a PERSISTENT nginx container on ana-docker :8091 + pi on nh3-dev wired to gen (vision, ~/.pi models.json + gen launcher, local box config) + foot-guns: litellm config-loaded models can't be hot-removed (/model/delete is DB-only; /model/new live-adds work no-bounce but dup on restart) and the * wildcard routes stale/typo'd names to decommissioned llama-swap -> misleading 'Connection error' not 'model not found' (bit a brokkr call to the renamed-away qwen-image-judge). 2026-06-19 18:51:03 -07:00
vh 740bcae45d feat(gateway-chat): persistent static-serve stack for the model-smoking web chat
Stands up tools/gateway-chat.html as a permanent URL on ana-docker (http://10.250.50.70:8091)
via a tiny nginx:alpine static container (no GPU, no DB). conf/index.html is a deployed
mirror of tools/gateway-chat.html (re-sync one-liner in README). Homepage tile + tnet per
convention. The enhanced tool (auto-discovers /v1/models, system prompts, streaming +
reasoning, image upload for vision) is now always-on for smoking new gateway models.
2026-06-19 12:32:51 -07:00
vh ef45f6d826 feat(litellm): add classifier -> granite + summarizer-large -> gen aliases (operator)
Duplicate-entry aliases. classifier -> granite-4.1-8b (:8004, same backend as the
existing summarizer alias). summarizer-large -> gen/qwen3.5-122-a10b (:8013, thinking
off) for heavier summarization on the 122B Qwopus. summarizer -> granite already
existed (no-op). Config-staged + deployed without bouncing the gateway; like any
config-add these activate on the next restart (no live-add performed).
2026-06-19 12:08:26 -07:00
vh 4c40b9fac6 feat(tools): gateway-chat.html — auto-discover gateway models + image upload for vision smoke
Model field now pulls /v1/models (the ↻ control; new gateway models just appear)
instead of a hardcoded stale list; 📎 attaches an image (base64 data: URL in
image_url content) so the multimodal models (Qwopus, image-judge) can be smoked.
Static-verified (JS syntax + element-id consistency); headless smoke was blocked
by a shared-browser version skew in /opt/ms-playwright, not a tool defect.
2026-06-19 11:56:20 -07:00
vh 75bd4c3679 remove gen-nt / gen-reasoning-nt litellm records (operator)
Source + deployed config cleaned without bouncing the gateway. NOTE: these were
config-loaded models, which the /model/delete API can't remove (DB-only -> 'not
found in db'), so the LIVE gateway still serves them until its next restart, at
which point the cleaned config drops them. No bounce performed.
2026-06-19 11:56:20 -07:00
vh 2e5ab72e2c feat(litellm): add gen-nt / gen-reasoning-nt (noop-tool + tool_choice:none compat variants)
Same Qwopus gen model as gen / gen-reasoning (served-name qwen3.5-122-a10b @
:8013, thinking off/on respectively), but each bakes a dummy 'noop' function tool
+ tool_choice:none into litellm_params so a NON-EMPTY tools array always reaches
vLLM — for consumers where the global strip_empty_tools hook isn't the right fix
(they need a valid tools structure present, not stripped). tool_choice:none means
the noop is never called. api_base = the real LAN endpoint http://10.250.50.54:8013
(the requested http://vllm:8000 template wouldn't resolve from the ana-docker
litellm container). Verified: gen-nt + gen-reasoning-nt both survive a client
tools:[] send; noop never invoked; reasoning split intact.
2026-06-19 11:35:48 -07:00
vh 378261763c memory: snapshot — 2026-06-19 gen model = Qwopus3.5-122B vision-intact NVFP4 LIVE on ana-ml2 GPU 0 (full 256K @ fp8 KV + CUDA graphs, util 0.95 + expandable_segments, 92.7 tok/s warm, 3.32x concurrency, text+image+video, tool-calling qwen3_coder; nightly+turboquant-4bit-KV proven UNNECESSARY — stable fp8 reaches 256K) replacing the bjk110 text-only qwen3.5-122b (which displaced mistral-small-4 → Worldtree character backend DARK until repointed, operator-acknowledged) + qwen-image-bench T2I judge replaced qwen3.6-35b-a3b on GPU 1 (alias image-judge) + TP=2 across both Blackwells REJECTED (PCIe-only PIX, no NVLink → all-reduce-bound, one-model-per-card is optimal; PP=2 only if a >96GB model is ever wanted) + foot-guns: MoE FusedMoE workspace is the ~3.1GB un-budgeted floor (can't fill to 0), discard cold tok/s reads (24.8 cold vs 92.7 warm). 2026-06-19 11:15:32 -07:00
vh 5b06514020 docs(litellm): gen records now describe Qwopus3.5-122B (vision-intact), not bjk110 text-only
Comment-only — routing records (served-name qwen3.5-122-a10b @ :8013) unchanged,
so the live gateway is functionally identical; no reload needed.
2026-06-19 10:25:45 -07:00
vh 20e796cf6b feat(qwopus3.5-122b): gen model → Qwopus3.5-122B vision-intact NVFP4, full 256K @ fp8
Replaces the bjk110 text-only qwen3.5-122b as the `gen` model on ana-ml2 GPU 0.
OpenYourMind/Qwopus3.5-122B-A10B-Kimi-K2.6-destilled-abliterated-NVFP4 — Kimi-
distilled, abliterated, NVFP4, and crucially VISION-INTACT (serves as plain
multimodal, no text-only patch). Served as qwen3.5-122-a10b so the litellm
gen / gen-reasoning / qwen-large records route here unchanged.

Tuned for full native context on the 96GB Blackwell:
- stable vLLM image + fp8 KV → 11GB pool = 870,014 tokens = 3.32x concurrency
  at the full 262144 (256K) window. Nightly+turboquant-4bit was unnecessary.
- CUDA graphs ON (no --enforce-eager) → 92.7 tok/s warm single-stream.
- util 0.95 + PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True — 0.96 OOM'd by
  0.1GB on the 3.09GB FusedMoE transient workspace (the hard floor; defrag
  reclaims the 4.2GB fragmentation, 0.95 adds margin).
- max-num-seqs 16 (short reqs fan out ~16x32k; 256K reqs pool-limit to 3.32x).
- text + image + video all enabled; tool-calling via qwen3_coder (XML), verified.
2026-06-19 10:24:34 -07:00
vh a5b626b3d5 fix(qwen3.5-122b): enable tool-calling (--enable-auto-tool-choice --tool-call-parser qwen3_xml)
gen/gen-reasoning tool-calling 400'd (operator + brokkr's capability battery both caught it):
the bjk110 serve command shipped --reasoning-parser qwen3 but no tool flags. Qwen3.5 emits XML
tool calls (<tool_call><function=NAME><parameter=K>V</parameter></function></tool_call>), NOT
Hermes JSON — so `hermes` mis-parsed to raw text; `qwen3_xml` is the correct parser. Reasoning +
tools coexist (gen-reasoning keeps its thinking split). Verified live: a get_weather request
returns tool_calls=[get_weather {"city":"Paris"}].
2026-06-19 01:56:56 -07:00
vh 5dfce049f4 rename(litellm): qwen-image-judge alias -> image-judge 2026-06-19 01:43:25 -07:00
vh bfae924048 feat(qwen-image-bench): replace qwen3.6-35b-a3b on GPU1 with the T2I judge (NVFP4)
flukethoughts/Qwen-Image-Bench-NVFP4 — Qwen's text-to-image quality JUDGE (vision-intact,
NVFP4) on ana-ml2 GPU 1, replacing qwen3.6-35b-a3b:
- stacks/qwen-image-bench/ — vLLM multimodal serve (Qwen3_5ForConditionalGeneration, no
  text-only patch — vision wanted), GPU1 device pin, :8014. util 0.32 (0.22 KV-starved →
  crash-loop "no available memory for cache blocks"; util is a fraction of TOTAL so it
  must clear the ~20GB weight floor).
- litellm: removed qwen3.6-35b-a3b + -thinking; added qwen-image-bench + qwen-image-judge alias.

Verified live: healthy (KV 9.4GB / 133K tokens), text + IMAGE (vision path) both respond.
NOTE: arbo's hero-judge was bound to qwen3.6-35b-a3b — comfy-dev notified to repoint.
2026-06-19 01:40:59 -07:00
vh 3ba0e544db tune(qwen3.5-122b): gpu-mem-util 0.90->0.95, max-num-seqs 4->8 (KV 260K->446K tokens, 3.4x concurrency @131K, no OOM) 2026-06-19 01:21:28 -07:00
vh 89c83c4271 feat(qwen3.5-122b): replace mistral-small-4 as gen (abliterated NVFP4, text-only)
bjk110/Qwen3.5-122B-A10B-abliterated-NVFP4 on ana-ml2 GPU 0 (heretic downed):
- stacks/qwen3.5-122b/ — vLLM serve via the repo's text-only patch (Qwen3.5 MoE is a
  multimodal arch but this checkpoint is text-only weights), --reasoning-parser qwen3,
  GPU 0 pin, :8013; entrypoint+patch mounted from the model dir.
- serve-qwen3.5-122b.yaml — displace heretic + serve + verify.
- litellm: REMOVED dead mistral-small-4 / -reasoning; added qwen3.5-122-a10b[-reasoning]
  + aliases qwen-large[-reasoning] + repointed gen[-reasoning] -> qwen (thinking split via
  chat_template_kwargs.enable_thinking + --reasoning-parser qwen3).

Verified live: qwen healthy on :8013; gen / qwen-large / qwen3.5-122-a10b route, and
gen-reasoning returns reasoning_content; mistral-small-4 removed.
NOTE: Worldtree character backend (was bound to mistral-small-4) is dark until repointed
(operator-acknowledged).
2026-06-19 00:49:04 -07:00
vh 67102b5b94 feat(litellm): add model aliases summarizer / gen / gen-reasoning
Duplicate-entry aliases (NOT router_settings.model_group_alias — that's hidden from
/v1/models and can be silently ignored in config per litellm #15020/#5524):
- summarizer     -> granite-4.1-8b
- gen            -> mistral-small-4
- gen-reasoning  -> mistral-small-4-reasoning (reasoning_effort:high preserved)

Each alias is a real model_name co-located with its target (keep api_base in sync).
Verified live: all 3 in /v1/models + route end-to-end; gen-reasoning returns
reasoning_content.
2026-06-18 23:56:05 -07:00
vh 91688a234b revert(litellm): remove mistral-medium-3.5 entry (GPU0 reverted to small-4 heretic) 2026-06-18 23:50:34 -07:00
vh 981ae4e6a1 feat(omnivoice): expose full generation surface (voice-design, language, diffusion params)
Wrapper /v1/audio/speech now accepts OmniVoice's whole surface:
- voice (clone, now OPTIONAL) and/or instruct (voice DESIGN). instruct is a CONTROLLED
  vocabulary (gender/age/pitch/accent/whisper tags, comma-separated), not free prose —
  discoverable at the new /v1/audio/instruct-items endpoint (23 items).
- language (Auto + 647, new /v1/audio/languages endpoint), speed, duration.
- diffusion controls: num_step, guidance_scale, denoise, preprocess_prompt,
  postprocess_output; plus a generation_overrides JSON passthrough for expert
  GenerationConfig knobs (t_shift, layer_penalty_factor, position/class temperature,
  audio_chunk_*).
- at least one of voice/instruct required (else 400).

Catalog (services.yaml): omnivoice v1 -> v2, 13 schema-valid fields; instruct as a
controlled-vocab text field sourced from the items endpoint.

Verified live on irv-ml1: clone, voice-design (instruct-only), and tuned-param synths
all -> 24 kHz PCM_16 WAV; 647 languages; 23 instruct items.
2026-06-18 23:25:39 -07:00
vh 71f5784016 feat(litellm): add mistral-medium-3.5 (RecViking NVFP4 :8012, temporary GPU0 tenant) 2026-06-18 23:12:31 -07:00
vh 06eb487a26 feat(omnivoice): wire to asset-engine via FastAPI wrapper + reuse chatterbox voices
- app.py: thin FastAPI wrapper exposing OpenAI /v1/audio/speech (+ /v1/audio/voices,
  /healthz) around OmniVoice's Python API; precomputes a voice-clone prompt per voice
  at startup (loaded Whisper auto-transcribes each reference). Replaces the Gradio demo.
- Dockerfile/compose: run the uvicorn wrapper, /healthz healthcheck, project name pinned
  to "omnivoice" so the asset-engine liveness probe matches.
- deploy-omnivoice.yaml: stage chatterbox /refs/*.wav as clone voices (skip _* artifacts)
  + verify the API surface.
- services.yaml: catalog entry (id omnivoice, :8199/v1/audio/speech, voice list sourced
  live from /v1/audio/voices) + reproducibility_audit row.

Verified live on irv-ml1: /healthz ok, 33 voices loaded, test synth -> 24kHz PCM_16 WAV.
2026-06-18 23:03:20 -07:00
vh 984b72757f feat(omnivoice): new TTS stack — k2-fsa/OmniVoice on irv-ml1 3090
Zero-shot, massively-multilingual (600+ language) voice-cloning + voice-design
TTS (diffusion-LM, Apache-2.0). No official image, so a thin CUDA container
around the pip package running upstream's own Gradio demo (no FastAPI wrapper).
Pinned to GPU 0 (3090) — the A6000 is ComfyUI-exclusive — port 8199. Built +
verified live on irv-ml1 (Gradio 200, container healthy). Surface is the Gradio
UI + Gradio API, NOT OpenAI-compat /v1/audio/speech (wrap later if asset-engine
should consume it). deploy-omnivoice.yaml builds local + verifies.
2026-06-18 22:25:54 -07:00
vh 715a68bee7 feat(comfyui): native --use-sage-attention (node path dead on 0.24.1)
ComfyUI 0.24.1 added native attention selection; the node-based
BlehGlobalSageAttention errors "does not support the new ComfyUI attention
changes". Add --use-sage-attention to COMFY_CMDLINE_EXTRA so the in-image
sageattention v2.2.0 sm_86 build (rebuilt vs pinned torch 2.12.1) binds via
the native path. OOM flags preserved. Deployed to irv-ml1 + recreated; log
confirms "Using sage attention", container healthy, serving 200.
(comfy-dev request, thread 01KVE89T2DKC)
2026-06-18 14:16:56 -07:00
vh 632124c8fb memory: nh3-extdev pi-on-GLM-5.2 wired (mark in-flight item done + residual gates) 2026-06-18 14:05:02 -07:00
vh 527a844714 feat(nh3-extdev): install pi (earendil-works) + wire /opt/externs client agents to GLM 5.2
- user-level Node v22.23.0 LTS (static tarball, checksum-verified) + pi 0.79.7
  installed -g into the user prefix (box is sudo-less: no root/apt/docker)
- every /opt/externs/<client> wired to GLM 5.2 via the litellm gateway with an
  isolated PI_CODING_AGENT_DIR + scoped per-client key (models.json/settings.json
  + run-pi.sh launcher); replaces the scaffold's incorrect config.example guess
- playbooks/install-pi-nh3-extdev.yaml: idempotent reproduce / add-client / upgrade
  (validated clean: 4 steps skipped, live gbcnc->GLM 5.2 round-trip OK)
- README: settled role + per-client workspace layout; refresh system-details
2026-06-18 14:04:29 -07:00
vh a67d4950d0 memory: snapshot — 2026-06-18 heretic abliterated Mistral Small 4 NVFP4 BUILT + LIVE as mistral-small-4 (in-house quant device_map=cpu → native-format convert → drop-in stack under same served-name, A/B'd vs official, operator "heretic stays"; byte-equivalent to official NVFP4) + irv-ml1 VRAM consolidation (ComfyUI pinned to A6000 exclusive/48GB, audio zoo→3090, downed dia/ace-step/csm, comfy-dev torch-pin DISABLE_UPGRADES@2.12.1 + SageAttention rebuilt) + ComfyUI 9-node accel set installed for comfy-dev + ana-ml2 durable vm.overcommit_memory=1 + GLM5.2 wired + nh3-extdev sudo-less manager box + /opt/externs pi-on-GLM client workspaces.
Lessons: mmartial-comfyui root-install-leaves-root-owned-venv-files → boot-script crash-loop (chown -R 1000:1000 fix) + torch-upgrade-on-boot (DISABLE_UPGRADES); mistral HF→NVFP4 quant device_map=cpu (auto OOMs, constrained→meta-tensor) + non-mmap shard reads (safe_open mmap ENOMEMs on /tank ZFS) + NVFP4 keeps the model. prefix; HF-format Mistral4 UNSERVEABLE on vLLM (native mandatory); ComfyUI 0.24.1-not-0.19.3 version-drift kills module-level node imports + tensorrt-defaults-cu13-vs-cu12.9.

Archived the [2026-06-14] cluster (11 entries: 6 decisions + 5 foot-guns; kept the still-active credential-migration directive, infra-ops litellm key, gitea-internal-route).
2026-06-18 13:48:12 -07:00
vh a8550ad4bc feat(irv-ml1): pin comfyui to A6000 + torch-pin; parakeet -> 3090 (VRAM consolidation)
Operator consolidation (2026-06-18): give ComfyUI the full 48 GB A6000 and move the
audio/TTS zoo to the 3090.

- comfyui: NVIDIA_VISIBLE_DEVICES all -> 1 (A6000 only), + DISABLE_UPGRADES=true to
  pin torch at 2.12.1+cu129 so the mmartial boot script stops auto-upgrading it and
  the compiled SageAttention kernels stay matched (comfy-dev torch-pin, approved).
- parakeet: NVIDIA_VISIBLE_DEVICES all -> 0 (3090).

Other GPU reassignments are deployment-side (not repo compose): chatterbox-fast via
its .env CBF_GPU_DEVICES=0; vibevoice device_ids ["1"]->["0"] (deployed from
/worktank/vibevoice/build); yt-voice-clipper worker via its override. dia2-2b,
ace-step, csm-expressiva downed (stale/unused).

Result: A6000 = ComfyUI alone (48.3 GB free); 3090 = chatterbox + parakeet + the
on-demand audio (vibevoice/ytvc/kokoro). SageAttention rebuilt against the pinned
torch; OOM cmdline (COMFY_CMDLINE_EXTRA) preserved; /object_info still lists the 9
acceleration nodes.
2026-06-18 11:07:43 -07:00
vh f566f61b24 feat(stacks): mistral-small-4-heretic drop-in (abliterated NVFP4 backend swap)
Serves the in-house abliterated Mistral Small 4 (heretic NVFP4, vision-intact)
under --served-model-name mistral-small-4 on ana-ml2 GPU0:8010 — a true drop-in
for the official mistral-small-4 backend. Both litellm entries (mistral-small-4 +
mistral-small-4-reasoning) route here with no litellm change.

GPU0 fits one mistral-class model, so this is a backend swap, not a co-tenant:
bring up after downing the official stack; revert by downing this and up-ing the
official. Verified live through the gateway: standard returns clean answers,
reasoning populates reasoning_content (the [THINK] split). Checkpoint built per
tools/mistral-small4-nvfp4/.
2026-06-17 22:33:29 -07:00
vh dd3a5c93fd feat(tools): Mistral Small 4 NVFP4 build pipeline (quant + HF->native converter)
Quantize a HF-format Mistral Small 4 (Mistral3ForConditionalGeneration MoE) to
NVFP4 with the vision tower intact, then convert HF NVFP4 -> Mistral native so
vLLM can serve it (there is no HF Mistral4 serving path in any vLLM version).

Built + validated end-to-end on ana-ml2 for the abliterated character-model
successor (darkc0de/Mistral-Small-4-119B-2603-heretic): quant -> dry-run (clean
vs the official native NVFP4 reference) -> convert -> serve-test (loads on the
native loader, correct text, vision functional).

Converter scaffold came from worldtree-codex (bf16 bin maps + fused-expert
split); fixed here: NVFP4 layer regexes (keep the `model.` prefix) + non-mmap
shard reads (ZFS large-mmap ENOMEM). nvfp4_quant.py is local. README documents
the pipeline + every gotcha that cost a failed run. Homed here per operator
direction (not Worldtree).
2026-06-17 22:19:58 -07:00
vh fc88eff06e feat(ana-ml2): durable vm.overcommit_memory=1 sysctl playbook
ana-ml2 ran overcommit_memory=0 with zero swap, capping the CommitLimit at
~RAM/2 (~283 GB of 566 GB). The resident vLLM services commit ~224 GB, so a
large model-file mmap (the 50 GB NVFP4 shard during HF->native conversion, or
a vLLM model load) failed with ENOMEM despite ~393 GB of RAM actually free.

overcommit_memory=1 is the conventional setting for ML hosts that mmap large
files. A drop-in under /etc/sysctl.d/ makes it reboot-durable. Operator-directed
permanent (2026-06-17). Idempotent via when:; sudo tee for the root-owned path
(elway runs steps as the SSH user, so a shell > redirect can't write there).
2026-06-17 22:19:58 -07:00
vh a841eab3ff servers: register nh3-extdev (sudo-less infra-ops manager box)
NH3 manager/external-dev box at 10.100.50.42 (Debian 13 VM on nh3-pve),
successor to the retired nh3-ansible. infra-ops identity here is sudo-LESS
by operator decision (2026-06-17): key-only, no NOPASSWD, not in docker
group — user-level management only. Adds servers/nh3-extdev/{README,
ssh-target,system-details.txt}, the CLAUDE.md inventory row, and a local
ssh alias (nh3-extdev -> infra-ops@10.100.50.42, infra-ops key). Login +
sudo-less posture verified.
2026-06-17 14:57:06 -07:00
vh fe77a3596a litellm: wire GLM 5.2 (glm-5.2 + glm-5.2-reasoning) via z.ai passthrough
GLM 5.2 released ~2026-06; confirmed reachable with our existing
Z_AI_API_KEY (z.ai /models lists glm-5.2; a live completion returned
clean). Added two model_list entries mirroring the glm-5.1 pattern:
glm-5.2 (thinking DISABLED by default, per the 2026-06-11 operator call)
and glm-5.2-reasoning (thinking ENABLED, opt-in). Deployed to
ana-docker /opt/docker/conf/litellm/config.yaml, litellm restarted,
both verified through the gateway (disabled -> reasoning_tokens 0;
reasoning -> 234).
2026-06-17 08:56:16 -07:00
vh 8cca365b78 memory: correct gitea action-log API note (per-job endpoint works)
Proven 2026-06-16 diagnosing arbo run #5/task 1175: the RUN-level
/runs/{id}/logs 404s, but the per-JOB endpoint
GET /api/v1/repos/{o}/{r}/actions/jobs/{job_id}/logs returns the full
plain-text log (claude-bot basic-auth, internal :3000) — no UI needed.
Also noted gitea's misleading per-step conclusions (every step shows
failure once any fails; trust the log + timestamps).
2026-06-16 14:56:12 -07:00
vh 03358dccd1 arbo: mount repo pyproject.toml ro into the engine (catalog_version observability)
/healthz catalog_version read the BAKED package version (importlib.metadata),
so a catalog/frontend-only webhook deploy (no image rebuild) left it stale —
v0.12.4 data went live but /healthz still reported 0.12.3. comfy-dev's v0.12.5
reads comfy_catalog.__version__ from the repo-root pyproject.toml; mounting it
on the same checkout mount (catalog/graphs/frontend) makes /healthz report the
MOUNTED version after a catalog-restart. Falls back cleanly if absent.

Pushed to irv-ml1's host compose + validated via `docker compose config`
(bind -> /app/pyproject.toml:ro resolves). Recreate deferred to comfy-dev's
imminent v0.12.5 rebuild (the mount is inert for v0.12.5 itself, which bakes
its own version — it only matters for subsequent catalog-only deploys — so no
separate prod blip). Requested by comfy-dev (engine owner), althing thread
01KV95R88A3Y.
2026-06-16 14:42:04 -07:00
vh 3a7236d51f playbook: put uv/uvx on the irv-ml1-arbo runner PATH
The irv-ml1-arbo Gitea Actions runner (host-executor as lkraven under
systemd) gets the bare service PATH (/usr/local/bin:/usr/bin:/bin), which
omits ~/.local/bin — so the CI uv bootstrap failed with "uv: not found".
Symlink uv/uvx into /usr/local/bin (on the systemd PATH) to fix it and
retire the per-run curl|sh bootstrap. Idempotent (creates: guard);
re-applies cleanly after a runner rebuild. Authorized by comfy-dev
(engine owner) per althing thread 01KV94VTS27B.
2026-06-16 14:24:24 -07:00
vh 47c30e85f9 memory: snapshot — 2026-06-16 litellm strip_empty_tools hook (d1bea13) + single-file gateway-chat.html playground (984ca3d) + claude-bot ADMIN on vh/arbo (arbo CI/CD via service account) + LitBench-RM reward judge served on irv-ml1 A6000 then taken to on-demand (held comfyui's slot) + #295 recall root-cause FLIPPED (score_breakdown-shape DISPROVEN → cold-recall agent_self scope axis vs ratatoskr conjunctive INV-005; Worldtree #297); lessons: litellm-500-Router.acompletion-missing-messages = a request missing Content-Type (NOT a gateway outage — cost 4 needless restarts), litellm-admin-UI-playground-cant-test-vLLM (#6228 empty-tools, proxy-hook-cant-reach-in-process-call), gitea-run-looks-like-never-fired-but-fired-then-skipped/failed-fast (check run list not runner). Archived the 06-09→06-13 cluster (24 entries: 17 decisions + 7 foot-guns). 2026-06-16 14:14:36 -07:00
vh 984ca3d383 feat(tools): single-file gateway chat playground
Zero-dependency, zero-backend HTML chat UI for the LiteLLM gateway. The
browser talks straight to :4000 (gateway CORS is open), so it's just one
file you open — no container, no stack. System-prompt textarea, model
datalist, streaming SSE, renders reasoning_content for the -thinking/
-reasoning models, settings persist in localStorage.

Deliberately never sends a `tools` field, sidestepping the vLLM "tools
must not be an empty array" bug that breaks the LiteLLM admin UI
playground for vLLM-backed models (litellm #6228; the gateway's
strip_empty_tools hook can't reach the UI's in-process completion call).

Verified against the live gateway: streams + parses a real completion
with no tools sent.
2026-06-16 01:40:30 -07:00
vh d1bea13994 fix(litellm): strip empty tools:[] before forwarding to vLLM
vLLM's OpenAI server 400s on an empty tools array ("tools must not be an
empty array"), which broke every gateway call carrying tools:[] (clients
that send it to mean "no tools" -- OpenAI tolerates it, vLLM does not).
drop_params doesn't help: it drops unsupported PARAMS, not empty VALUES.

Add a CustomLogger async_pre_call_hook (conf/strip_empty_tools.py) that
pops an empty/None tools field (+ orphaned tool_choice) before forwarding,
registered globally via litellm_settings.callbacks so it covers every
vLLM-backed model, not just mistral-small-4. Mounted at
/app/strip_empty_tools.py beside config.yaml (LiteLLM resolves callbacks
relative to the config dir). Surgical: only fires when tools is present
and empty; real tools pass through untouched.

Verified on live gateway (1.87.0): mistral-small-4 and granite-4.1-8b
with tools:[] now 200 (were 400); no-tools baseline unchanged; a real
tool still passes through.
2026-06-16 00:43:57 -07:00
vh f9277f5440 memory: snapshot — 2026-06-16 ratatoskr Tier-3 MEMORY plane wired (allowlist :8391, key reused, persist+dispatch GREEN; recall-injection root-caused to the score_breakdown shape seam → worldtree-dev #295) + infra-ops durable admin on corviduo (ssh alias + ssh-target) + demo/personal character model qwen→mistral (first-bind-is-default reorder, pin-safe recreate); lessons: bifrost-allowlist-is-per-port, promotion-gate=consumer-agent-memory-block-not-agent_self_enabled, WORLDTREE_IMAGE-pin-from-matrix-sibling 2026-06-16 00:13:14 -07:00
vh c99aa49cad feat(corviduo): wire ratatoskr memory plane :8391 into personal Worldtree bifrost allowlist
Append 10.100.10.50:8391 to BIFROST_CLIENT_ALLOWED_HOSTS on the personal
Worldtree (.env) so the consumer may bind the memory provider at session-create
(affect :8390 was already listed; the url-guard 422s un-allowlisted endpoints).
Idempotent elway playbook; surgical worldtree-api recreate that auto-derives the
image pin from the matrix sibling to avoid the stale-:latest crash-block footgun.

Repoint servers/corviduo-dev/ssh-target to infra-ops (operator granted durable
NOPASSWD admin on corviduo-dev 2026-06-15).
2026-06-15 23:22:06 -07:00