[nu-demo] hero_agent triage classifier routes 'What is Hero OS?' to Knowledge path (no tools offered) — grounding never happens #152
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptom
Even with:
hero_agent/src/prompt.rscontaining the MANDATORY directive (compiled into the binary, verified viastrings hero_agent_server | grep -c MANDATORY= 1, same forHero Vired,sovereign digital),tool_router.rslistingsearch_hero_docsinalways_include,llm_client.rsemittingtool_choice: "required"whenever tools are offered (#150),…the plain question
"What is Hero OS and what can it do?"still returns a generic OS description ("user-friendly and efficient, Lightweight performance, Runs smoothly on various devices") — no mention of "sovereign digital workspace," no doc citation.Root cause (diagnosed on heronu 2026-04-24)
hero_agenthas a triage classifier that routes every incoming chat message into one of (at least) two buckets:triage=Knowledge→ LLM called without the tools list. This is the "pure chat" path — the model gets only the system prompt + message, and composes an answer from training data. The MANDATORY directive is present in the system prompt, but with no tool offered,search_hero_docscan't be called; with no tool call, the model falls back to training priors;tool_choice: "required"is never emitted because tools is empty.triage=Tools→ LLM called with the full 58+ tool list (fromtool_router.rs),tool_choice: "required"forces a tool call, and grounding works."What is Hero OS?" is being classified as
Knowledge, so the hero-grounding chain is never invoked. The smoke test response proves it: no tool call, no doc citation, generic OS description.When the user instead asks
"Call search_hero_docs with query='Hero OS overview'", the triage classifier routes toToolsand grounding works perfectly — confirmed by repeated testing.Why this is wrong for Hero OS
The triage split is useful in principle (skip tool overhead for pure chat), but the classifier treats Hero-specific questions as "general knowledge" when they are in fact the ONE class of question we always want grounded. A user asking about Hero OS in the built-in AI Assistant should get docs_hero content, not hallucinated marketing copy.
Proposed fixes
Three options, in order of pragmatism:
Toolswhen the message contains anyhero_*keyword. Add a pre-triage override inhero_agent_server/src/routes.rs(or wherever triage lives):hero_*, proactively callsearch_hero_docsbefore asking the LLM and pass the snippets as context. No triage change; just augment the Knowledge handler.always_includetool names so it can route when any always-include tool is relevant. Removes the hard-coded keyword list.For the demo, (1) is the smallest change and unambiguous.
Related
development_mik_nu_demo)development_mik_nu_demo)Verification
After fix:
→ response must cite
hero_os_guideor use phrases directly from docs_hero ("sovereign digital workspace," "browser-based," "local-first").Signed-off-by: mik-tf
make demotarget — provision + install + seed + verify a fresh Hero OS demo VM in one command #163Fixed in hero_agent commit
b650591ondevelopment. Implements option 1 from the issue body — the smallest change with unambiguous behavior.Root cause re-confirmed by reading the code:
triage.rs::quick_triageruns through CHITCHAT_PATTERNS → TOOL_PATTERNS → short-message threshold → LLM fallback. None of those steps recognize "What is Hero OS?" as a tool-requiring query, so it ends up in the LLM-triage default → Knowledge → no tools offered → search_hero_docs never reaches the model → grounded answers are structurally impossible.Fix at
triage.rs::quick_triage— pre-empt every existing check with a hero_* pattern match at step 0:HERO_PATTERNSis one alternation regex covering every service prefix used inagent.rs::message_contains_hero_keyword(home#150) andprompt.rs's MANDATORY block (home#149):The inline doc on
HERO_PATTERNSexplicitly calls out that the three lists must stay in sync — adding a newhero_*service requires updating all three.Tests added (3):
test_hero_questions_route_to_tools— sanity matrix of 6 differenthero_*queries (What is Hero OS?,How does hero_books work?,Tell me about hero_aibroker.,explain hero_router routing,Why is hero_voice so slow?,hero_archipelagos overview) — all must classifyTools.test_hero_pattern_overrides_chitchat—"hi, what is hero_os?"must beat the chitchat-greeting regex (the new check sits at step 0, before chitchat patterns).test_hero_pattern_does_not_match_unrelated_words—"Who is your hero?"and"Tell me about Hero Vired"stay ambiguous → defer to LLM triage. Disambiguates from generic "hero" without a service suffix.Why this completes the grounding tripod:
prompt.rssystem promptsearch_hero_docsllm_client.rstool_choicetriage.rsquick_triageWithout all three, hero-stack questions fall back to training data. With all three: deterministic grounding via
search_hero_docs, citations from the docs corpus, no hallucinated marketing copy.Verification:
cargo fmt,cargo check -p hero_agentclean, all 10 triage tests pass + 87 pre-existing tests still pass.Meta-tracker: home#193.
Signed-off-by: mik-tf
make demotarget — provision + install + seed + verify a fresh Hero OS demo VM in one command #31