After a deep-research job completes, a follow-up like "check it out" / "read
that report" had the agent web_fetch the /api/research/report/{id} HTML render
(and then drift into unrelated searches) instead of reading the saved report
(issue #1363). The report text is already available via the manage_research
tool (action read), and action list returns ids most-recent-first, so the
agent can resolve "the recent report" itself.
Strengthen the manage_research instructions: read a finished report via
action list -> action read; do NOT web_fetch/app_api the report URL (it renders
HTML, not clean text) and do NOT start a fresh web_search just to read an
existing report. Annotate the app_api endpoint list to say the same.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
68 lines
2.6 KiB
Python
68 lines
2.6 KiB
Python
"""Regression tests for issue #1363 — after a deep-research job finishes, asking
|
|
the agent to "check it out / read that report" had it web_fetch the HTML report
|
|
render (and drift into unrelated searches) instead of reading the saved report.
|
|
|
|
Per the maintainer's diagnosis the fix is in the agent/tool-routing path: a
|
|
finished report should be read via `manage_research` (action read), resolving the
|
|
most-recent id with `action list` when none is given — not by fetching the
|
|
`/api/research/report/{id}` HTML.
|
|
|
|
These tests pin both halves:
|
|
1. the read path the agent is told to use actually returns the report text for a
|
|
saved `rp-...` id, and
|
|
2. the agent instructions steer to `manage_research read` and away from
|
|
web_fetching the HTML report.
|
|
"""
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from src.tool_implementations import do_manage_research
|
|
from src.agent_loop import TOOL_SECTIONS
|
|
|
|
_DATA_DIR = Path("data/deep_research")
|
|
|
|
|
|
@pytest.fixture
|
|
def saved_report():
|
|
_DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
rid = "rp-testreport1363"
|
|
path = _DATA_DIR / f"{rid}.json"
|
|
path.write_text(json.dumps({
|
|
"query": "trending blender video ideas",
|
|
"result": "## Findings\nShort-form Geometry Nodes tutorials are trending.",
|
|
"sources": [{"title": "Example", "url": "https://example.com"}],
|
|
"completed_at": 123,
|
|
}), encoding="utf-8")
|
|
try:
|
|
yield rid
|
|
finally:
|
|
path.unlink(missing_ok=True)
|
|
|
|
|
|
async def test_manage_research_read_returns_report_text(saved_report):
|
|
res = await do_manage_research(json.dumps({"action": "read", "id": saved_report}))
|
|
out = res.get("output", "")
|
|
# The agent must get the actual report body (not HTML, not an error).
|
|
assert "Geometry Nodes tutorials are trending" in out
|
|
assert "trending blender video ideas" in out
|
|
assert res.get("exit_code") == 0
|
|
|
|
|
|
async def test_panel_launched_rp_id_is_valid_for_read(saved_report):
|
|
# rp-* ids (panel-launched research) contain a hyphen; the read path's id
|
|
# guard must accept them, not reject them as invalid.
|
|
res = await do_manage_research(json.dumps({"action": "read", "id": saved_report}))
|
|
assert "error" not in res, res
|
|
|
|
|
|
def test_instructions_route_report_reads_to_manage_research():
|
|
desc = TOOL_SECTIONS["manage_research"]
|
|
# Steers to the read tool for a finished report...
|
|
assert "read that report" in desc.lower() or "that report" in desc.lower()
|
|
assert "action:list" in desc or "action: list" in desc
|
|
# ...and explicitly away from fetching the HTML report endpoint.
|
|
assert "/api/research/report/" in desc
|
|
assert "web_fetch" in desc.lower() or "app_api" in desc.lower()
|