refactor: unify AgentRequest/Response + ManagerRequest/Response into Request/Response (#691)
This commit is contained in:
parent
2fd6de7bab
commit
15617cef9a
6 changed files with 197 additions and 534 deletions
|
|
@ -63,17 +63,7 @@ struct AppState {
|
|||
gui_vnc_port: Option<u16>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
fn flavor(&self) -> Flavor {
|
||||
self.files.flavor
|
||||
}
|
||||
}
|
||||
|
||||
/// Which wire protocol the per-agent UI's `/send` handler should speak.
|
||||
/// Sub-agent → `AgentRequest::OperatorMsg`; manager →
|
||||
/// `ManagerRequest::OperatorMsg`. Reuses the MCP-side enum so a
|
||||
/// single value drives both the send protocol and (in
|
||||
/// `post_compact`) the allowed-tools surface claude sees.
|
||||
/// Re-export so callers in `turn.rs` can name the type via `web_ui::Flavor`.
|
||||
pub type Flavor = mcp::Flavor;
|
||||
|
||||
/// Bind the per-container web listener and serve the SPA.
|
||||
|
|
@ -379,7 +369,7 @@ async fn api_stats(
|
|||
// filters its counts to the same time range as the chart data.
|
||||
let window_secs = window.span_secs();
|
||||
let window_secs_u = u64::try_from(window_secs).unwrap_or(0);
|
||||
snapshot.reminder_stats = fetch_reminder_stats(&state.socket, state.flavor(), window_secs_u).await;
|
||||
snapshot.reminder_stats = fetch_reminder_stats(&state.socket, window_secs_u).await;
|
||||
axum::Json(snapshot)
|
||||
}
|
||||
|
||||
|
|
@ -505,39 +495,18 @@ struct SessionView {
|
|||
/// the `mcp__hyperhive__get_loose_ends` tool sees from inside the
|
||||
/// container.
|
||||
async fn api_loose_ends(State(state): State<AppState>) -> Response {
|
||||
let loose_ends: Vec<hive_sh4re::LooseEnd> = match state.flavor() {
|
||||
Flavor::Agent => {
|
||||
match client::request::<_, hive_sh4re::AgentResponse>(
|
||||
&state.socket,
|
||||
&hive_sh4re::AgentRequest::GetLooseEnds,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::AgentResponse::LooseEnds { loose_ends }) => loose_ends,
|
||||
Ok(hive_sh4re::AgentResponse::Err { message }) => {
|
||||
return error_response(&format!("get_loose_ends: {message}"));
|
||||
}
|
||||
Ok(other) => return error_response(&format!("unexpected response: {other:?}")),
|
||||
Err(e) => return error_response(&format!("transport: {e:#}")),
|
||||
}
|
||||
}
|
||||
Flavor::Manager => {
|
||||
match client::request::<_, hive_sh4re::ManagerResponse>(
|
||||
&state.socket,
|
||||
// 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
|
||||
{
|
||||
Ok(hive_sh4re::ManagerResponse::LooseEnds { loose_ends }) => loose_ends,
|
||||
Ok(hive_sh4re::ManagerResponse::Err { message }) => {
|
||||
return error_response(&format!("get_loose_ends: {message}"));
|
||||
}
|
||||
Ok(other) => return error_response(&format!("unexpected response: {other:?}")),
|
||||
Err(e) => return error_response(&format!("transport: {e:#}")),
|
||||
}
|
||||
let loose_ends: Vec<hive_sh4re::LooseEnd> = match client::request::<_, hive_sh4re::Response>(
|
||||
&state.socket,
|
||||
&hive_sh4re::Request::GetLooseEnds { agent: None },
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::Response::LooseEnds { loose_ends }) => loose_ends,
|
||||
Ok(hive_sh4re::Response::Err { message }) => {
|
||||
return error_response(&format!("get_loose_ends: {message}"));
|
||||
}
|
||||
Ok(other) => return error_response(&format!("unexpected response: {other:?}")),
|
||||
Err(e) => return error_response(&format!("transport: {e:#}")),
|
||||
};
|
||||
axum::Json(serde_json::json!({ "loose_ends": loose_ends })).into_response()
|
||||
}
|
||||
|
|
@ -567,7 +536,7 @@ async fn api_state(State(state): State<AppState>) -> axum::Json<StateSnapshot> {
|
|||
.ok()
|
||||
.and_then(|s| s.parse::<u16>().ok())
|
||||
.unwrap_or(7000);
|
||||
let inbox = recent_inbox(&state.socket, state.flavor()).await;
|
||||
let inbox = recent_inbox(&state.socket).await;
|
||||
let (turn_state, turn_state_since) = state.bus.state_snapshot();
|
||||
let model = state.bus.model();
|
||||
let context_window_tokens = state
|
||||
|
|
@ -676,67 +645,34 @@ struct ExtraLink {
|
|||
/// Best-effort: pull the last 30 messages addressed to us via the
|
||||
/// per-agent / manager socket. Empty list on any transport / decode
|
||||
/// failure — the inbox section is decorative, not authoritative.
|
||||
async fn recent_inbox(socket: &std::path::Path, flavor: Flavor) -> Vec<hive_sh4re::InboxRow> {
|
||||
async fn recent_inbox(socket: &std::path::Path) -> Vec<hive_sh4re::InboxRow> {
|
||||
const LIMIT: u64 = 30;
|
||||
match flavor {
|
||||
Flavor::Agent => {
|
||||
match client::request::<_, hive_sh4re::AgentResponse>(
|
||||
socket,
|
||||
&hive_sh4re::AgentRequest::Recent { limit: LIMIT },
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::AgentResponse::Recent { rows }) => rows,
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
Flavor::Manager => {
|
||||
match client::request::<_, hive_sh4re::ManagerResponse>(
|
||||
socket,
|
||||
&hive_sh4re::ManagerRequest::Recent { limit: LIMIT },
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::ManagerResponse::Recent { rows }) => rows,
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
match client::request::<_, hive_sh4re::Response>(
|
||||
socket,
|
||||
&hive_sh4re::Request::Recent { limit: LIMIT },
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::Response::Recent { rows }) => rows,
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch reminder activity stats from the broker via the per-agent /
|
||||
/// manager socket. Returns None on any transport / decode failure — the
|
||||
/// stats are decorative, not authoritative.
|
||||
async fn fetch_reminder_stats(socket: &std::path::Path, flavor: Flavor, window_secs: u64) -> Option<hive_sh4re::ReminderStats> {
|
||||
match flavor {
|
||||
Flavor::Agent => {
|
||||
match client::request::<_, hive_sh4re::AgentResponse>(
|
||||
socket,
|
||||
&hive_sh4re::AgentRequest::ReminderRollup {
|
||||
since_secs: window_secs,
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::AgentResponse::ReminderRollup(stats)) => Some(stats),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Flavor::Manager => {
|
||||
match client::request::<_, hive_sh4re::ManagerResponse>(
|
||||
socket,
|
||||
&hive_sh4re::ManagerRequest::ReminderRollup {
|
||||
since_secs: window_secs,
|
||||
// Manager's own stats page — its own reminders.
|
||||
agent: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::ManagerResponse::ReminderRollup(stats)) => Some(stats),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
async fn fetch_reminder_stats(socket: &std::path::Path, window_secs: u64) -> Option<hive_sh4re::ReminderStats> {
|
||||
match client::request::<_, hive_sh4re::Response>(
|
||||
socket,
|
||||
&hive_sh4re::Request::ReminderRollup {
|
||||
since_secs: window_secs,
|
||||
agent: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::Response::ReminderRollup(stats)) => Some(stats),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -754,29 +690,16 @@ async fn post_send(State(state): State<AppState>, Form(form): Form<SendForm>) ->
|
|||
if body.is_empty() {
|
||||
return error_response("send: `body` required");
|
||||
}
|
||||
let result = match state.flavor() {
|
||||
Flavor::Agent => match client::request::<_, hive_sh4re::AgentResponse>(
|
||||
&state.socket,
|
||||
&hive_sh4re::AgentRequest::OperatorMsg { body },
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::AgentResponse::Ok) => Ok(()),
|
||||
Ok(hive_sh4re::AgentResponse::Err { message }) => Err(message),
|
||||
Ok(other) => Err(format!("unexpected response: {other:?}")),
|
||||
Err(e) => Err(format!("transport: {e:#}")),
|
||||
},
|
||||
Flavor::Manager => match client::request::<_, hive_sh4re::ManagerResponse>(
|
||||
&state.socket,
|
||||
&hive_sh4re::ManagerRequest::OperatorMsg { body },
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::ManagerResponse::Ok) => Ok(()),
|
||||
Ok(hive_sh4re::ManagerResponse::Err { message }) => Err(message),
|
||||
Ok(other) => Err(format!("unexpected response: {other:?}")),
|
||||
Err(e) => Err(format!("transport: {e:#}")),
|
||||
},
|
||||
let result = match client::request::<_, hive_sh4re::Response>(
|
||||
&state.socket,
|
||||
&hive_sh4re::Request::OperatorMsg { body },
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(hive_sh4re::Response::Ok) => Ok(()),
|
||||
Ok(hive_sh4re::Response::Err { message }) => Err(message),
|
||||
Ok(other) => Err(format!("unexpected response: {other:?}")),
|
||||
Err(e) => Err(format!("transport: {e:#}")),
|
||||
};
|
||||
match result {
|
||||
// 200 instead of 303 → the client doesn't refetch /api/state.
|
||||
|
|
|
|||
Loading…
Reference in a new issue