mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
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:
@@ -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` |
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user