manager: add optional agent param to GetLooseEnds
GetLooseEnds now takes agent: Option<String>:
- None = manager's own loose ends (default; the bug fix)
- Some("*") = hive-wide view (every approval/question/reminder)
- Some("name") = that agent's loose ends
The get_loose_ends MCP tool exposes this as an optional agent arg, so
the manager can still scan the whole swarm on demand. The web UI and
post-turn counts pass None (manager's own).
This commit is contained in:
parent
873d5a083d
commit
d348ce885f
5 changed files with 50 additions and 22 deletions
|
|
@ -334,7 +334,7 @@ fn now_unix() -> i64 {
|
||||||
async fn fetch_manager_post_turn_counts(socket: &Path) -> (Option<u64>, Option<u64>) {
|
async fn fetch_manager_post_turn_counts(socket: &Path) -> (Option<u64>, Option<u64>) {
|
||||||
let threads = match client::request::<_, ManagerResponse>(
|
let threads = match client::request::<_, ManagerResponse>(
|
||||||
socket,
|
socket,
|
||||||
&ManagerRequest::GetLooseEnds,
|
&ManagerRequest::GetLooseEnds { agent: None },
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -756,6 +756,18 @@ pub struct CancelLooseEndArgs {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||||
|
pub struct GetLooseEndsArgs {
|
||||||
|
/// Whose loose ends to list. Omit (or `null`) for your own — the
|
||||||
|
/// manager's: approvals you submitted + questions where you are
|
||||||
|
/// asker/target + your own pending reminders. Pass `"*"` for a
|
||||||
|
/// hive-wide view of EVERY pending approval, unanswered question,
|
||||||
|
/// and reminder across the swarm. Pass a specific agent name to
|
||||||
|
/// inspect just that agent's threads.
|
||||||
|
#[serde(default)]
|
||||||
|
pub agent: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||||
pub struct RequestApplyCommitArgs {
|
pub struct RequestApplyCommitArgs {
|
||||||
/// Agent whose config repo the commit lives in (use `"hm1nd"` for the
|
/// Agent whose config repo the commit lives in (use `"hm1nd"` for the
|
||||||
|
|
@ -1126,18 +1138,19 @@ impl ManagerServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tool(
|
#[tool(
|
||||||
description = "Hive-wide loose ends: EVERY pending approval + EVERY unanswered \
|
description = "List loose ends. By default returns your OWN — the manager's: \
|
||||||
question + EVERY pending reminder across the swarm. Use to scan for stalled \
|
pending approvals you submitted + unanswered questions where you are \
|
||||||
coordination — questions sub-agents asked each other that nobody's answering, \
|
asker/target + your own pending reminders. Pass `agent: \"*\"` for a \
|
||||||
approvals stuck waiting on the operator, reminders piling up on an offline \
|
hive-wide scan (EVERY pending approval, unanswered question, and reminder \
|
||||||
agent, etc. No args. The sub-agent flavour only returns the agent's own \
|
across the swarm) — use it to spot stalled coordination, e.g. questions \
|
||||||
threads; the manager flavour is unfiltered. Cancel any question or reminder \
|
sub-agents asked each other that nobody's answering. Pass `agent: \
|
||||||
|
\"<name>\"` to inspect one agent's threads. Cancel any question or reminder \
|
||||||
row via `cancel_loose_end` (manager bypasses the owner check)."
|
row via `cancel_loose_end` (manager bypasses the owner check)."
|
||||||
)]
|
)]
|
||||||
async fn get_loose_ends(&self) -> String {
|
async fn get_loose_ends(&self, Parameters(args): Parameters<GetLooseEndsArgs>) -> String {
|
||||||
run_tool_envelope("get_loose_ends", String::new(), async move {
|
run_tool_envelope("get_loose_ends", String::new(), async move {
|
||||||
let (resp, retries) = self
|
let (resp, retries) = self
|
||||||
.dispatch(hive_sh4re::ManagerRequest::GetLooseEnds)
|
.dispatch(hive_sh4re::ManagerRequest::GetLooseEnds { agent: args.agent })
|
||||||
.await;
|
.await;
|
||||||
annotate_retries(format_loose_ends(resp), retries)
|
annotate_retries(format_loose_ends(resp), retries)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -409,7 +409,9 @@ async fn api_loose_ends(State(state): State<AppState>) -> Response {
|
||||||
Flavor::Manager => {
|
Flavor::Manager => {
|
||||||
match client::request::<_, hive_sh4re::ManagerResponse>(
|
match client::request::<_, hive_sh4re::ManagerResponse>(
|
||||||
&state.socket,
|
&state.socket,
|
||||||
&hive_sh4re::ManagerRequest::GetLooseEnds,
|
// Manager's own loose ends — the web page is the
|
||||||
|
// manager's page, not a hive-wide console.
|
||||||
|
&hive_sh4re::ManagerRequest::GetLooseEnds { agent: None },
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -396,12 +396,19 @@ async fn dispatch(req: &ManagerRequest, coord: &Arc<Coordinator>) -> ManagerResp
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ManagerRequest::GetLooseEnds => match crate::loose_ends::for_agent(coord, MANAGER_AGENT) {
|
ManagerRequest::GetLooseEnds { agent } => {
|
||||||
|
let result = match agent.as_deref() {
|
||||||
|
Some("*") => crate::loose_ends::hive_wide(coord),
|
||||||
|
Some(name) => crate::loose_ends::for_agent(coord, name),
|
||||||
|
None => crate::loose_ends::for_agent(coord, MANAGER_AGENT),
|
||||||
|
};
|
||||||
|
match result {
|
||||||
Ok(loose_ends) => ManagerResponse::LooseEnds { loose_ends },
|
Ok(loose_ends) => ManagerResponse::LooseEnds { loose_ends },
|
||||||
Err(e) => ManagerResponse::Err {
|
Err(e) => ManagerResponse::Err {
|
||||||
message: format!("{e:#}"),
|
message: format!("{e:#}"),
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
|
}
|
||||||
ManagerRequest::CountPendingReminders => {
|
ManagerRequest::CountPendingReminders => {
|
||||||
match coord.broker.count_pending_reminders_for(MANAGER_AGENT) {
|
match coord.broker.count_pending_reminders_for(MANAGER_AGENT) {
|
||||||
Ok(count) => ManagerResponse::PendingRemindersCount { count },
|
Ok(count) => ManagerResponse::PendingRemindersCount { count },
|
||||||
|
|
|
||||||
|
|
@ -792,12 +792,18 @@ pub enum ManagerRequest {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
file_path: Option<String>,
|
file_path: Option<String>,
|
||||||
},
|
},
|
||||||
/// Hive-wide loose-ends view: EVERY pending approval + EVERY
|
/// Loose-ends view for the manager surface. The optional `agent`
|
||||||
/// unanswered question in the swarm. Used by the manager to scan
|
/// field selects scope:
|
||||||
/// for stalled coordination — the per-agent equivalent on the
|
/// - `None` — the manager's own loose ends: approvals it
|
||||||
/// sub-agent surface is `AgentRequest::GetLooseEnds` which
|
/// submitted + questions where it is asker/target + its own
|
||||||
/// only returns rows where the agent itself is asker / target.
|
/// pending reminders. This is the default.
|
||||||
GetLooseEnds,
|
/// - `Some("*")` — hive-wide: EVERY pending approval, unanswered
|
||||||
|
/// question, and pending reminder across the swarm.
|
||||||
|
/// - `Some("<name>")` — that specific agent's loose ends.
|
||||||
|
GetLooseEnds {
|
||||||
|
#[serde(default)]
|
||||||
|
agent: Option<String>,
|
||||||
|
},
|
||||||
/// Count of the manager's own pending reminders. Mirror of
|
/// Count of the manager's own pending reminders. Mirror of
|
||||||
/// `AgentRequest::CountPendingReminders` on the manager surface.
|
/// `AgentRequest::CountPendingReminders` on the manager surface.
|
||||||
CountPendingReminders,
|
CountPendingReminders,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue