agent loop: claude drives; tool envelope (log/run/status/log)
This commit is contained in:
parent
a061f83cfa
commit
3c9d42b2a7
6 changed files with 147 additions and 47 deletions
|
|
@ -48,6 +48,50 @@ impl AgentServer {
|
|||
pub fn new(socket: PathBuf) -> Self {
|
||||
Self { socket }
|
||||
}
|
||||
|
||||
/// Wrap every tool handler in the same envelope:
|
||||
/// 1. Log the request (tool name + args via `Debug`).
|
||||
/// 2. Run the tool's actual logic.
|
||||
/// 3. Append a status line (inbox state) to the result so claude always
|
||||
/// has a current "how many unread messages" hint without an extra
|
||||
/// tool call.
|
||||
/// 4. Log the result body.
|
||||
///
|
||||
/// New tools just call `self.run_tool("name", &args, async { ... })`
|
||||
/// and get the same shape for free.
|
||||
async fn run_tool<F>(&self, tool: &'static str, args: String, body: F) -> String
|
||||
where
|
||||
F: std::future::Future<Output = String>,
|
||||
{
|
||||
tracing::info!(tool, %args, "tool: request");
|
||||
let result = body.await;
|
||||
let status = self.status_line().await;
|
||||
let full = if status.is_empty() {
|
||||
result
|
||||
} else {
|
||||
format!("{result}\n\n[status] {status}")
|
||||
};
|
||||
tracing::info!(tool, result = %full, "tool: result");
|
||||
full
|
||||
}
|
||||
|
||||
/// Non-mutating peek used in the status line. Falls back to a vague
|
||||
/// note rather than failing the whole tool call when the socket
|
||||
/// hiccups.
|
||||
async fn status_line(&self) -> String {
|
||||
match client::request::<_, hive_sh4re::AgentResponse>(
|
||||
&self.socket,
|
||||
&hive_sh4re::AgentRequest::Status,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::AgentResponse::Status { unread }) => {
|
||||
format!("{unread} unread message(s) in inbox")
|
||||
}
|
||||
Ok(other) => format!("status: unexpected response {other:?}"),
|
||||
Err(e) => format!("status: transport error: {e:#}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tool_router]
|
||||
|
|
@ -57,33 +101,42 @@ impl AgentServer {
|
|||
Use this to talk to peers or to surface output for the human at the dashboard."
|
||||
)]
|
||||
async fn send(&self, Parameters(args): Parameters<SendArgs>) -> String {
|
||||
let req = hive_sh4re::AgentRequest::Send {
|
||||
to: args.to.clone(),
|
||||
body: args.body,
|
||||
};
|
||||
match client::request::<_, hive_sh4re::AgentResponse>(&self.socket, &req).await {
|
||||
Ok(hive_sh4re::AgentResponse::Ok) => format!("sent to {}", args.to),
|
||||
Ok(hive_sh4re::AgentResponse::Err { message }) => format!("send failed: {message}"),
|
||||
Ok(other) => format!("send unexpected response: {other:?}"),
|
||||
Err(e) => format!("send transport error: {e:#}"),
|
||||
}
|
||||
let log = format!("{args:?}");
|
||||
let to = args.to.clone();
|
||||
self.run_tool("send", log, async move {
|
||||
let req = hive_sh4re::AgentRequest::Send {
|
||||
to: args.to,
|
||||
body: args.body,
|
||||
};
|
||||
match client::request::<_, hive_sh4re::AgentResponse>(&self.socket, &req).await {
|
||||
Ok(hive_sh4re::AgentResponse::Ok) => format!("sent to {to}"),
|
||||
Ok(hive_sh4re::AgentResponse::Err { message }) => format!("send failed: {message}"),
|
||||
Ok(other) => format!("send unexpected response: {other:?}"),
|
||||
Err(e) => format!("send transport error: {e:#}"),
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[tool(
|
||||
description = "Pop one message from this agent's inbox. Returns the sender and body, \
|
||||
or an empty marker if nothing is waiting."
|
||||
)]
|
||||
async fn recv(&self, Parameters(_): Parameters<RecvArgs>) -> String {
|
||||
let req = hive_sh4re::AgentRequest::Recv;
|
||||
match client::request::<_, hive_sh4re::AgentResponse>(&self.socket, &req).await {
|
||||
Ok(hive_sh4re::AgentResponse::Message { from, body }) => {
|
||||
format!("from: {from}\n\n{body}")
|
||||
async fn recv(&self, Parameters(args): Parameters<RecvArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
self.run_tool("recv", log, async move {
|
||||
let req = hive_sh4re::AgentRequest::Recv;
|
||||
match client::request::<_, hive_sh4re::AgentResponse>(&self.socket, &req).await {
|
||||
Ok(hive_sh4re::AgentResponse::Message { from, body }) => {
|
||||
format!("from: {from}\n\n{body}")
|
||||
}
|
||||
Ok(hive_sh4re::AgentResponse::Empty) => "(empty)".into(),
|
||||
Ok(hive_sh4re::AgentResponse::Err { message }) => format!("recv failed: {message}"),
|
||||
Ok(other) => format!("recv unexpected response: {other:?}"),
|
||||
Err(e) => format!("recv transport error: {e:#}"),
|
||||
}
|
||||
Ok(hive_sh4re::AgentResponse::Empty) => "(empty)".into(),
|
||||
Ok(hive_sh4re::AgentResponse::Err { message }) => format!("recv failed: {message}"),
|
||||
Ok(other) => format!("recv unexpected response: {other:?}"),
|
||||
Err(e) => format!("recv transport error: {e:#}"),
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue