winx_code_agent/utils/
orchestration.rs1use std::fmt::Write as _;
2
3const DEFAULT_INSTRUCTIONS: &str = concat!(
4 "Initialize Winx once for the intended workspace. Treat structuredContent.status as ",
5 "authoritative. Never repeat a failed tool call unchanged: execute next_action and every ",
6 "required_read first. Keep the exact thread_id/workspace_root pair for the user's current ",
7 "project; never borrow one from another chat. workspace_root identifies the session, not a ",
8 "path sandbox: allowed absolute targets outside it do not require rebinding. If Initialize ",
9 "reports initialize_workspace_already_bound or workspace_change_requires_new_session, do not ",
10 "call Initialize again in that conversation. Use CodeMap with a concise query to locate code, ",
11 "then batch ReadFiles for exact text. Read targets before editing; use MultiFileEdit for atomic ",
12 "cross-file changes. Combine related finite checks with && or edit verify_command. For ",
13 "BashCommand, follow next_action only while status is running and never auto-approve a prompt ",
14 "that changes permissions, data, or system state. Use ReadFiles for unsupported CodeMap ",
15 "languages; never transform source solely to make CodeMap parse it. Put useful derived helpers ",
16 "only in the temporary_artifact_dir returned by Initialize (exported as WINX_TEMP_DIR). Keep ",
17 "a small stable set: overwrite or reuse the same descriptive helper per purpose, retain ",
18 "source-path/line provenance, remove obsolete files, and treat helpers as non-canonical. Never turn ",
19 "command, lint, test, or search output into a parseable carrier merely to call CodeMap. CodeMap ",
20 "on helpers accepts only an existing single file and has a smaller aggregate session budget; ",
21 "canonical source maps remain available. Never encode payload in names or create .winx-* or ",
22 ".winx_tmp artifacts at the project root."
23);
24
25const DISALLOW_INSTRUCTION: &str = "As soon as you encounter \"The user has chosen to disallow the tool call.\", immediately stop doing everything and ask the user for the reason.";
26
27pub fn server_instructions() -> String {
31 let mut instructions = format!("{DEFAULT_INSTRUCTIONS}\n\n{DISALLOW_INSTRUCTION}");
32 if let Some(extra) = crate::config::env_text("WINX_SERVER_INSTRUCTIONS") {
33 let _ = write!(instructions, "\n\nOperator instructions:\n{extra}");
34 }
35 instructions
36}
37
38pub fn append_initialize_instructions(response: &mut String) {
41 let _ = write!(response, "\n# Winx orchestration contract\n{}\n", server_instructions());
42}
43
44#[cfg(test)]
45mod tests {
46 use super::server_instructions;
47
48 #[test]
49 fn default_contract_names_structured_recovery_before_optional_operator_text() {
50 let instructions = server_instructions();
51 let prefix = instructions.chars().take(512).collect::<String>();
52 assert!(prefix.contains("structuredContent.status"));
53 assert!(prefix.contains("Never repeat a failed tool call unchanged"));
54 assert!(prefix.contains("required_read"));
55 assert!(prefix.contains("thread_id/workspace_root pair"));
56 assert!(prefix.contains("user's current project"));
57 assert!(prefix.contains("not a path sandbox"));
58 }
59
60 #[test]
61 fn default_contract_keeps_agent_artifacts_coherent() {
62 let instructions = server_instructions();
63 assert!(instructions.contains("never transform source solely"));
64 assert!(instructions.contains("Use ReadFiles"));
65 assert!(instructions.contains("temporary_artifact_dir returned by Initialize"));
66 assert!(instructions.contains("exported as WINX_TEMP_DIR"));
67 assert!(instructions.contains("helpers as non-canonical"));
68 assert!(instructions.contains("overwrite or reuse the same descriptive helper"));
69 assert!(instructions.contains("merely to call CodeMap"));
70 assert!(instructions.contains("existing single file"));
71 assert!(instructions.contains("Never encode payload in names"));
72 assert!(instructions.contains(".winx-* or .winx_tmp artifacts"));
73 }
74
75 #[test]
76 fn default_contract_stops_terminal_initialize_retries() {
77 let instructions = server_instructions();
78 assert!(instructions.contains("initialize_workspace_already_bound"));
79 assert!(instructions.contains("workspace_change_requires_new_session"));
80 assert!(instructions.contains("do not call Initialize again"));
81 assert!(instructions.contains("allowed absolute targets outside it"));
82 }
83}