scheduled prompts: edit existing schedule (closes #474)

This commit is contained in:
damocles 2026-05-26 15:04:05 +02:00
commit 9fee1a1e56
6 changed files with 428 additions and 0 deletions

View file

@ -981,6 +981,33 @@ pub struct CancelScheduleArgs {
pub targets: Option<Vec<String>>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct EditScheduleArgs {
/// Schedule id from a prior `list_schedules` call or the
/// approval-resolved event for a `request_schedule_prompt`.
pub id: i64,
/// New body text. Omit to keep the existing one.
#[serde(default)]
pub body: Option<String>,
/// New description. Omit to keep the existing one. (To CLEAR
/// the description, use the dashboard PATCH endpoint
/// directly — the agent surface intentionally keeps the args
/// flat / non-nullable to dodge the doubly-wrapped Option
/// schemars quirk; clearing fields is rare and operator-side.)
#[serde(default)]
pub description: Option<String>,
/// Recurring interval in seconds. Omit to keep the existing
/// cadence; pass an explicit value to set a new one. Toggling
/// recurring↔one-shot (clearing the interval) is operator-only
/// for the same reason as `description` above.
#[serde(default)]
pub interval_seconds: Option<u64>,
/// New absolute unix timestamp for the next fire. Omit to
/// leave the schedule on its current cadence.
#[serde(default)]
pub next_fire_at_unix: Option<i64>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct GetLogsArgs {
/// Logical agent name to fetch logs for (e.g. `gui`, `hm1nd`).
@ -1327,6 +1354,44 @@ impl ManagerServer {
.await
}
#[tool(
description = "Edit an existing scheduled prompt's mutable fields (#474). Pass only \
the fields you want to change anything omitted keeps its current value. Editable: \
`body`, `description`, `interval_seconds` (positive only via this tool; flipping \
recurringone-shot is operator-only via the dashboard), `next_fire_at_unix`. \
Targets are immutable: per-target last-result history is keyed on them. To change \
the recipient list, cancel and submit a new schedule. \n\n\
Authorization mirrors `cancel_schedule` / `fire_schedule_now`: you can edit your \
own schedules + any owned by a sub-agent in your subtree per topology.json. \
Refuses cancelled schedules (the row's terminal submit a fresh one)."
)]
async fn edit_schedule(&self, Parameters(args): Parameters<EditScheduleArgs>) -> String {
let log = format!("{args:?}");
run_tool_envelope("edit_schedule", log, async move {
let id = args.id;
let (resp, retries) = self
.dispatch(hive_sh4re::ManagerRequest::EditSchedule {
id: args.id,
body: args.body,
// The agent-side args use plain Option<T>; the
// manager wire type's `Some(None)` ("set to
// null") cases stay operator-exclusive, so we
// promote agent-supplied values into
// `Some(Some(v))` and omit when the agent
// didn't pass a value.
description: args.description.map(Some),
interval_seconds: args.interval_seconds.map(Some),
next_fire_at_unix: args.next_fire_at_unix,
})
.await;
annotate_retries(
format_ack(resp, "edit_schedule", format!("edited #{id}")),
retries,
)
})
.await
}
#[tool(
description = "List every scheduled prompt in the queue (active + cancelled but \
not yet reaped). Returns the full snapshot schedule id, owner, body, target set \