harness: add request_next_turn MCP tool — immediate self-continuation (closes #216)

This commit is contained in:
damocles 2026-05-22 00:35:13 +02:00
parent de6ff3da29
commit c99261b042
3 changed files with 68 additions and 0 deletions

View file

@ -273,6 +273,11 @@ async fn serve(
if pending > 0 {
tracing::info!(%pending, "pending messages after turn; fetching next");
}
// `request_next_turn` MCP tool: agent wrote a sentinel
// requesting an immediate self-continuation turn. Clear
// the file and inject a synthetic wake so the outer loop
// fires a bare turn even if the inbox is empty.
check_and_inject_continue(socket, label).await;
}
Ok(AgentResponse::Messages { .. }) => {
// Idle: empty list = nothing pending. Brief sleep
@ -408,3 +413,41 @@ async fn fetch_agent_post_turn_counts(socket: &Path) -> (Option<u64>, Option<u64
(threads, reminders)
}
/// Check for the `request_next_turn` sentinel file. If present, remove it
/// and inject a synthetic `from: "self", body: "continue"` message so the
/// serve loop fires an immediate follow-up turn even when the inbox is empty.
/// Best-effort: any I/O error is logged and ignored (the agent just waits
/// for a real message as normal).
async fn check_and_inject_continue(socket: &Path, label: &str) {
let sentinel = hive_ag3nt::paths::state_dir().join("hyperhive-continue");
if !sentinel.exists() {
return;
}
if let Err(e) = std::fs::remove_file(&sentinel) {
tracing::warn!(error = %e, "check_and_inject_continue: remove sentinel failed");
return;
}
// Sentinel was present: inject a wake so the outer loop fires immediately.
// Route through the `Wake` request which is already wired in agent_server.
let res = client::request::<_, AgentResponse>(
socket,
&AgentRequest::Wake {
from: "self".into(),
body: "continue".into(),
},
)
.await;
match res {
Ok(AgentResponse::Ok) => {
tracing::info!(%label, "request_next_turn: injected self-continue wake");
}
Ok(AgentResponse::Err { message }) => {
tracing::warn!(%message, "check_and_inject_continue: wake rejected");
}
Err(e) => {
tracing::warn!(error = ?e, "check_and_inject_continue: wake transport error");
}
_ => {}
}
}