feat: add guided exploration and share user-started MCP backend
This commit is contained in:
1 parent
f86db1ced6
commit
ee256ad7ce
144 files changed
+8625
-2075
No files matched your search
@@ -51,6 +51,79 @@ DONE_PLAN_WITH_CHECKS = (
|
||||
DONE_PLAN_NO_CHECKS = "- [x] Create alarm\n"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def exploration_exit(tmp_path, monkeypatch):
|
||||
from apps.admin_console.services.automation_store import AutomationStore
|
||||
from artemis.config.exploration import ExplorationConfig
|
||||
from artemis.exploration.store import ExplorationStore
|
||||
from artemis.runtime import task_control
|
||||
|
||||
repo = ExplorationStore(AutomationStore(tmp_path / "history.db"))
|
||||
session = repo.create("逐步探索,听用户指导", ExplorationConfig(), {}, "create")
|
||||
run = repo.reserve_run(session["id"], "run", kind="exploration", goal="探索", task_config={})
|
||||
repo.set_run_state(run["id"], "running")
|
||||
monkeypatch.setattr("artemis.exploration.runtime.explorations", repo)
|
||||
monkeypatch.setattr("artemis.exploration.store.explorations", repo)
|
||||
monkeypatch.setattr(task_control, "TRACES_PATH", tmp_path)
|
||||
ctx = _make_ctx(tmp_path)
|
||||
ctx.exploration_id = session["id"]
|
||||
ctx.exploration_run_id = run["id"]
|
||||
ctx.exploration_guidance_count = 0
|
||||
ctx.on_execution_review = AsyncMock()
|
||||
ctx.on_execution_resume = AsyncMock()
|
||||
_write_plan(tmp_path, DONE_PLAN_NO_CHECKS)
|
||||
return ctx, repo, session, run
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exploration_question_prevents_completed_plan_from_starting_final_review(
|
||||
exploration_exit,
|
||||
):
|
||||
ctx, repo, session, run = exploration_exit
|
||||
repo.ask(run["id"], "下一步做什么?", "返回主页", "ask")
|
||||
with patch("artemis.graph.graph.run_final_check", new=AsyncMock()) as reviewer:
|
||||
assert convergence_gate(_make_state(), ctx) == "continue"
|
||||
result = await exit_settlement_node(_make_state(), ctx)
|
||||
assert result == {"exit_settlement_route": "continue"}
|
||||
reviewer.assert_not_called()
|
||||
assert repo.get(session["id"])["pending_question"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exploration_late_return_home_guidance_invalidates_final_review(exploration_exit):
|
||||
ctx, repo, session, run = exploration_exit
|
||||
|
||||
async def review(*args, **kwargs):
|
||||
repo.add_message(
|
||||
session["id"], "先回主页,然后结束", "home", metadata={"run_id": run["id"]}
|
||||
)
|
||||
return CheckReport(verdicts=[], unmet_subgoals=[])
|
||||
|
||||
with patch("artemis.graph.graph.run_final_check", new=review):
|
||||
result = await exit_settlement_node(_make_state(), ctx)
|
||||
assert result == {"exit_settlement_route": "continue"}
|
||||
assert repo.run(run["id"])["status"] == "running"
|
||||
assert repo.run(run["id"])["user_guidance_count"] == 1
|
||||
assert not (ctx.data_engine.base_dir / "run_outcome.json").exists()
|
||||
ctx.on_execution_review.assert_awaited_once()
|
||||
ctx.on_execution_resume.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_review_stops_capture_before_waiting_and_seals_exploration(exploration_exit):
|
||||
ctx, repo, session, run = exploration_exit
|
||||
|
||||
async def review(*args, **kwargs):
|
||||
ctx.on_execution_review.assert_awaited_once()
|
||||
return CheckReport(verdicts=[], unmet_subgoals=[])
|
||||
|
||||
with patch("artemis.graph.graph.run_final_check", new=review):
|
||||
result = await exit_settlement_node(_make_state(), ctx)
|
||||
assert result["exit_settlement_route"] == "end"
|
||||
assert repo.get(session["id"])["status"] == "finalizing"
|
||||
ctx.on_execution_resume.assert_not_called()
|
||||
|
||||
|
||||
def _make_ctx(tmp_path, **setup_kwargs):
|
||||
setup_kwargs.setdefault("disable_checker", False)
|
||||
ctx = MagicMock(spec=ArtemisContext)
|
||||
|
||||
Reference in new issue
Block a user