diff --git a/config.json b/config.json new file mode 100644 index 0000000..84df243 --- /dev/null +++ b/config.json @@ -0,0 +1,33 @@ +{ + "providers": { + "default": { + "type": "openai", + "base_url": "", + "api_key": "", + "extra_headers": {} + } + }, + "models": { + "default": { + "model_id": "", + "temperature": 0.2 + } + }, + "agents": { + "default": { + "provider": "default", + "model": "default" + } + }, + "gateway": { + "host": "0.0.0.0", + "port": 19876, + "agent_prompt_reinject_every": 100 + }, + "scheduler": { + "enabled": true, + "tick_resolution_ms": 1000, + "misfire_policy": "skip", + "jobs": [] + } +} \ No newline at end of file diff --git a/src/config/mod.rs b/src/config/mod.rs index 14c84db..5b912a6 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -427,7 +427,7 @@ impl Default for ClientConfig { impl Default for SchedulerConfig { fn default() -> Self { Self { - enabled: false, + enabled: true, tick_resolution_ms: default_scheduler_tick_resolution_ms(), worker_queue_capacity: default_scheduler_worker_queue_capacity(), misfire_policy: SchedulerMisfirePolicy::default(), @@ -770,7 +770,7 @@ mod tests { let file = write_test_config(); let config = Config::load(file.path().to_str().unwrap()).unwrap(); - assert!(!config.scheduler.enabled); + assert!(config.scheduler.enabled); assert_eq!(config.scheduler.tick_resolution_ms, 1_000); assert_eq!(config.scheduler.worker_queue_capacity, 64); assert_eq!(config.scheduler.misfire_policy, SchedulerMisfirePolicy::Skip); diff --git a/src/scheduler/mod.rs b/src/scheduler/mod.rs index 16091f8..13cf941 100644 --- a/src/scheduler/mod.rs +++ b/src/scheduler/mod.rs @@ -702,7 +702,7 @@ mod tests { use super::*; use std::collections::HashMap; use crate::bus::MessageBus; - use crate::config::LLMProviderConfig; + use crate::config::{BUILTIN_MEMORY_MAINTENANCE_JOB_ID, LLMProviderConfig}; use crate::gateway::session::SessionManager; use crate::skills::SkillRuntime; use crate::storage::{SchedulerJobUpsert, SessionStore}; @@ -862,4 +862,60 @@ mod tests { assert_eq!(saved.run_count, 0); assert_eq!(saved.state, SchedulerJobState::Scheduled); } + + #[test] + fn sync_config_jobs_persists_builtin_memory_maintenance_job() { + let store = Arc::new(SessionStore::in_memory().unwrap()); + + let provider_config = LLMProviderConfig { + provider_type: "openai".to_string(), + name: "default".to_string(), + base_url: "http://localhost".to_string(), + api_key: "test-key".to_string(), + extra_headers: HashMap::new(), + llm_timeout_secs: 30, + model_id: "test-model".to_string(), + temperature: Some(0.0), + max_tokens: None, + model_extra: HashMap::new(), + token_limit: 4096, + max_tool_iterations: 4, + }; + let session_manager = SessionManager::new( + 4, + 100, + false, + provider_config.clone(), + HashMap::from([("default".to_string(), provider_config)]), + Arc::new(SkillRuntime::default()), + ) + .unwrap(); + let scheduler = Scheduler::new( + MessageBus::new(8), + SchedulerConfig::default(), + store.clone(), + session_manager, + ); + + scheduler.sync_config_jobs().unwrap(); + + let saved = store + .get_scheduler_job(BUILTIN_MEMORY_MAINTENANCE_JOB_ID) + .unwrap() + .unwrap(); + + assert_eq!(saved.id, BUILTIN_MEMORY_MAINTENANCE_JOB_ID); + assert_eq!(saved.kind, "internal_event"); + assert!(saved.enabled); + assert_eq!(saved.state, SchedulerJobState::Scheduled); + assert_eq!(saved.payload.get("event").and_then(|value| value.as_str()), Some("memory_maintenance")); + assert_eq!( + saved.schedule, + serde_json::json!({ + "type": "cron", + "expression": "0 19 * * *" + }) + ); + assert!(saved.next_fire_at.is_some()); + } } \ No newline at end of file