fix: retain last non-empty result set in search polling loop
DSM sends files=[] on the final finished=True poll even when results exist in earlier rounds. Overwriting files each iteration discarded the real results, producing a false "No files found" response. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -287,7 +287,9 @@ def register_filestation(
|
|||||||
)
|
)
|
||||||
return f"Error: {e}"
|
return f"Error: {e}"
|
||||||
|
|
||||||
files = poll_data.get("files", [])
|
current_files: list[dict] = poll_data.get("files", [])
|
||||||
|
if current_files:
|
||||||
|
files = current_files # keep the last non-empty result set
|
||||||
finished: bool = poll_data.get("finished", False)
|
finished: bool = poll_data.get("finished", False)
|
||||||
|
|
||||||
if finished:
|
if finished:
|
||||||
|
|||||||
@@ -502,6 +502,41 @@ async def test_search_polls_until_finished(config: AppConfig) -> None:
|
|||||||
assert "1 match(es) found" in result
|
assert "1 match(es) found" in result
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_search_empty_final_poll(config: AppConfig) -> None:
|
||||||
|
"""search returns results from an earlier poll when the final finished=True poll is empty.
|
||||||
|
|
||||||
|
DSM can return files=[]] on the finishing poll even when results exist — the tool
|
||||||
|
must retain the last non-empty result set rather than overwriting with [].
|
||||||
|
"""
|
||||||
|
client = MagicMock()
|
||||||
|
poll_calls = 0
|
||||||
|
|
||||||
|
async def _request(api, method, **kwargs):
|
||||||
|
nonlocal poll_calls
|
||||||
|
if method == "start":
|
||||||
|
return {"taskid": "t_empty_final"}
|
||||||
|
if method == "list":
|
||||||
|
poll_calls += 1
|
||||||
|
if poll_calls == 1:
|
||||||
|
# First poll: results available, not yet finished
|
||||||
|
return {"files": [_SEARCH_FILE], "finished": False, "total": 1}
|
||||||
|
# Second poll: finished, but DSM returns empty files
|
||||||
|
return {"files": [], "finished": True, "total": 1}
|
||||||
|
return {}
|
||||||
|
|
||||||
|
client.request = AsyncMock(side_effect=_request)
|
||||||
|
|
||||||
|
tools = _make_mcp_and_tools(config, client)
|
||||||
|
|
||||||
|
with patch("asyncio.sleep", new_callable=AsyncMock):
|
||||||
|
result = await tools["search"](path="/docker", pattern="*.yaml")
|
||||||
|
|
||||||
|
# Must surface the result from the first poll, not treat the empty final as "no results"
|
||||||
|
assert "1 match(es) found" in result
|
||||||
|
assert "/docker/app/compose.yaml" in result
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_search_no_results(config: AppConfig) -> None:
|
async def test_search_no_results(config: AppConfig) -> None:
|
||||||
"""search returns a friendly message when no files are found."""
|
"""search returns a friendly message when no files are found."""
|
||||||
|
|||||||
Reference in New Issue
Block a user