Files
openclaw/src/agents/current-time.ts
Peter Steinberger edecdbd05e refactor(config): config-surface reduction tranche 3 — product consolidations (review request) (#111527)
* refactor(config): consolidate media model lists

* refactor(config): unify memory configuration

* refactor(config): consolidate TTS ownership

* refactor(config): move typing policy to agents

* refactor(config): retire product-level config surfaces

* refactor(config): share scoped tool policy type

* chore(config): refresh generated baselines

* fix(config): honor agent typing overrides

* fix(config): migrate sibling config consumers

* refactor(infra): keep base64url decoder private

* fix(config): strip invalid legacy TTS values

* chore(config): refresh rebased baseline hash

* fix(doctor): route legacy messages.tts.realtime voice to talk during tts move

* refactor(config): polish final layout names

* refactor(config): freeze retired tuning defaults

* feat(config): add fast mode default symmetry

* refactor(config): key agent entries by id

* docs(config): update final layout reference

* test(config): cover final layout migrations

* chore(config): refresh final layout baselines

* fix(config): align final layout runtime readers

* fix(config): align remaining readers

* fix(config): stabilize final layout migrations

* fix(config): finalize config projection proof

* fix(config): address final layout review

* docs(release): preserve historical config names

* fix(config): complete keyed agent migration

* fix(config): close final migration gaps

* fix(config): finish full-branch review

* fix(config): complete runtime secret detection

* fix(config): close final review findings

* fix(config): finish canonical docs and heartbeat migration

* fix(config): integrate latest main after rebase

* refactor(env): isolate test-only controls

* refactor(env): isolate build and development controls

* refactor(env): collapse process identity indirection

* refactor(env): remove duplicate config and temp aliases

* docs(env): define the operator-facing allowlist

* ci(env): ratchet production variable count

* fix(env): remove stale provider helper import

* fix(env): make ratchet sorting explicit

* test(env): keep test seam in dead-code audit

* test(env): cover ratchet growth and boundary; document surface budgets

* docs(config): document tier-eval consolidations

* docs(config): clarify speech preference ownership

* test(memory): align retired tuning fixtures

* refactor(memory): freeze engine heuristics

* refactor(config): apply tier-eval tranche

* refactor(tts): move persona shaping to providers

* refactor(compaction): move prompt policy to providers

* test(config): align hookified prompt fixtures

* chore(deadcode): classify test-only exports

* chore(github): remove unused spawn helper

* chore(deadcode): classify queue diagnostics

* chore(deadcode): remove unused lane snapshot export

* chore(plugin-sdk): ratchet consolidated surface

* fix(config): integrate latest main after rebase
2026-07-21 20:28:43 -07:00

76 lines
3.0 KiB
TypeScript

/**
* Formats cron-style current-time prompt text with local and UTC references.
*/
import { resolveDateTimestampMs } from "@openclaw/normalization-core/number-coercion";
import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone } from "./date-time.js";
type CronStyleNow = {
userTimezone: string;
formattedTime: string;
timeLine: string;
};
type TimeConfigLike = {
agents?: {
defaults?: {
userTimezone?: string;
timeFormat?: "auto" | "12" | "24";
};
};
};
/** Resolve localized and UTC current-time text for agent prompts. */
export function resolveCronStyleNow(cfg: TimeConfigLike, nowMs: number): CronStyleNow {
const userTimezone = resolveUserTimezone(cfg.agents?.defaults?.userTimezone);
const userTimeFormat = resolveUserTimeFormat(undefined);
const timestampMs = resolveDateTimestampMs(nowMs);
const date = new Date(timestampMs);
const formattedTime = formatUserTime(date, userTimezone, userTimeFormat) ?? date.toISOString();
const utcTime = date.toISOString().replace("T", " ").slice(0, 16) + " UTC";
const timeLine = `Current time: ${formattedTime} (${userTimezone})\nReference UTC: ${utcTime}`;
return { userTimezone, formattedTime, timeLine };
}
/**
* Append a fresh current-time block, or refresh a previously helper-injected one,
* so heartbeat/cron prompts flowing through this helper repeatedly never leak a
* stale `Current time:` value (issue #44993).
*/
// Matches the helper's own injected two-line `Current time: ...\nReference UTC: ...` block.
// Upstream #42654 split the helper output across two lines:
// Line 1: `Current time: <formattedTime> (<userTimezone>)`
// Line 2: `Reference UTC: YYYY-MM-DD HH:MM UTC`
// The natural-language `formattedTime` portion is locale/format-dependent (e.g.
// `Thursday, April 30th, 2026 - 10:00 AM` from `formatUserTime`, or an ISO fallback),
// so we anchor on the helper-only deterministic shape: `(<TZ>)` on line 1 immediately
// followed by `Reference UTC: <ISO UTC>` on line 2. The `(TZ)` group rejects parens (so
// timezone IDs like `Asia/Seoul` are accepted), and the strict `Reference UTC:` prefix
// plus ISO+UTC tail rejects user-authored reminder lines that happen to start with
// `Current time:` but lack the helper's exact two-line tail format.
const CURRENT_TIME_LINE_RE =
/^Current time: .+? \([^)]+\)\nReference UTC: \d{4}-\d{2}-\d{2} \d{2}:\d{2} UTC$/gm;
export function appendCronStyleCurrentTimeLine(text: string, cfg: TimeConfigLike, nowMs: number) {
const base = text.trimEnd();
if (!base) {
return base;
}
const { timeLine } = resolveCronStyleNow(cfg, nowMs);
if (!CURRENT_TIME_LINE_RE.test(base)) {
return `${base}\n${timeLine}`;
}
CURRENT_TIME_LINE_RE.lastIndex = 0;
let replaced = false;
const refreshed = base.replace(CURRENT_TIME_LINE_RE, () => {
if (replaced) {
return "";
}
replaced = true;
return timeLine;
});
return refreshed
.replace(/\n{3,}/g, "\n\n")
.replace(/\n\n+(?=Current time:)/g, "\n")
.trimEnd();
}