Agent Development (cheap-token chat backend)
SkillAI & modelsUse when building, enhancing, or testing the NPA chat agent backend — grounded-first routing, cost-aware Token Factory model selection, the embedded-backend mechanism, and cheap-token test tiers.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Agent Development (cheap-token chat backend) skill
What this skill tells your AI
The instructions your AI receives, as published by nebius/nebius-physical-ai in skills/atomic/agent-development/SKILL.md and read by ahel’s review.
How to develop the NPA agent chat backend. For operating a deployed agent
(deploy/bootstrap/verify, chat UX, API grounding, Rerun) use
skills/tools/npa-agent/SKILL.md; for fresh deploy/teardown loops use
skills/workflows/agent-fresh-operate/SKILL.md.
Guiding principle: the cheapest token is the one you never spend. Protect and widen the zero-token grounded path; make the unavoidable model calls small, structured, and cheap-model-first.
Architecture (three layers)
- Grounded intent router (zero tokens) —
npa/src/npa/cli/agent_chat.py.match_chat_intent()classifies a turn;build_grounded_reply()answers from live session state with no model call ("grounded": true). Most operator turns end here. - Cost-tier routing (cheap model calls) —
npa/src/npa/cli/agent_routing.py. Only turns that fall through the router reach Token Factory, and this layer keeps them cheap. - Token Factory client —
npa/src/npa/clients/token_factory.py(operator/SDK path) and the embedded_provider_chat/_chat_with_resilienceinnpa/src/npa/cli/agent.py(agent-VM path).
The embedded-backend mechanism (critical)
The agent VM runs backend.py, which is built as one big f-string inside
_bootstrap_agent_stack in npa/src/npa/cli/agent.py. Pure helper modules are
inlined into it via placeholder substitution — the pattern to reuse when adding
logic:
- Real module (normal Python, no brace escaping):
agent_chat.py,agent_workflow.py,agent_routing.py. - Embed helper
_embedded_agent_<name>_source()strips the docstring +from __future__line. - Placeholder constant
_AGENT_<NAME>_EMBEDappears in the template and is replaced in the.replace(...)chain near the end of_bootstrap_agent_stack.
Rules:
- Put testable logic in a real module and embed it; do not write new logic directly inside the f-string unless it must touch template variables.
- Code written inside the f-string must escape literal braces as
{{/}}and newlines in strings as\\n; substitutions use single{var}. - After editing the template, validate the rendered backend compiles (see
Testing). A stray brace is a
SyntaxErrorat import ofagent.py. - Embedded routes register before the template's own routes. The
_AGENT_*_EMBEDplaceholders sit earlier in the f-string than most@app.*blocks, and Starlette resolves the first matching route, so an embedded module silently wins over a same-path handler written further down inagent.py./artifacts/file/{filename}and/artifacts/downloadeach carried two definitions this way, and the shadowed copies inagent.pywere the weaker ones — noContent-Disposition/nosniffheaders, no run-scoped inventory authorization — so the file a maintainer would open described a contract the deployment did not serve. Before adding a route, grep the embedded modules for its path;test_rendered_backend_registers_no_shadowed_routesfails the build on any method+path registered twice.
Cost-tier routing (agent_routing.py)
Pure, side-effect-free functions (no network) so they unit-test cheaply:
classify_tier(text, intent, messages)→cheap(default) /standard(long/compound) /reasoning(analytical language) /vision(image content).build_model_ladder(tier, configured, interactive, requested_model, allow_tier_defaults)→ cheapest-capable first; explicit user model wins; operator allowlist (NPA_AGENT_LLM_MODELS) respected when set.flavor_variants+filter_available— use only documented concrete model IDs and drop unavailable defaults. The current public replacements have no verified-fastvariants; never invent one. Explicit selections are tried even when absent from the model list (dedicated endpoints can differ).chat_extra/thinking_enabled— disable hidden reasoning traces off the reasoning tier (don't pay for discarded tokens).enforce_input_budget— cap oversized pastes (head+tail preserved).usage_summary— surface per-turn token usage.
The /chat handler classifies the tier, enforces the input guardrail, honors an
explicit model override, and returns tier + usage + input_budget_ok.
Adding a capability cheaply (decision order)
- Grounded intent — can a regex intent + grounded state reply answer it?
(0 tokens) Add to
_INTENT_RULES/build_grounded_replyinagent_chat.pyand cover it intest_agent_chat.py. Prefer this for anything high-frequency. Three invariants apply to every new or edited rule:- Add an
INTENT_APISentry. It is not only reply metadata:_semantic_routebuilds the semantic fallthrough'sknown_intentsfrom its keys, so an intent missing from it is unreachable by any paraphrase the regex misses and its grounded replies report an emptyapis_used.test_every_intent_declares_its_apisfails the build otherwise. - Earlier rules win, and
match_chat_intentapplies several hard-coded checks before the list at all. Adding a phrasing an earlier rule already claims silently changes nothing; check what currently matches first. - Keep sibling rules symmetric. The tool-capability rules are near copies, so a verb added to one belongs in all of them. "what can lancedb do" degraded to the generic component reply for exactly this reason while the identical Sonic/LeRobot/Genesis wording stayed tool-specific. A phrasing that matches nothing is not neutral — it falls through to a paid model call for an answer the grounded layer already had.
- Add an
- Cheap model — if it needs generation, let routing pick the cheap tier;
only add reasoning/vision signals to
classify_tierwhen the turn truly needs them. - Escalate deliberately — reserve
MiniMaxAI/MiniMax-M3for analytical/physical-AI/vision turns; it is overkill for routine chat. - Visual feedback — UI Describe this captures the active viewer frame
and posts multimodal
/api/chatwithvisual_context. Helpers live inagent_visual_feedback.py(embedded). Never ground these turns; use vision when an image is attached. Seeskills/atomic/agent-visual-feedback/SKILL.md.
Token Factory notes
- OpenAI-compatible: base
https://api.tokenfactory.nebius.com/v1/, keyNEBIUS_TOKEN_FACTORY_KEY. Samechat/completionsshape everywhere. - Public defaults follow the August 2026 migration notice:
nvidia/Nemotron-3_5-Lightningfor cheap/standard text,MiniMaxAI/MiniMax-M3for reasoning/vision. No default-fastIDs are added. Vision never falls back to the text-only Lightning default. - Cost-ordered default ladder lives in
DEFAULT_LLM_MODELS(cheap first). A barenpa agent deployseeds this whole ladder, so per-turn routing reaches every tier without--llm-models. Explicit--llm-modelsis a governance allowlist;/api/modelsstill surfaces every model the key can serve for per-request selection. - Reasoning-trace handling:
split_reasoning()normalizes Cosmos3 inline<think>and Kimi/GLMreasoningfields. chat_extra(tier, model)selects thinking parameters per attempted model: Lightning useschat_template_kwargs.enable_thinking=false; MiniMax useschat_template_kwargs.thinking_mode="disabled". Analytical turns retain reasoning, and unknown custom models receive no guessed template options.
/api/models and /api/session share observed model availability. Prefer the
configured default only when the provider lists it as chat-capable and it is
within the explicit operator allowlist; otherwise choose the first eligible
configured fallback. Keep the actual full provider catalog for explicit model
selection. Never append an unavailable configured model to make a default look
valid. The documented GET /v1/models?verbose=true supplies architecture
modality; basic listings identify only known chat families, not arbitrary
embedding or custom models. Empty successful discovery reports unavailable;
failed discovery or unknown chat suitability reports unknown, with a null
default and no provider diagnostics. Grounded/session operations still work.
test_agent_model_availability.py exercises the rendered routes, refresh and
failure cache, allowlist, explicit selection and non-chat exclusion. A catalog
entry proves listing availability, not successful inference; retain live chat
verification after deployment.
Testing tiers (keep tokens out of CI)
Follow skills/atomic/testing-conventions/SKILL.md; use npa/.venv/bin/python.
- Tier 0 — pure logic (0 tokens):
npa/tests/cli/test_agent_routing.py(tiers, ladder, flavor, availability filter, budget, usage) andtest_agent_chat.py(intent router, grounded replies). Highest-value coverage. - Tier 1 — mocked LLM (0 tokens): patch
_provider_chat/_chat_with_resilience; assert prompt assembly, resilience fallthrough, and tier/usage in the response. - Rendered-backend check: confirm the embedded backend compiles with all
wiring inlined — render
setup_scriptwith mocked SSH, extract thebackend.pyheredoc body, andast.parse+compileit. Guards the f-string. - Whole-surface audit (0 tokens):
npa/scripts/audit_agent_capabilities.pygoes one step further than the compile check — it runs the rendered backend against a sandbox state root and probes every parameterlessGETplus every advertised intent. Use it to prove a change did not silently unregister a route or re-route an intent, and to answer "does the agent really support X" without a VM. Compiling is not running: an import-time failure in a shippedagent_backendmodule passes the compile check and fails here.--serve-liveruns the same probes against a realuvicornprocess on loopback with the deployed systemd unit's arguments, which is the only tier that covers lifespan and websocket-flag behavior. - Tier 2 — live e2e (bounded tokens): gate behind
NPA_AGENT_CHAT_LIVE=1/NPA_INTEGRATION_E2E=1; pin the cheapest model; assertgrounded: truewhere possible so most turns cost 0 tokens. - Live public-model migration coverage:
npa/tests/e2e/test_agent_token_factory_e2e.pyruns the rendered backend under uvicorn on loopback, sends synthetic text/reasoning/vision requests through/chat, and checks real Token Factory answers and model selection. Only the deployment SSH transport is replaced while rendering; inference is real. It usestoken_factory_e2eand skips without configured provider credentials.
For action-loop validation, inspect the final answer against the original goal
as well as the successful tool observations. stopped_reason="done" can come
from a deterministic empty-result reply; it does not prove the model produced a
final answer or that every requested part was answered. An empty lookup is
terminal only when its subject and scope satisfy the whole request. A filtered
query with zero matches cannot establish an empty store, and an unrelated empty
run lookup cannot replace an available status or tool-catalog answer. Preserve
these distinctions in evaluation receipts and regression tests.
npa/.venv/bin/python -m pytest npa/tests/cli/test_agent_routing.py \
npa/tests/cli/test_agent.py npa/tests/cli/test_agent_chat.py \
npa/tests/smoke/test_agent_smoke.py npa/tests/smoke/test_agent_chat_smoke.py \
npa/tests/guardrails/test_agent_secret_guard.py -q
Guardrails
- Never leak credentials/auth env/secrets into chat, logs, or workflow YAML.
- Do not hardcode project IDs, tenant IDs, bucket names, registry IDs, usernames, or public IPs in code or examples.
- Preserve the chat contract: grounded-first, then a cheap LLM fallback. Do not regress the agent into a chat-only (always-LLM) design.
Agentic surface (fallthrough beyond grounded)
Everything below runs only after the grounded intent router misses; the
zero-token path stays the default. Design doc:
docs/architecture/agent-competitive-plan.md.
- Bounded tool-calling loop —
npa/src/npa/cli/agent_actions.py(run_action_loop): classify → plan → call → observe → decide → stop with a hardmax_stepsguard, an explicitTOOL_ALLOWLIST, and a confirmation-gate contract. GPU/destructive tools need a token bound to the action digest (action_digest); tokens are single-use. Route:POST /api/agent/act. - Autonomous Sim2Real drive —
npa/src/npa/cli/agent_sim2real_loop.py(drive_sim2real_loop): launch→status→gate→diagnose→adjust→re-run, mirroring the enginepromote_checkpoint/loop_backgate. Every launch is confirmation-gated; stages complete only when live status confirms the run (no fabrication); stops on insufficient signal / no-adjustment to avoid runaway GPU. Route:POST /api/agent/sim2real/drive; chat intentdrive_sim2realreturns grounded guidance. - Semantic fallthrough —
npa/src/npa/cli/agent_semantic_router.py(classify_intent_semantic): keyword + cache (0 tokens) then one cheap structured call to map regex-missed paraphrases to a known intent/action. Wired into the/chatfallthrough; degrades tononeon failure. Parity intents still match inmatch_chat_intentand never reach it. - Quantitative viewer eval + memory —
agent_visual_feedback.py(extract_quantitative_signals,compare_rollouts) and the shipped packagenpa/src/npa/agent_backend/memory.py(RunMemory, storage-injected, no hardcoded bucket). Routes:GET/POST /api/agent/memory/*. - Task-eval harness —
npa/tests/agent_eval/(mocked, 0 tokens): scenarios- scorecard (
success_rate/avg_steps/avg_tokens); live variant gated onNPA_AGENT_CHAT_LIVE=1.
- scorecard (
Shipped vs embedded (Phase G): new logic still uses the embed mechanism by
default; agent_backend/ is the shipped-package migration target (uploaded to
/opt/npa-agent/agent_backend/, imported via sys.path). agent_memory is the
migrated pilot; cli/agent_memory.py is a re-export shim. Rendered-backend
compile check: npa/tests/cli/test_agent_backend_render.py.
Blueprint incorporation (retrieval, observability, adversarial eval)
Open-source-only parity with the Nebius "Blueprints" reference agent — Token
Factory (LLM + embeddings) + AI Cloud only, no LangSmith/Pinecone/Tavily/
Snowglobe. Design doc: docs/architecture/blueprint-incorporation-plan.md.
- Retrieval / grounding (Phase H) — shipped
npa/src/npa/agent_backend/retrieval.py(shimcli/agent_retrieval.py).index_corpus()chunks + embeds repodocs/+skills/(and optional live web) into an injected vector store (InMemoryVectorStore/JsonVectorStore/build_lance_storefor LanceDB);retrieve()returns typedCitations;format_grounded_answer()is extractive (0 generation tokens).embedandweb_search(SearXNG-shaped, provider- agnostic) are injected. Read-onlyretrieval_searchtool inTOOL_ALLOWLIST; routesPOST /api/agent/retrieval/index,GET /api/agent/retrieval/search,GET /api/agent/retrieval/status; grounded-first/chatfallthrough that only fires when a corpus is indexed and the top match clears the score floor. - Observability (Phase I) — shipped
npa/src/npa/agent_backend/trace.py(shimcli/agent_trace.py).spans_from_action_loop/spans_from_drivewrap the existing step/iteration traces in structured spans emitted through an injected tracer (NullTracerdefault;build_langfuse_tracer/build_otel_tracerguarded).redact_attributeskeeps secrets/PII out of spans.analyze_tracesclusters traces + flags silent failures (truncation, empty tool results, unsurfaced errors, max-steps). Routes:GET /api/agent/trace/spans,POST /api/agent/trace/analyze. - Adversarial eval (Phase J) —
npa/tests/agent_eval/adversarial.py: persona (Token-Factory-generated, mocked in CI) × prompt-injection scenarios run against the real modules;validate_outputalways runs the repository-owned pure-Python checks.test_agent_adversarial_scorecard.pygatesdefense_ratedelta-vs-baseline (adversarial_baseline.json).
Optional extras (injected/guarded, absent degrades gracefully):
npa[agent-eval] is a compatibility alias with no extra dependencies.
npa[agent-trace] (langfuse /
opentelemetry-sdk). The LanceDB store is now part of the base install.
Embeddings default to
NPA_AGENT_EMBED_MODEL (confirm with npa workbench token-factory models);
LanceDB URI, SearXNG URL, and tracer keys are env/config-resolved, never
hardcoded. New agentic tests: test_agent_retrieval.py, test_agent_trace.py,
and agent_eval/test_agent_adversarial_scorecard.py.
Evidence-backed improvements
The shipped agent_backend/improvements.py queue detects explicit tool failures,
nonterminal empty results, truncation and exhausted action loops. Direct action,
Sim2Real drive and semantic-action chat record observations linked to the active
trajectory episode. Successful recovery and empty discovery that answers the
whole request are not implementation defects. Premature empty-result termination
requires separate goal-answer review even when the loop reports done.
The queue produces triage work packages; it does not run
shell commands, modify source, launch workers or publish code.
Enable it explicitly with NPA_AGENT_IMPROVEMENT_CONFIG, pointing to an
owner-only JSON file outside the checkout. Configure directory, repository,
evidence_directory, reviewers, optional private_literals, and scopes.
Each scope requires a stable scope_id, known component, exact relative
files, full base_revision, required_checks, supported lesson_keys, and
optional version. Queue and evidence directories must be outside the source
repository, mode 0700; configuration, database and reports are mode 0600.
Dataset URI/prefix and the configured trajectory literal denylist also apply
before queue persistence. Never put a live configuration or raw report in Git.
Use ImprovementStore.claim to obtain an exact work package and opaque
claim_token. Its field name ensures trajectory redaction removes the credential.
SQLite transactions prevent overlapping file ownership across processes; every
update requires the current generation and lease. Release only after joining
the worker. Scope comes from coordinator configuration, never an exception or
model-supplied path. Changed scope configuration requires explicit reconciliation.
The coordinator captures begin_candidate before running the scope's real
checks with npa/.venv/bin/python. Supply the complete candidate changed-file
list, excluding separately owned concurrent work. Feed the actual
subprocess.CompletedProcess and nonempty report bytes to
write_validation_receipt, then record_validation. The adapter binds the
report digest, check identity, exit code, source snapshot, scope and claim
generation. It never executes commands supplied by a finding. Failed, partial,
missing or changed evidence cannot advance to independent review.
An independently obtained review report enters through the local trusted
write_review_receipt adapter and review. Reviewer identities are explicitly
coordinator-attested external evidence; the agent's shared HTTP login does not
establish multiple independent reviewers. HTTP routes under
/agent/improvements accept existing protected receipt references, never a
passed flag or an asserted reviewer name as proof. Workers cannot create
receipts through HTTP. Retain the separate actor's actual report privately.
Verified lessons are fixed behavior keys with evidence references, not arbitrary
prose inserted into prompts. Current keys are
trajectory_observation_conservation and inspect_failed_tool_evidence.
Relevant skill/action context retrieves them without a model call. Reuse checks
the source snapshot and retained evidence, records consumption and action
outcome, and deactivates after a distinct recurring failure. A storage failure
returns pending feedback while preserving the completed product action; never
repeat a successful GPU operation to repair feedback. Missing opt-in config
reports disabled.
Regression checks include test_agent_improvements.py,
test_improvement_episode_context.py, and test_agent_improvement_render.py.
The rendered tests exercise all three action hooks and actual shipped modules.
They do not replace a deployed zero-token lifecycle exercise with independent
review evidence. The opt-in test_agent_improvements_live.py uses
NPA_AGENT_IMPROVEMENT_LIVE=1, a dedicated approved component supplied through
NPA_AGENT_IMPROVEMENT_LIVE_COMPONENT, and an owner-only lifecycle bundle at
NPA_AGENT_IMPROVEMENT_LIVE_BUNDLE. The coordinator prepares that bundle from
actual check receipts and a separately obtained review; the live test cannot
invent either. Use the existing private live-agent credential configuration.
Source Layout
- CLI + bootstrap + embedded backend:
npa/src/npa/cli/agent.py - Grounded intent router (testable):
npa/src/npa/cli/agent_chat.py - Cost-tier routing (testable):
npa/src/npa/cli/agent_routing.py - Agentic tool loop / sim2real drive / semantic router:
npa/src/npa/cli/agent_actions.py,agent_sim2real_loop.py,agent_semantic_router.py - Shipped backend package:
npa/src/npa/agent_backend/(memory pilot) - Token Factory client:
npa/src/npa/clients/token_factory.py - Routing tests:
npa/tests/cli/test_agent_routing.py; agentic tests:test_agent_actions.py,test_agent_sim2real_loop.py,test_agent_semantic_router.py,test_agent_memory.py,test_agent_backend_render.py; eval harness:npa/tests/agent_eval/
Signals
- GitHub stars
- 28
- Forks
- 15
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
agent-development-nebius- Source
- github.com/nebius/nebius-physical-ai