add get_logs tool to manager mcp surface
This commit is contained in:
parent
fca480b86e
commit
1023acf69f
3 changed files with 90 additions and 0 deletions
|
|
@ -39,6 +39,7 @@ pub enum SocketReply {
|
||||||
Status(u64),
|
Status(u64),
|
||||||
QuestionQueued(i64),
|
QuestionQueued(i64),
|
||||||
Recent(Vec<hive_sh4re::InboxRow>),
|
Recent(Vec<hive_sh4re::InboxRow>),
|
||||||
|
Logs(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<hive_sh4re::AgentResponse> for SocketReply {
|
impl From<hive_sh4re::AgentResponse> for SocketReply {
|
||||||
|
|
@ -65,6 +66,7 @@ impl From<hive_sh4re::ManagerResponse> for SocketReply {
|
||||||
hive_sh4re::ManagerResponse::Status { unread } => Self::Status(unread),
|
hive_sh4re::ManagerResponse::Status { unread } => Self::Status(unread),
|
||||||
hive_sh4re::ManagerResponse::QuestionQueued { id } => Self::QuestionQueued(id),
|
hive_sh4re::ManagerResponse::QuestionQueued { id } => Self::QuestionQueued(id),
|
||||||
hive_sh4re::ManagerResponse::Recent { rows } => Self::Recent(rows),
|
hive_sh4re::ManagerResponse::Recent { rows } => Self::Recent(rows),
|
||||||
|
hive_sh4re::ManagerResponse::Logs { content } => Self::Logs(content),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -351,6 +353,15 @@ pub struct RequestApplyCommitArgs {
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||||
|
pub struct GetLogsArgs {
|
||||||
|
/// Logical name of the sub-agent container to fetch logs for.
|
||||||
|
pub agent: String,
|
||||||
|
/// How many journal lines to return (default: 50, max: 500).
|
||||||
|
#[serde(default)]
|
||||||
|
pub lines: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ManagerServer {
|
pub struct ManagerServer {
|
||||||
socket: PathBuf,
|
socket: PathBuf,
|
||||||
|
|
@ -580,6 +591,40 @@ impl ManagerServer {
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tool(
|
||||||
|
description = "Fetch recent journal log lines for a sub-agent container. Useful \
|
||||||
|
for diagnosing MCP server registration failures, startup crashes, plugin install \
|
||||||
|
errors, or any harness issue you can't see from inside the container. `lines` \
|
||||||
|
defaults to 50 (max capped at 500 on the host side)."
|
||||||
|
)]
|
||||||
|
async fn get_logs(&self, Parameters(args): Parameters<GetLogsArgs>) -> String {
|
||||||
|
let log = format!("{args:?}");
|
||||||
|
let agent = args.agent.clone();
|
||||||
|
run_tool_envelope("get_logs", log, async move {
|
||||||
|
let lines = args.lines.map(|n| n.min(500));
|
||||||
|
let (resp, retries) = self
|
||||||
|
.dispatch(hive_sh4re::ManagerRequest::GetLogs {
|
||||||
|
agent: agent.clone(),
|
||||||
|
lines,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
let s = match resp {
|
||||||
|
Ok(SocketReply::Logs(content)) => {
|
||||||
|
if content.is_empty() {
|
||||||
|
format!("(no journal output for {agent})")
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(SocketReply::Err(m)) => format!("get_logs failed: {m}"),
|
||||||
|
Ok(other) => format!("get_logs unexpected response: {other:?}"),
|
||||||
|
Err(e) => format!("get_logs transport error: {e:#}"),
|
||||||
|
};
|
||||||
|
annotate_retries(s, retries)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tool_handler(
|
#[tool_handler(
|
||||||
|
|
@ -635,6 +680,7 @@ pub fn allowed_mcp_tools(flavor: Flavor) -> Vec<String> {
|
||||||
"update",
|
"update",
|
||||||
"request_apply_commit",
|
"request_apply_commit",
|
||||||
"ask_operator",
|
"ask_operator",
|
||||||
|
"get_logs",
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
let mut out: Vec<String> = names
|
let mut out: Vec<String> = names
|
||||||
|
|
|
||||||
|
|
@ -273,6 +273,35 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc<Coordinator>) -> ManagerResp
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ManagerRequest::GetLogs { agent, lines } => {
|
||||||
|
let n = lines.unwrap_or(50);
|
||||||
|
tracing::info!(%agent, %n, "manager: get_logs");
|
||||||
|
match tokio::process::Command::new("journalctl")
|
||||||
|
.args([
|
||||||
|
"-M",
|
||||||
|
agent,
|
||||||
|
"-n",
|
||||||
|
&n.to_string(),
|
||||||
|
"--no-pager",
|
||||||
|
"--output=short",
|
||||||
|
])
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(out) => {
|
||||||
|
let content = if out.status.success() || !out.stdout.is_empty() {
|
||||||
|
String::from_utf8_lossy(&out.stdout).into_owned()
|
||||||
|
} else {
|
||||||
|
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||||
|
format!("journalctl exited {}: {stderr}", out.status)
|
||||||
|
};
|
||||||
|
ManagerResponse::Logs { content }
|
||||||
|
}
|
||||||
|
Err(e) => ManagerResponse::Err {
|
||||||
|
message: format!("journalctl spawn failed: {e:#}"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
ManagerRequest::RequestApplyCommit {
|
ManagerRequest::RequestApplyCommit {
|
||||||
agent,
|
agent,
|
||||||
commit_ref,
|
commit_ref,
|
||||||
|
|
|
||||||
|
|
@ -475,6 +475,17 @@ pub enum ManagerRequest {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
ttl_seconds: Option<u64>,
|
ttl_seconds: Option<u64>,
|
||||||
},
|
},
|
||||||
|
/// Fetch recent journal lines for a sub-agent container. hive-c0re
|
||||||
|
/// runs `journalctl -M <agent> -n <lines> --no-pager` and returns
|
||||||
|
/// the output as a string. Useful for diagnosing MCP registration
|
||||||
|
/// failures, startup crashes, and harness errors.
|
||||||
|
///
|
||||||
|
/// `lines` defaults to 50 when omitted.
|
||||||
|
GetLogs {
|
||||||
|
agent: String,
|
||||||
|
#[serde(default)]
|
||||||
|
lines: Option<u32>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
@ -502,4 +513,8 @@ pub enum ManagerResponse {
|
||||||
Recent {
|
Recent {
|
||||||
rows: Vec<InboxRow>,
|
rows: Vec<InboxRow>,
|
||||||
},
|
},
|
||||||
|
/// `GetLogs` result: journal lines for the requested container.
|
||||||
|
Logs {
|
||||||
|
content: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue