Skip to main content

vtcode_core/prompts/
runtime_contract.rs

1use 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}