fix(inbound-meta): include seconds in timestamps

Include second-level precision in inbound metadata and auto-reply envelope timestamps, matching the timestamp helper contract used by providers and channel adapters.

Docs now show the weekday plus seconds form in date-time and timezone examples.

Verification:
- node scripts/run-vitest.mjs src/auto-reply/envelope.test.ts src/auto-reply/reply/inbound-meta.test.ts
- pnpm docs:list >/tmp/openclaw-docs-list-87360.log
- git diff --check origin/main...HEAD
- pnpm format:docs:check
- pnpm lint:docs
- pnpm lint:extensions:bundled
- pnpm lint
- PR CI green on 495bb6c10f

Fixes #87257

Co-authored-by: GarlicGo <582149912@qq.com>
This commit is contained in:
GarlicGo
2026-05-28 04:18:08 +08:00
committed by GitHub
parent f4329fe0d6
commit 2900c1c25c
7 changed files with 27 additions and 23 deletions

View File

@@ -12,7 +12,7 @@ OpenClaw standardizes timestamps so the model sees a **single reference time** i
| Surface | What it shows | Default | Configured via |
| ----------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------------------- |
| Message envelopes | Wraps inbound channel messages: `[Signal +1555 2026-01-18 00:19 PST] hello` | Host-local | `agents.defaults.envelopeTimezone` |
| Message envelopes | Wraps inbound channel messages: `[Signal +1555 Sun 2026-01-18 00:19:42 PST] hello` | Host-local | `agents.defaults.envelopeTimezone` |
| Tool payloads | Channel `readMessages`-style tools return raw provider time + normalized `timestampMs` / `timestampUtc` | UTC fields always present | Not configurable — preserves provider-native timestamps |
| System prompt | A small `Current Date & Time` block with the **time zone only** (no clock value, for cache stability) | Host timezone if `userTimezone` unset | `agents.defaults.userTimezone` |

View File

