From 30a7fcc8ec9ab2ee24a5090892471728316064d6 Mon Sep 17 00:00:00 2001 From: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Date: Fri, 24 Jul 2026 16:04:43 +0800 Subject: [PATCH] fix(views): fold copy timestamps into full-body copy (merge #5873) Reconcile #5873's "timestamps in copied events" (merged to main) with this branch's full-body copy rewrite: traceEventCopyText now prefixes each line with the RFC 3339 timestamp when created_at is valid, on top of the complete (untruncated) body, events separated by a blank line. The two #5873 copy tests are updated to the full-body format; the orphaned formatEventForClipboard helper is removed. Co-Authored-By: Claude Fable 5 --- .../task-transcript/agent-transcript-dialog.test.tsx | 8 +++++--- .../views/common/task-transcript/trace-event-presenter.ts | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/views/common/task-transcript/agent-transcript-dialog.test.tsx b/packages/views/common/task-transcript/agent-transcript-dialog.test.tsx index e8cf14f2e..17020185c 100644 --- a/packages/views/common/task-transcript/agent-transcript-dialog.test.tsx +++ b/packages/views/common/task-transcript/agent-transcript-dialog.test.tsx @@ -408,11 +408,13 @@ describe("AgentTranscriptDialog", () => { fireEvent.click(screen.getByRole("button", { name: "Copy all" })); + // Full body (not the truncated summary) with the RFC 3339 prefix, events + // separated by a blank line. expect(copyTextMock).toHaveBeenCalledWith( [ - "[2026-06-08T00:00:00.000Z] [Agent] Agent summary", + "[2026-06-08T00:00:00.000Z] [Agent] Agent summary\nAgent hidden detail", "[2026-06-08T08:00:05.123Z] [Thinking] Thinking summary", - ].join("\n"), + ].join("\n\n"), ); }); @@ -434,7 +436,7 @@ describe("AgentTranscriptDialog", () => { fireEvent.click(screen.getByRole("button", { name: "Copy all" })); expect(copyTextMock).toHaveBeenCalledWith( - ["[Agent] Missing timestamp", "[Error] Invalid timestamp"].join("\n"), + ["[Agent] Missing timestamp", "[Error] Invalid timestamp"].join("\n\n"), ); }); }); diff --git a/packages/views/common/task-transcript/trace-event-presenter.ts b/packages/views/common/task-transcript/trace-event-presenter.ts index fc04601ab..6ccddda69 100644 --- a/packages/views/common/task-transcript/trace-event-presenter.ts +++ b/packages/views/common/task-transcript/trace-event-presenter.ts @@ -147,7 +147,8 @@ export function traceEventSummary(event: TraceEvent): string { /** * Full, untruncated text for "copy all" — the complete body, not the one-line * summary. Tool calls copy their full input JSON; results and prose copy their - * whole content. Callers apply secret redaction on the result. + * whole content. An RFC 3339 timestamp prefixes the line when the event has a + * valid `created_at` (#5873). Callers apply secret redaction on the result. */ export function traceEventCopyText(event: TraceEvent): string { const label = traceEventLabel(event); @@ -162,7 +163,9 @@ export function traceEventCopyText(event: TraceEvent): string { default: body = event.content ?? ""; } - return body ? `[${label}] ${body}` : `[${label}]`; + const date = event.created_at ? new Date(event.created_at) : null; + const timestamp = date && !Number.isNaN(date.getTime()) ? `[${date.toISOString()}] ` : ""; + return body ? `${timestamp}[${label}] ${body}` : `${timestamp}[${label}]`; } export function traceEventHasDetail(event: TraceEvent): boolean {