vtcode_core/prompts/
runtime_contract.rs1use std::fmt::Write as _;
2
3use super::system::{
4 PLAN_MODE_EXIT_INSTRUCTION_LINE, PLAN_MODE_INTERVIEW_POLICY_LINE, PLAN_MODE_NO_AUTO_EXIT_LINE,
5 PLAN_MODE_NO_REQUEST_USER_INPUT_POLICY_LINE, PLAN_MODE_PLAN_QUALITY_LINE,
6 PLAN_MODE_READ_ONLY_HEADER, PLAN_MODE_READ_ONLY_NOTICE_LINE, PLAN_MODE_TASK_TRACKER_LINE,
7};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub struct RuntimePromptContract {
11 pub full_auto: bool,
12 pub plan_mode: bool,
13 pub request_user_input_enabled: bool,
14}
15
16pub fn append_runtime_mode_sections(prompt: &mut String, contract: RuntimePromptContract) {
17 if contract.full_auto {
18 append_full_auto_notice(prompt, contract);
19 }
20
21 if contract.plan_mode {
22 append_plan_mode_notice(prompt, contract.request_user_input_enabled);
23 }
24}
25
26fn append_full_auto_notice(prompt: &mut String, contract: RuntimePromptContract) {
27 let header = if contract.plan_mode {
28 "# FULL-AUTO (PLAN MODE): Work autonomously within Plan Mode constraints."
29 } else {
30 "# FULL-AUTO: Complete task autonomously until done or blocked."
31 };
32
33 if prompt.contains(header) {
34 return;
35 }
36
37 let _ = writeln!(prompt, "\n{header}");
38 let _ = writeln!(
39 prompt,
40 "- Stay within the exposed tool list and adapt when a tool is unavailable or denied."
41 );
42 let _ = writeln!(
43 prompt,
44 "- Treat completion language as a checkpoint, not proof; only stop when `task_tracker`, verification, and resumable state agree."
45 );
46 if !contract.request_user_input_enabled {
47 let _ = writeln!(
48 prompt,
49 "- `request_user_input` is unavailable in this runtime; make reasonable assumptions and continue with the available context."
50 );
51 }
52}
53
54fn append_plan_mode_notice(prompt: &mut String, request_user_input_enabled: bool) {
55 if prompt.contains(PLAN_MODE_READ_ONLY_HEADER) {
56 return;
57 }
58
59 prompt.push('\n');
60 prompt.push_str(PLAN_MODE_READ_ONLY_HEADER);
61 prompt.push('\n');
62 prompt.push_str(PLAN_MODE_READ_ONLY_NOTICE_LINE);
63 prompt.push('\n');
64 prompt.push_str(PLAN_MODE_EXIT_INSTRUCTION_LINE);
65 prompt.push('\n');
66 prompt.push_str(PLAN_MODE_PLAN_QUALITY_LINE);
67 prompt.push('\n');
68 prompt.push_str(if request_user_input_enabled {
69 PLAN_MODE_INTERVIEW_POLICY_LINE
70 } else {
71 PLAN_MODE_NO_REQUEST_USER_INPUT_POLICY_LINE
72 });
73 prompt.push('\n');
74 prompt.push_str(PLAN_MODE_NO_AUTO_EXIT_LINE);
75 prompt.push('\n');
76 prompt.push_str(PLAN_MODE_TASK_TRACKER_LINE);
77 prompt.push('\n');
78}
79
80#[cfg(test)]
81mod tests {
82 use super::{RuntimePromptContract, append_runtime_mode_sections};
83 use crate::prompts::system::{
84 PLAN_MODE_INTERVIEW_POLICY_LINE, PLAN_MODE_NO_REQUEST_USER_INPUT_POLICY_LINE,
85 PLAN_MODE_READ_ONLY_HEADER,
86 };
87
88 #[test]
89 fn plan_mode_uses_interview_policy_when_request_user_input_is_enabled() {
90 let mut prompt = "Base prompt".to_string();
91
92 append_runtime_mode_sections(
93 &mut prompt,
94 RuntimePromptContract {
95 plan_mode: true,
96 request_user_input_enabled: true,
97 ..RuntimePromptContract::default()
98 },
99 );
100
101 assert!(prompt.contains(PLAN_MODE_READ_ONLY_HEADER));
102 assert!(prompt.contains(PLAN_MODE_INTERVIEW_POLICY_LINE));
103 assert!(!prompt.contains(PLAN_MODE_NO_REQUEST_USER_INPUT_POLICY_LINE));
104 }
105
106 #[test]
107 fn plan_mode_uses_noninteractive_policy_when_request_user_input_is_disabled() {
108 let mut prompt = "Base prompt".to_string();
109
110 append_runtime_mode_sections(
111 &mut prompt,
112 RuntimePromptContract {
113 plan_mode: true,
114 request_user_input_enabled: false,
115 ..RuntimePromptContract::default()
116 },
117 );
118
119 assert!(prompt.contains(PLAN_MODE_READ_ONLY_HEADER));
120 assert!(prompt.contains(PLAN_MODE_NO_REQUEST_USER_INPUT_POLICY_LINE));
121 assert!(!prompt.contains(PLAN_MODE_INTERVIEW_POLICY_LINE));
122 }
123
124 #[test]
125 fn full_auto_notice_mentions_missing_request_user_input_when_disabled() {
126 let mut prompt = "Base prompt".to_string();
127
128 append_runtime_mode_sections(
129 &mut prompt,
130 RuntimePromptContract {
131 full_auto: true,
132 request_user_input_enabled: false,
133 ..RuntimePromptContract::default()
134 },
135 );
136
137 assert!(prompt.contains("# FULL-AUTO: Complete task autonomously until done or blocked."));
138 assert!(prompt.contains("`request_user_input` is unavailable in this runtime"));
139 assert!(prompt.contains("completion language as a checkpoint"));
140 }
141}