agents: remove send(operator) and the operator inbox; alert on turn failures
Agents reach the operator over matrix now (#5115). A `send` to `operator` is refused, by the broker and by the MCP allow-list check, with an error that names the matrix MCP tools. The dashboard's Y3R C4LL tab goes with it: the operator inbox, `GET /api/operator-inbox`, `Broker::unread_for_recipient`, and the browser notifications that only ever fired on operator-bound messages. The harness no longer posts turn failures and plugin-install failures to the operator inbox. Both are already logged at warn; a new Grafana rule, `hh-agent-turn-failed`, fires per agent on the harness's `turn failed` line. Dashboard-to-agent messaging (op-send, the agent web UI's message box, mark-all-read for agent inboxes) is unchanged. Decisions per mara on #5115: q1 a, q2 a plus a grafana alert, q3 keep dashboard-to-agent messaging and leave swarm-level code alone.
This commit is contained in:
parent
2bf809cbe5
commit
7e6a4c7727
37 changed files with 246 additions and 848 deletions
|
|
@ -301,44 +301,6 @@ impl Broker {
|
|||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Unacknowledged messages addressed to `recipient`, newest-first.
|
||||
/// Backs the dashboard's operator inbox: the operator never
|
||||
/// `recv`s over an agent socket, so messages to `"operator"` sit in
|
||||
/// the broker with `acked_at IS NULL` until the operator hits "mark
|
||||
/// all read" (which calls [`Broker::mark_all_read`]). This read
|
||||
/// mirrors that filter EXACTLY — `recipient = ?1 AND acked_at IS
|
||||
/// NULL`, with no `delivered_at` condition — so everything listed
|
||||
/// here is precisely what `mark_all_read` will clear (operator rows
|
||||
/// may never get `delivered_at` set). Returned as
|
||||
/// [`MessageEvent::Sent`] so the dashboard reuses its live renderer.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `Err` if the `SQLite` prepare or query fails.
|
||||
pub fn unread_for_recipient(&self, recipient: &str, limit: u64) -> Result<Vec<MessageEvent>> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let limit_i = i64::try_from(limit.min(i64::MAX as u64)).unwrap_or(i64::MAX);
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, sender, recipient, body, sent_at, in_reply_to
|
||||
FROM messages
|
||||
WHERE recipient = ?1 AND acked_at IS NULL
|
||||
ORDER BY id DESC
|
||||
LIMIT ?2",
|
||||
)?;
|
||||
let rows = stmt.query_map(params![recipient, limit_i], |row| {
|
||||
Ok(MessageEvent::Sent {
|
||||
id: row.get(0)?,
|
||||
from: row.get(1)?,
|
||||
to: row.get(2)?,
|
||||
body: row.get(3)?,
|
||||
at: row.get(4)?,
|
||||
in_reply_to: row.get(5)?,
|
||||
})
|
||||
})?;
|
||||
rows.collect::<rusqlite::Result<Vec<_>>>()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Number of undelivered messages addressed to `recipient`. Non-mutating
|
||||
/// — used by the harness to surface "N unread" in tool-result status
|
||||
/// lines without popping the queue.
|
||||
|
|
|
|||
Loading…
Reference in a new issue