@@ -780,9 +780,17 @@ async fn execute_job(
780780
781781 let prompt_text = recipe
782782 . prompt
783- . as_ref ( )
784- . or ( recipe. instructions . as_ref ( ) )
785- . unwrap ( ) ;
783+ . as_deref ( )
784+ . filter ( |s| !s. trim ( ) . is_empty ( ) )
785+ . or_else ( || {
786+ recipe
787+ . instructions
788+ . as_deref ( )
789+ . filter ( |s| !s. trim ( ) . is_empty ( ) )
790+ } )
791+ . ok_or_else ( || {
792+ anyhow ! ( "Recipe must specify at least one of `instructions` or `prompt`." )
793+ } ) ?;
786794
787795 let user_message = Message :: user ( ) . with_text ( prompt_text) ;
788796 let mut conversation = Conversation :: new_unvalidated ( vec ! [ user_message. clone( ) ] ) ;
@@ -985,4 +993,41 @@ mod tests {
985993 let jobs = scheduler. list_scheduled_jobs ( ) . await ;
986994 assert ! ( jobs[ 0 ] . last_run. is_none( ) , "Paused job should not run" ) ;
987995 }
996+
997+ #[ tokio:: test]
998+ async fn test_job_with_no_prompt_does_not_panic ( ) {
999+ let temp_dir = tempdir ( ) . unwrap ( ) ;
1000+ let recipe_path = temp_dir. path ( ) . join ( "no_prompt.yaml" ) ;
1001+ fs:: write (
1002+ & recipe_path,
1003+ "title: missing\n description: no prompt or instructions\n " ,
1004+ )
1005+ . unwrap ( ) ;
1006+
1007+ let storage_path = temp_dir. path ( ) . join ( "schedule.json" ) ;
1008+ let session_manager = Arc :: new ( SessionManager :: new ( temp_dir. path ( ) . to_path_buf ( ) ) ) ;
1009+ let scheduler = Scheduler :: new ( storage_path, session_manager) . await . unwrap ( ) ;
1010+
1011+ let job = ScheduledJob {
1012+ id : "no_prompt_job" . to_string ( ) ,
1013+ source : recipe_path. to_string_lossy ( ) . to_string ( ) ,
1014+ cron : "* * * * * *" . to_string ( ) ,
1015+ last_run : None ,
1016+ currently_running : false ,
1017+ paused : false ,
1018+ current_session_id : None ,
1019+ process_start_time : None ,
1020+ } ;
1021+
1022+ // Schedule the job and let it run — should not panic
1023+ scheduler. add_scheduled_job ( job, true ) . await . unwrap ( ) ;
1024+ sleep ( Duration :: from_millis ( 1500 ) ) . await ;
1025+
1026+ // The job should have attempted to run (last_run set) but not crashed the scheduler
1027+ let jobs = scheduler. list_scheduled_jobs ( ) . await ;
1028+ assert ! (
1029+ jobs[ 0 ] . last_run. is_some( ) ,
1030+ "Job should have attempted to run without panicking"
1031+ ) ;
1032+ }
9881033}
0 commit comments