mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] add clock current-time tool (#29011)
## Summary
- expose `clock.curr_time` when current-time reminders are enabled
- query the session's configured time provider with the calling thread
id
- return the existing UTC reminder text for direct model calls
- return `{ "current_time": "YYYY-MM-DD HH:MM:SS UTC" }` in Code Mode
Clock lookup failures remain fatal, matching pre-inference reminder
behavior.
## Testing
- `just test -p codex-core current_time_tool_returns_the_latest_time`
- `just test -p codex-core
code_mode_current_time_returns_structured_result`
- `just fix -p codex-core`
This commit is contained in:
@@ -11,6 +11,12 @@ impl CurrentTimeReminder {
|
||||
pub(crate) fn new(current_time: DateTime<Utc>) -> Self {
|
||||
Self { current_time }
|
||||
}
|
||||
|
||||
pub(crate) fn formatted_time(&self) -> String {
|
||||
self.current_time
|
||||
.format("%Y-%m-%d %H:%M:%S UTC")
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl ContextualUserFragment for CurrentTimeReminder {
|
||||
@@ -27,9 +33,6 @@ impl ContextualUserFragment for CurrentTimeReminder {
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
format!(
|
||||
"It is {}.",
|
||||
self.current_time.format("%Y-%m-%d %H:%M:%S UTC")
|
||||
)
|
||||
format!("It is {}.", self.formatted_time())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
use crate::context::ContextualUserFragment;
|
||||
use crate::context::CurrentTimeReminder;
|
||||
use crate::function_tool::FunctionCallError;
|
||||
use crate::tools::context::FunctionToolOutput;
|
||||
use crate::tools::context::ToolInvocation;
|
||||
use crate::tools::context::ToolOutput;
|
||||
use crate::tools::context::ToolPayload;
|
||||
use crate::tools::context::boxed_tool_output;
|
||||
use crate::tools::registry::CoreToolRuntime;
|
||||
use crate::tools::registry::ToolExecutor;
|
||||
use codex_protocol::models::ResponseInputItem;
|
||||
use codex_tools::JsonSchema;
|
||||
use codex_tools::ResponsesApiNamespace;
|
||||
use codex_tools::ResponsesApiNamespaceTool;
|
||||
use codex_tools::ResponsesApiTool;
|
||||
use codex_tools::ToolName;
|
||||
use codex_tools::ToolSpec;
|
||||
use serde_json::Value as JsonValue;
|
||||
use serde_json::json;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
const NAMESPACE: &str = "clock";
|
||||
const TOOL_NAME: &str = "curr_time";
|
||||
|
||||
struct CurrentTimeOutput(CurrentTimeReminder);
|
||||
|
||||
impl ToolOutput for CurrentTimeOutput {
|
||||
fn log_preview(&self) -> String {
|
||||
self.0.render()
|
||||
}
|
||||
|
||||
fn success_for_logging(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn to_response_item(&self, call_id: &str, payload: &ToolPayload) -> ResponseInputItem {
|
||||
FunctionToolOutput::from_text(self.0.render(), Some(true))
|
||||
.to_response_item(call_id, payload)
|
||||
}
|
||||
|
||||
fn code_mode_result(&self, _payload: &ToolPayload) -> JsonValue {
|
||||
json!({
|
||||
"current_time": self.0.formatted_time(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CurrentTimeHandler;
|
||||
|
||||
impl ToolExecutor<ToolInvocation> for CurrentTimeHandler {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::namespaced(NAMESPACE, TOOL_NAME)
|
||||
}
|
||||
|
||||
fn spec(&self) -> ToolSpec {
|
||||
ToolSpec::Namespace(ResponsesApiNamespace {
|
||||
name: NAMESPACE.to_string(),
|
||||
description: "Tools for reading the current time.".to_string(),
|
||||
tools: vec![ResponsesApiNamespaceTool::Function(ResponsesApiTool {
|
||||
name: TOOL_NAME.to_string(),
|
||||
description: "Return the current time in UTC.".to_string(),
|
||||
strict: false,
|
||||
defer_loading: None,
|
||||
parameters: JsonSchema::object(
|
||||
BTreeMap::new(),
|
||||
/*required*/ None,
|
||||
/*additional_properties*/ Some(false.into()),
|
||||
),
|
||||
output_schema: Some(json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"current_time": {
|
||||
"type": "string",
|
||||
"description": "Current UTC time formatted as YYYY-MM-DD HH:MM:SS UTC."
|
||||
}
|
||||
},
|
||||
"required": ["current_time"],
|
||||
"additionalProperties": false
|
||||
})),
|
||||
})],
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
Box::pin(async move {
|
||||
if !matches!(invocation.payload, ToolPayload::Function { .. }) {
|
||||
return Err(FunctionCallError::RespondToModel(format!(
|
||||
"{TOOL_NAME} handler received unsupported payload"
|
||||
)));
|
||||
}
|
||||
|
||||
let current_time = invocation
|
||||
.session
|
||||
.services
|
||||
.time_provider
|
||||
.current_time(invocation.session.thread_id)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
FunctionCallError::Fatal(format!("failed to read current time: {err:#}"))
|
||||
})?;
|
||||
Ok(boxed_tool_output(CurrentTimeOutput(
|
||||
CurrentTimeReminder::new(current_time),
|
||||
)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CoreToolRuntime for CurrentTimeHandler {}
|
||||
@@ -2,6 +2,7 @@ pub(crate) mod agent_jobs;
|
||||
pub(crate) mod agent_jobs_spec;
|
||||
pub(crate) mod apply_patch;
|
||||
pub(crate) mod apply_patch_spec;
|
||||
mod current_time;
|
||||
mod dynamic;
|
||||
pub(crate) mod extension_tools;
|
||||
mod get_context_remaining;
|
||||
@@ -55,6 +56,7 @@ pub(crate) use crate::tools::code_mode::CodeModeWaitHandler;
|
||||
pub use apply_patch::ApplyPatchHandler;
|
||||
use codex_protocol::models::AdditionalPermissionProfile;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
pub use current_time::CurrentTimeHandler;
|
||||
pub use dynamic::DynamicToolHandler;
|
||||
pub use get_context_remaining::GetContextRemainingHandler;
|
||||
pub use list_available_plugins_to_install::ListAvailablePluginsToInstallHandler;
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::tools::effective_tool_mode;
|
||||
use crate::tools::handlers::ApplyPatchHandler;
|
||||
use crate::tools::handlers::CodeModeExecuteHandler;
|
||||
use crate::tools::handlers::CodeModeWaitHandler;
|
||||
use crate::tools::handlers::CurrentTimeHandler;
|
||||
use crate::tools::handlers::DynamicToolHandler;
|
||||
use crate::tools::handlers::ExecCommandHandler;
|
||||
use crate::tools::handlers::ExecCommandHandlerOptions;
|
||||
@@ -711,6 +712,10 @@ fn add_core_utility_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut
|
||||
planned_tools.add(GetContextRemainingHandler);
|
||||
}
|
||||
|
||||
if features.enabled(Feature::CurrentTimeReminder) {
|
||||
planned_tools.add(CurrentTimeHandler);
|
||||
}
|
||||
|
||||
if features.enabled(Feature::SleepTool) {
|
||||
planned_tools.add(SleepHandler);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user