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
+53
-1
@@ -245,6 +245,22 @@ async def execution_check_node(state: State, ctx: ArtemisContext):
|
||||
|
||||
|
||||
async def exit_settlement_node(state: State, ctx: ArtemisContext):
|
||||
from artemis.exploration.runtime import needs_exploration_turn
|
||||
|
||||
if needs_exploration_turn(ctx):
|
||||
return {"exit_settlement_route": "continue"}
|
||||
stop_capture = getattr(ctx, "on_execution_review", None)
|
||||
if stop_capture:
|
||||
await stop_capture()
|
||||
update = await _exit_settlement_node(state, ctx)
|
||||
if update.get("exit_settlement_route") == "continue":
|
||||
resume_capture = getattr(ctx, "on_execution_resume", None)
|
||||
if resume_capture:
|
||||
await resume_capture()
|
||||
return update
|
||||
|
||||
|
||||
async def _exit_settlement_node(state: State, ctx: ArtemisContext):
|
||||
"""Two-phase exit: settlement (unconditional) then final review (gated).
|
||||
|
||||
Phase 1 — settlement barrier: the only intentional blocking wait in the
|
||||
@@ -262,6 +278,8 @@ async def exit_settlement_node(state: State, ctx: ArtemisContext):
|
||||
if not ctx.data_engine:
|
||||
return update
|
||||
|
||||
from artemis.exploration.runtime import needs_exploration_turn
|
||||
|
||||
# Phase 1: settle every outstanding attempt (bounded by settlement_timeout).
|
||||
await settle_all_checkpoints(ctx, state)
|
||||
# Queued-but-never-spawned checkpoints are dropped here: their items simply
|
||||
@@ -310,7 +328,7 @@ async def exit_settlement_node(state: State, ctx: ArtemisContext):
|
||||
)
|
||||
|
||||
try:
|
||||
report = await asyncio.wait_for(
|
||||
review = asyncio.wait_for(
|
||||
run_final_check(
|
||||
ctx,
|
||||
goal=getattr(state, "initial_goal", ""),
|
||||
@@ -321,6 +339,21 @@ async def exit_settlement_node(state: State, ctx: ArtemisContext):
|
||||
),
|
||||
timeout=checkpoint_timeout,
|
||||
)
|
||||
control = getattr(ctx, "task_control", None)
|
||||
if getattr(ctx, "exploration_id", None) and control:
|
||||
interrupted, report = await control.run_interruptibly(
|
||||
review,
|
||||
on_pause=getattr(ctx, "on_task_pause", None),
|
||||
on_resume=getattr(ctx, "on_task_resume", None),
|
||||
)
|
||||
if interrupted or needs_exploration_turn(ctx):
|
||||
ctx.final_check_attempts -= 1
|
||||
return {"exit_settlement_route": "continue"}
|
||||
else:
|
||||
report = await review
|
||||
if needs_exploration_turn(ctx):
|
||||
ctx.final_check_attempts -= 1
|
||||
return {"exit_settlement_route": "continue"}
|
||||
case_result = report.test_result
|
||||
except Exception as e:
|
||||
# Fail-open: release, but the verdict value stays inconclusive.
|
||||
@@ -447,6 +480,16 @@ async def exit_settlement_node(state: State, ctx: ArtemisContext):
|
||||
route="end",
|
||||
)
|
||||
|
||||
# A newly accepted instruction invalidates this review, even if it arrived
|
||||
# after the model returned. Never let editorial work consume device guidance.
|
||||
if getattr(ctx, "exploration_id", None):
|
||||
from artemis.exploration.store import explorations
|
||||
|
||||
if needs_exploration_turn(ctx) or not explorations.seal_execution(
|
||||
ctx.exploration_run_id, getattr(ctx, "exploration_guidance_count", 0)
|
||||
):
|
||||
return {"exit_settlement_route": "continue"}
|
||||
|
||||
# END path: assemble the machine-readable run outcome.
|
||||
records = read_ledger(base_dir)
|
||||
retired = getattr(ctx, "guidance_retired_checks", None)
|
||||
@@ -913,6 +956,11 @@ def convergence_gate(
|
||||
) -> Literal["continue", "exit_settlement", "end"]:
|
||||
logger.info("Starting convergence_gate")
|
||||
|
||||
from artemis.exploration.runtime import needs_exploration_turn
|
||||
|
||||
if needs_exploration_turn(ctx):
|
||||
return "continue"
|
||||
|
||||
if not ctx.data_engine:
|
||||
return "end"
|
||||
|
||||
@@ -997,6 +1045,10 @@ async def get_graph(ctx: ArtemisContext) -> CompiledStateGraph:
|
||||
]
|
||||
|
||||
native_tools = get_tools_from_wrappers(ctx, native_wrappers)
|
||||
if getattr(ctx, "exploration_id", None):
|
||||
from artemis.exploration.runtime import question_tool, history_tool
|
||||
|
||||
native_tools.extend([question_tool(ctx), history_tool(ctx)])
|
||||
|
||||
## Define nodes
|
||||
graph_builder.add_node("planner", PlannerNode(ctx, tools=native_tools))
|
||||
|
||||
Reference in new issue
Block a user