Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/agentacct/tool_activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@
"update_plan": "plan",
# Generic shell aliases other agents use (e.g. Hermes' ``terminal``).
"terminal": "execute",
# opencode: the names it uses that are not already shared with the
# Claude/Codex tools above. Without these they collapsed to ``other``.
"list": "search",
"patch": "edit",
"todoread": "plan",
# Anthropic's official text-editor tool — one tool whose NAME varies by API
# version (str_replace_based_edit_tool / str_replace_editor / text_editor).
"str_replace_based_edit_tool": "edit",
"str_replace_editor": "edit",
"text_editor": "edit",
# Cross-agent snake_case names used by Cursor/Windsurf and various MCP
# servers; each of these otherwise fell through to ``other``.
"read_file": "read",
"write_file": "edit",
"edit_file": "edit",
"list_dir": "search",
"codebase_search": "search",
"run_terminal_cmd": "execute",
"web_search": "network",
}


Expand Down
4 changes: 2 additions & 2 deletions tests/test_codex_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def test_tool_activity_from_calls_aggregates_all_signals():
("exec_command", json.dumps({"cmd": "pytest -q"})),
("apply_patch", "*** Begin Patch\n*** Add File: src/a.py\n+x\n*** End Patch\n"),
("spawn_agent", "{}"),
("read_file", "{}"), # unknown -> category "other", name kept
("some_unknown_tool", "{}"), # unknown -> category "other", name kept
]
activity = _tool_activity_from_calls(calls, cwd="/work/project")
assert activity["tool_category_counts"] == {
Expand All @@ -161,7 +161,7 @@ def test_tool_activity_from_calls_aggregates_all_signals():
"exec_command": 1,
"apply_patch": 1,
"spawn_agent": 1,
"read_file": 1,
"some_unknown_tool": 1,
}
assert activity["commands"] == ["git status", "pytest -q"]
assert activity["touched_files"] == ["src/a.py"]
Expand Down
18 changes: 18 additions & 0 deletions tests/test_tool_activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ def test_tool_category_maps_names_only_and_collapses_mcp() -> None:
assert tool_category("WebFetch") == "network"
assert tool_category("Task") == "agent"
assert tool_category("TodoWrite") == "plan"
# Names are matched case-insensitively.
assert tool_category("READ_FILE") == "read"
# opencode names not shared with the Claude/Codex tools.
assert tool_category("list") == "search"
assert tool_category("patch") == "edit"
assert tool_category("todoread") == "plan"
# Anthropic's text-editor tool, whatever the API version names it.
assert tool_category("str_replace_based_edit_tool") == "edit"
assert tool_category("str_replace_editor") == "edit"
assert tool_category("text_editor") == "edit"
# Cross-agent snake_case names (Cursor/Windsurf/MCP) that used to be `other`.
assert tool_category("read_file") == "read"
assert tool_category("write_file") == "edit"
assert tool_category("edit_file") == "edit"
assert tool_category("list_dir") == "search"
assert tool_category("codebase_search") == "search"
assert tool_category("run_terminal_cmd") == "execute"
assert tool_category("web_search") == "network"
# Any MCP tool collapses to a single bucket by PREFIX, so a specific MCP
# tool name (which could reveal a connector) is never recorded.
assert tool_category("mcp__github__create_issue") == "mcp"
Expand Down
Loading