From 34809c98803e630286366a9c5bcd380d512b5b54 Mon Sep 17 00:00:00 2001 From: kevin zhao Date: Thu, 30 Oct 2025 18:17:52 -0400 Subject: [PATCH] timezones --- codex-rs/core/src/codex.rs | 8 ++-- codex-rs/core/src/environment_context.rs | 51 +++++++++++---------- codex-rs/core/tests/suite/prompt_caching.rs | 8 ++-- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 3843e0b7ec..c3dd127a7d 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -268,7 +268,7 @@ 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) system_date: Option, + pub(crate) local_date_with_timezone: Option, pub(crate) developer_instructions: Option, pub(crate) base_instructions: Option, pub(crate) compact_prompt: Option, @@ -425,7 +425,7 @@ impl Session { sub_id, client, cwd: session_configuration.cwd.clone(), - system_date: Some(Local::now().format("%Y-%m-%d").to_string()), + local_date_with_timezone: Some(Local::now().format("%Y-%m-%d %:z").to_string()), developer_instructions: session_configuration.developer_instructions.clone(), base_instructions: session_configuration.base_instructions.clone(), compact_prompt: session_configuration.compact_prompt.clone(), @@ -1010,7 +1010,7 @@ impl Session { } items.push(ResponseItem::from(EnvironmentContext::new( Some(turn_context.cwd.clone()), - turn_context.system_date.clone(), + turn_context.local_date_with_timezone.clone(), Some(turn_context.approval_policy), Some(turn_context.sandbox_policy.clone()), Some(self.user_shell().clone()), @@ -1696,7 +1696,7 @@ async fn spawn_review_thread( sandbox_policy: parent_turn_context.sandbox_policy.clone(), shell_environment_policy: parent_turn_context.shell_environment_policy.clone(), cwd: parent_turn_context.cwd.clone(), - system_date: parent_turn_context.system_date.clone(), + local_date_with_timezone: parent_turn_context.local_date_with_timezone.clone(), final_output_json_schema: None, codex_linux_sandbox_exe: parent_turn_context.codex_linux_sandbox_exe.clone(), tool_call_gate: Arc::new(ReadinessFlag::new()), diff --git a/codex-rs/core/src/environment_context.rs b/codex-rs/core/src/environment_context.rs index ba66964c01..f48b880249 100644 --- a/codex-rs/core/src/environment_context.rs +++ b/codex-rs/core/src/environment_context.rs @@ -24,7 +24,7 @@ pub enum NetworkAccess { #[serde(rename = "environment_context", rename_all = "snake_case")] pub(crate) struct EnvironmentContext { pub cwd: Option, - pub system_date: Option, + pub local_date: Option, pub approval_policy: Option, pub sandbox_mode: Option, pub network_access: Option, @@ -35,14 +35,14 @@ pub(crate) struct EnvironmentContext { impl EnvironmentContext { pub fn new( cwd: Option, - system_date: Option, + local_date: Option, approval_policy: Option, sandbox_policy: Option, shell: Option, ) -> Self { Self { cwd, - system_date, + local_date, approval_policy, sandbox_mode: match sandbox_policy { Some(SandboxPolicy::DangerFullAccess) => Some(SandboxMode::DangerFullAccess), @@ -82,7 +82,7 @@ impl EnvironmentContext { pub fn equals_except_shell(&self, other: &EnvironmentContext) -> bool { let EnvironmentContext { cwd, - system_date, + local_date, approval_policy, sandbox_mode, network_access, @@ -92,7 +92,7 @@ impl EnvironmentContext { } = other; self.cwd == *cwd - && self.system_date == *system_date + && self.local_date == *local_date && self.approval_policy == *approval_policy && self.sandbox_mode == *sandbox_mode && self.network_access == *network_access @@ -105,8 +105,8 @@ impl EnvironmentContext { } else { None }; - let system_date = if before.system_date != after.system_date { - after.system_date.clone() + let local_date = if before.local_date_with_timezone != after.local_date_with_timezone { + after.local_date_with_timezone.clone() } else { None }; @@ -120,7 +120,7 @@ impl EnvironmentContext { } else { None }; - EnvironmentContext::new(cwd, system_date, approval_policy, sandbox_policy, None) + EnvironmentContext::new(cwd, local_date, approval_policy, sandbox_policy, None) } } @@ -128,7 +128,7 @@ impl From<&TurnContext> for EnvironmentContext { fn from(turn_context: &TurnContext) -> Self { Self::new( Some(turn_context.cwd.clone()), - turn_context.system_date.clone(), + turn_context.local_date_with_timezone.clone(), Some(turn_context.approval_policy), Some(turn_context.sandbox_policy.clone()), // Shell is not configurable from turn to turn @@ -145,6 +145,7 @@ impl EnvironmentContext { /// ```xml /// /// ... + /// ... /// ... /// ... /// ... @@ -157,8 +158,8 @@ impl EnvironmentContext { if let Some(cwd) = self.cwd { lines.push(format!(" {}", cwd.to_string_lossy())); } - if let Some(system_date) = self.system_date { - lines.push(format!(" {system_date}")); + if let Some(local_date) = self.local_date { + lines.push(format!(" {local_date}")); } if let Some(approval_policy) = self.approval_policy { lines.push(format!( @@ -226,7 +227,7 @@ mod tests { fn serialize_workspace_write_environment_context() { let context = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnRequest), Some(workspace_write_policy(vec!["/repo", "/tmp"], false)), None, @@ -234,7 +235,7 @@ mod tests { let expected = r#" /repo - 2025-01-01 + 2025-01-01 +00:00 on-request workspace-write restricted @@ -251,14 +252,14 @@ mod tests { fn serialize_read_only_environment_context() { let context = EnvironmentContext::new( None, - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::Never), Some(SandboxPolicy::ReadOnly), None, ); let expected = r#" - 2025-01-01 + 2025-01-01 +00:00 never read-only restricted @@ -271,14 +272,14 @@ mod tests { fn serialize_full_access_environment_context() { let context = EnvironmentContext::new( None, - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnFailure), Some(SandboxPolicy::DangerFullAccess), None, ); let expected = r#" - 2025-01-01 + 2025-01-01 +00:00 on-failure danger-full-access enabled @@ -292,14 +293,14 @@ mod tests { // Approval policy let context1 = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnRequest), Some(workspace_write_policy(vec!["/repo"], false)), None, ); let context2 = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::Never), Some(workspace_write_policy(vec!["/repo"], true)), None, @@ -311,14 +312,14 @@ mod tests { fn equals_except_shell_compares_sandbox_policy() { let context1 = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnRequest), Some(SandboxPolicy::new_read_only_policy()), None, ); let context2 = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnRequest), Some(SandboxPolicy::new_workspace_write_policy()), None, @@ -331,14 +332,14 @@ mod tests { fn equals_except_shell_compares_workspace_write_policy() { let context1 = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnRequest), Some(workspace_write_policy(vec!["/repo", "/tmp", "/var"], false)), None, ); let context2 = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnRequest), Some(workspace_write_policy(vec!["/repo", "/tmp"], true)), None, @@ -351,7 +352,7 @@ mod tests { fn equals_except_shell_ignores_shell() { let context1 = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnRequest), Some(workspace_write_policy(vec!["/repo"], false)), Some(Shell::Bash(BashShell { @@ -361,7 +362,7 @@ mod tests { ); let context2 = EnvironmentContext::new( Some(PathBuf::from("/repo")), - Some("2025-01-01".to_string()), + Some("2025-01-01 +00:00".to_string()), Some(AskForApproval::OnRequest), Some(workspace_write_policy(vec!["/repo"], false)), Some(Shell::Zsh(ZshShell { diff --git a/codex-rs/core/tests/suite/prompt_caching.rs b/codex-rs/core/tests/suite/prompt_caching.rs index 4034feecb5..dc32b2b561 100644 --- a/codex-rs/core/tests/suite/prompt_caching.rs +++ b/codex-rs/core/tests/suite/prompt_caching.rs @@ -41,11 +41,11 @@ fn text_user_input(text: String) -> serde_json::Value { } fn default_env_context_str(cwd: &str, shell: &Shell) -> String { - let system_date = Local::now().format("%Y-%m-%d").to_string(); + let local_date = Local::now().format("%Y-%m-%d %:z").to_string(); format!( r#" {} - {system_date} + {local_date} on-request read-only restricted @@ -348,11 +348,11 @@ async fn prefixes_context_and_instructions_once_and_consistently_across_requests let shell = default_user_shell().await; let expected_env_text = { - let system_date = Local::now().format("%Y-%m-%d").to_string(); + let local_date = Local::now().format("%Y-%m-%d %:z").to_string(); format!( r#" {} - {system_date} + {local_date} on-request read-only restricted