diff --git a/common/arg.cpp b/common/arg.cpp
index 49b33806a..0766087c3 100644
--- a/common/arg.cpp
+++ b/common/arg.cpp
@@ -3362,7 +3362,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
{"--tools"}, "TOOL1,TOOL2,...",
"experimental: whether to enable built-in tools for AI agents - do not enable in untrusted environments (default: no tools)\n"
"specify \"all\" to enable all tools\n"
- "available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_datetime, get_info\n"
+ "available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_info\n"
"note: for security reasons, this will limit --cors-origins to localhost by default",
[](common_params & params, const std::string & value) {
params.server_tools = parse_csv_row(value);
diff --git a/tools/server/README.md b/tools/server/README.md
index c3cbf7be0..017981fd1 100644
--- a/tools/server/README.md
+++ b/tools/server/README.md
@@ -196,7 +196,7 @@ For the full list of features, please refer to [server's changelog](https://gith
| `--ui-config, --webui-config JSON` | JSON that provides default UI settings (overrides UI defaults)
(env: LLAMA_ARG_UI_CONFIG) |
| `--ui-config-file, --webui-config-file PATH` | JSON file that provides default UI settings (overrides UI defaults)
(env: LLAMA_ARG_UI_CONFIG_FILE) |
| `--ui-mcp-proxy, --webui-mcp-proxy, --no-ui-mcp-proxy, --no-webui-mcp-proxy` | experimental: whether to enable MCP CORS proxy - do not enable in untrusted environments (default: disabled)
(env: LLAMA_ARG_UI_MCP_PROXY) |
-| `--tools TOOL1,TOOL2,...` | experimental: whether to enable built-in tools for AI agents - do not enable in untrusted environments (default: no tools)
specify "all" to enable all tools
available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_datetime, get_info
note: for security reasons, this will limit --cors-origins to localhost by default
(env: LLAMA_ARG_TOOLS) |
+| `--tools TOOL1,TOOL2,...` | experimental: whether to enable built-in tools for AI agents - do not enable in untrusted environments (default: no tools)
specify "all" to enable all tools
available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_info
note: for security reasons, this will limit --cors-origins to localhost by default
(env: LLAMA_ARG_TOOLS) |
| `--tools-runtime OPTION` | experimental: run tools in a separate runtime environment (default: none, use host environment)
available options:
'docker:', 'podman:': spin up a new container and reuse it for all invocations, clean up on server exit
'docker-container:', 'podman-container:': use an existing container by ID, won't stop on server exit
'ssh:': run tools on a remote POSIX host over SSH, key-based auth and a trusted host key are required
(env: LLAMA_ARG_TOOLS_RUNTIME) |
| `--mcp-servers-config PATH` | experimental: path to JSON file with MCP server definitions (Cursor-compatible format) - do not enable in untrusted environments (default: none)
note: for security reasons, this will limit --cors-origins to localhost by default
(env: LLAMA_ARG_MCP_SERVERS_CONFIG) |
| `--mcp-servers-json JSON` | experimental: inline JSON with MCP server definitions (Cursor-compatible format) - do not enable in untrusted environments (default: none)
note: for security reasons, this will limit --cors-origins to localhost by default
(env: LLAMA_ARG_MCP_SERVERS_JSON) |
diff --git a/tools/server/server-tools.cpp b/tools/server/server-tools.cpp
index fd0ff8ddd..5e5e60efd 100644
--- a/tools/server/server-tools.cpp
+++ b/tools/server/server-tools.cpp
@@ -8,7 +8,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -1692,61 +1691,6 @@ private:
}
};
-//
-// get_datetime: returns the current date and time
-//
-
-struct server_tool_get_datetime : server_tool {
- server_tool_get_datetime() {
- name = "get_datetime";
- display_name = "Get Date & Time";
- permission_write = false;
- }
-
- json get_definition() const override {
- return {
- {"type", "function"},
- {"function", {
- {"name", name},
- {"description", "Returns the current date and time in UTC"},
- {"parameters", {
- {"type", "object"},
- {"properties", {
- {"format", {
- {"type", "string"},
- {"description",
- "strftime()-style format string for the output (default: \"%Y-%m-%dT%H:%M:%SZ\", "
- "e.g. ISO 8601). Choose your own format if you need something else, "
- "e.g. \"%A, %B %d %Y\" for a human-readable date."},
- }},
- }},
- }},
- }},
- };
- }
-
- json invoke(json params, server_tool::stream *) const override {
- std::string format = json_value(params, "format", std::string("%Y-%m-%dT%H:%M:%SZ"));
-
- auto now = std::chrono::system_clock::now();
- auto time = std::chrono::system_clock::to_time_t(now);
- std::tm tm_utc;
-#ifdef _WIN32
- gmtime_s(&tm_utc, &time);
-#else
- gmtime_r(&time, &tm_utc);
-#endif
-
- char buf[256];
- size_t len = std::strftime(buf, sizeof(buf), format.c_str(), &tm_utc);
- if (len == 0) {
- return {{"error", "invalid format string"}};
- }
-
- return {{"result", std::string(buf, len)}};
- }
-};
-
//
// get_info: returns runtime info (OS name/version and cwd)
//
@@ -2005,6 +1949,10 @@ static server_tool & find_tool(std::vector> & tools
//
static std::vector> build_tools() {
+ // IMPORTANT: for contributors, please keep this array of tools as minimal as possible
+ // we only accept minimal i/o and shell command tools here
+ // for example, do not add: web search, get date time, etc.
+ // high-level functionality should be added either via MCP or web UI
std::vector> tools;
tools.push_back(std::make_unique());
tools.push_back(std::make_unique());
@@ -2012,7 +1960,6 @@ static std::vector> build_tools() {
tools.push_back(std::make_unique());
tools.push_back(std::make_unique());
tools.push_back(std::make_unique());
- tools.push_back(std::make_unique());
tools.push_back(std::make_unique());
return tools;
}
diff --git a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockGetDatetime.svelte b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockGetDatetime.svelte
index 23de7cbd6..44b3ec645 100644
--- a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockGetDatetime.svelte
+++ b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageToolCall/ChatMessageToolCallBlockGetDatetime.svelte
@@ -33,7 +33,7 @@
if (typeof obj.result === 'string') return { dateString: obj.result.trim() };
}
} catch {
- return { dateString: toolResultString.trim() };
+ // not JSON - nothing to show
}
return {};
diff --git a/tools/ui/src/lib/constants/built-in-tools.constants.ts b/tools/ui/src/lib/constants/built-in-tools.constants.ts
index 679c61459..61e90e105 100644
--- a/tools/ui/src/lib/constants/built-in-tools.constants.ts
+++ b/tools/ui/src/lib/constants/built-in-tools.constants.ts
@@ -34,7 +34,7 @@ export const BUILTIN_TOOL_UI: Readonly>
label: 'Search files',
source: ToolSource.BUILTIN
},
- [BuiltInTool.GET_DATETIME]: { icon: Clock, label: 'Current time', source: ToolSource.BUILTIN },
+ [BuiltInTool.GET_DATETIME]: { icon: Clock, label: 'Current time', source: ToolSource.FRONTEND },
[BuiltInTool.GET_INFO]: { icon: Info, label: 'Runtime info', source: ToolSource.BUILTIN },
[BuiltInTool.GREP_SEARCH]: {
icon: SearchCode,
diff --git a/tools/ui/src/lib/constants/get-datetime.ts b/tools/ui/src/lib/constants/get-datetime.ts
new file mode 100644
index 000000000..c8726d9b5
--- /dev/null
+++ b/tools/ui/src/lib/constants/get-datetime.ts
@@ -0,0 +1,20 @@
+import { BuiltInTool, JsonSchemaType, ToolCallType } from '$lib/enums';
+import type { OpenAIToolDefinition } from '$lib/types';
+
+export const GET_DATETIME_TOOL_NAME = BuiltInTool.GET_DATETIME;
+
+export function buildGetDatetimeToolDefinition(): OpenAIToolDefinition {
+ return {
+ function: {
+ description:
+ 'Returns the current local date and time in ISO 8601 format, with the IANA time zone name',
+ name: GET_DATETIME_TOOL_NAME,
+ parameters: {
+ properties: {},
+ required: [],
+ type: JsonSchemaType.OBJECT
+ }
+ },
+ type: ToolCallType.FUNCTION
+ };
+}
diff --git a/tools/ui/src/lib/constants/index.ts b/tools/ui/src/lib/constants/index.ts
index cdd91a073..289239113 100644
--- a/tools/ui/src/lib/constants/index.ts
+++ b/tools/ui/src/lib/constants/index.ts
@@ -59,4 +59,5 @@ export * from './uri-template.constants';
export * from './url.constants';
export * from './working-directory.constants';
export * from './read-media';
+export * from './get-datetime';
export * from './browser-info';
diff --git a/tools/ui/src/lib/stores/agentic.svelte.ts b/tools/ui/src/lib/stores/agentic.svelte.ts
index d6b57ffa8..06c7661fe 100644
--- a/tools/ui/src/lib/stores/agentic.svelte.ts
+++ b/tools/ui/src/lib/stores/agentic.svelte.ts
@@ -84,7 +84,12 @@ import type {
DatabaseMessageExtraAudioFile,
DatabaseMessageExtraImageFile
} from '$lib/types/database';
-import { executeBrowserInfoTool, getAudioInputFormat, isAbortError } from '$lib/utils';
+import {
+ executeBrowserInfoTool,
+ executeGetDatetimeTool,
+ getAudioInputFormat,
+ isAbortError
+} from '$lib/utils';
import { SvelteMap } from 'svelte/reactivity';
function createDefaultSession(): AgenticSession {
@@ -946,7 +951,9 @@ class AgenticStore {
let executionResult: ToolExecutionResult;
- if (toolName === BuiltInTool.GET_INFO) {
+ if (toolName === BuiltInTool.GET_DATETIME) {
+ executionResult = executeGetDatetimeTool();
+ } else if (toolName === BuiltInTool.GET_INFO) {
executionResult = executeBrowserInfoTool();
} else if (toolName === BuiltInTool.READ_MEDIA) {
executionResult = await ReadMediaService.executeTool(
diff --git a/tools/ui/src/lib/stores/tools.svelte.ts b/tools/ui/src/lib/stores/tools.svelte.ts
index fb3662025..4cfb9f370 100644
--- a/tools/ui/src/lib/stores/tools.svelte.ts
+++ b/tools/ui/src/lib/stores/tools.svelte.ts
@@ -1,6 +1,7 @@
import { browser } from '$app/environment';
import {
buildBrowserInfoToolDefinition,
+ buildGetDatetimeToolDefinition,
buildReadMediaToolDefinition,
DISABLED_TOOL_KEYS_LOCALSTORAGE_KEY,
HOME_TILDE,
@@ -176,7 +177,7 @@ class ToolsStore {
}
get frontendTools(): OpenAIToolDefinition[] {
- const tools: OpenAIToolDefinition[] = [];
+ const tools: OpenAIToolDefinition[] = [buildGetDatetimeToolDefinition()];
if (settingsStore.config.jsSandboxEnabled) {
tools.push(buildSandboxToolDefinition(!!settingsStore.config.symbolicMathEnabled));
diff --git a/tools/ui/src/lib/utils/get-datetime.ts b/tools/ui/src/lib/utils/get-datetime.ts
new file mode 100644
index 000000000..cd17bb1e8
--- /dev/null
+++ b/tools/ui/src/lib/utils/get-datetime.ts
@@ -0,0 +1,38 @@
+/**
+ * Frontend executor for the `get_datetime` tool. It runs in the browser, so it
+ * reports the user's own clock and time zone instead of the server's UTC time -
+ * a chat about "tomorrow" means the user's tomorrow, not the host's.
+ *
+ * @see buildGetDatetimeToolDefinition in constants/get-datetime.ts - tool schema sent to the LLM
+ */
+
+import type { ToolExecutionResult } from '$lib/types';
+
+function pad(value: number): string {
+ return String(value).padStart(2, '0');
+}
+
+/** ISO 8601 in local time, e.g. `2026-08-17T14:05:09+02:00` */
+function localIsoString(date: Date): string {
+ // getTimezoneOffset() counts minutes behind UTC, ISO 8601 counts them ahead
+ const offset = -date.getTimezoneOffset();
+ const sign = offset < 0 ? '-' : '+';
+ const absOffset = Math.abs(offset);
+ const day = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
+ const time = `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
+
+ return `${day}T${time}${sign}${pad(Math.floor(absOffset / 60))}:${pad(absOffset % 60)}`;
+}
+
+/** The `result` field keeps the shape the `get_datetime` renderer already reads. */
+export function executeGetDatetimeTool(): ToolExecutionResult {
+ const now = new Date();
+
+ return {
+ content: JSON.stringify({
+ result: localIsoString(now),
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
+ }),
+ isError: false
+ };
+}
diff --git a/tools/ui/src/lib/utils/index.ts b/tools/ui/src/lib/utils/index.ts
index d991363fc..dd997c206 100644
--- a/tools/ui/src/lib/utils/index.ts
+++ b/tools/ui/src/lib/utils/index.ts
@@ -331,6 +331,9 @@ export { getChatCommands } from './chat-commands';
// SANDBOX_TOOL_DEFINITION is deprecated; kept for backward compatibility.
export { buildSandboxToolDefinition, SANDBOX_TOOL_DEFINITION } from './sandbox-tool';
+// Frontend `get_datetime` executor (the browser clock, not the server's)
+export { executeGetDatetimeTool } from './get-datetime';
+
// Browser fallback for the server's get_info tool
export { executeBrowserInfoTool } from './browser-info';