refactor(ai): single-source tool registration via register_tool() (#56) #68
Loading…
Reference in a new issue
No description provided.
Delete branch "refactor/issue-56-tool-registry"
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?
Closes #56.
Adding a tool used to require updating two parallel structures in
ai.py: a name→handler entry in_TOOL_DISPATCHand a schema dict in_DIR_TOOLS(or_SYNTHESIS_TOOLSor_SURVEY_TOOLS). Forgetting one half was silent. Internals.md §9.1 documented this as a 5-step process.The new shape
A single
register_tool()call per (tool, scope):The function appends the schema to one or more scope lists (
_DIR_TOOLS/_SYNTHESIS_TOOLS/_SURVEY_TOOLS) and lands the handler in_TOOL_DISPATCH. Tools intercepted by the loop body (submit_report,submit_survey) register schema only withhandler=None.Tools whose schema differs by scope (
submit_reporthas different shapes in dir vs synthesis loops) get oneregister_tool()call per scope.flagis also registered twice because it appears in dir + synthesis at different positions in each list — the order is preserved with two calls rather than reordered.Verification
_DIR_TOOLS,_SYNTHESIS_TOOLS,_SURVEY_TOOLScontain the same names in the same order as before. Verified via runtime introspection:read_file, list_directory, run_command, parse_structure, write_cache, think, checkpoint, flag, submit_reportread_cache, list_cache, flag, submit_reportsubmit_survey_TOOL_DISPATCHcontains the same 10 handlers as before.Internals.md updates
Out of scope
register_tool()collapses to a one-line forward. The structure introduced here is naturally MCP-shaped: a single registry of (name, schema, scopes, handler) is exactly what an MCP tool list looks like.Adding a tool used to require updating two parallel structures in ai.py: a name->handler entry in _TOOL_DISPATCH and a schema dict in _DIR_TOOLS (or _SYNTHESIS_TOOLS or _SURVEY_TOOLS). Forgetting one half was silent. Internals.md §9.1 documented this as a 5-step process. Replaced both with a single register_tool() call per (tool, scope): register_tool( name="read_file", description="...", schema={...}, scopes=["dir"], handler=_tool_read_file, ) The function appends the schema to one or more scope lists (_DIR_TOOLS / _SYNTHESIS_TOOLS / _SURVEY_TOOLS) and lands the handler in _TOOL_DISPATCH. Tools intercepted by the loop body (submit_report, submit_survey) register schema only with handler=None. Tools whose schema differs by scope (submit_report has different shapes in dir vs synthesis loops) get one register_tool() call per scope. flag is also registered twice because it appears in dir + synthesis at different positions in each list — the order is preserved with two calls rather than reordered for fewer calls. Verification: - _DIR_TOOLS, _SYNTHESIS_TOOLS, _SURVEY_TOOLS contain the same names in the same order as before. - _TOOL_DISPATCH contains the same 10 handlers as before. - 164 tests pass. No behavior change. Phase 3.5 (#39) MCP backend will eventually replace this with dynamic discovery from the connected MCP server, at which point register_tool() collapses to a one-line forward.