From 40b1c4e75ab027a87c15f0f4dd72bc8f1ff7a2fc Mon Sep 17 00:00:00 2001 From: AgentRun Codex Date: Mon, 20 Jul 2026 05:37:30 +0200 Subject: [PATCH] =?UTF-8?q?fix(events):=20=E4=BF=9D=E7=95=99=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=B6=88=E6=81=AF=E6=8F=90=E4=BA=A4=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/events.ts | 12 +++++- src/selftest/cases/67-user-submitted-at.ts | 47 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 src/selftest/cases/67-user-submitted-at.ts diff --git a/src/common/events.ts b/src/common/events.ts index ad6716f..4524114 100644 --- a/src/common/events.ts +++ b/src/common/events.ts @@ -52,12 +52,14 @@ export function userMessagePayloadForCommand(run: RunRecord, command: CommandRec const text = promptBearingText(command.payload); if (text === null) return null; const targetTraceId = command.type === "steer" ? nonEmptyText(command.payload.targetTraceId) : null; + const submittedAt = isoTimestamp(command.payload.submittedAt); return { commandId: command.id, traceId: agentRunBusinessTraceId(run, command), userMessageId: nonEmptyText(command.payload.userMessageId) ?? `msg_${command.id}_user`, text, source: command.type === "steer" ? "agentrun-steer-command-payload" : "agentrun-turn-command-payload", + ...(submittedAt ? { submittedAt } : {}), ...(targetTraceId ? { targetTraceId } : {}), valuesPrinted: false, }; @@ -103,16 +105,22 @@ function normalizeCommandOutputPayload(payload: JsonRecord): JsonRecord { } function normalizeUserMessagePayload(payload: JsonRecord): JsonRecord { - const { targetTraceId: _targetTraceId, ...rest } = payload; + const { targetTraceId: _targetTraceId, submittedAt: _submittedAt, ...rest } = payload; const commandId = nonEmptyText(payload.commandId); const userMessageId = nonEmptyText(payload.userMessageId); const text = typeof payload.text === "string" && payload.text.trim().length > 0 ? redactText(payload.text) : null; const source = nonEmptyText(payload.source); const targetTraceId = nonEmptyText(payload.targetTraceId); + const submittedAt = isoTimestamp(payload.submittedAt); if (!commandId || !userMessageId || text === null || !source) { throw new AgentRunError("schema-invalid", "user_message event requires commandId, userMessageId, non-empty text, and source", { httpStatus: 400 }); } - return { ...rest, commandId, userMessageId, text, source, ...(targetTraceId ? { targetTraceId } : {}), valuesPrinted: false }; + return { ...rest, commandId, userMessageId, text, source, ...(targetTraceId ? { targetTraceId } : {}), ...(submittedAt ? { submittedAt } : {}), valuesPrinted: false }; +} + +function isoTimestamp(value: unknown): string | null { + const timestamp = nonEmptyText(value); + return timestamp && Number.isFinite(Date.parse(timestamp)) ? new Date(Date.parse(timestamp)).toISOString() : null; } function promptBearingText(payload: JsonRecord): string | null { diff --git a/src/selftest/cases/67-user-submitted-at.ts b/src/selftest/cases/67-user-submitted-at.ts new file mode 100644 index 0000000..93ef004 --- /dev/null +++ b/src/selftest/cases/67-user-submitted-at.ts @@ -0,0 +1,47 @@ +import assert from "node:assert/strict"; +import type { CreateRunInput } from "../../common/types.js"; +import { MemoryAgentRunStore } from "../../mgr/store.js"; +import type { SelfTestCase } from "../harness.js"; + +const selfTest: SelfTestCase = () => { + const store = new MemoryAgentRunStore(); + const run = store.createRun(runInput()); + const submittedAt = "2026-07-20T01:13:07.699Z"; + const command = store.createCommand(run.id, { + type: "turn", + idempotencyKey: "user-submitted-at", + payload: { + prompt: "hi", + traceId: "trc_user_submitted_at", + userMessageId: "msg_user_submitted_at", + submittedAt, + }, + }); + const event = store.listEvents(run.id, 0, 10) + .find((candidate) => candidate.type === "user_message" && candidate.payload.commandId === command.id); + + assert.equal(event?.payload.submittedAt, submittedAt); + return { name: "user-submitted-at", tests: ["command-user-message-preserves-submitted-at"] }; +}; + +function runInput(): CreateRunInput { + return { + tenantId: "hwlab", + projectId: "pikasTech/HWLAB", + workspaceRef: { kind: "host-path", path: "/tmp/agentrun-user-submitted-at" }, + sessionRef: { sessionId: "ses_user_submitted_at", metadata: { hwlabSessionId: "ses_user_submitted_at" } }, + resourceBundleRef: null, + providerId: "NC01", + backendProfile: "gpt-pika", + executionPolicy: { + sandbox: "danger-full-access", + approval: "never", + timeoutMs: 60_000, + network: "enabled", + secretScope: { allowCredentialEcho: false, providerCredentials: [] }, + }, + traceSink: null, + }; +} + +export default selfTest;