diff --git a/src/agent_loop.py b/src/agent_loop.py index ad0ad00..94bed46 100644 --- a/src/agent_loop.py +++ b/src/agent_loop.py @@ -2001,8 +2001,11 @@ async def stream_agent_loop( ) desc, result = await _tool_task - # Extract structured web sources from web_search tool output - _src_text = result.get("results") or result.get("stdout") or "" + # Extract structured web sources from web_search tool output. + # web_search returns {"output": ..., "exit_code": 0}; check "output" + # first so the marker is found and stripped even + # when the result doesn't carry a "results" or "stdout" key. + _src_text = result.get("output") or result.get("results") or result.get("stdout") or "" if block.tool_type == "web_search" and _src_text: _src_marker = "" + return {key: text, "exit_code": 0} + + # ── Regression: the old lookup missed "output" ────────────────────── + + def test_old_lookup_missed_output_key(self): + """Documents the bug: result.get('results') and result.get('stdout') + are both absent when web_search returns its canonical {"output": ...} + shape, so _src_text was always '' and the if-block never ran.""" + result = self._make_result("output") + old_src_text = result.get("results") or result.get("stdout") or "" + assert old_src_text == "", "confirms the pre-fix behaviour" + + def test_fixed_lookup_finds_output_key(self): + """After the fix, "output" is checked first so _src_text is non-empty.""" + result = self._make_result("output") + src_text = result.get("output") or result.get("results") or result.get("stdout") or "" + assert src_text != "" + assert "SOURCES" in src_text + + # ── Marker extraction works once _src_text is non-empty ───────────── + + def test_sources_extracted_from_output(self): + result = self._make_result("output") + src_text = result.get("output") or result.get("results") or result.get("stdout") or "" + marker = "", idx) + extracted = _json.loads(src_text[idx + len(marker):end]) + assert extracted == self._SOURCES + + def test_marker_stripped_from_output_key(self): + """After extraction the "output" value is cleaned so the LLM never + sees the raw JSON blob in its round-2 context.""" + result = self._make_result("output") + src_text = result.get("output") or result.get("results") or result.get("stdout") or "" + marker = "