[tool system] Circular import chain between agent_tools, tool_parsing, and tool_schemas #672

Closed
opened 2026-06-02 23:40:04 +02:00 by sleepy · 1 comment
Owner

Circular import chain in tool modules

The tool module graph has a circular dependency chain:

agent_tools.py → tool_parsing.py → agent_tools.py (imports ToolBlock, TOOL_TAGS)
agent_tools.py → tool_schemas.py → agent_tools.py (imports ToolBlock, TOOL_TAGS)
                       tool_schemas.py → tool_parsing.py (imports _TOOL_NAME_MAP)
tool_execution.py → tool_security.py (clean)
tool_execution.py → agent_tools.py (imports get_mcp_manager via local import)
tool_implementations.py → agent_tools.py (imports get_mcp_manager via local import)

Current workaround

  • tool_parsing.py and tool_schemas.py import from agent_tools.py at module level
  • agent_tools.py imports from tool_parsing.py and tool_schemas.py at module level
  • This works only because Python processes the imports in a specific order, but it's fragile

Evidence

  • tool_parsing.py:13: from src.agent_tools import ToolBlock, TOOL_TAGS
  • tool_schemas.py:15: from src.agent_tools import ToolBlock, TOOL_TAGS
  • tool_schemas.py:16: from src.tool_parsing import _TOOL_NAME_MAP
  • agent_tools.py:92: from src.tool_parsing import ...
  • agent_tools.py:104: from src.tool_schemas import ...

Suggested fix

  • Move ToolBlock (a namedtuple) and TOOL_TAGS (a set) into a standalone src/tools/types.py or src/tools/constants.py
  • Both tool_parsing.py and tool_schemas.py import from the constants module instead of from agent_tools.py
  • This breaks the cycle cleanly
## Circular import chain in tool modules The tool module graph has a circular dependency chain: ``` agent_tools.py → tool_parsing.py → agent_tools.py (imports ToolBlock, TOOL_TAGS) agent_tools.py → tool_schemas.py → agent_tools.py (imports ToolBlock, TOOL_TAGS) tool_schemas.py → tool_parsing.py (imports _TOOL_NAME_MAP) tool_execution.py → tool_security.py (clean) tool_execution.py → agent_tools.py (imports get_mcp_manager via local import) tool_implementations.py → agent_tools.py (imports get_mcp_manager via local import) ``` ### Current workaround - `tool_parsing.py` and `tool_schemas.py` import from `agent_tools.py` at module level - `agent_tools.py` imports from `tool_parsing.py` and `tool_schemas.py` at module level - This works only because Python processes the imports in a specific order, but it's fragile ### Evidence - `tool_parsing.py:13`: `from src.agent_tools import ToolBlock, TOOL_TAGS` - `tool_schemas.py:15`: `from src.agent_tools import ToolBlock, TOOL_TAGS` - `tool_schemas.py:16`: `from src.tool_parsing import _TOOL_NAME_MAP` - `agent_tools.py:92`: `from src.tool_parsing import ...` - `agent_tools.py:104`: `from src.tool_schemas import ...` ### Suggested fix - Move `ToolBlock` (a `namedtuple`) and `TOOL_TAGS` (a `set`) into a standalone `src/tools/types.py` or `src/tools/constants.py` - Both `tool_parsing.py` and `tool_schemas.py` import from the constants module instead of from `agent_tools.py` - This breaks the cycle cleanly
Author
Owner

Fixed via PR #903 — extracted ToolBlock + TOOL_TAGS into tool_types.py leaf module, breaking the cycle. Backward-compatible re-exports preserved.

Fixed via PR #903 — extracted ToolBlock + TOOL_TAGS into tool_types.py leaf module, breaking the cycle. Backward-compatible re-exports preserved.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sleepy/odysseus#672
No description provided.