From d30ba16ab23b0e0e6bf08929bf41d2180411f04e Mon Sep 17 00:00:00 2001
From: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Date: Mon, 16 Jun 2025 09:47:04 -0400
Subject: [PATCH 1/5] Platform scheduler tool initial work (#1)
---
crates/goose-server/src/commands/agent.rs | 5 +-
crates/goose-server/src/routes/schedule.rs | 10 +-
crates/goose/src/agents/agent.rs | 546 +++++++++++++-
crates/goose/src/agents/mod.rs | 5 +
crates/goose/src/agents/platform_tools.rs | 43 ++
crates/goose/src/agents/private_tests.rs | 802 +++++++++++++++++++++
crates/goose/src/agents/test_support.rs | 413 +++++++++++
crates/goose/src/scheduler_test_support.rs | 21 +
8 files changed, 1842 insertions(+), 3 deletions(-)
create mode 100644 crates/goose/src/agents/private_tests.rs
create mode 100644 crates/goose/src/agents/test_support.rs
create mode 100644 crates/goose/src/scheduler_test_support.rs
diff --git a/crates/goose-server/src/commands/agent.rs b/crates/goose-server/src/commands/agent.rs
index 619451a7cdff..104e3b8128e6 100644
--- a/crates/goose-server/src/commands/agent.rs
+++ b/crates/goose-server/src/commands/agent.rs
@@ -29,7 +29,10 @@ pub async fn run() -> Result<()> {
.join("schedules.json");
let scheduler_instance = SchedulerFactory::create(schedule_file_path).await?;
- app_state.set_scheduler(scheduler_instance).await;
+ app_state.set_scheduler(scheduler_instance.clone()).await;
+
+ // NEW: Provide scheduler access to the agent
+ agent_ref.set_scheduler(scheduler_instance).await;
let cors = CorsLayer::new()
.allow_origin(Any)
diff --git a/crates/goose-server/src/routes/schedule.rs b/crates/goose-server/src/routes/schedule.rs
index cb1199ded702..9b4433c52ee4 100644
--- a/crates/goose-server/src/routes/schedule.rs
+++ b/crates/goose-server/src/routes/schedule.rs
@@ -93,6 +93,8 @@ fn parse_session_name_to_iso(session_name: &str) -> String {
request_body = CreateScheduleRequest,
responses(
(status = 200, description = "Scheduled job created successfully", body = ScheduledJob),
+ (status = 400, description = "Invalid cron expression or recipe file"),
+ (status = 409, description = "Job ID already exists"),
(status = 500, description = "Internal server error")
),
tag = "schedule"
@@ -128,7 +130,13 @@ async fn create_schedule(
.await
.map_err(|e| {
eprintln!("Error creating schedule: {:?}", e); // Log error
- StatusCode::INTERNAL_SERVER_ERROR
+ match e {
+ goose::scheduler::SchedulerError::JobNotFound(_) => StatusCode::NOT_FOUND,
+ goose::scheduler::SchedulerError::CronParseError(_) => StatusCode::BAD_REQUEST,
+ goose::scheduler::SchedulerError::RecipeLoadError(_) => StatusCode::BAD_REQUEST,
+ goose::scheduler::SchedulerError::JobIdExists(_) => StatusCode::CONFLICT,
+ _ => StatusCode::INTERNAL_SERVER_ERROR,
+ }
})?;
Ok(Json(job))
}
diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs
index 991603007c87..c0d77655cbe1 100644
--- a/crates/goose/src/agents/agent.rs
+++ b/crates/goose/src/agents/agent.rs
@@ -4,6 +4,7 @@ use std::pin::Pin;
use std::sync::Arc;
use anyhow::{anyhow, Result};
+use chrono::Utc;
use futures::stream::BoxStream;
use futures::{FutureExt, Stream, TryStreamExt};
use futures_util::stream;
@@ -17,6 +18,7 @@ use crate::permission::PermissionConfirmation;
use crate::providers::base::Provider;
use crate::providers::errors::ProviderError;
use crate::recipe::{Author, Recipe};
+use crate::scheduler_trait::SchedulerTrait;
use crate::tool_monitor::{ToolCall, ToolMonitor};
use regex::Regex;
use serde_json::Value;
@@ -27,7 +29,8 @@ use crate::agents::extension::{ExtensionConfig, ExtensionError, ExtensionResult,
use crate::agents::extension_manager::{get_parameter_names, ExtensionManager};
use crate::agents::platform_tools::{
PLATFORM_LIST_RESOURCES_TOOL_NAME, PLATFORM_MANAGE_EXTENSIONS_TOOL_NAME,
- PLATFORM_READ_RESOURCE_TOOL_NAME, PLATFORM_SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME,
+ PLATFORM_MANAGE_SCHEDULE_TOOL_NAME, PLATFORM_READ_RESOURCE_TOOL_NAME,
+ PLATFORM_SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME,
};
use crate::agents::prompt_manager::PromptManager;
use crate::agents::router_tool_selector::{
@@ -59,6 +62,7 @@ pub struct Agent {
pub(super) tool_result_rx: ToolResultReceiver,
pub(super) tool_monitor: Mutex