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:
1 parent
2328a4df0c
commit
e1ea099592
128 files changed
+4944
-700
No files matched your search
@@ -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")])
|
||||
|
||||
Reference in new issue
Block a user