fix(cron): persist delivery for api-created cron jobs (#4087)
Resolves merge conflicts from PR #4064. Uses typed DeliveryConfig in CronAddBody and passes delivery directly to add_shell_job_with_approval and add_agent_job instead of post-creation patching. Preserves master's richer API fields (session_target, model, allowed_tools, delete_after_run).
This commit is contained in:
+51
-15
@@ -235,6 +235,19 @@ impl Tool for CronAddTool {
|
||||
.get("approved")
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
.unwrap_or(false);
|
||||
let delivery = match args.get("delivery") {
|
||||
Some(v) => match serde_json::from_value::<DeliveryConfig>(v.clone()) {
|
||||
Ok(cfg) => Some(cfg),
|
||||
Err(e) => {
|
||||
return Ok(ToolResult {
|
||||
success: false,
|
||||
output: String::new(),
|
||||
error: Some(format!("Invalid delivery config: {e}")),
|
||||
});
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let result = match job_type {
|
||||
JobType::Shell => {
|
||||
@@ -261,7 +274,14 @@ impl Tool for CronAddTool {
|
||||
return Ok(blocked);
|
||||
}
|
||||
|
||||
cron::add_shell_job_with_approval(&self.config, name, schedule, command, approved)
|
||||
cron::add_shell_job_with_approval(
|
||||
&self.config,
|
||||
name,
|
||||
schedule,
|
||||
command,
|
||||
delivery,
|
||||
approved,
|
||||
)
|
||||
}
|
||||
JobType::Agent => {
|
||||
let prompt = match args.get("prompt").and_then(serde_json::Value::as_str) {
|
||||
@@ -307,20 +327,6 @@ impl Tool for CronAddTool {
|
||||
None => None,
|
||||
};
|
||||
|
||||
let delivery = match args.get("delivery") {
|
||||
Some(v) => match serde_json::from_value::<DeliveryConfig>(v.clone()) {
|
||||
Ok(cfg) => Some(cfg),
|
||||
Err(e) => {
|
||||
return Ok(ToolResult {
|
||||
success: false,
|
||||
output: String::new(),
|
||||
error: Some(format!("Invalid delivery config: {e}")),
|
||||
});
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
if let Some(blocked) = self.enforce_mutation_allowed("cron_add") {
|
||||
return Ok(blocked);
|
||||
}
|
||||
@@ -406,6 +412,36 @@ mod tests {
|
||||
assert!(result.output.contains("next_run"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn shell_job_persists_delivery() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let cfg = test_config(&tmp).await;
|
||||
let tool = CronAddTool::new(cfg.clone(), test_security(&cfg));
|
||||
let result = tool
|
||||
.execute(json!({
|
||||
"schedule": { "kind": "cron", "expr": "*/5 * * * *" },
|
||||
"job_type": "shell",
|
||||
"command": "echo ok",
|
||||
"delivery": {
|
||||
"mode": "announce",
|
||||
"channel": "discord",
|
||||
"to": "1234567890",
|
||||
"best_effort": true
|
||||
}
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(result.success, "{:?}", result.error);
|
||||
|
||||
let jobs = cron::list_jobs(&cfg).unwrap();
|
||||
assert_eq!(jobs.len(), 1);
|
||||
assert_eq!(jobs[0].delivery.mode, "announce");
|
||||
assert_eq!(jobs[0].delivery.channel.as_deref(), Some("discord"));
|
||||
assert_eq!(jobs[0].delivery.to.as_deref(), Some("1234567890"));
|
||||
assert!(jobs[0].delivery.best_effort);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn blocks_disallowed_shell_command() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
@@ -244,6 +244,7 @@ mod tests {
|
||||
tz: None,
|
||||
},
|
||||
"touch cron-run-approval",
|
||||
None,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -315,6 +315,7 @@ impl ScheduleTool {
|
||||
tz: None,
|
||||
},
|
||||
command,
|
||||
None,
|
||||
approved,
|
||||
) {
|
||||
Ok(job) => job,
|
||||
|
||||
Reference in New Issue
Block a user