feat: add official Codex skill and harden task execution

Install and update artemis-use with task diagnostics and plugin guidance. Preserve cross-device file receipts, review canonical reports, guard stage transitions and reduce small history summaries. Improve exploration lifecycle, request recovery and browser live connections.
This commit is contained in:
chenmingxuan committed 2026-10-18 14:18:37 +08:00
1 parent 2328a4df0c
commit e1ea099592
128 files changed
+4944 -700

No files matched your search

+55 -4
View File
@@ -127,23 +127,74 @@ async def test_completed_exploration_plan_does_not_force_an_extra_action(
content="Confirmed home; recorded evidence.",
tool_calls=[{"name": "save_note", "args": {}, "id": "plan"}],
)
invoke = AsyncMock(side_effect=[response, click()])
final = AIMessage(content="# 完整调查报告\n已回主页,证据见步骤 3。未检查其他页面。")
finishing = scenario in {"complete", "unchanged"}
invoke = AsyncMock(side_effect=[response, final if finishing else click()])
monkeypatch.setattr("artemis.agents.operator.operator.acomplete", invoke)
messages = []
result = await node._invoke_llm_loop(
Mock(), messages, [SimpleNamespace(name="save_note")], [], state
)
if scenario == "complete":
if finishing:
assert invoke.await_count == 2
assert result[0] is None
assert final.content in result[1]
assert state.execution_report == final.content
assert any("完整报告正文" in m.content for m in messages if isinstance(m, SystemMessage))
assert result[3] is False
elif scenario == "pending":
assert invoke.await_count == 1
assert result[0] is None
assert result[1] == "Confirmed home; recorded evidence."
assert result[3] is False
assert state.execution_report is None
return
else:
assert invoke.await_count == 2
assert result[0]
assert state.execution_report is None
assert any(isinstance(m, ToolMessage) and m.tool_call_id == "plan" for m in messages)
@pytest.mark.asyncio
async def test_final_report_is_discarded_when_guidance_arrives(operator, monkeypatch):
node, state = operator
state.execution_report = "旧报告"
node.ctx.exploration_id = "exploration"
node._read_task_plan_text = lambda: "- [x] 调查完成"
pending = {"value": False}
monkeypatch.setattr(
"artemis.exploration.runtime.needs_exploration_turn", lambda ctx: pending["value"]
)
publish = Mock()
monkeypatch.setattr("artemis.exploration.runtime.publish_response", publish)
async def answer(*args):
pending["value"] = True
return AIMessage(content="这是过时的最终报告")
monkeypatch.setattr("artemis.agents.operator.operator.acomplete", answer)
result = await node._invoke_llm_loop(Mock(), [], [], [], state)
assert result[0] is None
assert state.execution_report is None
publish.assert_not_called()
@pytest.mark.asyncio
async def test_empty_final_report_uses_bounded_recovery(operator, monkeypatch):
node, state = operator
node.ctx.exploration_id = "exploration"
node._read_task_plan_text = lambda: "- [x] 调查完成"
monkeypatch.setattr("artemis.exploration.runtime.needs_exploration_turn", lambda ctx: False)
monkeypatch.setattr("artemis.exploration.runtime.publish_response", Mock())
monkeypatch.setattr("artemis.agents.operator.operator.get_llm", Mock(return_value=Mock()))
monkeypatch.setattr(settings, "ARTEMIS_TOOL_FALLBACK_MAX_NO_PROGRESS_ATTEMPTS", 2)
invoke = AsyncMock(return_value=AIMessage(content=" "))
monkeypatch.setattr("artemis.agents.operator.operator.acomplete", invoke)
with pytest.raises(OperatorNoProgressError):
await node._invoke_llm_loop(Mock(), [], [], [], state)
assert state.execution_report is None
assert invoke.await_count == 5
@pytest.mark.asyncio
async def test_invalid_target_can_be_corrected_before_limit(operator, monkeypatch):
result, messages, invoke = await run_loop(operator, monkeypatch, [click("14"), click("13")])