A staged Rust reimplementation of OpenFugu — Sakana AI's Fugu ("one model commanding a pool of models") rebuilt in Rust: candle Qwen3-0.6B router + SVF, an OpenAI-compatible serving layer, real heterogeneous worker pools, and gradient-free training. All phases run.
Independent reimplementation. Not affiliated with Sakana AI. No third-party code/weights are redistributed — model weights are fetched at setup. See
NOTICE. Licensed under Apache-2.0 (LICENSE).
| Phase | Scope | State |
|---|---|---|
| 0 | pure-logic core: types, Conductor parser+DAG, TRINITY step_trinity loop, mock workers, CLI |
✅ done |
| 1 | OpenAI-compatible axum service + reqwest (OpenAI-compatible) ApiWorker pool |
✅ done |
| 2a | fugu-router math: 19456 split, SVF reconstruction (vs NumPy golden), bias-free head, raw transcript; backbone behind a Backbone trait; 5-layer golden harness |
✅ done |
| 2b | fugu-backbone-candle: real candle Qwen3-0.6B backbone + SVF-adapted weights + trained head → verify37 = 100% agent / 100% role on the 37-case fixture |
✅ done |
| 3 | fugu-train: gradient-free self-training (ES) on a mock world — chance → 4/4 specialists, reward 0.43→0.94 |
✅ done (mock) |
| 4 | candle optimization; 5 | GRPO (stays Python/trl unless an all-Rust goal is set) |
89 tests across all crates; cargo clippy --all-targets --all-features clean.
Phase 2a hardening (post-review): Router/Backbone are fallible (a backbone
forward error propagates → 5xx, never panics — symmetric with Worker);
svf_reconstruct rejects non-finite inputs, returns a zero matrix for zero
energy, and uses a scale-relative degeneracy guard; apply_agent_mask requires a
full-length, not-all-false mask; the SVF_KEYS constant pins the exact 9-matrix
state_dict order/shapes the Phase 2b loader must follow; the golden test honestly
covers head+argmax only (tokenizer/hidden captured for 2b) and hard-fails
under FUGU_REQUIRE_GOLDEN=1 so real-weight parity can't be deferred silently.
Artifact sources (verified reachable 2026-06, sha256-checked): the trained
router ships not as model_iter_60.npy but as a structured safetensors set on
the HF dataset nshkrdotcom/trinity-coordinator-adapted-qwen3-0.6b:
router_head.safetensors— F32 [10,1024], keytrinity_router_head, sha7ff2db0e…(loaded + tested).- 9
checkpoints/000N_*.kernel.safetensors— each ONE BF16 tensor = the SVF-already-applied (adapted) weight matrix (NOT offsets), in Nx/Bumblebeekernellayout[in, out](transposed vs torch[out, in]for the 7 layer-26 linears; embed/lm_head[vocab,hidden]are identical).source_names matchSVF_KEYSexactly.
The 37-case fixture is on GitHub raw; Qwen3-0.6B is on both HF and ModelScope.
Tested against real data: load_router_head (41 KB head) and load_adapted_matrix
(BF16→f32 + Nx→torch transpose, verified element-wise on the real query matrix).
Phase 2b result. The candle Qwen3-0.6B backbone + the published SVF-adapted
weights + the trained head reproduces (and beats) the reference: 100% agent /
100% role on the 37-case fixture (cargo run -p fugu-backbone-candle --bin verify37) — correctly-applied SVF even resolves the 2 documented "agent misses"
that base-only (95%/100%) leaves. FUGU_NO_SVF=1 runs the base-only path.
Debugging note (kept honest): an earlier version reported 49% with SVF and wrongly concluded an "artifact/head mismatch". The real cause was a transpose bug —
load_adapted_matrixinferred transpose from shape, so the square k/v_proj matrices ([1024,1024]) were loaded asWᵀinstead ofW. Atransformersreference shared the same shape-inference bug, so both agreed at 49% (consistent, but both wrong). Fixing the transpose to be explicit (transpose=truefor all 7 layer-26 linears, pinned by a square-matrix regression test) gives 100%/100%. Lesson: shape-inferred transpose is unsafe for square matrices, and a reference that shares your bug validates nothing.
Numeric strategy (revised by the artifact format): SVF is pre-applied in the
published checkpoints, so serving loads patched matrices directly — no SVD on
the hot path (and no offline svf-apply step needed for these weights). For
routing only embed_tokens + layer-26 (8 matrices) matter; lm_head's patch is
irrelevant (the LM head is never run). svf_reconstruct (nalgebra, cross-checked
vs NumPy <1e-4) remains for the from-scratch / training path. The headline
95%/100% is re-validated via scripts/gen_router_golden.py → tests/golden.rs
(gated; skips offline, hard-fails under FUGU_REQUIRE_GOLDEN=1).
Phase 1 hardening (post-review): Worker is fallible — a provider error aborts
the run and returns 502 rather than a fake 200; the service has per-run
concurrency limits (429 when saturated), a wall-clock timeout (504), HTTP
connect/read timeouts on the pool, uuid request ids, standard usage token
fields, trailing-slash tolerance, JSON 404, and graceful shutdown.
Heterogeneous worker pool + security (post-review): each slot is its own
provider via model[@base][@ENV_KEY] (keys referenced by env var name, never
in argv); a present-but-empty @ segment or an unset env var is a hard error
(no silent wrong-key fallback). Secrets are kept out of logs/errors: Slot has a
redacted Debug, the pool summary prints model@base only, and worker errors
returned to the client are category-redacted (upstream returned HTTP 4xx),
never the URL/headers. Per-request worker timeout (--worker-timeout-secs) is
capped to the whole-run --timeout-secs so one upstream call can't outlive
the run the client waits on; raise --timeout-secs for slow reasoning models.
Fugu-Ultra (Conductor) serving accepts both conductor output formats: the native
3-list DAG (general models) and the official 3B's ToolScale <answer> tool-call
plan (mapped to a linear workflow). --conductor-format threelist|toolscale
picks the prompt; parsing honors it (with the other format as fallback). A
ToolScale name resolves to a worker only via an explicit in-range
worker_<id> — a domain tool like 404/multiply is never misrouted.
Phase 0 deliberately carries zero ML or network dependencies (only regex),
so the orchestration logic is fully testable offline — which is exactly where
the load-bearing behavioural quirks live.
fugu-core— constants (VEC_LEN=19456, …),Message/Role/RouteDecision/RunResult, theRouter/Workertraits, verbatim prompts.fugu-workers—Workerimpls: offlineMockWorker/UltraMockWorker, the OpenAI-compatibleApiWorker(per-slot heterogeneous pool), andUserAgentConfig— a thin provider over a local UserAgent aggregator gateway (base normalization,/v1/modelsdiscovery, SSEdelta.contentaccumulation,useragent:-alias mapping, friendly 401/connect/404 hints) that reusesApiWorkerwholesale.fugu-conductor— Fugu-Ultra (Conductor) line:conductor_prompt(asks an LLM to emit the workflow), the 3-list parser (model_id/subtasks/access_list) with the four-stage fallback (smart-quote → literal → CSV),visible_indices(topological, forward-ref-banned,"all"), and the DAG executor. End-to-end viaopenfugu ultra-demo.fugu-coordinator— thestep_trinityloop: cold-verifier suppression, obs-updates-only-on-Worker,<suggested_role>override, ACCEPT/max-turns termination.fugu-cli— offline entry points mirroring the Python--self-test/--demo.fugu-serve— axum OpenAI-compatible/v1/chat/completions(+/v1/models,/health).--model <qwen3 dir>loads the real candle Qwen3 router (resident, shared viaSharedRouterbehind a per-route lock — concurrent across requests); without it, the offlineMockRouter.--slot-modelsswitches the pool from mock to a realApiWorker. Verified live: real routing returns one answer in ~2s/query (release, CPU), pool hidden.fugu-router— TRINITY router math (split / SVF / head / transcript) + theBackbonetrait +FuguRouter. Weight-independent and fully tested.fugu-backbone-candle— real Qwen3-0.6BBackbonevia candle 0.10 (loads base + optional SVF-adapted weights, returns the penultimate hidden state).verify37bin = the Rustverify_37acceptance (100%/100% with SVF).fugu-train— gradient-free self-training of the coordinator: a (μ/μ_w,λ)-ES with CSA (the isotropic limit sep-CMA-ES reduces to per docs §5.1) learns feature→specialist routing on a mock world.train-trinitybin: chance→optimal, 4/4 specialists.eval-orchestrationbin: routing vs best-single vs random (synthetic, honestly labelled). Zero deps, runs anywhere.fugu-backbone-candlealso shipsbench-real— a REAL small-scale ground-truth benchmark (12 Qs across math/reason/logic/facts EN+ZH/code) over a real heterogeneous API pool via the candle router. Measured (DeepSeek + Qwen + GLM-4-Flash): single 100%/100%/17%, best-single 100%, Fugu routed 100% (tie — no headroom), but +28 pts over random (the router sent 0 calls to the 17% worker — dist[2,10,0]). Honest takeaways printed: no lift over best-single needs complementary models on harder Qs; routing did beat random by avoiding the weak worker, despite not being calibrated for this pool.
cargo test # all crates
cargo run --bin openfugu -- conductor-selftest # parity with `python openfugu/ultra.py --self-test`
cargo run --bin openfugu -- trinity-demo # Fugu (TRINITY): offline step_trinity loop
cargo run --bin openfugu -- ultra-demo # Fugu-Ultra (Conductor): prompt -> DAG -> execute
# serve Fugu as one OpenAI-compatible model (offline mock router + pool)
cargo run --bin fugu-serve -- --port 8088
curl localhost:8088/v1/chat/completions -H 'Content-Type: application/json' \
-d '{"messages":[{"role":"user","content":"flatten a nested list in one line"}]}'
# REAL end-to-end: the trained candle Qwen3-0.6B router decides each turn
# (build --release; ~2s/query on CPU). Pool is mock here; add --slot-models for live workers.
cargo run --release --bin fugu-serve -- --model artifacts/qwen3-0.6b --port 8090
# HETEROGENEOUS pool — each slot its OWN provider/base/key, no aggregator.
# Slot syntax: model[@base][@ENV_KEY]; the key is an ENV VAR NAME (never in argv),
# a named-but-unset var is a hard error, and local bases need no key.
export OPENAI_API_KEY=sk-... DEEPSEEK_API_KEY=sk-...
cargo run --release --bin fugu-serve -- --model artifacts/qwen3-0.6b --slot-models \
"gpt-4o-mini@https://api.openai.com/v1@OPENAI_API_KEY,deepseek-chat@https://api.deepseek.com/v1@DEEPSEEK_API_KEY,qwen2.5:0.5b@http://localhost:11434/v1"
# omit @base/@ENV_KEY on an entry to fall back to --api-base + FUGU_API_KEY (single-provider pool)
# LOCAL aggregator: route over the UserAgent Node (one OpenAI-compatible gateway,
# 100+ models, one key — no cloud OpenAI, no per-provider keys in OpenFugu).
# API_KEYS="sk-useragent-local:local" AXUM_BIND_ADDRESS="127.0.0.1:58700" axum_server
export USERAGENT_API_KEY=sk-useragent-local # USERAGENT_BASE_URL defaults to http://127.0.0.1:58700/v1
cargo run --release --bin fugu-serve -- --model artifacts/qwen3-0.6b \
--useragent-models "deepseek-v4-pro,qwen-3-7-max,zhipu-glm-5-2"
# --useragent (no list) uses USERAGENT_MODEL (default `auto`, gateway picks the model)
# Fugu-Ultra serving: a Conductor LLM emits a workflow DAG, executed over the pool.
# (--conductor-model = the generating model; without it, offline uses a canned DAG.)
cargo run --release --bin fugu-serve -- --ultra \
--conductor-model "deepseek-chat@https://api.deepseek.com/v1@DEEPSEEK_API_KEY" \
--slot-models "gpt-4o-mini@https://api.openai.com/v1@OPENAI_API_KEY,..."conductor-selftest reproduces the Python self-test output exactly (model_id [2,0,1], access_list [[],[0],[0,1]], dispatch gemini→gpt-5→claude).
- Conductor: forward references rejected (topological order, not arbitrary DAG);
"all"⇒ all earlier steps;>5steps truncated, not errored;model_id % len(pool)wrap; smart-quote normalization + CSV fallback. - Coordinator: only the SOLVER updates the router observation (via
<reference_thought_N>); a Thinker's<suggested_role>overrides the next turn's role; a cold verifier is re-routed to Worker by default (suppress_cold_verifier), togglable to rawstep_trinitybehaviour;ACCEPTmatched only as a leading prefix.
The parser models the real workflow domain — model_id ints, subtasks
strings, access_list of ints/lists/"all" — via PyVal::{Int,Str,List}. It is
not a full ast.literal_eval. Exotic Python literals a Conductor never emits
fall back to the CSV path or are rejected rather than matched bit-for-bit:
True/False/None, floats / scientific notation (1e2), and tuples. Integers
larger than i64 degrade to a string (and an un-int-able model_id raises
InvalidModelId) instead of Python's arbitrary precision. Common string escapes
(\n \t \r) are decoded, matching ast.literal_eval.
Anything needing model weights or the network: the real FuguRouter (SVF/SVD —
to be done offline at build time, never in the serving path), live/local
worker pools, the HTTP server, and training. See the phase table.