feat: release 2.2.0 with PC-only tests and execution reliability fixes
Unify task scheduling and queue state, fix Android input and observation recovery, preserve screenshot paths, and match final review criteria accurately. Add collapsible copyable results and publish the complete 2.1.0 upgrade notes. Validation: 3189 backend tests, 326 frontend tests, 24 client tests, production build and quality gates.
This commit is contained in:
1 parent
fac4ccb760
commit
be6e8c2abd
79 files changed
+2263
-277
No files matched your search
@@ -135,7 +135,12 @@ async def test_completed_exploration_plan_does_not_force_an_extra_action(
|
||||
result = await node._invoke_llm_loop(
|
||||
Mock(), messages, [SimpleNamespace(name="save_note")], [], state
|
||||
)
|
||||
if finishing:
|
||||
if scenario == "pro":
|
||||
assert invoke.await_count == 1
|
||||
assert result[0] is None
|
||||
assert state.execution_report is None
|
||||
assert result[3] is False
|
||||
elif finishing:
|
||||
assert invoke.await_count == 2
|
||||
assert result[0] is None
|
||||
assert final.content in result[1]
|
||||
@@ -154,6 +159,112 @@ async def test_completed_exploration_plan_does_not_force_an_extra_action(
|
||||
assert any(isinstance(m, ToolMessage) and m.tool_call_id == "plan" for m in messages)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
("plan", "released", "finishes"),
|
||||
[
|
||||
("- [x] Inspect page", False, True),
|
||||
("- [ ] Inspect page", False, False),
|
||||
("- [!] Inspect page", False, False),
|
||||
("- [x] Inspect page\n - [ ] Check input", False, False),
|
||||
("- [x] Inspect page\n - [/] Check input", False, False),
|
||||
("- [x] [Loop:continuous] Inspect page", False, False),
|
||||
("- [x] [Loop:continuous] Inspect page", True, True),
|
||||
("", False, False),
|
||||
],
|
||||
)
|
||||
async def test_pro_completion_does_not_request_a_synthetic_action(
|
||||
operator, monkeypatch, plan, released, finishes
|
||||
):
|
||||
node, state = operator
|
||||
node._read_task_plan_text = lambda: plan
|
||||
state.user_stop_requested = released
|
||||
result, messages, invoke = await run_loop(operator, monkeypatch, [click()])
|
||||
assert invoke.await_count == (0 if finishes else 1)
|
||||
assert bool(result[0]) is not finishes
|
||||
assert state.execution_report is None
|
||||
assert result[3] is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pro_completion_on_last_tool_iteration_still_reaches_final_review(
|
||||
operator, monkeypatch, tmp_path
|
||||
):
|
||||
from artemis.context import ExecutionSetup
|
||||
from artemis.graph.graph import convergence_gate
|
||||
from artemis.utils.notes import get_note_file_path
|
||||
|
||||
node, state = operator
|
||||
node.ctx.data_engine = Mock(base_dir=str(tmp_path))
|
||||
node.ctx.execution_setup = ExecutionSetup(disable_checker=False)
|
||||
path = get_note_file_path(tmp_path, "task_plan")
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text("- [/] Inspect page\n- assert@end: Input is empty", encoding="utf-8")
|
||||
|
||||
async def save_note(**kwargs):
|
||||
path.write_text("- [x] Inspect page\n- assert@end: Input is empty", encoding="utf-8")
|
||||
return ToolMessage(content="Saved plan", tool_call_id="plan")
|
||||
|
||||
monkeypatch.setattr("artemis.agents.operator.operator.OPERATOR_MAX_TOOL_ITERATIONS", 1)
|
||||
monkeypatch.setattr("artemis.agents.operator.operator.invoke_tool_with_injection", save_note)
|
||||
invoke = AsyncMock(
|
||||
return_value=AIMessage(
|
||||
content="Input is empty; recording completion.",
|
||||
tool_calls=[{"name": "save_note", "args": {}, "id": "plan"}],
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr("artemis.agents.operator.operator.acomplete", invoke)
|
||||
result = await node._invoke_llm_loop(Mock(), [], [SimpleNamespace(name="save_note")], [], state)
|
||||
assert result[0] is None
|
||||
assert result[3] is False
|
||||
assert invoke.await_count == 1
|
||||
assert convergence_gate(state, node.ctx) == "exit_settlement"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("feedback_field", ["injected_instruction", "operator_feedback"])
|
||||
async def test_completed_pro_plan_still_processes_new_feedback(
|
||||
operator, monkeypatch, feedback_field
|
||||
):
|
||||
node, state = operator
|
||||
node.ctx.data_engine = None
|
||||
node._read_task_plan_text = lambda: "- [x] Inspect page"
|
||||
setattr(state, feedback_field, "Review the saved evidence before finishing.")
|
||||
monkeypatch.setattr(
|
||||
"artemis.agents.operator.operator.invoke_tool_with_injection",
|
||||
AsyncMock(return_value=ToolMessage(content="Saved evidence", tool_call_id="read")),
|
||||
)
|
||||
invoke = AsyncMock(
|
||||
side_effect=[
|
||||
AIMessage(
|
||||
content="Reading evidence.",
|
||||
tool_calls=[
|
||||
{"name": "read_note", "args": {"key": "evidence"}, "id": "read"},
|
||||
],
|
||||
),
|
||||
AIMessage(content="Reviewed the evidence; input is empty."),
|
||||
]
|
||||
)
|
||||
monkeypatch.setattr("artemis.agents.operator.operator.acomplete", invoke)
|
||||
messages = []
|
||||
result = await node._invoke_llm_loop(
|
||||
Mock(), messages, [SimpleNamespace(name="read_note")], [], state
|
||||
)
|
||||
assert invoke.await_count == 2
|
||||
assert result[0] is None
|
||||
assert result[3] is False
|
||||
assert messages[-1].content == "Reviewed the evidence; input is empty."
|
||||
|
||||
|
||||
def test_pro_completion_does_not_bypass_pending_guidance(operator, monkeypatch, tmp_path):
|
||||
node, state = operator
|
||||
node._read_task_plan_text = lambda: "- [x] Inspect page"
|
||||
monkeypatch.setattr(task_control, "TRACES_PATH", tmp_path)
|
||||
node.ctx.task_control = task_control.TaskControl("pro-guidance", Mock())
|
||||
task_control.add_instruction("pro-guidance", "Inspect another input first.")
|
||||
assert not node._pro_ready_for_settlement(state)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_final_report_is_discarded_when_guidance_arrives(operator, monkeypatch):
|
||||
node, state = operator
|
||||
|
||||
Reference in new issue
Block a user