From 0aa470b0959e4c8d796d1010532d9ac7591a741d Mon Sep 17 00:00:00 2001 From: pewdiepie-archdaemon Date: Thu, 17 Sep 2026 13:34:36 +0000 Subject: [PATCH] recover synthesis after unavailable web search --- src/agent_loop.py | 34 ++++++++++++++++++++++++++++++++ tests/test_tool_routing_audit.py | 29 ++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/agent_loop.py b/src/agent_loop.py index 4c29f5423..ccf664c9e 100644 --- a/src/agent_loop.py +++ b/src/agent_loop.py @@ -18111,6 +18111,22 @@ def _tool_routing_audit_payload( } +def _unoffered_web_search_should_synthesize( + requested_not_accepted: Sequence[str], + *, + accepted_tools: Sequence[str], + tool_events: Sequence[dict[str, Any]], +) -> bool: + """Recover an unavailable search request after usable evidence exists.""" + if accepted_tools or "web_search" not in set(requested_not_accepted or ()): + return False + return any( + _resolved_tool_event_name(event) in {"web_fetch", "private_browser"} + and tool_result_is_successful(event) + for event in (tool_events or ()) + ) + + def _web_search_safety_touch_hygiene_postprocess(user_text: str, answer: str) -> str: """Keep safety-touch web answers practical instead of just descriptive.""" text = str(answer or "").strip() @@ -26651,6 +26667,24 @@ async def stream_agent_loop( _resolution_audit["requested_not_accepted"] ) yield f'data: {json.dumps(_resolution_audit)}\n\n' + if _unoffered_web_search_should_synthesize( + _resolution_audit["requested_not_accepted"], + accepted_tools=_accepted_tool_names, + tool_events=tool_events, + ): + _force_answer = True + messages.append({ + "role": "system", + "content": ( + "Web search is not available in this round, but authoritative " + "source evidence has already been retrieved. Stop using tools and " + "answer the user's complete request from that evidence now. Cover " + "every requested fact, comparison, and caveat, and cite the source " + "URLs present in the retrieved evidence." + ), + }) + yield f'data: {json.dumps({"type": "agent_step", "round": round_num + 1})}\n\n' + continue _malformed_write_missing = ( tuple( EvidenceLedger.from_tool_events( diff --git a/tests/test_tool_routing_audit.py b/tests/test_tool_routing_audit.py index 3a2d829d7..32154995c 100644 --- a/tests/test_tool_routing_audit.py +++ b/tests/test_tool_routing_audit.py @@ -1,4 +1,7 @@ -from src.agent_loop import _tool_routing_audit_payload +from src.agent_loop import ( + _tool_routing_audit_payload, + _unoffered_web_search_should_synthesize, +) def test_tool_routing_audit_preserves_each_stage_and_gap(): @@ -112,3 +115,27 @@ def test_local_media_artifact_compaction_identifies_web_as_intentional_exclusion assert {"web_search", "web_fetch"} <= set( payload["intentionally_excluded_tools"] ) + + +def test_unoffered_search_after_successful_fetch_requires_synthesis(): + fetched = [{ + "tool": "web_fetch", + "exit_code": 0, + "output": "Authoritative evidence", + }] + + assert _unoffered_web_search_should_synthesize( + ["web_search"], + accepted_tools=[], + tool_events=fetched, + ) + assert not _unoffered_web_search_should_synthesize( + ["web_search"], + accepted_tools=["web_fetch"], + tool_events=fetched, + ) + assert not _unoffered_web_search_should_synthesize( + ["web_search"], + accepted_tools=[], + tool_events=[{"tool": "web_fetch", "exit_code": 1, "output": "failed"}], + )