c0re: schedule_prompt approval kind + worker + manager surface (#444 step 2)
This commit is contained in:
parent
c803bb714e
commit
aa7d8d9c9a
9 changed files with 612 additions and 4 deletions
|
|
@ -110,6 +110,14 @@ pub enum ApprovalKind {
|
|||
/// JSON-encoded inputs array (`"[]"` = all inputs). Agent field is
|
||||
/// set to `hm1nd` (the requesting manager).
|
||||
UpdateMetaInputs,
|
||||
/// Add a scheduled prompt (closes #444). On approval hive-c0re
|
||||
/// inserts a row into `scheduled_prompts` with
|
||||
/// `source = Approval { id }`; the worker fans the body out as
|
||||
/// inbox messages to each target at the scheduled time, recurring
|
||||
/// when `interval_seconds` is set. `commit_ref` stores the
|
||||
/// JSON-encoded `SchedulePromptPayload` so the approval row carries
|
||||
/// the full submission verbatim (target list, body, schedule).
|
||||
SchedulePrompt,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
|
|
@ -910,6 +918,93 @@ pub enum ManagerRequest {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
description: Option<String>,
|
||||
},
|
||||
/// Queue an approval to add a scheduled prompt (#444). The
|
||||
/// requester (caller of this request) is recorded as the schedule
|
||||
/// owner; on operator approval hive-c0re inserts the schedule and
|
||||
/// the worker fans the body out at fire time. Even agent-self
|
||||
/// schedules go through approval — the existing `remind` MCP tool
|
||||
/// is the unapproved self-wake path.
|
||||
RequestSchedulePrompt(SchedulePromptPayload),
|
||||
/// Cancel a scheduled prompt (#444). `targets = None` cancels the
|
||||
/// whole schedule; `Some(list)` cancels just those recipients,
|
||||
/// auto-cancelling the parent when no active targets remain.
|
||||
/// Authorization: manager can cancel its own schedules + any
|
||||
/// sub-agent schedules (i.e. owner reachable via topology); the
|
||||
/// operator surface bypasses this check.
|
||||
CancelSchedule {
|
||||
id: i64,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
targets: Option<Vec<String>>,
|
||||
},
|
||||
/// List every schedule in the queue. Manager-side this is
|
||||
/// unfiltered — the dashboard does the topology-filter for the
|
||||
/// per-agent view.
|
||||
ListSchedules,
|
||||
}
|
||||
|
||||
/// Submission payload for `RequestSchedulePrompt`. Lives outside the
|
||||
/// enum so it can also serialize into the approval row's `commit_ref`
|
||||
/// (the dispatcher re-parses it on approve and inserts the schedule).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct SchedulePromptPayload {
|
||||
/// Names of recipient agents. Operator + `hm1nd` allowed.
|
||||
pub targets: Vec<String>,
|
||||
/// Message body delivered to each target's inbox at fire time.
|
||||
/// Same size budget as `Send.body` — soft cap at the broker level.
|
||||
pub body: String,
|
||||
/// Absolute unix timestamp (seconds) for the FIRST fire. For
|
||||
/// recurring schedules the worker then re-arms in
|
||||
/// `interval_seconds` steps.
|
||||
pub first_fire_at_unix: i64,
|
||||
/// `None` = one-shot. `Some(n > 0)` = recurring every `n` seconds.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub interval_seconds: Option<u64>,
|
||||
/// Optional description shown on the dashboard approval card AND
|
||||
/// stored on the resulting schedule row for the operator's
|
||||
/// "what is this?" reference later.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
/// Schedule row shape on the wire — mirror of
|
||||
/// `scheduled_prompts::Schedule` but in the public crate so dashboard
|
||||
/// + agent surfaces can deserialize without depending on
|
||||
/// hive-c0re-internal types. Kept structurally identical to the
|
||||
/// in-process type; the conversion is field-by-field in
|
||||
/// `manager_server` / `dashboard`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WireSchedule {
|
||||
pub id: i64,
|
||||
pub owner: String,
|
||||
pub body: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub interval_seconds: Option<u64>,
|
||||
pub next_fire_at_unix: i64,
|
||||
pub created_at_unix: i64,
|
||||
pub source: WireScheduleSource,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub cancelled_at_unix: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
pub targets: Vec<WireScheduleTarget>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
pub enum WireScheduleSource {
|
||||
Operator,
|
||||
Approval { id: i64 },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WireScheduleTarget {
|
||||
pub target: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub cancelled_at_unix: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub last_fired_at_unix: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub last_result: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
|
@ -944,6 +1039,12 @@ pub enum ManagerResponse {
|
|||
Logs {
|
||||
content: String,
|
||||
},
|
||||
/// `ListSchedules` result (#444). Snapshot of every schedule
|
||||
/// (active + cancelled-but-not-yet-reaped); the dashboard does the
|
||||
/// per-agent topology filter on top.
|
||||
Schedules {
|
||||
schedules: Vec<WireSchedule>,
|
||||
},
|
||||
/// `GetLooseEnds` result: hive-wide loose ends (approvals +
|
||||
/// unanswered questions). Same `LooseEnd` variants as the
|
||||
/// agent surface; the manager's view is unfiltered.
|
||||
|
|
|
|||
Loading…
Reference in a new issue