610
format!("{}\n\n{session_context}", system_prompt_for_model(true))
611
}
612
613
+/// `base` followed by the session context for the directory sigit was launched
614
+/// in. The terminal UI has no ACP session to carry a cwd, so it uses this for
615
+/// every system prompt it builds. Without the working directory the model has no
616
+/// idea where the project is, and a small on-device model will happily invent
617
+/// one (`/path/to/repo/AGENTS.md` on `/init`).
618
+#[cfg(unix)]
619
+pub(crate) fn with_launch_context(base: &str) -> String {
620
+ match std::env::current_dir() {
621
+ Ok(cwd) => format!(
622
+ "{base}\n\n{}",
623
+ session_context_message(&cwd, &workspace::additional_roots())
624
+ ),
625
+ Err(_) => base.to_string(),
626
+ }
627
+}
628
+
629
fn session_context_message(cwd: &std::path::Path, additional_roots: &[PathBuf]) -> String {
630
let mut message = if additional_roots.is_empty() {
631
format!(
4082
// channel so the loading-phase plumbing in `chat::run_with` is unchanged.
4083
let (load_tx, load_rx) = std::sync::mpsc::channel::<Result<(), String>>();
4084
4069
- // Project instruction files (AGENTS.md / CLAUDE.md) for the launch directory,
4070
- // injected into the system prompt so the TUI shares the same always-on
4071
- // project context the ACP sessions get.
4072
- let project_instructions = std::env::current_dir()
4073
- .ok()
4074
- .and_then(|cwd| instructions::load_project_instructions(&cwd));
4075
- let with_instructions = |base: String| match &project_instructions {
4076
- Some(extra) => format!("{base}\n\n{extra}"),
4077
- None => base,
4078
- };
4085
+ // The launch directory and its project instruction files, injected into the
4086
+ // system prompt so the TUI shares the same always-on project context the
4087
+ // ACP sessions get.
4088
+ let with_instructions = |base: String| with_launch_context(&base);
4089
4090
// Pick the inference backend: a configured provider if present, else on-device.
4091
let (inference_backend, startup_model_name): (Arc<dyn InferenceBackend>, String) =
4916
assert!(multi.contains("absolute paths"));
4917
}
4918
4919
+ #[cfg(unix)]
4920
+ #[test]
4921
+ fn launch_context_tells_the_tui_model_where_the_project_is() {
4922
+ // The TUI has no ACP session carrying a cwd; without this the model
4923
+ // guesses paths like `/path/to/repo/AGENTS.md`. Only assert on the
4924
+ // guidance, not the path: the cwd is process-global and other tests
4925
+ // move it briefly.
4926
+ let prompt = with_launch_context("BASE PROMPT");
4927
+ assert!(prompt.starts_with("BASE PROMPT\n\n"));
4928
+ assert!(prompt.contains("absolute paths"));
4929
+ }
4930
+
4931
#[test]
4932
fn history_replay_redraws_the_conversation_for_the_client() {
4933
// A fixed path, not `std::env::current_dir()`: the cwd is process-global