Tags: oRKLLM/oRKLLM
Tags
feat: native dflash safetensors to gguf converter (no python/torch) Replaces the Python convert_hf_to_gguf.py default with an in-process, on-board converter so the DFlash auto-convert scheduler needs no torch env: - addon convert_dflash_gguf: dlopens the sibling libggml-base and reuses ggml's exact quantize (BF16 to F32 to Q8_0/F16) + the gguf writer; copies the tokenizer KVs wholesale from the target's existing GGUF (gguf_set_kv) then overrides the dflash arch/hparam keys. Synchronous (runs in a subprocess). - dflash_convert_runner.js: parses config.json + the safetensors header, maps HF tensor names to the dflash GGUF names, calls the addon. Spawned as a subprocess (non-blocking, SIGTERM-preemptible). - dflash_conversion.js: default command now spawns the node runner; resolves a target GGUF (for the tokenizer copy) instead of an HF dir. Validated: z-lab Qwen3.6-27B-DFlash (3.3G BF16) to 1.85G Q8_0 GGUF, arch dflash, 58 tensors, target_layers/block_size + tokenizer all correct.
feat: dflash auto-convert scheduler (safetensors to gguf) Auto-converts downloaded z-lab DFlash draft heads (HF safetensors, arch DFlashDraftModel) into the GGUF (arch dflash) that run_dflash loads, the same idle-driven / preemptible / scan-at-startup way ConversionScheduler builds .orkpacks: - src/dflash_conversion.js: DFlashConversionScheduler — detects DFlashDraftModel dirs lacking their GGUF, resolves the target model dir (for --target-model-dir, since the draft borrows the target tokenizer/embeddings), and runs the convert when idle. The convert EXECUTION is parameterized (ORKLLM_DFLASH_CONVERT_CMD) so it runs in a local torch/gguf venv OR offloads to the conversion box; it stays dormant (logs disabled) until such an env is provisioned. - server.js: init + scanAndEnqueue at startup (gated by ork_autoconvert) - admin/routes.js: preempt on model load; re-scan after a safetensors/json download completes
feat: dflash speculative decode (co-resident block-diffusion drafter) Adds a 'dflash' per-model speculative_mode. The DFlash draft is a llama.cpp model that must be co-resident with the target (it borrows the target's tok_embd/output and reads its extracted hidden layers), so the whole block-draft/verify loop runs natively in the llama addon via a new run_dflash method; the JS side just drives it and streams tokens. - addon: run_dflash (loads the draft co-resident with ctx_other=target, runs the skip-ahead block-verify loop on a worker thread, streams tokens) - worker/pool/routes: 'dflash' dispatch -> pool.generateDflash -> run_dflash, with a safe fallback to standard generate if no draft or the runtime lacks the DFlash symbols; gguf models keep their mode when it is 'dflash' - Models.vue: DFlash mode option + draft-path / block-size settings - conversion: UNSUPPORTED_ARCHS gate skips .orkpack conversion for arch 'dflash' (draft head, no standalone pack) and 'qwen35' (SSM/GDN hybrid)
feat: filter logs by application (source) + level; tag every line's s… …ource Every log line carries a `source` field so the Logs page can filter by which app emitted it: oRKLLM (Pino mixin source:'orkllm'), llama.cpp, ork-driver. Runtime workers' native output is emitted as Pino-shaped JSON with source + parsed level (ork-driver levels from its [ork] ERROR:/WARNING: prefixes; llama.cpp via keyword heuristic). Logs page: filter-icon menu with a per-application toggle (combines with the level filter); each rendered line shows its source. One consistent JSON shape for all three apps. De-flakes the auto-unload-timeout E2E: setSlider presses the Vuetify thumb toward the target while re-reading the value chip each step, so a keystroke dropped under full-suite load just costs another iteration instead of landing off-target.
feat: surface native llama.cpp + ork-driver logs in the Logs page The serving/draft runtime workers were forked with the default silent:false, so the native llama.cpp + ork-driver stdout/stderr INHERITED to the terminal and bypassed the parent's log hook — never reaching /ws/logs or the Logs page. Fork them silent (piped) and route each output line through the unified logger (console.* → Pino JSON → /ws/logs) at its parsed level, tagged by source ([ork…] → ork-driver, else llama). Now the Logs page shows oRKLLM, llama.cpp, and ork-driver lines together in one consistent JSON format (and the Logs nav badge counts their errors/warnings). IPC (process.send) is unaffected by silent, so results still flow normally.
feat: navbar notification badges (WebSocket-driven, shared streams) Top-right v-badge on each navbar tab, driven by a shared badge store: - Dashboard: red dot when NPU/GPU activity is detected; cleared on view or when activity drops to 0 - Models: count of models actively converting (live) - Settings: count of new features since last release not yet seen; cleared on view - Logs: count of unviewed errors/warnings, colored by worst (red=error, amber=warn); cleared on view - Bench: red dot while running, green when ready (green cleared on view) - Chat: count of messages that finished while away; cleared on view - Help: count of new help entries since last viewed; cleared on view All fed by WebSocket with NO duplicate sockets: a new streams.js multiplexes ONE /ws/metrics + ONE /ws/logs to every consumer. Dashboard and Logs now subscribe to these shared streams instead of each opening its own. /ws/metrics payload gains a converting count. Bench/Chat badges mirror the existing bench.js/chat.js stores. Settings/Help counts use a curated whatsnew.js manifest + localStorage baseline.
feat: pre-build .orkpack on GGUF download + show models dir on card - On a completed GGUF download, enqueue its .orkpack build so it packs during the next idle window (moves the one-time build off the first load's critical path; the pool's build-then-load guard still guarantees no cold serve regardless). - GET /api/admin/library now returns modelsDir (MODELS_DIR); the Available Models card shows the models root directory under its header.
fix(logs): unify log format (console.* → Pino JSON) + WARN failed con…
…versions + pretty-render
The stream mixed plain '[INFO] ...' (tagged console.*) with Pino JSON '{"level":"info",...}'.
Now console.log/info/warn/error route through fastify.log (Pino) via util.format, so every line is
one JSON shape; the [LEVEL]-tagging capture hack is gone. Conversion failed/killed now logs WARN (was
INFO). The Logs viewer pretty-renders each JSON line to 'HH:MM:SS LEVEL msg' (consistent + readable),
and still filters by parsed level.
PreviousNext