diff --git a/crates/colibri-client/tests/live_socket_smoke.rs b/crates/colibri-client/tests/live_socket_smoke.rs index 7130865..56e1681 100644 --- a/crates/colibri-client/tests/live_socket_smoke.rs +++ b/crates/colibri-client/tests/live_socket_smoke.rs @@ -27,6 +27,7 @@ fn smoke_config() -> DaemonConfig { max_context_tokens: 128_000, max_uncompacted_turns: 20, cost_mode: "smart".to_string(), + scheduler_prompt_injection: false, } } diff --git a/crates/colibri-daemon/src/config.rs b/crates/colibri-daemon/src/config.rs index fb52e35..647ed7c 100644 --- a/crates/colibri-daemon/src/config.rs +++ b/crates/colibri-daemon/src/config.rs @@ -43,6 +43,9 @@ pub struct DaemonConfig { pub max_uncompacted_turns: usize, /// Current cost mode (fast/smart/max). pub cost_mode: String, + /// Inject session prompt context into spawned agent env (T1.4 PR3a). + /// Disabled by default — enable when prompt discipline is verified. + pub scheduler_prompt_injection: bool, } impl DaemonConfig { @@ -86,6 +89,8 @@ impl DaemonConfig { max_context_tokens: env_parse("COLIBRI_MAX_CONTEXT_TOKENS").unwrap_or(128_000), max_uncompacted_turns: env_parse("COLIBRI_MAX_UNCOMPACTED_TURNS").unwrap_or(20), cost_mode: std::env::var("COLIBRI_COST_MODE").unwrap_or_else(|_| "smart".to_string()), + scheduler_prompt_injection: env_parse("COLIBRI_SCHEDULER_PROMPT_INJECTION") + .unwrap_or(false), } } } diff --git a/crates/colibri-daemon/src/scheduler.rs b/crates/colibri-daemon/src/scheduler.rs index 25a2fa2..29f44da 100644 --- a/crates/colibri-daemon/src/scheduler.rs +++ b/crates/colibri-daemon/src/scheduler.rs @@ -360,6 +360,7 @@ mod tests { max_context_tokens: 128_000, max_uncompacted_turns: 20, cost_mode: "smart".to_string(), + scheduler_prompt_injection: true, } } diff --git a/crates/colibri-daemon/src/socket.rs b/crates/colibri-daemon/src/socket.rs index a748db6..5b93d07 100644 --- a/crates/colibri-daemon/src/socket.rs +++ b/crates/colibri-daemon/src/socket.rs @@ -9,6 +9,8 @@ use std::time::SystemTime; +use std::collections::HashMap; + use colibri_glasspane::DEFAULT_STALL_AFTER; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::net::{UnixListener, UnixStream}; @@ -310,11 +312,41 @@ async fn cmd_spawn_agent( args, provider, model, - session_id, + session_id: session_id.clone(), system_prompt, ..Default::default() }; + // T1.4 PR3a: inject session prompt context as env var when enabled + let mut extra_env = HashMap::new(); + if state.config.scheduler_prompt_injection { + if let Some(ref sid) = session_id { + if let Some(session) = state.sessions.get(sid) { + let assembly = session.value().build_prompt_assembly().await; + let cost_mode = + crate::cost::CostMode::parse(&state.config.cost_mode).unwrap_or_default(); + let _ = assembly; // trimmed context available for injection + let context_json = + serde_json::to_string(&assembly.to_messages()).unwrap_or_default(); + extra_env.insert("COLIBRI_SESSION_CONTEXT".to_string(), context_json); + extra_env.insert( + "COLIBRI_COST_MODE".to_string(), + cost_mode.as_str().to_string(), + ); + info!( + session_id = %sid, + context_bytes = assembly.total_bytes, + cost_mode = cost_mode.as_str(), + "injected session prompt context" + ); + } + } + } + + // Merge extra env into agent config + let mut agent_config = agent_config; + agent_config.env.extend(extra_env); + let spawner = Spawner::new(state.config.clone().into()); match spawner.spawn(agent_config).await { Ok(handle) => { @@ -605,6 +637,7 @@ mod tests { max_context_tokens: 128_000, max_uncompacted_turns: 20, cost_mode: "smart".to_string(), + scheduler_prompt_injection: true, } }