diff --git a/agent/coding_context.py b/agent/coding_context.py index 723279abe..c5db3bdda 100644 --- a/agent/coding_context.py +++ b/agent/coding_context.py @@ -318,12 +318,11 @@ def _edit_format_line(model: Optional[str]) -> str: "Operate like a careful senior engineer.\n" "\n" "Gather context first:\n" - "- Before exploring an unfamiliar codebase, call `repo_map` FIRST — when it " - "is in your toolset and the codebase is Python (it is Python-only) — to get " + "- Before exploring an unfamiliar Python codebase, call `repo_map` FIRST to get " "a structured overview (functions/classes/methods with file:line and " "hot-symbol ranking). It is far cheaper than 10+ sequential " "`read_file`/`search_files` calls. After the overview, read only the " - "specific files you need. Without `repo_map`, start from `search_files`.\n" + "specific files you need.\n" "- Read the relevant files with `read_file` and locate code with " "`search_files` before changing anything. Trace a symbol to its definition " "and usages rather than guessing its shape.\n" diff --git a/tests/agent/test_coding_context.py b/tests/agent/test_coding_context.py index c74617b2c..ed123333c 100644 --- a/tests/agent/test_coding_context.py +++ b/tests/agent/test_coding_context.py @@ -14,7 +14,7 @@ def test_coding_guidance_advertises_repo_map_first(): assert "repo_map" in cc.CODING_AGENT_GUIDANCE assert ( - "Before exploring an unfamiliar codebase, call `repo_map` FIRST" + "Before exploring an unfamiliar Python codebase, call `repo_map` FIRST" in cc.CODING_AGENT_GUIDANCE ) @@ -156,6 +156,7 @@ def test_coding_toolset_is_registered(self): "write_file", "patch", "search_files", + "repo_map", "terminal", "todo", ): @@ -452,7 +453,9 @@ def test_coding_instructions_accept_a_list(self, tmp_path): def test_no_instructions_block_when_unset(self, tmp_path): _git_init(tmp_path) - mode = cc.resolve_runtime_mode(platform="cli", cwd=tmp_path, config={"agent": {"coding_context": "on"}}) + mode = cc.resolve_runtime_mode( + platform="cli", cwd=tmp_path, config={"agent": {"coding_context": "on"}} + ) assert not any("Operator instructions" in b for b in mode.system_blocks()) def test_toolset_selection_gated_on_focus(self, tmp_path): diff --git a/tests/test_toolsets.py b/tests/test_toolsets.py index 1773d281a..0c4d203d2 100644 --- a/tests/test_toolsets.py +++ b/tests/test_toolsets.py @@ -61,6 +61,13 @@ def test_composite_toolset(self): assert "web_search" in tools assert "web_extract" in tools + def test_coding_posture_toolsets_expose_repo_map(self): + # The coding-posture brief and loop-guard nudges advise calling + # repo_map first; the toolsets they target must actually expose it + # (#669 — no prompt may advertise an uncallable tool). + assert "repo_map" in resolve_toolset("coding") + assert "repo_map" in resolve_toolset("hermes-acp") + def test_cycle_detection(self): # Create a cycle: A includes B, B includes A TOOLSETS["_cycle_a"] = {"description": "test", "tools": ["t1"], "includes": ["_cycle_b"]} diff --git a/toolsets.py b/toolsets.py index 9f5bdc620..0d15ff250 100644 --- a/toolsets.py +++ b/toolsets.py @@ -193,7 +193,12 @@ "file": { - "description": "File manipulation tools: read, write, patch (with fuzzy matching), and search (content + files)", + "description": "File manipulation tools: read, write, patch (with fuzzy matching), search (content + files), and repo_map (Python codebase overview)", + # repo_map is deliberately NOT listed here: it self-registers into this + # toolset at import time (tools/repo_map.py, toolset="file"). Listing it + # statically breaks hermes_cli/tools_config.py's composite-subset + # inference — 'file' must stay a subset of the static hermes-* platform + # tool lists, which do not carry repo_map. "tools": ["read_file", "write_file", "patch", "search_files"], "includes": [] }, @@ -365,7 +370,7 @@ "tools": [ "web_search", "web_extract", "terminal", "process", "read_terminal", "close_terminal", - "read_file", "write_file", "patch", "search_files", + "read_file", "write_file", "patch", "search_files", "repo_map", "vision_analyze", "skills_list", "skill_view", "skill_manage", "browser_navigate", "browser_snapshot", "browser_click", @@ -397,7 +402,7 @@ "tools": [ "web_search", "web_extract", "terminal", "process", - "read_file", "write_file", "patch", "search_files", + "read_file", "write_file", "patch", "search_files", "repo_map", "vision_analyze", "skills_list", "skill_view", "skill_manage", "browser_navigate", "browser_snapshot", "browser_click",