Repository navigation
v0.31.0
Added
-
Hummin becomes a first-class LLM provider (
ModelProvider.HUMMIN) and the GLM go-to — the GLM-nativehumminCLI (a pi-harness fork) running headless in Docker on the GLM Coding Plan. The kimi pattern with the OpenRouter auth shape: the operator's Z.ai key is stored Fernet-encrypted (PUT /providers/hummin-key, migration102_seed_hummin_providerseeds theenabled=truerow after101_modelprovider_humminadds the enum value) and injected asZAI_API_KEYat spawn — no~/.hummincredential mount, no refresh loop, initial prompt as an env var never an argv token. The provider quartet (roboco/llm/providers/hummin.py+hummin_cli_config.py/_cli_sniff.py/_cli_usage.py) renders fleet-safe~/.hummin/agent/settings.jsondefaults plus a per-role--toolsstrict allowlist (kimi's permission-rules semantics mapped onto hummin's allowlist; no hooks/MCP exist to port — see below), scrapes the tee'd--mode jsonrun log (sum ofmessage.usageacross ALL assistantmessage_endevents, a genuine 4-bucket split, turns = assistant count), and classifies rate-limit/auth parks from ONLY the structuredstopReason/errorMessage/error.messagechannels plus stderr — load-bearing because hummin's JSON mode exits 0 even when the assistant errored, so the entrypoint branches on the sniff result, never the raw exit code. Theroboco-agent-humminimage (docker/agent-hummin.Dockerfile+docker/scripts/hummin-cli-agent-entrypoint.sh,hummin-clinpm install, Node >= 22.19 build-fails-loud guard, prompt_guard, hummin's ownauth check --provider zai --jsonpreflight mapped to the fleet's exit-78/75 park convention); the routing-service integration (set_hummin_api_key,apply_mode("hummin")/_apply_hummin— spawn-time key gate, the openrouter precedent;derive_mode; HUMMIN in the interactive guard and the upsert auto-enable tuple); the runtime plumbing (registry registration, per-agent usage dirs, finalize token/turn readers, rate-limit/auth park handlers, active-token sweep reader, an uncapped-by-defaulthummin_max_concurrent); the API (GET/PUT /providers/hummin-key,HumminKeyStatus/SetHumminKeyRequest,"hummin"in the three mode Literals); and the full panel surface (HumminProviderKeyRow, the key-gated mode button,ProviderBadgevariant, the GLM group in the Mix picker). The static catalog's GLM entries (glm-5.3,glm-5.3-flash, newglm-5.3-highspeed) re-pointed from ZAI to HUMMIN — ZAI (the Anthropic-protocol Claude-spawn path) keeps its row and key endpoint as a manual fallback but has no catalog entries left, andglm-5.3:cloud/glm-5.3-flash:cloudstay on OLLAMA_CLOUD. Two documented V1 degradations, both live-verified against the hummin source: hummin has NO MCP client, so the RoboCo gateway is unreachable from a hummin agent (completion rides the orchestrator's still-owned-task path; an explicit-ebridge extension is the named follow-up), and there is no PreToolUse hook surface, so the bash-guard cannot install — the tool-level allowlist is the only boundary.HUMMIN_MEMORY=0is force-set in the container env so hummin's memory extension can never write the operator's personal vault. No_PRICINGrow forglm-5.3-highspeedyet (no verifiable published rate):calculate_costfalls back to theglm-5.3rates via longest-fragment match, over-attributing spend at the full rate — the safe direction — until a published price lands. -
The Z.ai GLM provider (
ModelProvider.ZAI) runs GLM through Claude Code via the built-in Anthropic translator - the manual fallback hummin now fronts. A static-catalog batch of GLM ids (glm-5.3,glm-5.3-flash), a Fernet-stored key endpoint pair (GET/PUT /providers/zai-key, migrations097_modelprovider_zai+098_seed_zai_providerseeding key-gated), and spawn-timeANTHROPIC_BASE_URLinjection pointing at z.ai's Anthropic-compatible endpoint, so ZAI agents speak the Anthropic Messages protocol with no new CLI runtime. Panel: the four provider key boxes laid out in a 2x2 band and the routing mode strip wrapped into rows with a Z.ai mode button (an intermediate tabs restructure of the card was rejected and reverted same-day). When hummin landed, the GLM catalog entries re-pointed from ZAI to HUMMIN: ZAI keeps its provider row and key endpoint as the manual path but holds no catalog entries.derive_mode's return Literal gainedzaiin the same cycle. -
Nebius Token Factory becomes a first-class LLM provider (
ModelProvider.NEBIUS) - the full-parity twin of the OpenRouter provider. Nebius Token Factory (https://tokenfactory.nebius.com) is an OpenAI-compatible inference API serving 60+ open models (NVIDIA Nemotron, DeepSeek, Qwen, Llama) behind one metered API key athttps://api.tokenfactory.nebius.com/v1; the provider's default model is NVIDIA's Nemotron 3 Super (nvidia/nemotron-3-super-120b-a12b,nebius_cli_model), so a Nebius-mode fleet runs an NVIDIA open model by construction. The openrouter pattern is cloned end to end: the provider quartet (roboco/llm/providers/nebius.py+nebius_cli_config.py/_cli_sniff.py/_cli_usage.py, the Ollama shape - static Fernet-stored key injected asNEBIUS_API_KEY/NEBIUS_BASE_URLenv at spawn, no auth mount, no refresh loop, initial prompt as an env var never an argv token); theroboco-agent-nebiusimage (docker/agent-nebius.Dockerfile+docker/scripts/nebius-agent-entrypoint.sh, opencode CLI runtime, prompt_guard + exit-78 auth preflight + exit-75/78 park sniffing); migrations099_modelprovider_nebius(enum add in anautocommit_block) and100_seed_nebius_provider(key-gatedenabled=falseseed; renumbered from 097/098 in the slave merge after the ZAI provider took those numbers); the routing-service integration inroboco/services/llm.py(set_nebius_api_key,apply_mode("nebius")/_apply_nebiuswithprovider_type_override,derive_mode,probe_nebius_models, NEBIUS in the interactive guard and the upsert auto-enable tuple); the runtime plumbing (registry registration, per-agent usage dirs, finalize token/cost readers off the meteredusage.cost, rate-limit/auth park handlers, active-token sweep reader); the API (GET/PUT /providers/nebius-key,GET /providers/nebius/modelsreusing theOpenRouterModelEntryschema,NebiusKeyStatus/SetNebiusKeyRequest,"nebius"in the three mode Literals); and the full panel surface (NebiusProviderKeyRow, the key-gated Nebius mode button + model picker,useNebiusKey/useSetNebiusKey/useSearchNebiusModels). Two deliberate differences from OpenRouter: Token Factory's model list carries no capability metadata, so the search proxy has no tools filter and onlyidis substantive; and there are no attribution-header settings (no referer/title dashboard to feed). Per-agent Mix-mode pins were out of scope at ship time (the openrouter decision) and landed in the levels-parity batch below. Docs:docs/backend/api/nebius-provider.md,docs/frontend/nebius-provider.md,docs/frontend/components/nebius-routing-ui.md. -
Hackathon submission notes (
HACKATHON.md) + a Nebius provider block in the README. RoboCo predates the Nebius x NVIDIA hackathon's submission window (August 26 to October 30, 2026), and Stage One screens for "not a superficial rebrand", so the new root-levelHACKATHON.mdisolates exactly what changed in-window for that pass/fail review: the Nebius Token Factory provider integration with NVIDIA's Nemotron 3 Super (nvidia/nemotron-3-super-120b-a12b) as the fleet-wide default by construction (apply_mode("nebius")resolvesdefault_model or settings.nebius_cli_model), the v0.30.0 platform release (2026-09-13, 16 merged PRs), and the post-release panel contract fixes; it also walks the judge path frommake quickstartthrough saving the Token Factory key and flipping the fleet to Nebius mode. The README gained a matching "run agents on Nebius Token Factory (NVIDIA Nemotron)" optional-provider block alongside Grok/Kimi and a hackathon section linking the doc. -
The
run_sandbox_testsgateway verb executes the QA test run inside a Token Factory Sandbox microVM (the Coding and Agentic Engineering track's signature product). A new never-raise REST client (roboco/llm/providers/nebius_sandboxes.py) drives the Sandboxes service (https://api.tokenfactory.nebius.com/sandboxes/v1, Contree) three-call flow - octet-stream file upload (POST /v1/files), disposable instance spawn (POST /v1/instanceswith the uploaded uuid infiles,shell: true, a per-runtimeout, output truncation bounded), and operation polling (GET /v1/operations/{id}untilSUCCESS/FAILED/CANCELLED, cancelling best-effort at the deadline, flatteningmetadata.resultintoexit_code/stdout/stderr/meteredcost). The verb (in_DEV_DO/_QA_DOonly - the two roles that run test suites - so no coordinator/board manifest offers it; request schemaRunSandboxTestsRequestwith a 2000-charcommand, optionalimage, optional 30-3600stimeout_seconds) guards flag off -> no active project-bound task -> no stored Nebius key (the Sandboxes API shares the inference key, bearer + optionalProjectheader) -> workspace/team/project unresolvable ->git archivefailure -> the new 64 MiB upload ceiling, then archives the committed HEAD (worktree else clone root, mirroringrequest_render's choice), runs the composedmkdir -p /workspace && tar -xzf ... && cd /workspace && <command>shell inside the microVM, and returnsevidence.sandbox(exit code, stdout/stderr tails, cost, duration, instance/operation uuids) plus a journal entry, heartbeating the claim before and after the wait. Default-off viaROBOCO_TOKEN_FACTORY_SANDBOXES_ENABLED(also on the Feature Flags card) and inert on any failure - QA keeps its container shell; the local path is never broken.commandjoined_WAF_FREETEXT_BODY_FIELDS(test commands are agent-authored free text; the route keeps mesh WAF scanning, and the command only ever executes inside the ephemeral sandbox VM). Config settings, panel copy,tests/unit/llm/providers/test_nebius_sandboxes.py+tests/unit/gateway/test_run_sandbox_tests_verb.py(23 cases: contract shapes, headers, Location polling, deadline cancel, result flattening, the full guard matrix, evidence shape, and QA-only manifest scoping), anddocs/backend/api/token-factory-sandboxes.md(with live bring-up verification items for the bearer/Project and default-image assumptions). Post-merge live verification with beta-granted Sandboxes access ran the full client flow green end to end (echo-scale run: exit 0, metered cost about 0.0003) and caught one real bug, fixed in the same cycle: the spawn response'sLocationheader is HOST-ROOTED, so polling appended it to the/v1base and double-pathed into empty 404s forever -wait_sandbox_operationnow normalizes the path to the last/v1/anchor, with a regression test pinning the host-rooted case. -
Nebius levels parity: the four live-verified Nemotron ids joined
MODEL_CATALOG, so Nemotron models are configurable at every routing level exactly like Claude. Before this batch the fleet default was the only Nebius knob: the static catalog carried noNEBIUSrows, which locked Nemotron out of the Mix-mode per-agent picker (the Select groups render from the catalog) and out of the complexity-override validator (resolve_provider_for_modelis a catalog lookup). The new entries are the Nemotron family the liveGET /v1/modelsreturned with the hackathon key (Nanonvidia/NVIDIA-Nemotron-3-Nano-30B-A3B, Supernvidia/nemotron-3-super-120b-a12b, Ultranvidia/Nemotron-3-Ultra-550b-a55b,nvidia/Nemotron-3_5-Lightning; the first two ids' correctness matters most - the shipped default had been a best-effort guess). With the entries in place: the Mix picker renders a Nebius group (badge "N"), complexity-override rows accept Nemotron models (downgrade-only vs each role's Anthropic baseline; no_PRICINGrows exist yet, so the comparator ranks them cheapest-tier - the same documented ceiling as OpenRouter), and mix pins resolve to the auto-enabled NEBIUS provider row. Nebius joins Codex/Gemini/Kimi in the interactive-only group's exclusions (one-shot V1). Tests: catalog membership + the fleet default being a catalog member (unit), a mix pin resolving to the NEBIUS provider row (integration), and a complexity override round-trip with the non-null cross-family warning (integration). -
NAS deployment went blue-green: one compose carries both colors, and a deploy is an nginx include-file flip with zero dropped requests.
docker-compose.nas.ymlruns blue unprefixed and green under thegreenprofile with per-color image tags;deploy/active-upstreams.confholds threesetdirectives consumed by a variableproxy_pass+ the docker resolver, so upstreams resolve at request time and nginx can never crash on an absent color (it 502s that one route). The flip is a tmp+mv swap guarded bynginx -t(restore the previous file and abort on failure) followed bynginx -s reload, and the old color stops only after the new one passes health checks - rollback is re-running the stopped color.deploy-nas.shensures ALL images exist on the host BEFORE the new color comes up (a pull pass, then a host-side build pass for any missingdocker/*.Dockerfile- in-container builds cannot work against a bind-mounted host path), polls health instead of--wait, and exports a per-colorROBOCO_API_URLso agents always resolve their own generation's dispatcher. An earlier option-0 script (pre-build/pull while serving, thenup --wait) landed mid-batch and was superseded. -
The runtime warns when an active spawn session's finalize records zero tokens - capture gaps used to undercount spend as $0 silently; the check now surfaces them at finalize time instead.
Fixed
- The Nebius fleet default model id is live-verified against the Token Factory catalog: the shipped
nvidia/nemotron-3-super-120bwas a best-effort guess that does not exist - the real id isnvidia/nemotron-3-super-120b-a12b(Nemotron 3 Super, 120B-A12B). Verified with the hackathon Token Factory key (GET /v1/models, 200, zero credits): the catalog carries 24 models including the Nemotron familyNVIDIA-Nemotron-3-Nano-30B-A3B,nemotron-3-super-120b-a12b,Nemotron-3-Ultra-550b-a55b, andNemotron-3_5-Lightning. The old id would have failed every Nebius-mode spawn at runtime (the exit-78 auth preflight only checks key presence, not model validity). Fixed everywhere the id is pinned:nebius_cli_modeldefault, the entrypoint's--modelfallback, the usage reader's default, all tests, and the docs. The same live session settled the Sandboxes integration's assumptions: theProjectheader is REQUIRED (400 without it; the service-account id embedded in the key resolves as its value), and the hackathon static key is inference-only (403 spawn) - Sandboxes spawn permission must be granted console-side beforerun_sandbox_testscan execute, and the verb degrades to a 403 error string until then. - The OpenRouter and Nebius model pickers in Settings -> AI Routing rendered blank rows and could not actually select a model. The panel's
OpenRouterModel/NebiusModeltypes (and every field access in the two picker blocks ofai-routing-card.tsx) were written against an invented{model_name, display_name, pricing: {prompt, completion}}shape, while the backend'sOpenRouterModelEntryschema (which bothGET /providers/openrouter/modelsandGET /providers/nebius/modelsreturn, the Nebius endpoint reusing it verbatim) has always carried{id, name, context_length, prompt_price, completion_price}. Every model name, display name, and price therefore renderedundefined(the screenshots' nameless rows with bare "— in / — out" and "1,000,000 ctx"), and clicking a row storedundefinedas the picked model, so flipping to OpenRouter/Nebius mode never sent adefault_modelat all. The panel types now mirror the backend schema (idis the slug used as the routing model_name, prices are per-token USD floats), the rows rendername/idand formatprompt_price/completion_priceper million tokens, and the vitest mocks were rewritten to the real contract (they had been written against the invented shape, which is how the suite stayed green under a broken UI) plus a new regression test pinning that clicking a row selects it and reports the picked id. The same audit removed the panel's remaining phantom contract fields:Taskdeclaredwork_session_id/execution_log/outputs(the backend sends awork_sessionsummary object instead, now typed asWorkSessionInTaskmirroring the backend'sWorkSessionSummaryInTask, andFileRef/ExecutionLogwent with their only consumers) andNotificationdeclaredacked_by/acked_at/related_message_ids(per-recipient ack state is resolved server-side intois_acknowledged/is_fully_acknowledged); the notifications client also stopped sending apriority_filterquery param the backend'sListNotificationsParamshas never accepted. - Model pricing re-verified against source (2026-09-16): sonnet-5's 2/10 standard rate is permanent - the announced increase was cancelled - and
glm-5.3-flashgained its missing_PRICINGrow. - The release workflow builds and publishes the OpenRouter agent image, and the image is listed in every compose image set. On v0.30.0 it was missing from the release build map and the registry compose, so an OpenRouter-mode fleet had no image to pull and the pull-smoke could not catch the gap.