@@ -11,10 +11,10 @@ Provider timestamps are preserved so tools keep their native semantics (current
## Message envelopes (local by default)
Inbound messages are wrapped with a timestamp (minute precision):
Inbound messages are wrapped with a timestamp (second precision):
```
[Provider ... 2026-01-05 16:26 PST] message text
[Provider ... Mon 2026-01-05 16:26:34 PST] message text
```
This envelope timestamp is **host-local by default**, regardless of the provider timezone.
@@ -45,19 +45,19 @@ You can override this behavior:
**Local (default):**
```
[WhatsApp +1555 2026-01-18 00:19 PST] hello
[WhatsApp +1555 Sun 2026-01-18 00:19:42 PST] hello
```
**User timezone:**
```
[WhatsApp +1555 2026-01-18 00:19 CST] hello
[WhatsApp +1555 Sun 2026-01-18 00:19:42 CST] hello
```
**Elapsed time enabled:**
```
[WhatsApp +1555 +30s 2026-01-18T05:19Z] follow-up
[WhatsApp +1555 +30s Sun 2026-01-18T05:19:00Z] follow-up
```
## System prompt: current date and time

View File

@@ -141,7 +141,7 @@ describe("web auto-reply connection", () => {
it("handles helper envelope timestamps with trimmed timezones (regression)", () => {
const d = new Date("2025-01-01T00:00:00.000Z");
expect(formatEnvelopeTimestamp(d, " America/Los_Angeles ")).toBe("Tue 2024-12-31 16:00 PST");
expect(formatEnvelopeTimestamp(d, " America/Los_Angeles ")).toBe("Tue 2024-12-31 16:00:00 PST");
});
it("handles reconnect progress and max-attempt stop behavior", async () => {

View File

@@ -10,7 +10,7 @@ import {
describe("formatAgentEnvelope", () => {
it("includes channel, from, ip, host, and timestamp", () => {
withEnv({ TZ: "UTC" }, () => {
const ts = Date.UTC(2025, 0, 2, 3, 4); // 2025-01-02T03:04:00Z
const ts = Date.UTC(2025, 0, 2, 3, 4, 5); // 2025-01-02T03:04:05Z
const body = formatAgentEnvelope({
channel: "WebChat",
from: "user1",
@@ -21,7 +21,7 @@ describe("formatAgentEnvelope", () => {
body: "hello",
});
expect(body).toBe("[WebChat user1 mac-mini 10.0.0.5 Thu 2025-01-02T03:04Z] hello");
expect(body).toBe("[WebChat user1 mac-mini 10.0.0.5 Thu 2025-01-02T03:04:05Z] hello");
});
});
@@ -39,7 +39,7 @@ describe("formatAgentEnvelope", () => {
it("formats timestamps in UTC when configured", () => {
withEnv({ TZ: "America/Los_Angeles" }, () => {
const ts = Date.UTC(2025, 0, 2, 3, 4); // 2025-01-02T03:04:00Z (19:04 PST)
const ts = Date.UTC(2025, 0, 2, 3, 4, 5); // 2025-01-02T03:04:05Z (19:04:05 PST)
const body = formatAgentEnvelope({
channel: "WebChat",
timestamp: ts,
@@ -47,12 +47,12 @@ describe("formatAgentEnvelope", () => {
body: "hello",
});
expect(body).toBe("[WebChat Thu 2025-01-02T03:04Z] hello");
expect(body).toBe("[WebChat Thu 2025-01-02T03:04:05Z] hello");
});
});
it("formats timestamps in user timezone when configured", () => {
const ts = Date.UTC(2025, 0, 2, 3, 4); // 2025-01-02T03:04:00Z (04:04 CET)
const ts = Date.UTC(2025, 0, 2, 3, 4, 5); // 2025-01-02T03:04:05Z (04:04:05 CET)
const body = formatAgentEnvelope({
channel: "WebChat",
timestamp: ts,
@@ -60,7 +60,7 @@ describe("formatAgentEnvelope", () => {
body: "hello",
});
expect(body).toMatch(/\[WebChat Thu 2025-01-02 04:04 [^\]]+\] hello/);
expect(body).toMatch(/\[WebChat Thu 2025-01-02 04:04:05 [^\]]+\] hello/);
});
it("omits timestamps when configured", () => {

View File

@@ -142,10 +142,10 @@ export function formatEnvelopeTimestamp(
const formatted =
zone.mode === "utc"
? formatUtcTimestamp(date)
? formatUtcTimestamp(date, { displaySeconds: true })
: zone.mode === "local"
? formatZonedTimestamp(date)
: formatZonedTimestamp(date, { timeZone: zone.timeZone });
? formatZonedTimestamp(date, { displaySeconds: true })
: formatZonedTimestamp(date, { timeZone: zone.timeZone, displaySeconds: true });
if (!formatted) {
return undefined;

View File

@@ -422,13 +422,13 @@ describe("buildInboundUserContextPrefix", () => {
{
ChatType: "group",
MessageSid: "msg-with-ts",
Timestamp: Date.UTC(2026, 1, 15, 13, 35),
Timestamp: Date.UTC(2026, 1, 15, 13, 35, 42),
} as TemplateContext,
{ timezone: "utc" },
);
const conversationInfo = parseConversationInfoPayload(text);
expect(conversationInfo["timestamp"]).toBe("Sun 2026-02-15T13:35Z");
expect(conversationInfo["timestamp"]).toBe("Sun 2026-02-15T13:35:42Z");
});
it("honors envelope user timezone for conversation timestamps", () => {
@@ -437,7 +437,7 @@ describe("buildInboundUserContextPrefix", () => {
{
ChatType: "group",
MessageSid: "msg-with-user-tz",
Timestamp: Date.UTC(2026, 2, 19, 0, 0),
Timestamp: Date.UTC(2026, 2, 19, 0, 0, 27),
} as TemplateContext,
{
timezone: "user",
@@ -446,7 +446,7 @@ describe("buildInboundUserContextPrefix", () => {
);
const conversationInfo = parseConversationInfoPayload(text);
expect(conversationInfo["timestamp"]).toBe("Thu 2026-03-19 09:00 GMT+9");
expect(conversationInfo["timestamp"]).toBe("Thu 2026-03-19 09:00:27 GMT+9");
});
});

View File

@@ -27,14 +27,18 @@ export function formatEnvelopeTimestamp(date: Date, zone: EnvelopeTimestampZone
})();
if (normalized === "utc" || normalized === "gmt") {
const ts = formatUtcTimestamp(date);
const ts = formatUtcTimestamp(date, { displaySeconds: true });
return weekday ? `${weekday} ${ts}` : ts;
}
if (normalized === "local" || normalized === "host") {
const ts = formatZonedTimestamp(date) ?? formatUtcTimestamp(date);
const ts =
formatZonedTimestamp(date, { displaySeconds: true }) ??
formatUtcTimestamp(date, { displaySeconds: true });
return weekday ? `${weekday} ${ts}` : ts;
}
const ts = formatZonedTimestamp(date, { timeZone: trimmedZone }) ?? formatUtcTimestamp(date);
const ts =
formatZonedTimestamp(date, { timeZone: trimmedZone, displaySeconds: true }) ??
formatUtcTimestamp(date, { displaySeconds: true });
return weekday ? `${weekday} ${ts}` : ts;
}