diff --git a/services/search/providers.py b/services/search/providers.py index 4a2a9bd1b..32bec41ce 100644 --- a/services/search/providers.py +++ b/services/search/providers.py @@ -149,7 +149,10 @@ def _safesearch_for(provider: str) -> Optional[str]: # ── SearXNG ── -_NEWS_HINTS = ("news", "nyheter", "headlines", "breaking", "latest", "today", "idag") +_NEWS_HINTS = ( + "news", "nyheter", "headlines", "breaking", "latest", "today", "idag", + "current events", "what's happening", "what is happening", +) _NEWS_EVENT_HINT_RE = re.compile( r"\b(?:deport(?:ation|ed|ing)?|arrest(?:ed|s)?|election(?:s)?|" r"evacuat(?:e|ed|ion)|flood(?:ing|s|ed)?|sanction(?:s|ed)?)\b", diff --git a/src/agent_tools/web_tools.py b/src/agent_tools/web_tools.py index 0975f149d..7c191d07c 100644 --- a/src/agent_tools/web_tools.py +++ b/src/agent_tools/web_tools.py @@ -232,7 +232,10 @@ class WebSearchTool: query = raw.split("\n")[0].strip() if time_filter is None: q_lc = query.lower() - if any(kw in q_lc for kw in ("today", "latest", "breaking", "this morning", "right now", "currently")): + if any(kw in q_lc for kw in ( + "today", "latest", "breaking", "this morning", "right now", + "currently", "current events", "what's happening", "what is happening", + )): time_filter = "day" elif any(kw in q_lc for kw in ("this week", "past week", "recent news", "last few days")): time_filter = "week" diff --git a/src/clean_agent_preview.py b/src/clean_agent_preview.py index 8ef6ead64..b40aa61a0 100644 --- a/src/clean_agent_preview.py +++ b/src/clean_agent_preview.py @@ -4447,9 +4447,10 @@ async def stream_preview(*, endpoint_url, model, messages, headers, turn_contrac ) if tool_type == 'web_search': web_search_attempts += 1 - if web_search_attempts > 4: + if not native_workspace_enabled and web_search_attempts > 4: suppressed_tool_until_round['web_search'] = round_limit + 1 force_no_tools_next_round = True + terminal_budget_violation = True calls += 1 raise ValueError( 'The bounded search-attempt budget is exhausted. Do not search ' diff --git a/tests/test_service_search_provider_guards.py b/tests/test_service_search_provider_guards.py index ebff7a475..fd9576220 100644 --- a/tests/test_service_search_provider_guards.py +++ b/tests/test_service_search_provider_guards.py @@ -21,7 +21,9 @@ def test_valid_configured_fallback_is_preserved(monkeypatch): monkeypatch.setattr(core, "_get_search_settings", lambda: {"search_fallback_chain": ["google_pse"]}) monkeypatch.setattr(providers, "_get_search_settings", lambda: {"google_pse_cx": "test-cx"}) monkeypatch.setattr(providers, "_get_provider_key", lambda name: "test-key") - assert core._build_provider_chain("searxng") == ["searxng", "google_pse"] + assert core._build_provider_chain("searxng") == [ + "searxng", "searxng_yep", "google_pse", + ] def test_service_safesearch_values_match_provider_contract(monkeypatch): diff --git a/tests/test_web_search_metadata_mode.py b/tests/test_web_search_metadata_mode.py index c99b9f4fa..e5b36b05a 100644 --- a/tests/test_web_search_metadata_mode.py +++ b/tests/test_web_search_metadata_mode.py @@ -20,6 +20,24 @@ def test_search_reports_evidence_availability_independently_of_execution(monkeyp assert result['evidence_status'] == status +@pytest.mark.parametrize('query', [ + 'Norway current events', + "What's happening in Norway", +]) +def test_current_event_phrasing_uses_recent_search_mode(monkeypatch, query): + seen = {} + + def search_call(*args, **kwargs): + seen.update(kwargs) + return 'Current reporting.', [{'title': 'Report', 'url': 'https://example.org/news'}] + + monkeypatch.setattr(search, 'comprehensive_web_search', search_call) + result = asyncio.run(WebSearchTool().execute(json.dumps({'query': query}), {})) + + assert result['evidence_status'] == 'available' + assert seen['time_filter'] == 'day' + + def test_scholarly_metadata_intent_accepts_title_only_queries(): assert _is_scholarly_metadata_query(