generated from coulomb/repo-seed
feat(WARDEN-WP-0020): T3 — guarded executor (worker now acts, not just plans)
HubClient gains writes (mark_read, send_reply, add_progress). execute_plan/execute_plans run the safe, allowlisted actions autonomously: route_answer (reply with the computed answer + auto mark-read), reply (LLM-drafted body), progress_note, mark_read. Escalated plans and non-auto-executable kinds are left for a human; every action is metadata-only (no secret value read/sent/logged). Deliberate guardrail: propose_catalog_diff and any code/routing change is NOT auto-executed even under full-auto — a bad catalog commit could misroute credentials, so it goes to human review (recoverability over convenience). AUTO_EXECUTABLE is the messaging/hub tier only. `warden worker run --execute` runs the executor (dry-run still default). 7 executor tests (reply+mark, with/without body, escalated skip, catalog-diff-left-for-human, progress, failure-without-crash); 243 pass, lint clean. First live --execute shakedown is the operator's (staged rollout); T4 schedules it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1171,30 +1171,34 @@ def worker_run(
|
||||
Either way the allowlist + no-secret guardrails are enforced on every action. --execute
|
||||
is rejected until the guarded executor (T3) ships; dry-run is the default.
|
||||
"""
|
||||
from warden.worker import HubClient, LlmConnectBrain, RuleBrain, build_plans, render_plans
|
||||
|
||||
if not dry_run:
|
||||
err.print(
|
||||
"[red]--execute is not available yet[/red] (WP-0020 T3). "
|
||||
"The worker runs dry-run only until the guarded executor lands."
|
||||
)
|
||||
raise typer.Exit(2)
|
||||
from warden.worker import (
|
||||
HubClient, LlmConnectBrain, RuleBrain, build_plans, execute_plans, render_plans,
|
||||
)
|
||||
|
||||
if brain not in ("rule", "llm"):
|
||||
err.print(f"[red]Unknown --brain {brain!r}[/red] (expected 'rule' or 'llm').")
|
||||
raise typer.Exit(2)
|
||||
|
||||
hub = HubClient()
|
||||
try:
|
||||
messages = HubClient().unread()
|
||||
messages = hub.unread()
|
||||
except Exception as e: # noqa: BLE001 — surface any transport error as a clean message
|
||||
err.print(f"[red]Could not read the State Hub inbox:[/red] {e}")
|
||||
raise typer.Exit(1)
|
||||
|
||||
chosen = LlmConnectBrain() if brain == "llm" else RuleBrain()
|
||||
plans = build_plans(messages, chosen)
|
||||
console.print(render_plans(plans))
|
||||
auto = sum(1 for p in plans if not p.escalated)
|
||||
console.print(
|
||||
f"\n[dim]{len(plans)} request(s): {auto} auto-actionable, "
|
||||
f"{len(plans) - auto} need a human. (dry-run — nothing executed)[/dim]"
|
||||
)
|
||||
|
||||
if dry_run:
|
||||
console.print(render_plans(plans))
|
||||
console.print(
|
||||
f"\n[dim]{len(plans)} request(s): {auto} auto-actionable, "
|
||||
f"{len(plans) - auto} need a human. (dry-run — nothing executed)[/dim]"
|
||||
)
|
||||
return
|
||||
|
||||
# --execute: run the guarded executor. Topic for audit progress events.
|
||||
topic_id = "cee7bedf-2b48-46ef-8601-006474f2ad7a"
|
||||
console.print("[yellow]Executing (full-auto, in-scope only; escalations left for a human)…[/yellow]")
|
||||
console.print(execute_plans(plans, hub, topic_id=topic_id))
|
||||
|
||||
Reference in New Issue
Block a user