fix(gemma_policy): add craft category + narrow inventory_query keyword scope - #8
Open
Pablomonte wants to merge 239 commits into
Open
fix(gemma_policy): add craft category + narrow inventory_query keyword scope#8Pablomonte wants to merge 239 commits into
Pablomonte wants to merge 239 commits into
Conversation
When tui.history_nav_requires_empty_input is true, Up/Down arrows no longer cycle history/queue if the composer input has text. This makes multiline editing less surprising: arrow-up on the first line of a non-empty buffer stays in the buffer instead of jumping to the previous history item. Also adds ConfigTuiConfig to gatewayTypes so the TUI can read the setting from config.get full responses.
…anscript corruption Adds _sanitize_unanswered_tool_calls() to backfill synthetic role=tool results for any assistant tool_calls that weren't answered before an interrupt or error exits the loop. This prevents the next API call from failing with a missing tool response error. Also removes the duplicated inline logic from the outer-loop error handler and calls the helper from _persist_session() so every exit path guarantees an API-valid transcript.
When a user interrupts with an image paste/attachment, the payload is a tuple (text, images). The post-interrupt re-queue code did '\n'.join(all_parts) which crashed with: TypeError: sequence item 0: expected str instance, tuple found Split text and images from each part, combine text with join, and preserve image attachments so process_loop can unpack them normally.
Recovers input_max_lines, collapse_large_pastes, history_nav_requires_empty_input, and show_full_input that were accidentally dropped during Kimi cleanup (bbb91391).
…ture pinning - Reads Kimi CLI tokens from ~/.kimi/credentials/kimi-code.json - resolve_kimi_coding_runtime_credentials(): OAuth first, refresh token support, fallback to KIMI_API_KEY - kimi_coding_default_headers(): proper User-Agent and X-Msh-* headers for coding endpoint - kimi_coding_required_temperature(): pins temperature to 0.6 for kimi-k2.6 on coding endpoint - 401 retry with token refresh before aborting - Integrates into run_agent.py and auxiliary_client.py
The upstream _fixed_temperature_for_model() already omits temperature for Kimi models, letting the server choose the correct value. Our manual 0.6 pinning was unnecessary and could conflict with server-side mode selection (thinking vs non-thinking). Verified working without it.
The auxiliary client's _refresh_provider_credentials() handled auth refresh for Codex, Nous, and Anthropic, but not for Kimi. When the Kimi OAuth token expired, auxiliary calls (memory flush, compression, session search) failed with HTTP 401 while the main client recovered automatically. Add a kimi-coding / kimi-coding-cn case that calls resolve_kimi_coding_runtime_credentials(force_refresh=True) and evicts the cached auxiliary client, mirroring the existing provider refresh paths. Fixes auxiliary memory flush failures when using Kimi OAuth.
# Conflicts: # .gitignore
# Conflicts: # cli.py # hermes_cli/config.py
# Conflicts: # ui-tui/src/app/interfaces.ts # ui-tui/src/app/uiStore.ts # ui-tui/src/app/useConfigSync.ts
- Add protect_first_n to DEFAULT_CONFIG['compression'] (default 3, allows 0)
- Add compression.prompt {preamble, template} for custom summary prompts
- Bump config version 22 -> 23
- Extract hardcoded prompt constants in ContextCompressor to module-level defaults
- Pass custom preamble/template through ContextCompressor constructor
- Read protect_first_n and prompt config in run_agent.py, pass to compressor
- Update status display to show protect_first_n
- Add tests for protect_first_n=0 and custom prompts
- Always preserve system prompt as literal even when protect_first_n=0
- Fix missing import resolve_kimi_coding_runtime_credentials in runtime_provider.py
- Update wiki and website docs
# Conflicts: # hermes_cli/config.py # tests/agent/test_auxiliary_client.py # tests/hermes_cli/test_runtime_provider_resolution.py # ui-tui/src/app/uiStore.ts # ui-tui/src/app/useConfigSync.ts
# Conflicts: # hermes_cli/config.py
…_messages transport PR NousResearch#12846 enabled Anthropic prompt caching for third-party gateways, but gated it on is_claude, which excluded providers like MiniMax that serve their own model families (MiniMax-M2.7, etc.) through the native Anthropic protocol. MiniMax documents full cache_control support on its /anthropic endpoints (global and China). This patch adds MiniMax detection to _anthropic_prompt_cache_policy() using: - Built-in provider id (minimax, minimax-cn), or - Known Anthropic-compatible hostname (api.minimax.io, api.minimaxi.com) Both paths receive the native cache_control layout. Refs: NousResearch#8294 (related, but only covered Claude-named models on third-party gateways). Closes NousResearch#17332
AIAgent.__init__ now detects provider=minimax/minimax-cn and defaults to: - api_mode='anthropic_messages' (was 'chat_completions') - base_url='https://api.minimax.io/anthropic' or 'https://api.minimaxi.com/anthropic' This ensures prompt caching (and all other Anthropic-protocol features) work out of the box for AIAgent users, not just CLI users. Previously, AIAgent(provider='minimax') fell through to chat_completions because base_url was empty and there was no provider-name detection for MiniMax in the api_mode resolution logic. The CLI already resolved this correctly via runtime_provider.py; this change mirrors that behaviour in the low-level agent constructor. Tests added: - 5 new tests in test_minimax_provider.py covering defaults, cn variant, explicit base_url preservation, explicit api_mode override, and prompt caching enabled by default. - 2 new tests in test_anthropic_prompt_cache_policy.py covering empty base_url with provider=minimax/minimax-cn.
…base_url PR NousResearch#17425 (merged) enabled prompt caching for MiniMax models on the anthropic_messages transport, but users still had to manually configure both api_mode and base_url to actually benefit from it. This patch makes the defaults ergonomic: - AIAgent.__init__ now auto-detects provider=minimax / minimax-cn and defaults to api_mode=anthropic_messages + the correct /anthropic base_url (global or China endpoint respectively). - .env.example suggests the /anthropic endpoints instead of /v1. - Explicit base_url or api_mode are preserved when the user sets them. Tests: 5 new cases covering both providers, explicit overrides, and prompt-caching flags. Refs: NousResearch#17332, NousResearch#17333, NousResearch#17425
…h perception-only tools" This reverts commit 6375935.
After a failed /intent call with spatial error types (target_occupied, no_solid_neighbor, bot_in_target), retry once with previous_error payload so Gemma-Andy can replan around the obstacle. Refs: t_336ffcd5
Documents the current working prototype where Grok web generates shell snippets (CMD: prefix) that the proxy executes locally and pipes back. Includes open questions and next steps.
Documents the current working prototype where Grok web generates shell snippets (CMD: prefix) that the proxy executes locally and pipes back. Includes open questions and next steps.
This reverts commit d95e3a3.
Copied STRATEGY_MAP and NEEDS_SETUP from DaemonCraft gemma_policy.py. embodied_plan_tool.py now includes strategy and needs_setup in mitigation output so callers can auto-select execution path. Navigation → embodied_plan with narrow tools. Building → embodied_plan with needs_setup flag. Fallback → mc_direct when Andy fails.
# Conflicts: # run_agent.py
# Conflicts: # CHANGELOG.md # agent/auxiliary_client.py # gateway/platforms/daemoncraft.py # tests/tools/test_embodied_plan_tool.py # tools/embodied_plan_tool.py
# Conflicts: # CHANGELOG.md
…d scope
GemmaPolicy's L4 classifier had two collaborating bugs that made any
craft-style intent unable to dispatch the actual crafting tools.
(1) No 'craft' category existed. Intents like
"Craft a stone shovel using cobblestone and sticks from my inventory"
had nothing to match in CATEGORY_KEYWORDS.
(2) 'inventory_query' keyword 'inventory' was too broad — it matched
any intent that mentioned the word, including the perfectly natural
"...from my inventory" clause that captains emit constantly. The
inventory_query tool subset is only [get_inventory, ask_clarification,
report_execution_error], so the captain ended up with no actionable
body tools at all and replied "no tengo capacidad de craftear".
Observed live with Hermes-K2.6 + DaemonCraft:
Captain → embodied_plan(intent="Craft a stone shovel ... from my inventory.")
→ policy.classify_category() → 'inventory_query' (keyword 'inventory')
→ allowed_tools = [ask_clarification, get_inventory, report_execution_error]
→ Gemma-Andy plan: ask_clarification("craft_item not available; should I wait?")
→ captain explains "no tengo capacidad" to the player
Three additive changes:
1. New 'craft' category, inserted before mining/build:
keywords = craft / craftear / fabricar / smelt / fundir / cocinar /
horno / furnace / forja / forge
tools = [get_inventory, view_craftable, craft_item, smelt_item,
check_furnace, take_from_furnace, equip_item,
place_block, scan_nearby, goto]
STRATEGY_MAP entry → embodied_plan
2. Narrow 'inventory_query' keyword scope: drop bare 'inventory',
keep 'inventario' (Spanish), 'show inventory', 'list inventory',
'list my items', and the existing Spanish phrases.
3. Extend 'build' tools with fill_volume + ignite and keywords with
'fill ', 'rellena/rellená', 'construir' (the infinitive — only
imperative forms were covered).
Verification
>>> for it in [
... "Craft a stone shovel using cobblestone and sticks from my inventory.",
... "craft 4 oak planks", "fundir 16 arena en vidrio",
... "construir una casa de 5x5", "fill volume con cobblestone",
... "mostrame el inventario", "inventory check",
... ]:
... cat = p.classify_category(it.lower())
... n = len(p.get_allowed_tools(cat) or [])
... print(f"{cat:18s} [{n:>3}]")
craft [ 12]
craft [ 12]
craft [ 12]
build [ 9]
build [ 9]
inventory_query [ 3]
default [ 38]
Before this patch, the first three returned `inventory_query 3`, so the
agent literally could not dispatch craft_item.
This is the vendored upstream copy of DaemonCraft's agents/gemma_policy.py.
The DaemonCraft canonical source is at nicoechaniz/DaemonCraft PR nicoechaniz#16 with
the same patch applied — they should land together.
nicoechaniz
force-pushed
the
main
branch
2 times, most recently
from
May 24, 2026 04:37
26d4c51 to
b54dc71
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Vendored copy of `agents/gemma_policy.py` from `nicoechaniz/DaemonCraft` is in `tools/gemma_policy.py` of this repo (used by `tools/embodied_plan_tool.py` when DaemonCraft is the active platform).
The L4 keyword classifier has two collaborating bugs that prevent any craft-style intent from dispatching the actual crafting tools:
The `inventory_query` tool subset is only `[get_inventory, ask_clarification, report_execution_error]`, so the captain ends up with no actionable body tools at all and tells the player "no tengo capacidad de craftear".
Observed live
End-to-end trace from a Hermes-K2.6 + DaemonCraft session:
```
Captain (Kimi-K2.6) → embodied_plan(intent=
"Craft a stone shovel using cobblestone and sticks from my inventory."
)
→ policy.classify_category() loops CATEGORY_KEYWORDS
→ hits 'inventory_query' via keyword 'inventory'
→ allowed_tools = [ask_clarification, get_inventory, report_execution_error]
→ Gemma-Andy plan: ask_clarification("craft_item is not available
in this turn; should I wait?")
→ captain tells player: "no tengo capacidad de craftear ahora"
```
The fix (additive)
1. New 'craft' category, inserted before mining/build
```python
("craft", ["craft ", "craftear", "crafteá", "craftea",
"fabricar", "fabricá", "fabrica",
"smelt", "fundir", "fundí", "fundi",
"cocinar", "cociná", "cocina",
"horno", "furnace", "forja", "forjar", "forge"]),
```
Tool subset (10 tools + the 2 COMMON_SAFE = 12 total):
```python
"craft": ["get_inventory", "view_craftable", "craft_item", "smelt_item",
"check_furnace", "take_from_furnace", "equip_item",
"place_block", "scan_nearby", "goto"],
```
Includes `place_block` for placing a crafting_table/furnace first, and `goto`/`scan_nearby` for finding existing crafting stations nearby.
Mapped through `STRATEGY_MAP["craft"] = "embodied_plan"` like every other category.
2. Narrow 'inventory_query' keyword scope
```diff
```
Drop bare `"inventory"` — too greedy. Pure inventory-show intents still classify correctly via `"inventario"` (Spanish-only), `"show inventory"`, `"list inventory"`, etc.
3. Extend 'build' tools + keywords
Bonus cleanup surfaced while fixing #1:
```diff
```
`fill_volume` enables bulk construction without dropping category. `ignite` covers torch/lava placement scenarios.
Build keywords also extended with `"fill "`, `"rellena/rellená"`, `"construir"` (the infinitive — only imperative forms were covered).
Verification
```python
craft [ 12]
craft [ 12]
craft [ 12]
build [ 9]
build [ 9]
inventory_query [ 3]
default [ 38]
```
Before this patch, the first three returned `inventory_query 3`, so the agent literally could not dispatch `craft_item`.
Coordination with the canonical source
This is the vendored upstream copy of DaemonCraft's `agents/gemma_policy.py`. The DaemonCraft canonical source has the identical patch at nicoechaniz/DaemonCraft#16. The two should land together to keep the mirror in sync.
Test plan