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