1use std::sync::Arc;
2
3use crate::schema::json_schema_for;
4use action_log::ActionLog;
5use anyhow::{Result, anyhow};
6use assistant_tool::{Tool, ToolResult};
7use chrono::{Local, Utc};
8use gpui::{AnyWindowHandle, App, Entity, Task};
9use language_model::{LanguageModel, LanguageModelRequest, LanguageModelToolSchemaFormat};
10use project::Project;
11use schemars::JsonSchema;
12use serde::{Deserialize, Serialize};
13use ui::IconName;
14
15#[derive(Debug, Serialize, Deserialize, JsonSchema)]
16#[serde(rename_all = "snake_case")]
17pub enum Timezone {
18 /// Use UTC for the datetime.
19 Utc,
20 /// Use local time for the datetime.
21 Local,
22}
23
24#[derive(Debug, Serialize, Deserialize, JsonSchema)]
25pub struct NowToolInput {
26 /// The timezone to use for the datetime.
27 timezone: Timezone,
28}
29
30pub struct NowTool;
31
32impl Tool for NowTool {
33 fn name(&self) -> String {
34 "now".into()
35 }
36
37 fn needs_confirmation(&self, _: &serde_json::Value, _: &Entity<Project>, _: &App) -> bool {
38 false
39 }
40
41 fn may_perform_edits(&self) -> bool {
42 false
43 }
44
45 fn description(&self) -> String {
46 "Returns the current datetime in RFC 3339 format. Only use this tool when the user specifically asks for it or the current task would benefit from knowing the current datetime.".into()
47 }
48
49 fn icon(&self) -> IconName {
50 IconName::Info
51 }
52
53 fn input_schema(&self, format: LanguageModelToolSchemaFormat) -> Result<serde_json::Value> {
54 json_schema_for::<NowToolInput>(format)
55 }
56
57 fn ui_text(&self, _input: &serde_json::Value) -> String {
58 "Get current time".to_string()
59 }
60
61 fn run(
62 self: Arc<Self>,
63 input: serde_json::Value,
64 _request: Arc<LanguageModelRequest>,
65 _project: Entity<Project>,
66 _action_log: Entity<ActionLog>,
67 _model: Arc<dyn LanguageModel>,
68 _window: Option<AnyWindowHandle>,
69 _cx: &mut App,
70 ) -> ToolResult {
71 let input: NowToolInput = match serde_json::from_value(input) {
72 Ok(input) => input,
73 Err(err) => return Task::ready(Err(anyhow!(err))).into(),
74 };
75
76 let now = match input.timezone {
77 Timezone::Utc => Utc::now().to_rfc3339(),
78 Timezone::Local => Local::now().to_rfc3339(),
79 };
80 let text = format!("The current datetime is {now}.");
81
82 Task::ready(Ok(text.into())).into()
83 }
84}