fix(hermes): detect worker prompt readiness
Some checks failed
Tests / Declarative: Post Actions failed: 2, passed: 154
Some checks failed
Tests / Declarative: Post Actions failed: 2, passed: 154
This commit is contained in:
parent
d3097c6bb8
commit
42f5f80146
@ -24,7 +24,7 @@ spec:
|
|||||||
ai.bstein.dev/execution: Herdr-supervised Codex and Claude Code
|
ai.bstein.dev/execution: Herdr-supervised Codex and Claude Code
|
||||||
ai.bstein.dev/model-policy: difficulty-aware low through xhigh, cross-provider fallback
|
ai.bstein.dev/model-policy: difficulty-aware low through xhigh, cross-provider fallback
|
||||||
ai.bstein.dev/placement: rpi5 preferred; Jetson deferred until state storage is available
|
ai.bstein.dev/placement: rpi5 preferred; Jetson deferred until state storage is available
|
||||||
ai.bstein.dev/config-rev: "20260808-herdr-browser-tui-prompt-ready"
|
ai.bstein.dev/config-rev: "20260808-herdr-browser-tui-prompt-marker"
|
||||||
vault.hashicorp.com/agent-inject: "true"
|
vault.hashicorp.com/agent-inject: "true"
|
||||||
vault.hashicorp.com/role: hermes-agent
|
vault.hashicorp.com/role: hermes-agent
|
||||||
vault.hashicorp.com/agent-inject-secret-anthropic-token: kv/data/atlas/hermes/agent-tokens
|
vault.hashicorp.com/agent-inject-secret-anthropic-token: kv/data/atlas/hermes/agent-tokens
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -17,7 +16,10 @@ ALLOWED_EFFORTS = ("low", "medium", "high", "xhigh")
|
|||||||
ROUTING_PATH = Path("/opt/data/workspace/coordinator/model-routing.json")
|
ROUTING_PATH = Path("/opt/data/workspace/coordinator/model-routing.json")
|
||||||
HERDR_BIN = Path("/opt/data/tools/bin/herdr")
|
HERDR_BIN = Path("/opt/data/tools/bin/herdr")
|
||||||
CODEX_AUTH = Path("/opt/data/home/.codex/auth.json")
|
CODEX_AUTH = Path("/opt/data/home/.codex/auth.json")
|
||||||
CLAUDE_PROMPT_SETTLE_SECONDS = 3
|
PROMPT_READY_MARKERS = {
|
||||||
|
"codex": "OpenAI Codex",
|
||||||
|
"claude": "accept edits on",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _load_routes(path: Path) -> dict[str, Any]:
|
def _load_routes(path: Path) -> dict[str, Any]:
|
||||||
@ -180,10 +182,25 @@ def launch_worker(
|
|||||||
started = _run(command, env)
|
started = _run(command, env)
|
||||||
result = {**plan, "agent": agent_name, "pane": pane, "started": started}
|
result = {**plan, "agent": agent_name, "pane": pane, "started": started}
|
||||||
if prompt:
|
if prompt:
|
||||||
# Claude reports interactive readiness just before its prompt finishes
|
# Herdr can detect the process before the full-screen prompt has finished
|
||||||
# drawing. Give that terminal a moment so the submitted Enter is not lost.
|
# drawing. Wait for a pinned CLI marker so the submitted Enter is not lost.
|
||||||
if plan["worker"] == "claude":
|
_run(
|
||||||
time.sleep(CLAUDE_PROMPT_SETTLE_SECONDS)
|
[
|
||||||
|
str(HERDR_BIN),
|
||||||
|
"pane",
|
||||||
|
"wait-output",
|
||||||
|
pane,
|
||||||
|
"--match",
|
||||||
|
PROMPT_READY_MARKERS[plan["worker"]],
|
||||||
|
"--source",
|
||||||
|
"recent",
|
||||||
|
"--lines",
|
||||||
|
"120",
|
||||||
|
"--timeout",
|
||||||
|
"30000",
|
||||||
|
],
|
||||||
|
env,
|
||||||
|
)
|
||||||
result["prompted"] = _run(
|
result["prompted"] = _run(
|
||||||
[
|
[
|
||||||
str(HERDR_BIN),
|
str(HERDR_BIN),
|
||||||
|
|||||||
@ -55,7 +55,6 @@ def test_claude_worker_waits_for_prompt_readiness(tmp_path: Path, monkeypatch):
|
|||||||
project = tmp_path / "project"
|
project = tmp_path / "project"
|
||||||
project.mkdir()
|
project.mkdir()
|
||||||
calls = []
|
calls = []
|
||||||
sleeps = []
|
|
||||||
|
|
||||||
def fake_run(command, env):
|
def fake_run(command, env):
|
||||||
calls.append(command)
|
calls.append(command)
|
||||||
@ -65,7 +64,6 @@ def test_claude_worker_waits_for_prompt_readiness(tmp_path: Path, monkeypatch):
|
|||||||
|
|
||||||
monkeypatch.setattr(dispatch, "HERDR_BIN", herdr)
|
monkeypatch.setattr(dispatch, "HERDR_BIN", herdr)
|
||||||
monkeypatch.setattr(dispatch, "_run", fake_run)
|
monkeypatch.setattr(dispatch, "_run", fake_run)
|
||||||
monkeypatch.setattr(dispatch.time, "sleep", sleeps.append)
|
|
||||||
plan = {
|
plan = {
|
||||||
"worker": "claude",
|
"worker": "claude",
|
||||||
"model": "claude-haiku-4-5-20251001",
|
"model": "claude-haiku-4-5-20251001",
|
||||||
@ -74,7 +72,20 @@ def test_claude_worker_waits_for_prompt_readiness(tmp_path: Path, monkeypatch):
|
|||||||
|
|
||||||
dispatch.launch_worker(plan, project, "review", "Check the implementation.")
|
dispatch.launch_worker(plan, project, "review", "Check the implementation.")
|
||||||
|
|
||||||
assert sleeps == [dispatch.CLAUDE_PROMPT_SETTLE_SECONDS]
|
ready = calls[-2]
|
||||||
|
assert ready[1:] == [
|
||||||
|
"pane",
|
||||||
|
"wait-output",
|
||||||
|
"w2:p1",
|
||||||
|
"--match",
|
||||||
|
"accept edits on",
|
||||||
|
"--source",
|
||||||
|
"recent",
|
||||||
|
"--lines",
|
||||||
|
"120",
|
||||||
|
"--timeout",
|
||||||
|
"30000",
|
||||||
|
]
|
||||||
prompt = calls[-1]
|
prompt = calls[-1]
|
||||||
assert prompt[1:5] == [
|
assert prompt[1:5] == [
|
||||||
"agent",
|
"agent",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user