Добавить подсказки следующего шага stage-loop
This commit is contained in:
parent
a3378a3d52
commit
37d33bd6e6
|
|
@ -139,6 +139,8 @@ It stores the GUI review under `artifacts/domain_runs/stage_agent_loops/<stage_i
|
||||||
- `continue_repair_from_gui_review_p1` when the run is semantically usable but still noisy, over-broad, or poorly layered;
|
- `continue_repair_from_gui_review_p1` when the run is semantically usable but still noisy, over-broad, or poorly layered;
|
||||||
- `manual_gui_confirmation_or_stage_close` when the GUI run is clean enough for final human confirmation.
|
- `manual_gui_confirmation_or_stage_close` when the GUI run is clean enough for final human confirmation.
|
||||||
|
|
||||||
|
`stage_loop_summary.json` also includes `next_step_guidance.command_templates`, so the next operator or agent pass can continue from machine-readable commands instead of re-inferring the workflow from prose.
|
||||||
|
|
||||||
It also writes `stage_repair_handoff.md/json` next to the stage summary. That handoff is the preferred input for the next coder pass: it lists primary repair targets and sample user-facing failures without forcing the coder to reread the entire GUI conversation first.
|
It also writes `stage_repair_handoff.md/json` next to the stage summary. That handoff is the preferred input for the next coder pass: it lists primary repair targets and sample user-facing failures without forcing the coder to reread the entire GUI conversation first.
|
||||||
|
|
||||||
To prepare the next repair iteration from that handoff, run:
|
To prepare the next repair iteration from that handoff, run:
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ def build_stage_summary(stage_manifest: dict[str, Any], loop_dir: Path) -> dict[
|
||||||
next_action = "user_decision_required"
|
next_action = "user_decision_required"
|
||||||
else:
|
else:
|
||||||
next_action = "continue_autonomous_or_fix_blocker"
|
next_action = "continue_autonomous_or_fix_blocker"
|
||||||
return {
|
summary = {
|
||||||
"schema_version": STAGE_SUMMARY_SCHEMA_VERSION,
|
"schema_version": STAGE_SUMMARY_SCHEMA_VERSION,
|
||||||
"stage_id": stage_manifest["stage_id"],
|
"stage_id": stage_manifest["stage_id"],
|
||||||
"module_name": stage_manifest.get("module_name"),
|
"module_name": stage_manifest.get("module_name"),
|
||||||
|
|
@ -230,6 +230,60 @@ def build_stage_summary(stage_manifest: dict[str, Any], loop_dir: Path) -> dict[
|
||||||
"save_autorun_on_accept": bool(stage_manifest.get("save_autorun_on_accept", True)),
|
"save_autorun_on_accept": bool(stage_manifest.get("save_autorun_on_accept", True)),
|
||||||
"updated_at": now_iso(),
|
"updated_at": now_iso(),
|
||||||
}
|
}
|
||||||
|
summary["next_step_guidance"] = build_next_step_guidance(next_action)
|
||||||
|
return summary
|
||||||
|
|
||||||
|
|
||||||
|
def build_next_step_guidance(next_action: str) -> dict[str, Any]:
|
||||||
|
command_by_action: dict[str, list[str]] = {
|
||||||
|
"continue_repair_from_gui_review_p0": [
|
||||||
|
"python scripts/stage_agent_loop.py prepare-repair --manifest <stage_manifest.json>",
|
||||||
|
"python scripts/stage_agent_loop.py run-repair --manifest <stage_manifest.json> --dry-run",
|
||||||
|
],
|
||||||
|
"continue_repair_from_gui_review_p1": [
|
||||||
|
"python scripts/stage_agent_loop.py prepare-repair --manifest <stage_manifest.json>",
|
||||||
|
"python scripts/stage_agent_loop.py run-repair --manifest <stage_manifest.json> --dry-run",
|
||||||
|
],
|
||||||
|
"execute_repair_without_dry_run_or_review_command": [
|
||||||
|
"python scripts/stage_agent_loop.py run-repair --manifest <stage_manifest.json>",
|
||||||
|
],
|
||||||
|
"rerun_same_stage_or_gui_and_ingest_result": [
|
||||||
|
"rerun the same GUI/session or stage semantic pack",
|
||||||
|
"python scripts/stage_agent_loop.py ingest-gui-run --manifest <stage_manifest.json> --run-id assistant-stage1-<new_id>",
|
||||||
|
],
|
||||||
|
"rerun_or_inspect_repair_targets": [
|
||||||
|
"inspect repair_execution_summary.json and repair_targets.json",
|
||||||
|
"rerun the same GUI/session if the patch intentionally made no code changes",
|
||||||
|
],
|
||||||
|
"user_or_architecture_decision_required": [
|
||||||
|
"inspect repair_coder_result.json and decide whether to change scope, architecture, or acceptance bounds",
|
||||||
|
],
|
||||||
|
"inspect_repair_execution_result": [
|
||||||
|
"inspect repair_execution_summary.json before continuing",
|
||||||
|
],
|
||||||
|
"manual_gui_confirmation": [
|
||||||
|
"run or review the saved AGENT autorun in the GUI for final human confirmation",
|
||||||
|
],
|
||||||
|
"manual_gui_confirmation_or_stage_close": [
|
||||||
|
"review the latest GUI run visually; close the stage only if the user-facing answers are acceptable",
|
||||||
|
],
|
||||||
|
"stage_closed_without_manual_confirmation": [
|
||||||
|
"archive the stage artifacts and continue to the next module",
|
||||||
|
],
|
||||||
|
"user_decision_required": [
|
||||||
|
"read stage_loop_handoff.md and resolve the recorded user decision point",
|
||||||
|
],
|
||||||
|
"continue_autonomous_or_fix_blocker": [
|
||||||
|
"inspect stage_loop_handoff.md and rerun stage_agent_loop.py run after resolving the blocker",
|
||||||
|
],
|
||||||
|
"inspect_gui_review_status": [
|
||||||
|
"inspect run_review.md and repair_targets.json manually",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"next_action": next_action,
|
||||||
|
"command_templates": command_by_action.get(next_action, ["inspect stage_loop_handoff.md"]),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def build_stage_handoff_markdown(summary: dict[str, Any]) -> str:
|
def build_stage_handoff_markdown(summary: dict[str, Any]) -> str:
|
||||||
|
|
@ -258,6 +312,19 @@ def build_stage_handoff_markdown(summary: dict[str, Any]) -> str:
|
||||||
lines.extend(["", "## Acceptance invariants"])
|
lines.extend(["", "## Acceptance invariants"])
|
||||||
invariants = summary.get("acceptance_invariants") or []
|
invariants = summary.get("acceptance_invariants") or []
|
||||||
lines.extend([f"- {item}" for item in invariants] if invariants else ["- domain loop gate + analyst verdict"])
|
lines.extend([f"- {item}" for item in invariants] if invariants else ["- domain loop gate + analyst verdict"])
|
||||||
|
next_step_guidance = (
|
||||||
|
summary.get("next_step_guidance")
|
||||||
|
if isinstance(summary.get("next_step_guidance"), dict)
|
||||||
|
else {}
|
||||||
|
)
|
||||||
|
if next_step_guidance:
|
||||||
|
lines.extend(["", "## Next Step Guidance"])
|
||||||
|
commands = (
|
||||||
|
next_step_guidance.get("command_templates")
|
||||||
|
if isinstance(next_step_guidance.get("command_templates"), list)
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
lines.extend([f"- `{item}`" for item in commands] if commands else ["- inspect stage_loop_handoff.md"])
|
||||||
latest_gui_review = summary.get("latest_gui_review") if isinstance(summary.get("latest_gui_review"), dict) else {}
|
latest_gui_review = summary.get("latest_gui_review") if isinstance(summary.get("latest_gui_review"), dict) else {}
|
||||||
if latest_gui_review:
|
if latest_gui_review:
|
||||||
lines.extend(
|
lines.extend(
|
||||||
|
|
@ -369,6 +436,7 @@ def build_repair_execution_stage_summary(
|
||||||
"updated_at": now_iso(),
|
"updated_at": now_iso(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
base["next_step_guidance"] = build_next_step_guidance(next_action)
|
||||||
return base
|
return base
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -495,6 +563,7 @@ def build_gui_review_stage_summary(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
base["next_step_guidance"] = build_next_step_guidance(next_action)
|
||||||
latest_repair_validation = build_latest_repair_validation(
|
latest_repair_validation = build_latest_repair_validation(
|
||||||
previous_summary=previous_summary,
|
previous_summary=previous_summary,
|
||||||
review=review,
|
review=review,
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ class StageAgentLoopTests(unittest.TestCase):
|
||||||
self.assertEqual(summary["loop_final_status"], "accepted")
|
self.assertEqual(summary["loop_final_status"], "accepted")
|
||||||
self.assertTrue(summary["manual_confirmation_required"])
|
self.assertTrue(summary["manual_confirmation_required"])
|
||||||
self.assertEqual(summary["next_action"], "manual_gui_confirmation")
|
self.assertEqual(summary["next_action"], "manual_gui_confirmation")
|
||||||
|
self.assertIn("GUI", summary["next_step_guidance"]["command_templates"][0])
|
||||||
|
|
||||||
def test_build_stage_summary_continues_when_loop_is_partial(self) -> None:
|
def test_build_stage_summary_continues_when_loop_is_partial(self) -> None:
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
|
@ -203,6 +204,7 @@ class StageAgentLoopTests(unittest.TestCase):
|
||||||
self.assertEqual(summary["next_action"], "continue_repair_from_gui_review_p0")
|
self.assertEqual(summary["next_action"], "continue_repair_from_gui_review_p0")
|
||||||
self.assertFalse(summary["accepted_gate"])
|
self.assertFalse(summary["accepted_gate"])
|
||||||
self.assertEqual(summary["latest_gui_review"]["repair_targets_count"], 1)
|
self.assertEqual(summary["latest_gui_review"]["repair_targets_count"], 1)
|
||||||
|
self.assertIn("prepare-repair", summary["next_step_guidance"]["command_templates"][0])
|
||||||
|
|
||||||
def test_gui_review_stage_summary_links_post_repair_validation(self) -> None:
|
def test_gui_review_stage_summary_links_post_repair_validation(self) -> None:
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
|
@ -451,6 +453,7 @@ class StageAgentLoopTests(unittest.TestCase):
|
||||||
self.assertEqual(execution_summary["next_action"], "execute_repair_without_dry_run_or_review_command")
|
self.assertEqual(execution_summary["next_action"], "execute_repair_without_dry_run_or_review_command")
|
||||||
self.assertTrue(stage_summary["latest_repair_execution"]["dry_run"])
|
self.assertTrue(stage_summary["latest_repair_execution"]["dry_run"])
|
||||||
self.assertEqual(stage_summary["next_action"], "execute_repair_without_dry_run_or_review_command")
|
self.assertEqual(stage_summary["next_action"], "execute_repair_without_dry_run_or_review_command")
|
||||||
|
self.assertIn("run-repair", stage_summary["next_step_guidance"]["command_templates"][0])
|
||||||
|
|
||||||
def test_resolve_stage_repair_iteration_auto_prepares_from_handoff(self) -> None:
|
def test_resolve_stage_repair_iteration_auto_prepares_from_handoff(self) -> None:
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue