feat: add local date/timezone to turn environment context (#12947)

## Summary

This PR includes the session's local date and timezone in the
model-visible environment context and persists that data in
`TurnContextItem`.

  ## What changed
- captures the current local date and IANA timezone when building a turn
context, with a UTC fallback if the timezone lookup fails
- includes current_date and timezone in the serialized
<environment_context> payload
- stores those fields on TurnContextItem so they survive rollout/history
handling, subagent review threads, and resume flows
- treats date/timezone changes as environment updates, so prompt caching
and context refresh logic do not silently reuse stale time context
- updates tests to validate the new environment fields without depending
on a single hardcoded environment-context string

## test

built a local build and saw it in the rollout file:
```
{"timestamp":"2026-02-26T21:39:50.737Z","type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"<environment_context>\n  <shell>zsh</shell>\n  <current_date>2026-02-26</current_date>\n  <timezone>America/Los_Angeles</timezone>\n</environment_context>"}]}}
```
This commit is contained in:
Celia Chen 2026-02-26 15:17:35 -08:00 committed by GitHub
parent 4cb086d96f
commit 90cc4e79a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 288 additions and 47 deletions

1
codex-rs/Cargo.lock generated
View file

@ -1791,6 +1791,7 @@ dependencies = [
"eventsource-stream",
"futures",
"http 1.4.0",
"iana-time-zone",
"image",
"indexmap 2.13.0",
"insta",

View file

@ -186,6 +186,7 @@ icu_locale_core = "2.1"
icu_provider = { version = "2.1", features = ["sync"] }
ignore = "0.4.23"
image = { version = "^0.25.9", default-features = false }
iana-time-zone = "0.1.64"
include_dir = "0.7.4"
indexmap = "2.12.0"
insta = "1.46.3"

View file

@ -620,6 +620,8 @@ fn append_rollout_turn_context(path: &Path, timestamp: &str, model: &str) -> std
item: RolloutItem::TurnContext(TurnContextItem {
turn_id: None,
cwd: PathBuf::from("/"),
current_date: None,
timezone: None,
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::DangerFullAccess,
network: None,

View file

@ -61,6 +61,7 @@ env-flags = { workspace = true }
eventsource-stream = { workspace = true }
futures = { workspace = true }
http = { workspace = true }
iana-time-zone = { workspace = true }
indexmap = { workspace = true }
keyring = { workspace = true, features = ["crypto-rust"] }
libc = { workspace = true }

View file

@ -53,6 +53,8 @@ use crate::util::error_or_panic;
use crate::ws_version_from_features;
use async_channel::Receiver;
use async_channel::Sender;
use chrono::Local;
use chrono::Utc;
use codex_hooks::HookEvent;
use codex_hooks::HookEventAfterAgent;
use codex_hooks::HookPayload;
@ -595,6 +597,8 @@ pub(crate) struct TurnContext {
/// the model as well as sandbox policies are resolved against this path
/// instead of `std::env::current_dir()`.
pub(crate) cwd: PathBuf,
pub(crate) current_date: Option<String>,
pub(crate) timezone: Option<String>,
pub(crate) developer_instructions: Option<String>,
pub(crate) compact_prompt: Option<String>,
pub(crate) user_instructions: Option<String>,
@ -679,6 +683,8 @@ impl TurnContext {
reasoning_summary: self.reasoning_summary,
session_source: self.session_source.clone(),
cwd: self.cwd.clone(),
current_date: self.current_date.clone(),
timezone: self.timezone.clone(),
developer_instructions: self.developer_instructions.clone(),
compact_prompt: self.compact_prompt.clone(),
user_instructions: self.user_instructions.clone(),
@ -719,6 +725,8 @@ impl TurnContext {
TurnContextItem {
turn_id: Some(self.sub_id.clone()),
cwd: self.cwd.clone(),
current_date: self.current_date.clone(),
timezone: self.timezone.clone(),
approval_policy: self.approval_policy.value(),
sandbox_policy: self.sandbox_policy.get().clone(),
network: self.turn_context_network_item(),
@ -748,6 +756,16 @@ impl TurnContext {
}
}
fn local_time_context() -> (String, String) {
match iana_time_zone::get_timezone() {
Ok(timezone) => (Local::now().format("%Y-%m-%d").to_string(), timezone),
Err(_) => (
Utc::now().format("%Y-%m-%d").to_string(),
"Etc/UTC".to_string(),
),
}
}
#[derive(Clone)]
pub(crate) struct SessionConfiguration {
/// Provider identifier ("openai", "openrouter", ...).
@ -1017,6 +1035,7 @@ impl Session {
.features
.enabled(Feature::UseLinuxSandboxBwrap),
));
let (current_date, timezone) = local_time_context();
TurnContext {
sub_id,
config: per_turn_config.clone(),
@ -1028,6 +1047,8 @@ impl Session {
reasoning_summary,
session_source,
cwd,
current_date: Some(current_date),
timezone: Some(timezone),
developer_instructions: session_configuration.developer_instructions.clone(),
compact_prompt: session_configuration.compact_prompt.clone(),
user_instructions: session_configuration.user_instructions.clone(),
@ -4676,6 +4697,8 @@ async fn spawn_review_thread(
tools_config,
features: parent_turn_context.features.clone(),
ghost_snapshot: parent_turn_context.ghost_snapshot.clone(),
current_date: parent_turn_context.current_date.clone(),
timezone: parent_turn_context.timezone.clone(),
developer_instructions: None,
user_instructions: None,
compact_prompt: parent_turn_context.compact_prompt.clone(),
@ -7259,6 +7282,8 @@ mod tests {
let previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
cwd: turn_context.cwd.clone(),
current_date: turn_context.current_date.clone(),
timezone: turn_context.timezone.clone(),
approval_policy: turn_context.approval_policy.value(),
sandbox_policy: turn_context.sandbox_policy.get().clone(),
network: None,
@ -7296,6 +7321,8 @@ mod tests {
let mut previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
cwd: turn_context.cwd.clone(),
current_date: turn_context.current_date.clone(),
timezone: turn_context.timezone.clone(),
approval_policy: turn_context.approval_policy.value(),
sandbox_policy: turn_context.sandbox_policy.get().clone(),
network: None,
@ -7490,7 +7517,10 @@ mod tests {
.record_context_updates_and_set_reference_context_item(&turn_context, None)
.await;
let history_after_second_seed = session.clone_history().await;
assert_eq!(expected, history_after_second_seed.raw_items());
assert_eq!(
history_after_seed.raw_items(),
history_after_second_seed.raw_items()
);
}
#[tokio::test]
@ -7658,6 +7688,8 @@ mod tests {
let previous_context_item = TurnContextItem {
turn_id: Some(turn_context.sub_id.clone()),
cwd: turn_context.cwd.clone(),
current_date: turn_context.current_date.clone(),
timezone: turn_context.timezone.clone(),
approval_policy: turn_context.approval_policy.value(),
sandbox_policy: turn_context.sandbox_policy.get().clone(),
network: None,
@ -8823,6 +8855,42 @@ mod tests {
assert!(environment_update.contains("<denied>blocked.example.com</denied>"));
}
#[tokio::test]
async fn build_settings_update_items_emits_environment_item_for_time_changes() {
let (session, previous_context) = make_session_and_context().await;
let previous_context = Arc::new(previous_context);
let mut current_context = previous_context
.with_model(
previous_context.model_info.slug.clone(),
&session.services.models_manager,
)
.await;
current_context.current_date = Some("2026-02-27".to_string());
current_context.timezone = Some("Europe/Berlin".to_string());
let reference_context_item = previous_context.to_turn_context_item();
let update_items = session.build_settings_update_items(
Some(&reference_context_item),
None,
&current_context,
);
let environment_update = update_items
.iter()
.find_map(|item| match item {
ResponseItem::Message { role, content, .. } if role == "user" => {
let [ContentItem::InputText { text }] = content.as_slice() else {
return None;
};
text.contains("<environment_context>").then_some(text)
}
_ => None,
})
.expect("environment update item should be emitted");
assert!(environment_update.contains("<current_date>2026-02-27</current_date>"));
assert!(environment_update.contains("<timezone>Europe/Berlin</timezone>"));
}
#[tokio::test]
async fn record_context_updates_and_set_reference_context_item_injects_full_context_when_baseline_missing()
{

View file

@ -13,6 +13,8 @@ use std::path::PathBuf;
pub(crate) struct EnvironmentContext {
pub cwd: Option<PathBuf>,
pub shell: Shell,
pub current_date: Option<String>,
pub timezone: Option<String>,
pub network: Option<NetworkContext>,
pub subagents: Option<String>,
}
@ -27,12 +29,16 @@ impl EnvironmentContext {
pub fn new(
cwd: Option<PathBuf>,
shell: Shell,
current_date: Option<String>,
timezone: Option<String>,
network: Option<NetworkContext>,
subagents: Option<String>,
) -> Self {
Self {
cwd,
shell,
current_date,
timezone,
network,
subagents,
}
@ -44,11 +50,17 @@ impl EnvironmentContext {
pub fn equals_except_shell(&self, other: &EnvironmentContext) -> bool {
let EnvironmentContext {
cwd,
current_date,
timezone,
network,
subagents,
shell: _,
} = other;
self.cwd == *cwd && self.network == *network && self.subagents == *subagents
self.cwd == *cwd
&& self.current_date == *current_date
&& self.timezone == *timezone
&& self.network == *network
&& self.subagents == *subagents
}
pub fn diff_from_turn_context_item(
@ -63,18 +75,22 @@ impl EnvironmentContext {
} else {
None
};
let current_date = after.current_date.clone();
let timezone = after.timezone.clone();
let network = if before_network != after_network {
after_network
} else {
before_network
};
EnvironmentContext::new(cwd, shell.clone(), network, None)
EnvironmentContext::new(cwd, shell.clone(), current_date, timezone, network, None)
}
pub fn from_turn_context(turn_context: &TurnContext, shell: &Shell) -> Self {
Self::new(
Some(turn_context.cwd.clone()),
shell.clone(),
turn_context.current_date.clone(),
turn_context.timezone.clone(),
Self::network_from_turn_context(turn_context),
None,
)
@ -84,6 +100,8 @@ impl EnvironmentContext {
Self::new(
Some(turn_context_item.cwd.clone()),
shell.clone(),
turn_context_item.current_date.clone(),
turn_context_item.timezone.clone(),
Self::network_from_turn_context_item(turn_context_item),
None,
)
@ -143,6 +161,12 @@ impl EnvironmentContext {
let shell_name = self.shell.name();
lines.push(format!(" <shell>{shell_name}</shell>"));
if let Some(current_date) = self.current_date {
lines.push(format!(" <current_date>{current_date}</current_date>"));
}
if let Some(timezone) = self.timezone {
lines.push(format!(" <timezone>{timezone}</timezone>"));
}
match self.network {
Some(ref network) => {
lines.push(" <network enabled=\"true\">".to_string());
@ -193,12 +217,21 @@ mod tests {
#[test]
fn serialize_workspace_write_environment_context() {
let cwd = test_path_buf("/repo");
let context = EnvironmentContext::new(Some(cwd.clone()), fake_shell(), None, None);
let context = EnvironmentContext::new(
Some(cwd.clone()),
fake_shell(),
Some("2026-02-26".to_string()),
Some("America/Los_Angeles".to_string()),
None,
None,
);
let expected = format!(
r#"<environment_context>
<cwd>{cwd}</cwd>
<shell>bash</shell>
<current_date>2026-02-26</current_date>
<timezone>America/Los_Angeles</timezone>
</environment_context>"#,
cwd = cwd.display(),
);
@ -215,6 +248,8 @@ mod tests {
let context = EnvironmentContext::new(
Some(test_path_buf("/repo")),
fake_shell(),
Some("2026-02-26".to_string()),
Some("America/Los_Angeles".to_string()),
Some(network),
None,
);
@ -223,6 +258,8 @@ mod tests {
r#"<environment_context>
<cwd>{}</cwd>
<shell>bash</shell>
<current_date>2026-02-26</current_date>
<timezone>America/Los_Angeles</timezone>
<network enabled="true">
<allowed>api.example.com</allowed>
<allowed>*.openai.com</allowed>
@ -237,10 +274,19 @@ mod tests {
#[test]
fn serialize_read_only_environment_context() {
let context = EnvironmentContext::new(None, fake_shell(), None, None);
let context = EnvironmentContext::new(
None,
fake_shell(),
Some("2026-02-26".to_string()),
Some("America/Los_Angeles".to_string()),
None,
None,
);
let expected = r#"<environment_context>
<shell>bash</shell>
<current_date>2026-02-26</current_date>
<timezone>America/Los_Angeles</timezone>
</environment_context>"#;
assert_eq!(context.serialize_to_xml(), expected);
@ -248,10 +294,19 @@ mod tests {
#[test]
fn serialize_external_sandbox_environment_context() {
let context = EnvironmentContext::new(None, fake_shell(), None, None);
let context = EnvironmentContext::new(
None,
fake_shell(),
Some("2026-02-26".to_string()),
Some("America/Los_Angeles".to_string()),
None,
None,
);
let expected = r#"<environment_context>
<shell>bash</shell>
<current_date>2026-02-26</current_date>
<timezone>America/Los_Angeles</timezone>
</environment_context>"#;
assert_eq!(context.serialize_to_xml(), expected);
@ -259,10 +314,19 @@ mod tests {
#[test]
fn serialize_external_sandbox_with_restricted_network_environment_context() {
let context = EnvironmentContext::new(None, fake_shell(), None, None);
let context = EnvironmentContext::new(
None,
fake_shell(),
Some("2026-02-26".to_string()),
Some("America/Los_Angeles".to_string()),
None,
None,
);
let expected = r#"<environment_context>
<shell>bash</shell>
<current_date>2026-02-26</current_date>
<timezone>America/Los_Angeles</timezone>
</environment_context>"#;
assert_eq!(context.serialize_to_xml(), expected);
@ -270,10 +334,19 @@ mod tests {
#[test]
fn serialize_full_access_environment_context() {
let context = EnvironmentContext::new(None, fake_shell(), None, None);
let context = EnvironmentContext::new(
None,
fake_shell(),
Some("2026-02-26".to_string()),
Some("America/Los_Angeles".to_string()),
None,
None,
);
let expected = r#"<environment_context>
<shell>bash</shell>
<current_date>2026-02-26</current_date>
<timezone>America/Los_Angeles</timezone>
</environment_context>"#;
assert_eq!(context.serialize_to_xml(), expected);
@ -281,29 +354,65 @@ mod tests {
#[test]
fn equals_except_shell_compares_cwd() {
let context1 =
EnvironmentContext::new(Some(PathBuf::from("/repo")), fake_shell(), None, None);
let context2 =
EnvironmentContext::new(Some(PathBuf::from("/repo")), fake_shell(), None, None);
let context1 = EnvironmentContext::new(
Some(PathBuf::from("/repo")),
fake_shell(),
None,
None,
None,
None,
);
let context2 = EnvironmentContext::new(
Some(PathBuf::from("/repo")),
fake_shell(),
None,
None,
None,
None,
);
assert!(context1.equals_except_shell(&context2));
}
#[test]
fn equals_except_shell_ignores_sandbox_policy() {
let context1 =
EnvironmentContext::new(Some(PathBuf::from("/repo")), fake_shell(), None, None);
let context2 =
EnvironmentContext::new(Some(PathBuf::from("/repo")), fake_shell(), None, None);
let context1 = EnvironmentContext::new(
Some(PathBuf::from("/repo")),
fake_shell(),
None,
None,
None,
None,
);
let context2 = EnvironmentContext::new(
Some(PathBuf::from("/repo")),
fake_shell(),
None,
None,
None,
None,
);
assert!(context1.equals_except_shell(&context2));
}
#[test]
fn equals_except_shell_compares_cwd_differences() {
let context1 =
EnvironmentContext::new(Some(PathBuf::from("/repo1")), fake_shell(), None, None);
let context2 =
EnvironmentContext::new(Some(PathBuf::from("/repo2")), fake_shell(), None, None);
let context1 = EnvironmentContext::new(
Some(PathBuf::from("/repo1")),
fake_shell(),
None,
None,
None,
None,
);
let context2 = EnvironmentContext::new(
Some(PathBuf::from("/repo2")),
fake_shell(),
None,
None,
None,
None,
);
assert!(!context1.equals_except_shell(&context2));
}
@ -319,6 +428,8 @@ mod tests {
},
None,
None,
None,
None,
);
let context2 = EnvironmentContext::new(
Some(PathBuf::from("/repo")),
@ -329,6 +440,8 @@ mod tests {
},
None,
None,
None,
None,
);
assert!(context1.equals_except_shell(&context2));
@ -339,6 +452,8 @@ mod tests {
let context = EnvironmentContext::new(
Some(test_path_buf("/repo")),
fake_shell(),
Some("2026-02-26".to_string()),
Some("America/Los_Angeles".to_string()),
None,
Some("- agent-1: atlas\n- agent-2".to_string()),
);
@ -347,6 +462,8 @@ mod tests {
r#"<environment_context>
<cwd>{}</cwd>
<shell>bash</shell>
<current_date>2026-02-26</current_date>
<timezone>America/Los_Angeles</timezone>
<subagents>
- agent-1: atlas
- agent-2

View file

@ -1386,6 +1386,8 @@ mod tests {
item: RolloutItem::TurnContext(TurnContextItem {
turn_id: Some("turn-1".to_string()),
cwd: latest_cwd.clone(),
current_date: None,
timezone: None,
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
network: None,

View file

@ -44,14 +44,32 @@ fn text_user_input_parts(texts: Vec<String>) -> serde_json::Value {
})
}
fn default_env_context_str(cwd: &str, shell: &Shell) -> String {
fn assert_default_env_context(text: &str, cwd: &str, shell: &Shell) {
let shell_name = shell.name();
format!(
r#"<environment_context>
<cwd>{cwd}</cwd>
<shell>{shell_name}</shell>
</environment_context>"#
)
assert!(
text.starts_with(ENVIRONMENT_CONTEXT_OPEN_TAG),
"expected environment context fragment: {text}"
);
assert!(
text.contains(&format!("<cwd>{cwd}</cwd>")),
"expected cwd in environment context: {text}"
);
assert!(
text.contains(&format!("<shell>{shell_name}</shell>")),
"expected shell in environment context: {text}"
);
assert!(
text.contains("<current_date>") && text.contains("</current_date>"),
"expected current_date in environment context: {text}"
);
assert!(
text.contains("<timezone>") && text.contains("</timezone>"),
"expected timezone in environment context: {text}"
);
assert!(
text.ends_with("</environment_context>"),
"expected closing environment_context tag: {text}"
);
}
fn assert_tool_names(body: &serde_json::Value, expected_names: &[&str]) {
@ -318,10 +336,13 @@ async fn prefixes_context_and_instructions_once_and_consistently_across_requests
let shell = default_user_shell();
let cwd_str = config.cwd.to_string_lossy();
let expected_env_text = default_env_context_str(&cwd_str, &shell);
let env_text = input1[1]["content"][1]["text"]
.as_str()
.expect("environment context text");
assert_default_env_context(env_text, &cwd_str, &shell);
assert_eq!(
input1[1]["content"][1]["text"].as_str(),
Some(expected_env_text.as_str()),
input1[1]["content"][1]["type"].as_str(),
Some("input_text"),
"expected environment context bundled after UI message in cached contextual message"
);
assert_eq!(input1[2], text_user_input("hello 1".to_string()));
@ -523,6 +544,18 @@ async fn override_before_first_turn_emits_environment_context() -> anyhow::Resul
!env_texts.is_empty(),
"expected environment context to be emitted: {env_texts:?}"
);
assert!(
env_texts
.iter()
.any(|text| text.contains("<current_date>") && text.contains("</current_date>")),
"expected current_date in environment context: {env_texts:?}"
);
assert!(
env_texts
.iter()
.any(|text| text.contains("<timezone>") && text.contains("</timezone>")),
"expected timezone in environment context: {env_texts:?}"
);
let env_count = input
.iter()
@ -672,21 +705,6 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() -> anyhow::Res
"role": "user",
"content": [ { "type": "input_text", "text": "hello 2" } ]
});
let shell = default_user_shell();
let expected_env_text_2 = format!(
r#"<environment_context>
<cwd>{}</cwd>
<shell>{}</shell>
</environment_context>"#,
new_cwd.path().display(),
shell.name()
);
let expected_env_msg_2 = serde_json::json!({
"type": "message",
"role": "user",
"content": [ { "type": "input_text", "text": expected_env_text_2 } ]
});
let expected_permissions_msg = body1["input"][0].clone();
let body1_input = body1["input"].as_array().expect("input array");
let expected_settings_update_msg = body2["input"][body1_input.len()].clone();
@ -704,6 +722,14 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() -> anyhow::Res
}),
"expected model switch section after model override: {expected_settings_update_msg:?}"
);
let expected_env_msg_2 = body2["input"][body1_input.len() + 1].clone();
assert_eq!(expected_env_msg_2["role"].as_str(), Some("user"));
let env_text = expected_env_msg_2["content"][0]["text"]
.as_str()
.expect("environment context text");
let shell = default_user_shell();
let expected_cwd = new_cwd.path().display().to_string();
assert_default_env_context(env_text, &expected_cwd, &shell);
let mut expected_body2 = body1_input.to_vec();
expected_body2.push(expected_settings_update_msg);
expected_body2.push(expected_env_msg_2);
@ -798,13 +824,18 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
let shell = default_user_shell();
let default_cwd_lossy = default_cwd.to_string_lossy();
let expected_env_text_1 = expected_ui_msg["content"][1]["text"]
.as_str()
.expect("cached environment context text")
.to_string();
assert_default_env_context(&expected_env_text_1, &default_cwd_lossy, &shell);
let expected_contextual_user_msg_1 = text_user_input_parts(vec![
expected_ui_msg["content"][0]["text"]
.as_str()
.expect("cached user instructions text")
.to_string(),
default_env_context_str(&default_cwd_lossy, &shell),
expected_env_text_1,
]);
let expected_user_message_1 = text_user_input("hello 1".to_string());
@ -911,7 +942,11 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu
let expected_ui_msg = body1["input"][1].clone();
let shell = default_user_shell();
let expected_env_text_1 = default_env_context_str(&default_cwd.to_string_lossy(), &shell);
let expected_env_text_1 = expected_ui_msg["content"][1]["text"]
.as_str()
.expect("cached environment context text")
.to_string();
assert_default_env_context(&expected_env_text_1, &default_cwd.to_string_lossy(), &shell);
let expected_contextual_user_msg_1 = text_user_input_parts(vec![
expected_ui_msg["content"][0]["text"]
.as_str()

View file

@ -28,6 +28,8 @@ fn resume_history(
let turn_ctx = TurnContextItem {
turn_id: Some(turn_id.clone()),
cwd: config.cwd.clone(),
current_date: None,
timezone: None,
approval_policy: config.permissions.approval_policy.value(),
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
network: None,

View file

@ -2133,6 +2133,10 @@ pub struct TurnContextItem {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub turn_id: Option<String>,
pub cwd: PathBuf,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub current_date: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timezone: Option<String>,
pub approval_policy: AskForApproval,
pub sandbox_policy: SandboxPolicy,
#[serde(skip_serializing_if = "Option::is_none")]
@ -3361,6 +3365,8 @@ mod tests {
let item = TurnContextItem {
turn_id: None,
cwd: PathBuf::from("/tmp"),
current_date: None,
timezone: None,
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::DangerFullAccess,
network: Some(TurnContextNetworkItem {

View file

@ -252,6 +252,8 @@ mod tests {
&RolloutItem::TurnContext(TurnContextItem {
turn_id: Some("turn-1".to_string()),
cwd: PathBuf::from("/parent/workspace"),
current_date: None,
timezone: None,
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::DangerFullAccess,
network: None,
@ -286,6 +288,8 @@ mod tests {
&RolloutItem::TurnContext(TurnContextItem {
turn_id: Some("turn-1".to_string()),
cwd: PathBuf::from("/fallback/workspace"),
current_date: None,
timezone: None,
approval_policy: AskForApproval::OnRequest,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
network: None,

View file

@ -1272,6 +1272,8 @@ mod tests {
TurnContextItem {
turn_id: None,
cwd,
current_date: None,
timezone: None,
approval_policy: config.permissions.approval_policy.value(),
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
network: None,