generated from coulomb/repo-seed
feat(WARDEN-WP-0020): T2 — llm-connect brain (autonomous worker now thinks)
llm-connect is operational (operator set OPENROUTER_API_KEY). Contract discovered from
the running service: POST /execute {"prompt":...} -> {"content":...}.
LlmConnectBrain embeds the fixed charter + the inbox message as untrusted data, calls
/execute, and parses a JSON action plan (_extract_json tolerates fences/prose), escalating
defensively on malformed/empty/transport errors. The build_plans guardrail still enforces
the allowlist + no-secret invariant on whatever the model returns — the LLM cannot widen
ops-warden's authority. `warden worker run --brain rule|llm` selects the planner.
Live-verified on the real inbox: the LLM brain planned a sensible reply+mark_read for a
secrets-engine coordination message and correctly escalated a secret-custody request as
out-of-lane — better classification than the deterministic RuleBrain.
6 new tests, 236 pass, lint clean. T3 (guarded executor) and T4 (scheduling) remain.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1160,14 +1160,18 @@ def worker_run(
|
||||
bool,
|
||||
typer.Option("--dry-run/--execute", help="Plan only (default); --execute lands in WP-0020 T3"),
|
||||
] = True,
|
||||
brain: Annotated[
|
||||
str,
|
||||
typer.Option("--brain", help="Planner: 'rule' (deterministic, default) or 'llm' (llm-connect)"),
|
||||
] = "rule",
|
||||
) -> None:
|
||||
"""Read ops-warden's unread coordination requests and render a guardrailed plan.
|
||||
|
||||
T1 is dry-run only: it plans with the deterministic RuleBrain and applies the
|
||||
allowlist + no-secret guardrails. The llm-connect brain (T2) and executor (T3) plug
|
||||
into the same plan contract; --execute is rejected until T3 ships.
|
||||
Plans with the deterministic RuleBrain (default) or the llm-connect brain (--brain llm).
|
||||
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, RuleBrain, build_plans, render_plans
|
||||
from warden.worker import HubClient, LlmConnectBrain, RuleBrain, build_plans, render_plans
|
||||
|
||||
if not dry_run:
|
||||
err.print(
|
||||
@@ -1176,13 +1180,18 @@ def worker_run(
|
||||
)
|
||||
raise typer.Exit(2)
|
||||
|
||||
if brain not in ("rule", "llm"):
|
||||
err.print(f"[red]Unknown --brain {brain!r}[/red] (expected 'rule' or 'llm').")
|
||||
raise typer.Exit(2)
|
||||
|
||||
try:
|
||||
messages = HubClient().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)
|
||||
|
||||
plans = build_plans(messages, RuleBrain())
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user