@@ -8,11 +8,10 @@ use crate::protocol::AskForApproval;
8
8
use crate :: protocol:: SandboxPolicy ;
9
9
use crate :: shell:: Shell ;
10
10
use codex_protocol:: config_types:: SandboxMode ;
11
- use std:: fmt:: Display ;
12
11
use std:: path:: PathBuf ;
13
12
14
13
/// wraps environment context message in a tag for the model to parse more easily.
15
- pub ( crate ) const ENVIRONMENT_CONTEXT_START : & str = "<environment_context>\n " ;
14
+ pub ( crate ) const ENVIRONMENT_CONTEXT_START : & str = "<environment_context>" ;
16
15
pub ( crate ) const ENVIRONMENT_CONTEXT_END : & str = "</environment_context>" ;
17
16
18
17
#[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , DeriveDisplay ) ]
@@ -25,58 +24,87 @@ pub enum NetworkAccess {
25
24
#[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
26
25
#[ serde( rename = "environment_context" , rename_all = "snake_case" ) ]
27
26
pub ( crate ) struct EnvironmentContext {
28
- pub cwd : PathBuf ,
29
- pub approval_policy : AskForApproval ,
30
- pub sandbox_mode : SandboxMode ,
31
- pub network_access : NetworkAccess ,
32
- pub shell : Shell ,
27
+ pub cwd : Option < PathBuf > ,
28
+ pub approval_policy : Option < AskForApproval > ,
29
+ pub sandbox_mode : Option < SandboxMode > ,
30
+ pub network_access : Option < NetworkAccess > ,
31
+ pub shell : Option < Shell > ,
33
32
}
34
33
35
34
impl EnvironmentContext {
36
35
pub fn new (
37
- cwd : PathBuf ,
38
- approval_policy : AskForApproval ,
39
- sandbox_policy : SandboxPolicy ,
40
- shell : Shell ,
36
+ cwd : Option < PathBuf > ,
37
+ approval_policy : Option < AskForApproval > ,
38
+ sandbox_policy : Option < SandboxPolicy > ,
39
+ shell : Option < Shell > ,
41
40
) -> Self {
42
41
Self {
43
42
cwd,
44
43
approval_policy,
45
44
sandbox_mode : match sandbox_policy {
46
- SandboxPolicy :: DangerFullAccess => SandboxMode :: DangerFullAccess ,
47
- SandboxPolicy :: ReadOnly => SandboxMode :: ReadOnly ,
48
- SandboxPolicy :: WorkspaceWrite { .. } => SandboxMode :: WorkspaceWrite ,
45
+ Some ( SandboxPolicy :: DangerFullAccess ) => Some ( SandboxMode :: DangerFullAccess ) ,
46
+ Some ( SandboxPolicy :: ReadOnly ) => Some ( SandboxMode :: ReadOnly ) ,
47
+ Some ( SandboxPolicy :: WorkspaceWrite { .. } ) => Some ( SandboxMode :: WorkspaceWrite ) ,
48
+ None => None ,
49
49
} ,
50
50
network_access : match sandbox_policy {
51
- SandboxPolicy :: DangerFullAccess => NetworkAccess :: Enabled ,
52
- SandboxPolicy :: ReadOnly => NetworkAccess :: Restricted ,
53
- SandboxPolicy :: WorkspaceWrite { network_access, .. } => {
51
+ Some ( SandboxPolicy :: DangerFullAccess ) => Some ( NetworkAccess :: Enabled ) ,
52
+ Some ( SandboxPolicy :: ReadOnly ) => Some ( NetworkAccess :: Restricted ) ,
53
+ Some ( SandboxPolicy :: WorkspaceWrite { network_access, .. } ) => {
54
54
if network_access {
55
- NetworkAccess :: Enabled
55
+ Some ( NetworkAccess :: Enabled )
56
56
} else {
57
- NetworkAccess :: Restricted
57
+ Some ( NetworkAccess :: Restricted )
58
58
}
59
59
}
60
+ None => None ,
60
61
} ,
61
62
shell,
62
63
}
63
64
}
64
65
}
65
66
66
- impl Display for EnvironmentContext {
67
- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
68
- writeln ! (
69
- f,
70
- "Current working directory: {}" ,
71
- self . cwd. to_string_lossy( )
72
- ) ?;
73
- writeln ! ( f, "Approval policy: {}" , self . approval_policy) ?;
74
- writeln ! ( f, "Sandbox mode: {}" , self . sandbox_mode) ?;
75
- writeln ! ( f, "Network access: {}" , self . network_access) ?;
76
- if let Some ( shell_name) = self . shell . name ( ) {
77
- writeln ! ( f, "Shell: {shell_name}" ) ?;
67
+ impl EnvironmentContext {
68
+ /// Serializes the environment context to XML. Libraries like `quick-xml`
69
+ /// require custom macros to handle Enums with newtypes, so we just do it
70
+ /// manually, to keep things simple. Output looks like:
71
+ ///
72
+ /// ```xml
73
+ /// <environment_context>
74
+ /// <cwd>...</cwd>
75
+ /// <approval_policy>...</approval_policy>
76
+ /// <sandbox_mode>...</sandbox_mode>
77
+ /// <network_access>...</network_access>
78
+ /// <shell>...</shell>
79
+ /// </environment_context>
80
+ /// ```
81
+ pub fn serialize_to_xml ( self ) -> String {
82
+ let mut lines = vec ! [ ENVIRONMENT_CONTEXT_START . to_string( ) ] ;
83
+ if let Some ( cwd) = self . cwd {
84
+ lines. push ( format ! ( " <cwd>{}</cwd>" , cwd. to_string_lossy( ) ) ) ;
85
+ }
86
+ if let Some ( approval_policy) = self . approval_policy {
87
+ lines. push ( format ! (
88
+ " <approval_policy>{}</approval_policy>" ,
89
+ approval_policy
90
+ ) ) ;
91
+ }
92
+ if let Some ( sandbox_mode) = self . sandbox_mode {
93
+ lines. push ( format ! ( " <sandbox_mode>{}</sandbox_mode>" , sandbox_mode) ) ;
94
+ }
95
+ if let Some ( network_access) = self . network_access {
96
+ lines. push ( format ! (
97
+ " <network_access>{}</network_access>" ,
98
+ network_access
99
+ ) ) ;
100
+ }
101
+ if let Some ( shell) = self . shell
102
+ && let Some ( shell_name) = shell. name ( )
103
+ {
104
+ lines. push ( format ! ( " <shell>{}</shell>" , shell_name) ) ;
78
105
}
79
- Ok ( ( ) )
106
+ lines. push ( ENVIRONMENT_CONTEXT_END . to_string ( ) ) ;
107
+ lines. join ( "\n " )
80
108
}
81
109
}
82
110
@@ -86,7 +114,7 @@ impl From<EnvironmentContext> for ResponseItem {
86
114
id : None ,
87
115
role : "user" . to_string ( ) ,
88
116
content : vec ! [ ContentItem :: InputText {
89
- text: format! ( "{ENVIRONMENT_CONTEXT_START}{ec}{ENVIRONMENT_CONTEXT_END}" ) ,
117
+ text: ec . serialize_to_xml ( ) ,
90
118
} ] ,
91
119
}
92
120
}
0 commit comments