@@ -336,6 +336,26 @@ impl BulletinRefreshOutcome {
336336}
337337
338338const CORTEX_ONE_SHOT_MAX_TURNS : usize = 1 ;
339+ const CORTEX_INTRADAY_SYNTHESIS_SYSTEM_FALLBACK : & str = "You write concise working-memory summaries for the cortex.\n \n Output one narrative summary paragraph and nothing else." ;
340+ const CORTEX_DAILY_SUMMARY_SYSTEM_FALLBACK : & str = "You write daily activity summaries for the cortex.\n \n Output the daily activity summary and nothing else." ;
341+
342+ fn render_static_prompt_or_fallback (
343+ prompt_engine : & crate :: prompts:: engine:: PromptEngine ,
344+ template_name : & ' static str ,
345+ fallback : & ' static str ,
346+ ) -> String {
347+ match prompt_engine. render_static ( template_name) {
348+ Ok ( prompt) => prompt,
349+ Err ( error) => {
350+ tracing:: warn!(
351+ %error,
352+ template_name,
353+ "failed to render static cortex prompt, using fallback"
354+ ) ;
355+ fallback. to_string ( )
356+ }
357+ }
358+ }
339359
340360fn maybe_spawn_synthesis_task (
341361 task : & mut Option < tokio:: task:: JoinHandle < anyhow:: Result < bool > > > ,
@@ -3223,13 +3243,11 @@ pub async fn maybe_synthesize_intraday_batch(
32233243
32243244 // Render the synthesis prompt.
32253245 let prompt_engine = deps. runtime_config . prompts . load ( ) ;
3226- let synthesis_preamble = match prompt_engine. render_static ( "cortex_intraday_synthesis_system" ) {
3227- Ok ( prompt) => prompt,
3228- Err ( error) => {
3229- tracing:: warn!( %error, "failed to render cortex_intraday_synthesis_system prompt" ) ;
3230- return Err ( error. into ( ) ) ;
3231- }
3232- } ;
3246+ let synthesis_preamble = render_static_prompt_or_fallback (
3247+ & prompt_engine,
3248+ "cortex_intraday_synthesis_system" ,
3249+ CORTEX_INTRADAY_SYNTHESIS_SYSTEM_FALLBACK ,
3250+ ) ;
32333251 let prompt = prompt_engine. render_intraday_synthesis (
32343252 unsynthesized. len ( ) ,
32353253 & time_start_str,
@@ -3387,13 +3405,11 @@ pub async fn maybe_synthesize_daily_summary(
33873405
33883406 let wm_config = * * deps. runtime_config . working_memory . load ( ) ;
33893407 let prompt_engine = deps. runtime_config . prompts . load ( ) ;
3390- let synthesis_preamble = match prompt_engine. render_static ( "cortex_daily_summary_system" ) {
3391- Ok ( prompt) => prompt,
3392- Err ( error) => {
3393- tracing:: warn!( %error, "failed to render cortex_daily_summary_system prompt" ) ;
3394- return Err ( error. into ( ) ) ;
3395- }
3396- } ;
3408+ let synthesis_preamble = render_static_prompt_or_fallback (
3409+ & prompt_engine,
3410+ "cortex_daily_summary_system" ,
3411+ CORTEX_DAILY_SUMMARY_SYSTEM_FALLBACK ,
3412+ ) ;
33973413 let prompt = prompt_engine. render_daily_summary (
33983414 & yesterday,
33993415 wm_config. daily_summary_max_words ,
@@ -4614,22 +4630,24 @@ async fn fetch_memories_for_association(
46144630mod tests {
46154631 use super :: {
46164632 BULLETIN_REFRESH_CIRCUIT_OPEN_SECS , BULLETIN_REFRESH_CIRCUIT_OPEN_THRESHOLD , BranchTracker ,
4617- BulletinRefreshOutcome , CortexReceiverOutcome , GatheredSections , HealthRuntimeState ,
4618- MAINTENANCE_TASK_CANCEL_GRACE_SECS , MaintenanceTimeoutAction , ReceiverClosedBehavior ,
4619- Signal , SynthesisTaskBackoff , WorkerTracker , apply_cancelled_warmup_status,
4620- build_kill_targets, claim_detached_completion, collect_synthesis_task,
4621- detached_timeout_transition, handle_cortex_receiver_result, has_completed_initial_warmup,
4622- is_cancelled_control_result, is_terminal_control_result, maintenance_task_timeout,
4623- maintenance_timeout_action, mark_knowledge_synthesis_version_complete,
4624- maybe_close_bulletin_refresh_circuit, maybe_generate_bulletin_under_lock,
4625- maybe_spawn_synthesis_task, parse_structured_success_flag, push_signal_into_buffer,
4626- record_bulletin_refresh_failure, should_execute_warmup,
4633+ BulletinRefreshOutcome , CORTEX_INTRADAY_SYNTHESIS_SYSTEM_FALLBACK , CortexReceiverOutcome ,
4634+ GatheredSections , HealthRuntimeState , MAINTENANCE_TASK_CANCEL_GRACE_SECS ,
4635+ MaintenanceTimeoutAction , ReceiverClosedBehavior , Signal , SynthesisTaskBackoff ,
4636+ WorkerTracker , apply_cancelled_warmup_status, build_kill_targets,
4637+ claim_detached_completion, collect_synthesis_task, detached_timeout_transition,
4638+ handle_cortex_receiver_result, has_completed_initial_warmup, is_cancelled_control_result,
4639+ is_terminal_control_result, maintenance_task_timeout, maintenance_timeout_action,
4640+ mark_knowledge_synthesis_version_complete, maybe_close_bulletin_refresh_circuit,
4641+ maybe_generate_bulletin_under_lock, maybe_spawn_synthesis_task,
4642+ parse_structured_success_flag, push_signal_into_buffer, record_bulletin_refresh_failure,
4643+ render_static_prompt_or_fallback, should_execute_warmup,
46274644 should_generate_bulletin_from_bulletin_loop, signal_from_event, summarize_signal_text,
46284645 take_lagged_control_flag,
46294646 } ;
46304647 use crate :: ProcessEvent ;
46314648 use crate :: agent:: process_control:: ControlActionResult ;
46324649 use crate :: memory:: MemoryType ;
4650+ use crate :: prompts:: engine:: PromptEngine ;
46334651 use crate :: tasks:: TaskStatus ;
46344652 use crate :: tasks:: TaskStore ;
46354653 use futures:: FutureExt ;
@@ -4660,6 +4678,19 @@ mod tests {
46604678 assert ! ( should_execute_warmup( warmup_config, true ) ) ;
46614679 }
46624680
4681+ #[ test]
4682+ fn static_cortex_prompt_fallback_keeps_synthesis_running_when_template_fails ( ) {
4683+ let prompt_engine = PromptEngine :: new ( "en" ) . expect ( "prompt engine should build" ) ;
4684+
4685+ let prompt = render_static_prompt_or_fallback (
4686+ & prompt_engine,
4687+ "missing_cortex_synthesis_template" ,
4688+ CORTEX_INTRADAY_SYNTHESIS_SYSTEM_FALLBACK ,
4689+ ) ;
4690+
4691+ assert_eq ! ( prompt, CORTEX_INTRADAY_SYNTHESIS_SYSTEM_FALLBACK ) ;
4692+ }
4693+
46634694 #[ test]
46644695 fn run_warmup_once_semantics_enabled_runs_without_force ( ) {
46654696 let warmup_config = crate :: config:: WarmupConfig {
0 commit comments