fix: keyword routing fallback — never return zero tools

Previously narrow_tools_by_keywords returned [] when no category matched,
silently disabling all tools for messages that didn't hit a keyword.

Now:
- Falls back to _FALLBACK_TOOLS (web_search, session_search, session_read,
  scratch_read) when no category matches — tools always available for casual use
- Detects explicit "use your tools / look that up / can you check" phrases
  and returns the full role tool list (None = all permitted)
- Return type updated to list[str] | None; orchestrator log handles both

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-06-16 21:40:17 -04:00
parent 6ca588959d
commit 3eb3ce1146
2 changed files with 37 additions and 15 deletions

View File

@@ -77,12 +77,11 @@ async def run(
effective_confirm = (CONFIRM_REQUIRED - set(_confirm_allow)) | set(_confirm_deny)
# Keyword routing: narrow schemas to only what this message needs.
# Also scans the last assistant turn so follow-ups like "yes, do that" inherit tool context.
# Returns [] when no keywords match (zero tool overhead — model responds as plain chat).
# Returns None on explicit tool request (full role list), fallback set when no keywords match.
effective_tool_list = narrow_tools_by_keywords(task, tool_list, context_messages=session_messages)
logger.info(
"Keyword routing: %d tools active (role_tools=%s)",
len(effective_tool_list),
"Keyword routing: %s tools active (role_tools=%s)",
len(effective_tool_list) if effective_tool_list is not None else "all",
len(tool_list) if tool_list is not None else "all",
)