perf: stabilize system prompt time
This commit is contained in:
@@ -5,6 +5,7 @@ Docs: https://docs.clawd.bot
|
||||
## 2026.1.23 (Unreleased)
|
||||
|
||||
### Changes
|
||||
- Agents: keep system prompt time zone-only and move current time to `session_status` for better cache hits.
|
||||
- Browser: add node-host proxy auto-routing for remote gateways (configurable per gateway/node).
|
||||
- Plugins: add optional llm-task JSON-only tool for workflows. (#1498) Thanks @vignesh07.
|
||||
- CLI: restart the gateway by default after `clawdbot update`; add `--no-restart` to skip it.
|
||||
|
||||
@@ -66,12 +66,12 @@ To inspect how much each injected file contributes (raw vs injected, truncation,
|
||||
|
||||
## Time handling
|
||||
|
||||
The system prompt includes a dedicated **Current Date & Time** section when user
|
||||
time or timezone is known. It is explicit about:
|
||||
The system prompt includes a dedicated **Current Date & Time** section when the
|
||||
user timezone is known. To keep the prompt cache-stable, it now only includes
|
||||
the **time zone** (no dynamic clock or time format).
|
||||
|
||||
- The user’s **local time** (already converted).
|
||||
- The **time zone** used for the conversion.
|
||||
- The **time format** (12-hour / 24-hour).
|
||||
Use `session_status` when the agent needs the current time; the status card
|
||||
includes a timestamp line.
|
||||
|
||||
Configure with:
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ read_when:
|
||||
|
||||
# Date & Time
|
||||
|
||||
Clawdbot defaults to **host-local time for transport timestamps** and **user-local time only in the system prompt**.
|
||||
Provider timestamps are preserved so tools keep their native semantics.
|
||||
Clawdbot defaults to **host-local time for transport timestamps** and **user timezone only in the system prompt**.
|
||||
Provider timestamps are preserved so tools keep their native semantics (current time is available via `session_status`).
|
||||
|
||||
## Message envelopes (local by default)
|
||||
|
||||
@@ -63,16 +63,16 @@ You can override this behavior:
|
||||
|
||||
## System prompt: Current Date & Time
|
||||
|
||||
If the user timezone or local time is known, the system prompt includes a dedicated
|
||||
**Current Date & Time** section:
|
||||
If the user timezone is known, the system prompt includes a dedicated
|
||||
**Current Date & Time** section with the **time zone only** (no clock/time format)
|
||||
to keep prompt caching stable:
|
||||
|
||||
```
|
||||
Thursday, January 15th, 2026 — 3:07 PM (America/Chicago)
|
||||
Time format: 12-hour
|
||||
Time zone: America/Chicago
|
||||
```
|
||||
|
||||
If only the timezone is known, we still include the section and instruct the model
|
||||
to assume UTC for unknown time references.
|
||||
When the agent needs the current time, use the `session_status` tool; the status
|
||||
card includes a timestamp line.
|
||||
|
||||
## System event lines (local by default)
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ describe("buildAgentSystemPrompt", () => {
|
||||
expect(prompt).toContain("Reminder: commit your changes in this workspace after edits.");
|
||||
});
|
||||
|
||||
it("includes user time when provided (12-hour)", () => {
|
||||
it("includes user timezone when provided (12-hour)", () => {
|
||||
const prompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/clawd",
|
||||
userTimezone: "America/Chicago",
|
||||
@@ -133,11 +133,10 @@ describe("buildAgentSystemPrompt", () => {
|
||||
});
|
||||
|
||||
expect(prompt).toContain("## Current Date & Time");
|
||||
expect(prompt).toContain("Monday, January 5th, 2026 — 3:26 PM (America/Chicago)");
|
||||
expect(prompt).toContain("Time format: 12-hour");
|
||||
expect(prompt).toContain("Time zone: America/Chicago");
|
||||
});
|
||||
|
||||
it("includes user time when provided (24-hour)", () => {
|
||||
it("includes user timezone when provided (24-hour)", () => {
|
||||
const prompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/clawd",
|
||||
userTimezone: "America/Chicago",
|
||||
@@ -146,11 +145,10 @@ describe("buildAgentSystemPrompt", () => {
|
||||
});
|
||||
|
||||
expect(prompt).toContain("## Current Date & Time");
|
||||
expect(prompt).toContain("Monday, January 5th, 2026 — 15:26 (America/Chicago)");
|
||||
expect(prompt).toContain("Time format: 24-hour");
|
||||
expect(prompt).toContain("Time zone: America/Chicago");
|
||||
});
|
||||
|
||||
it("shows UTC fallback when only timezone is provided", () => {
|
||||
it("shows timezone when only timezone is provided", () => {
|
||||
const prompt = buildAgentSystemPrompt({
|
||||
workspaceDir: "/tmp/clawd",
|
||||
userTimezone: "America/Chicago",
|
||||
@@ -158,9 +156,7 @@ describe("buildAgentSystemPrompt", () => {
|
||||
});
|
||||
|
||||
expect(prompt).toContain("## Current Date & Time");
|
||||
expect(prompt).toContain(
|
||||
"Time zone: America/Chicago. Current time unknown; assume UTC for date/time references.",
|
||||
);
|
||||
expect(prompt).toContain("Time zone: America/Chicago");
|
||||
});
|
||||
|
||||
it("includes model alias guidance when aliases are provided", () => {
|
||||
|
||||
@@ -49,22 +49,9 @@ function buildUserIdentitySection(ownerLine: string | undefined, isMinimal: bool
|
||||
return ["## User Identity", ownerLine, ""];
|
||||
}
|
||||
|
||||
function buildTimeSection(params: {
|
||||
userTimezone?: string;
|
||||
userTime?: string;
|
||||
userTimeFormat?: ResolvedTimeFormat;
|
||||
}) {
|
||||
if (!params.userTimezone && !params.userTime) return [];
|
||||
return [
|
||||
"## Current Date & Time",
|
||||
params.userTime
|
||||
? `${params.userTime} (${params.userTimezone ?? "unknown"})`
|
||||
: `Time zone: ${params.userTimezone}. Current time unknown; assume UTC for date/time references.`,
|
||||
params.userTimeFormat
|
||||
? `Time format: ${params.userTimeFormat === "24" ? "24-hour" : "12-hour"}`
|
||||
: "",
|
||||
"",
|
||||
];
|
||||
function buildTimeSection(params: { userTimezone?: string }) {
|
||||
if (!params.userTimezone) return [];
|
||||
return ["## Current Date & Time", `Time zone: ${params.userTimezone}`, ""];
|
||||
}
|
||||
|
||||
function buildReplyTagsSection(isMinimal: boolean) {
|
||||
@@ -212,7 +199,7 @@ export function buildAgentSystemPrompt(params: {
|
||||
sessions_send: "Send a message to another session/sub-agent",
|
||||
sessions_spawn: "Spawn a sub-agent session",
|
||||
session_status:
|
||||
"Show a /status-equivalent status card (usage + Reasoning/Verbose/Elevated); use for model-use questions (📊 session_status); optional per-session model override",
|
||||
"Show a /status-equivalent status card (usage + time + Reasoning/Verbose/Elevated); use for model-use questions (📊 session_status); optional per-session model override",
|
||||
image: "Analyze an image with the configured image model",
|
||||
};
|
||||
|
||||
@@ -302,7 +289,6 @@ export function buildAgentSystemPrompt(params: {
|
||||
: undefined;
|
||||
const reasoningLevel = params.reasoningLevel ?? "off";
|
||||
const userTimezone = params.userTimezone?.trim();
|
||||
const userTime = params.userTime?.trim();
|
||||
const skillsPrompt = params.skillsPrompt?.trim();
|
||||
const heartbeatPrompt = params.heartbeatPrompt?.trim();
|
||||
const heartbeatPromptLine = heartbeatPrompt
|
||||
@@ -465,8 +451,6 @@ export function buildAgentSystemPrompt(params: {
|
||||
...buildUserIdentitySection(ownerLine, isMinimal),
|
||||
...buildTimeSection({
|
||||
userTimezone,
|
||||
userTime,
|
||||
userTimeFormat: params.userTimeFormat,
|
||||
}),
|
||||
"## Workspace Files (injected)",
|
||||
"These user-editable files are loaded by Clawdbot and included below in Project Context.",
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
resolveDefaultModelForAgent,
|
||||
resolveModelRefFromString,
|
||||
} from "../../agents/model-selection.js";
|
||||
import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone } from "../date-time.js";
|
||||
import { normalizeGroupActivation } from "../../auto-reply/group-activation.js";
|
||||
import { getFollowupQueueDepth, resolveQueueSettings } from "../../auto-reply/reply/queue.js";
|
||||
import { buildStatusMessage } from "../../auto-reply/status.js";
|
||||
@@ -215,7 +216,7 @@ export function createSessionStatusTool(opts?: {
|
||||
label: "Session Status",
|
||||
name: "session_status",
|
||||
description:
|
||||
"Show a /status-equivalent session status card (usage + cost when available). Use for model-use questions (📊 session_status). Optional: set per-session model override (model=default resets overrides).",
|
||||
"Show a /status-equivalent session status card (usage + time + cost when available). Use for model-use questions (📊 session_status). Optional: set per-session model override (model=default resets overrides).",
|
||||
parameters: SessionStatusToolSchema,
|
||||
execute: async (_toolCallId, args) => {
|
||||
const params = args as Record<string, unknown>;
|
||||
@@ -324,6 +325,13 @@ export function createSessionStatusTool(opts?: {
|
||||
resolved.entry.queueDebounceMs ?? resolved.entry.queueCap ?? resolved.entry.queueDrop,
|
||||
);
|
||||
|
||||
const userTimezone = resolveUserTimezone(cfg.agents?.defaults?.userTimezone);
|
||||
const userTimeFormat = resolveUserTimeFormat(cfg.agents?.defaults?.timeFormat);
|
||||
const userTime = formatUserTime(new Date(), userTimezone, userTimeFormat);
|
||||
const timeLine = userTime
|
||||
? `🕒 Time: ${userTime} (${userTimezone})`
|
||||
: `🕒 Time zone: ${userTimezone}`;
|
||||
|
||||
const agentDefaults = cfg.agents?.defaults ?? {};
|
||||
const defaultLabel = `${configured.provider}/${configured.model}`;
|
||||
const agentModel =
|
||||
@@ -346,6 +354,7 @@ export function createSessionStatusTool(opts?: {
|
||||
agentDir,
|
||||
}),
|
||||
usageLine,
|
||||
timeLine,
|
||||
queue: {
|
||||
mode: queueSettings.mode,
|
||||
depth: queueDepth,
|
||||
|
||||
@@ -52,6 +52,7 @@ type StatusArgs = {
|
||||
resolvedElevated?: ElevatedLevel;
|
||||
modelAuth?: string;
|
||||
usageLine?: string;
|
||||
timeLine?: string;
|
||||
queue?: QueueStatus;
|
||||
mediaDecisions?: MediaUnderstandingDecision[];
|
||||
subagentsLine?: string;
|
||||
@@ -381,6 +382,7 @@ export function buildStatusMessage(args: StatusArgs): string {
|
||||
|
||||
return [
|
||||
versionLine,
|
||||
args.timeLine,
|
||||
modelLine,
|
||||
usageCostLine,
|
||||
`📚 ${contextLine}`,
|
||||
|
||||
Reference in New Issue
Block a user