From 74f47097c2d456f6937b4a5d388efadd059d0756 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Mon, 15 Dec 2025 22:51:18 +0100 Subject: [PATCH] fix: complete web search integration with query enrichment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes several issues with the web search migration to Librarian: - Update Steward routing guidelines for web search/weather → Librarian - Register search_web, read_url, read_urls_batch tools with Librarian agent - Update Librarian system prompt with web search documentation - Fix query enrichment not being passed to delegations (location context) - Add URL reading keywords to RESEARCH action type detection Weather queries now automatically include user's stored location from the Biographer, enabling location-aware search results. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 23 +++++++++++++++++++++++ pyproject.toml | 2 +- src/agents/delegation.py | 3 +++ src/agents/librarian/agent.py | 25 +++++++++++++++++++++---- src/agents/steward/agent.py | 7 +++++-- src/responses/service.py | 7 +++++-- 6 files changed, 58 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb7736b..e3ba3aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.8.0] - 2025-12-15 + +### Fixed + +#### Steward Routing for Web Search +- Updated Steward guidelines to route web searches, weather, news → Librarian with `search_web` +- Added URL/article reading → Librarian with `read_url` to routing guidelines +- Added examples showing `search_web` and `read_url` tool usage + +#### Librarian Agent Tool Registration +- Registered `search_web`, `read_url`, `read_urls_batch` tools with the Librarian PydanticAI agent +- Updated Librarian system prompt with Web Search & Content Extraction section +- Fixed tool count in agent logger (11 → 14 tools) + +#### Query Enrichment Integration +- Fixed enriched query (with location/timezone context) not being passed to delegations +- Response service now uses `enriched_query` from Steward recommendation for all delegations +- Weather queries now automatically include user's stored location + +#### Action Type Detection +- Added "read", "fetch", "url", "http" keywords to RESEARCH action type for Librarian +- Ensures proper think messages for URL reading tasks + ## [1.7.0] - 2025-12-15 ### Added diff --git a/pyproject.toml b/pyproject.toml index e9772db..9528fc2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "tatlock" -version = "1.7.0" +version = "1.8.0" description = "OpenAI-compatible API with Ollama backend" requires-python = ">=3.12" dependencies = [] diff --git a/src/agents/delegation.py b/src/agents/delegation.py index cb11720..0db89e4 100644 --- a/src/agents/delegation.py +++ b/src/agents/delegation.py @@ -100,10 +100,13 @@ def _detect_action_type(expert: str, task: str) -> ActionType: task_lower = task.lower() if expert == "librarian": + # Web search, URL reading = RESEARCH (fresh external data) if any(w in task_lower for w in ["search", "find", "look up", "research"]): if any(w in task_lower for w in ["web", "online", "internet"]): return ActionType.RESEARCH return ActionType.RETRIEVE + if any(w in task_lower for w in ["read", "fetch", "url", "http"]): + return ActionType.RESEARCH # Reading URLs is research if any(w in task_lower for w in ["create", "write", "add", "make", "new"]): return ActionType.CREATE return ActionType.RETRIEVE diff --git a/src/agents/librarian/agent.py b/src/agents/librarian/agent.py index 91ce17f..8293e23 100644 --- a/src/agents/librarian/agent.py +++ b/src/agents/librarian/agent.py @@ -19,6 +19,9 @@ from src.agents.librarian.tools import ( get_wiki_page, hybrid_search, list_dossiers, + read_url, + read_urls_batch, + search_web, search_wiki, semantic_search, smart_create_wiki_page, @@ -47,8 +50,17 @@ Your role is to help users find, understand, synthesize, and manage information ## Your Tools -### Research Tools -- **hybrid_search**: Your primary research tool - searches all sources at once +### Web Search & Content Extraction +- **search_web**: Search the internet for current information (weather, news, facts) + - Use for: weather forecasts, current events, recent developments, external facts + - Returns extracted content from search results, not just snippets +- **read_url**: Read and extract content from a specific URL + - Use when: user provides a URL or you need to read a specific webpage +- **read_urls_batch**: Read multiple URLs in parallel (up to 20) + - Use for: comparing multiple sources, gathering info from several pages + +### Internal Research Tools +- **hybrid_search**: Your primary research tool - searches wiki, graph, and web at once - **search_wiki**: Find specific wiki pages by keyword - **semantic_search**: Find conceptually similar content - **explore_knowledge_graph** / **find_related_entities**: Discover connections @@ -130,7 +142,7 @@ def _create_librarian_agent() -> Agent[None, str]: retries=2, ) - # Register research tools + # Register research tools (internal knowledge) agent.tool_plain(hybrid_search) agent.tool_plain(search_wiki) agent.tool_plain(semantic_search) @@ -139,6 +151,11 @@ def _create_librarian_agent() -> Agent[None, str]: agent.tool_plain(explore_knowledge_graph) agent.tool_plain(find_related_entities) + # Register web search & content extraction tools + agent.tool_plain(search_web) + agent.tool_plain(read_url) + agent.tool_plain(read_urls_batch) + # Register wiki read tools agent.tool_plain(get_wiki_page) @@ -150,7 +167,7 @@ def _create_librarian_agent() -> Agent[None, str]: logger.info( "librarian_agent_created", model=config.OLLAMA_DEFAULT_MODEL, - tool_count=11, + tool_count=14, # 7 research + 3 web + 1 wiki read + 3 wiki write ) return agent diff --git a/src/agents/steward/agent.py b/src/agents/steward/agent.py index 10e3748..0d28baf 100644 --- a/src/agents/steward/agent.py +++ b/src/agents/steward/agent.py @@ -58,8 +58,9 @@ GUIDELINES: - Simple greetings/chat → no capabilities needed (conversational response only) - Questions about prior conversation ("what did I say", "my name", "what we discussed") → no capabilities (Tatlock has full history) - Math/calculations → tatlock_core -- Quick web searches → tatlock_core - Time/date queries → tatlock_core +- Web searches, weather, news, current information → librarian with search_web +- Read a URL or article → librarian with read_url - Wiki creation ("create a page about X", "add X to wiki") → librarian with smart_create - Wiki updates ("update the page", "add to dossier") → librarian with update - Research queries ("find info", "what do we know about", "search for") → librarian with hybrid_search @@ -74,8 +75,10 @@ COMPLEXITY: [simple/moderate/complex] CONTEXT: [any relevant conversation context, or "none"] EXAMPLES: +- "DELEGATE: librarian to search_web for tomorrow's weather forecast" - "DELEGATE: librarian to create a wiki page about CI/CD pipelines" -- "DELEGATE: librarian to search for information about Docker networking" +- "DELEGATE: librarian to hybrid_search for information about Docker networking" +- "DELEGATE: librarian to read_url https://example.com/article" - "DELEGATE: tatlock_core to calculate the result" - "DELEGATE: none (conversational response only)" diff --git a/src/responses/service.py b/src/responses/service.py index bc8eea0..b73878f 100644 --- a/src/responses/service.py +++ b/src/responses/service.py @@ -515,15 +515,18 @@ async def create_response_with_steward(request: ResponseRequest) -> Response: from src.agents.tatlock import TatlockAgent tatlock = TatlockAgent() + # Use enriched query (with location/timezone context) if available + effective_query = enriched.recommendation.enriched_query or user_message + if delegation_only: # Direct delegation path - collect results then synthesize orchestration_results = await _direct_delegation_with_results( - user_message, enriched.recommendation, tracker, conversation_id + effective_query, enriched.recommendation, tracker, conversation_id ) else: # Phase 1: Orchestrate tool calls orchestration_results = await tatlock.orchestrate_tool_calls( - user_message=user_message, + user_message=effective_query, steward_note=enriched.steward_note, scoped_tools=enriched.scoped_tools, message_history=conversation_history,