refactor: unify agent history and harden runtime diagnostics
Preserve user guidance through history compression, stabilize Flash index targets, and retire withdrawn checks without applying stale verdicts. Improve runtime diagnostics, tool responses, and history rendering. Simplify documentation and comments. Validation: 2076 tests passed in the full suite; 381 affected tests and 26 frontend tests passed after cleanup. Ruff and the quality ratchet passed.
This commit is contained in:
1 parent
e983180b5b
commit
5d92939d91
127 files changed
+13738
-1988
No files matched your search
@@ -255,9 +255,25 @@ async def test_run_command_kill(mock_exec, mock_ctx):
|
||||
"TaskId": task_id,
|
||||
}
|
||||
)
|
||||
assert f"Task {task_id} successfully terminated" in kill_res
|
||||
assert f"Terminated task {task_id}" in kill_res
|
||||
assert "successfully" not in kill_res
|
||||
assert task_id not in registry.background
|
||||
|
||||
# Refusals (unknown or already-finished task) are reported structurally.
|
||||
from artemis.core.tool_failure import is_tool_failure
|
||||
|
||||
again = await manage_task.ainvoke({"Action": "kill", "TaskId": task_id})
|
||||
assert is_tool_failure(again)
|
||||
assert f"Task {task_id} is not active or already finished." in str(again)
|
||||
|
||||
missing = await manage_task.ainvoke({"Action": "status", "TaskId": "task_nope"})
|
||||
assert is_tool_failure(missing)
|
||||
assert "Error: Task task_nope not found." in str(missing)
|
||||
|
||||
no_input = await manage_task.ainvoke({"Action": "send_input", "TaskId": task_id, "Input": "y"})
|
||||
assert is_tool_failure(no_input)
|
||||
assert f"Task {task_id} is not active." in str(no_input)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("asyncio.create_subprocess_exec")
|
||||
@@ -305,8 +321,8 @@ async def test_run_short_command_timeout(mock_exec, mock_ctx):
|
||||
@pytest.mark.asyncio
|
||||
@patch("asyncio.create_subprocess_exec")
|
||||
async def test_run_command_sync_long_output(mock_exec, mock_ctx):
|
||||
# Generate long output (> 500 lines)
|
||||
long_output = "\n".join(f"Output line {i}" for i in range(1, 600))
|
||||
# Generate long output (> 50000 chars): the trigger is size, not line count.
|
||||
long_output = "\n".join(f"Output line {i} {'x' * 90}" for i in range(1, 600))
|
||||
mock_process = MockProcess(
|
||||
output_bytes=long_output.encode() + b"\n===EXIT_CODE===0\n===ENV_START===\n",
|
||||
exit_code=0,
|
||||
@@ -326,9 +342,36 @@ async def test_run_command_sync_long_output(mock_exec, mock_ctx):
|
||||
assert "ADB command completed with exit code 0." in result
|
||||
assert "has been truncated" in result
|
||||
assert "Output line 599" in result
|
||||
assert "Output line 1" not in result # since it was truncated to last 200 lines
|
||||
assert "analyze_task_output" in result
|
||||
assert "Output line 1 " not in result # since it was truncated to last 200 lines
|
||||
assert "TaskId: task_sync_" in result
|
||||
task_id = result.split("TaskId: ")[1].split(".")[0]
|
||||
assert f"use analyze_task_output with TaskId {task_id}" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("asyncio.create_subprocess_exec")
|
||||
async def test_run_command_many_short_lines_is_shown_inline(mock_exec, mock_ctx):
|
||||
"""1000 short lines (~4 KB) are not 'long': the whole output stays inline."""
|
||||
output = "\n".join(str(i) for i in range(1, 1001))
|
||||
mock_exec.return_value = MockProcess(output_bytes=output.encode(), exit_code=0)
|
||||
|
||||
run_command = get_run_adb_command_tool(mock_ctx)
|
||||
result = await run_command.ainvoke({"CommandLine": "seq 1 1000", "WaitMsBeforeAsync": 500})
|
||||
|
||||
assert "has been truncated" not in result
|
||||
assert "\n1\n2\n" in result
|
||||
assert result.endswith("\n1000")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("asyncio.create_subprocess_exec")
|
||||
async def test_run_command_empty_output_is_labelled(mock_exec, mock_ctx):
|
||||
mock_exec.return_value = MockProcess(output_bytes=b"", exit_code=0)
|
||||
|
||||
run_command = get_run_adb_command_tool(mock_ctx)
|
||||
result = await run_command.ainvoke({"CommandLine": "true", "WaitMsBeforeAsync": 500})
|
||||
|
||||
assert result == "ADB command completed with exit code 0.\nOutput:\n(empty output)"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -704,7 +747,7 @@ def test_registry_is_per_context_and_notifications_do_not_leak():
|
||||
@pytest.mark.asyncio
|
||||
@patch("asyncio.create_subprocess_exec")
|
||||
async def test_sync_long_output_is_not_reannounced(mock_exec, mock_ctx):
|
||||
long_output = "\n".join(f"line {i}" for i in range(600))
|
||||
long_output = "\n".join(f"line {i} {'x' * 90}" for i in range(600))
|
||||
mock_exec.return_value = MockProcess(output_bytes=long_output.encode(), exit_code=0)
|
||||
run_command = get_run_adb_command_tool(mock_ctx)
|
||||
registry = get_adb_task_registry(mock_ctx)
|
||||
|
||||
Reference in new issue
Block a user