@sentry/junior-dashboard 0.280.0 → 0.281.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +23 -30
- package/dist/client-manifest.json +1 -1
- package/dist/index.js +23 -30
- package/dist/public/chunks/{AdminPage-YEKZOKH6.js → AdminPage-M5RBVZFN.js} +1 -1
- package/dist/public/chunks/{AutomationPage-5GS3IUAK.js → AutomationPage-WALCREDT.js} +1 -1
- package/dist/public/chunks/{AutomationRunsPage-IPYEZU4L.js → AutomationRunsPage-CV47E4UX.js} +1 -1
- package/dist/public/chunks/{AutomationsPage-HSAYPC3C.js → AutomationsPage-57L3AQVJ.js} +1 -1
- package/dist/public/chunks/{CodePage-IPFKXWFB.js → CodePage-XJUYMFJH.js} +1 -1
- package/dist/public/chunks/{ConnectionsPage-5XUEK6FS.js → ConnectionsPage-3QQAGYWF.js} +1 -1
- package/dist/public/chunks/{LocationDetailPage-27ETUGR6.js → LocationDetailPage-4IL5HQML.js} +1 -1
- package/dist/public/chunks/{LocationsPage-WOKMQAGM.js → LocationsPage-D2DUQAHJ.js} +1 -1
- package/dist/public/chunks/{PeoplePage-6YQLDOUL.js → PeoplePage-6F5GPQ7C.js} +1 -1
- package/dist/public/chunks/{PersonProfilePage-GYMAZFIK.js → PersonProfilePage-SPAYQPTD.js} +1 -1
- package/dist/public/chunks/{PersonalTokensPage-4BCR744B.js → PersonalTokensPage-SHAUJ74M.js} +1 -1
- package/dist/public/chunks/{PluginUserPage-IP6WL7MD.js → PluginUserPage-64FIWD7M.js} +1 -1
- package/dist/public/chunks/{RepositoryPage-TRD44LQ3.js → RepositoryPage-L7IHOXSN.js} +1 -1
- package/dist/public/chunks/{SettingsPage-4E3SLQ36.js → SettingsPage-U7WG4FHE.js} +1 -1
- package/dist/public/chunks/{SystemPage-C3XBKXKW.js → SystemPage-ZBC43OJH.js} +1 -1
- package/dist/public/chunks/{WorkspaceFormPage-2LS2X67Q.js → WorkspaceFormPage-3NVIIZ4P.js} +1 -1
- package/dist/public/chunks/{WorkspacesPage-5WB3CUTX.js → WorkspacesPage-G73HPBDD.js} +1 -1
- package/dist/public/chunks/{chunk-VFEBNOPX.js → chunk-2J3LGF5Q.js} +1 -1
- package/dist/public/chunks/chunk-2NNKHSZE.js +1 -0
- package/dist/public/chunks/chunk-4TQSTCIN.js +13 -0
- package/dist/public/chunks/chunk-64GPEGGE.js +1 -0
- package/dist/public/chunks/{chunk-WZVO3HG4.js → chunk-6FHY65EQ.js} +1 -1
- package/dist/public/chunks/{chunk-YYNMZ4WC.js → chunk-DEEO4D4N.js} +1 -1
- package/dist/public/chunks/{chunk-SDKV3OID.js → chunk-FSGVY7HB.js} +1 -1
- package/dist/public/chunks/chunk-GZBMHYYU.js +1 -0
- package/dist/public/chunks/{chunk-NQMDED2R.js → chunk-II4NXLSQ.js} +1 -1
- package/dist/public/chunks/{chunk-B6HGRBBX.js → chunk-ILH47V7O.js} +1 -1
- package/dist/public/chunks/{chunk-GRMX2HX6.js → chunk-JPL2NRWK.js} +1 -1
- package/dist/public/chunks/{chunk-NQOJAZFQ.js → chunk-JVJ5UWIK.js} +1 -1
- package/dist/public/chunks/{chunk-V5UDSIRA.js → chunk-K4TYMAA3.js} +1 -1
- package/dist/public/chunks/{chunk-EFEREKX4.js → chunk-KDUTK357.js} +1 -1
- package/dist/public/chunks/{chunk-RHIXHBS5.js → chunk-LZYAHJVQ.js} +1 -1
- package/dist/public/chunks/{chunk-5GZDBGAR.js → chunk-MKKFXRYO.js} +1 -1
- package/dist/public/chunks/{chunk-PEQNT5MO.js → chunk-NGQRNS3C.js} +1 -1
- package/dist/public/chunks/{chunk-IA6BJDKN.js → chunk-ONDKE72P.js} +1 -1
- package/dist/public/chunks/{chunk-WJ3OXMVX.js → chunk-PG7M7L24.js} +1 -1
- package/dist/public/chunks/{chunk-6GQL3EVJ.js → chunk-QQUFROWT.js} +1 -1
- package/dist/public/chunks/{chunk-UAH6DWNS.js → chunk-RB5FBDEY.js} +1 -1
- package/dist/public/chunks/{chunk-A2QWWA7O.js → chunk-RGXXD4DM.js} +1 -1
- package/dist/public/chunks/{chunk-AYXSBMWA.js → chunk-TC7TU4GK.js} +1 -1
- package/dist/public/chunks/chunk-WLIOZO3W.js +1 -0
- package/dist/public/chunks/{chunk-VXT3FIVL.js → chunk-XDUSY26N.js} +11 -11
- package/dist/public/client-4OAAOHF4.js +68 -0
- package/dist/tailwind.css +1 -1
- package/package.json +4 -4
- package/src/client/components/BottomSheet.tsx +1 -1
- package/src/client/components/DetailsPanel.tsx +2 -1
- package/src/client/conversations/ConversationBrief.tsx +129 -65
- package/src/client/conversations/ConversationDetails.tsx +13 -14
- package/src/client/conversations/ConversationEventLog.tsx +20 -97
- package/src/client/conversations/ConversationHeader.tsx +41 -26
- package/src/client/conversations/ConversationHeaderActions.tsx +3 -1
- package/src/client/conversations/ConversationLinkedWork.tsx +30 -10
- package/src/client/conversations/ConversationMeta.tsx +15 -15
- package/src/client/conversations/ConversationPage.tsx +31 -7
- package/src/client/conversations/ConversationTranscript.tsx +234 -186
- package/src/client/conversations/ConversationUsageBreakdown.tsx +142 -64
- package/src/client/conversations/DetailsList.tsx +7 -1
- package/src/client/conversations/PendingMailboxStack.tsx +88 -44
- package/src/client/conversations/TranscriptActivityGroup.tsx +7 -14
- package/src/client/conversations/TranscriptEventView.tsx +7 -3
- package/src/client/conversations/TranscriptReasoningView.tsx +4 -2
- package/src/client/conversations/TranscriptRows.tsx +37 -5
- package/src/client/conversations/TranscriptView.tsx +4 -0
- package/src/client/conversations/queries.ts +74 -43
- package/src/client/conversations/transcriptBottomPinning.ts +13 -5
- package/src/client/conversations/transcriptListRows.ts +215 -0
- package/src/client/conversations/virtualRows.ts +168 -0
- package/src/client/http.ts +6 -5
- package/src/client/sentry.ts +53 -3
- package/src/conversation-cache.ts +8 -10
- package/src/mock-reporting/fixtures.ts +0 -8
- package/dist/public/chunks/chunk-GO45RQDL.js +0 -1
- package/dist/public/chunks/chunk-N4AONKD3.js +0 -1
- package/dist/public/chunks/chunk-QNA7F7QB.js +0 -1
- package/dist/public/chunks/chunk-R4ORRE77.js +0 -1
- package/dist/public/chunks/chunk-Z2JPRGFT.js +0 -1
- package/dist/public/client-TYC7JKRE.js +0 -91
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
memo,
|
|
3
|
+
useCallback,
|
|
4
|
+
useMemo,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
} from "react";
|
|
2
9
|
import { History } from "lucide-react";
|
|
3
10
|
import type { ConversationMailboxMessage } from "./conversationOutbox";
|
|
4
11
|
|
|
@@ -20,11 +27,7 @@ import type {
|
|
|
20
27
|
} from "../types";
|
|
21
28
|
import { TranscriptSubagentView } from "./TranscriptSubagentView";
|
|
22
29
|
import { TranscriptContextEventView } from "./TranscriptContextEventView";
|
|
23
|
-
import {
|
|
24
|
-
isCollapsibleActivityEntry,
|
|
25
|
-
quietTurnEntryKeys,
|
|
26
|
-
TranscriptActivityGroup,
|
|
27
|
-
} from "./TranscriptActivityGroup";
|
|
30
|
+
import { TranscriptActivityGroup } from "./TranscriptActivityGroup";
|
|
28
31
|
import { TranscriptToolView } from "./TranscriptToolView";
|
|
29
32
|
import { TranscriptReasoningView } from "./TranscriptReasoningView";
|
|
30
33
|
import { TranscriptAttachmentsDeliveredView } from "./TranscriptAttachmentsDeliveredView";
|
|
@@ -50,16 +53,23 @@ import {
|
|
|
50
53
|
TranscriptAutomationTriggerView,
|
|
51
54
|
} from "./TranscriptAutomationTriggerView";
|
|
52
55
|
import { TranscriptTypingIndicator } from "./TranscriptTypingIndicator";
|
|
56
|
+
import { groupTranscriptMessages } from "./transcriptRenderModel";
|
|
57
|
+
import { useTranscriptSearch } from "./transcriptSearch";
|
|
53
58
|
import {
|
|
54
|
-
|
|
55
|
-
type RenderedTranscriptEntry,
|
|
56
|
-
} from "./transcriptRenderModel";
|
|
57
|
-
import { entryMatchesSearch, useTranscriptSearch } from "./transcriptSearch";
|
|
58
|
-
import {
|
|
59
|
+
TranscriptOpenRows,
|
|
59
60
|
TranscriptRow,
|
|
60
61
|
TranscriptRows,
|
|
61
62
|
TranscriptUnreadMarker,
|
|
62
63
|
} from "./TranscriptRows";
|
|
64
|
+
import {
|
|
65
|
+
defaultTranscriptRowSize,
|
|
66
|
+
rowIndexForSeq,
|
|
67
|
+
transcriptListRows,
|
|
68
|
+
transcriptRowSizeClass,
|
|
69
|
+
UNREAD_MARKER_KEY,
|
|
70
|
+
type TranscriptListRow,
|
|
71
|
+
} from "./transcriptListRows";
|
|
72
|
+
import { useVirtualRows } from "./virtualRows";
|
|
63
73
|
import { TranscriptTimestampProvider } from "./TranscriptTimestamp";
|
|
64
74
|
import type { TranscriptUnreadRange } from "./transcriptReadPosition";
|
|
65
75
|
|
|
@@ -81,7 +91,11 @@ type TranscriptToolEntry = Extract<TranscriptEntry, { kind: "tool" }>;
|
|
|
81
91
|
|
|
82
92
|
function renderReasoningEntry(entry: TranscriptReasoningEntry): ReactNode {
|
|
83
93
|
return (
|
|
84
|
-
<TranscriptReasoningView
|
|
94
|
+
<TranscriptReasoningView
|
|
95
|
+
openKey={entry.key}
|
|
96
|
+
part={entry.part}
|
|
97
|
+
timestamp={entry.timestamp}
|
|
98
|
+
/>
|
|
85
99
|
);
|
|
86
100
|
}
|
|
87
101
|
|
|
@@ -96,6 +110,10 @@ export const ConversationTranscriptView = memo(
|
|
|
96
110
|
/** Sends that history does not have yet. History wins on message id. */
|
|
97
111
|
pendingMessages?: readonly ConversationMailboxMessage[];
|
|
98
112
|
responding?: boolean;
|
|
113
|
+
/** Keep the rows around this event seq mounted, to show it. */
|
|
114
|
+
revealSeq?: number;
|
|
115
|
+
/** The row that holds the reader's place, from the scroll owner. */
|
|
116
|
+
scrollAnchorKey?: () => string | undefined;
|
|
99
117
|
/** Show the "New" marker before the first row in this range. */
|
|
100
118
|
unread?: TranscriptUnreadRange;
|
|
101
119
|
}) {
|
|
@@ -119,6 +137,8 @@ export const ConversationTranscriptView = memo(
|
|
|
119
137
|
conversation={props.conversation}
|
|
120
138
|
messages={messages}
|
|
121
139
|
responding={props.responding}
|
|
140
|
+
revealSeq={props.revealSeq}
|
|
141
|
+
scrollAnchorKey={props.scrollAnchorKey}
|
|
122
142
|
unread={props.unread}
|
|
123
143
|
/>
|
|
124
144
|
</section>
|
|
@@ -127,16 +147,22 @@ export const ConversationTranscriptView = memo(
|
|
|
127
147
|
},
|
|
128
148
|
);
|
|
129
149
|
|
|
130
|
-
function SegmentEvents(
|
|
131
|
-
|
|
132
|
-
|
|
150
|
+
function SegmentEvents(
|
|
151
|
+
props: TranscriptListPlacement & {
|
|
152
|
+
onOpenSubagentTranscript?: (args: {
|
|
153
|
+
part: TranscriptViewSubagentPart;
|
|
154
|
+
conversation: ConversationTranscript;
|
|
155
|
+
}) => void;
|
|
133
156
|
conversation: ConversationTranscript;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
157
|
+
messages: TranscriptViewMessage[];
|
|
158
|
+
responding?: boolean;
|
|
159
|
+
unread?: TranscriptUnreadRange;
|
|
160
|
+
},
|
|
161
|
+
) {
|
|
162
|
+
const placement = {
|
|
163
|
+
revealSeq: props.revealSeq,
|
|
164
|
+
scrollAnchorKey: props.scrollAnchorKey,
|
|
165
|
+
};
|
|
140
166
|
return (
|
|
141
167
|
<TranscriptRows>
|
|
142
168
|
{props.conversation.eventHistory.status === "expired" ? (
|
|
@@ -146,6 +172,7 @@ function SegmentEvents(props: {
|
|
|
146
172
|
/>
|
|
147
173
|
) : props.conversation.eventHistory.status === "available" ? (
|
|
148
174
|
<VisibleTranscriptEntries
|
|
175
|
+
{...placement}
|
|
149
176
|
onOpenSubagentTranscript={props.onOpenSubagentTranscript}
|
|
150
177
|
transcript={props.messages}
|
|
151
178
|
conversation={props.conversation}
|
|
@@ -154,12 +181,14 @@ function SegmentEvents(props: {
|
|
|
154
181
|
) : props.conversation.eventHistory.status === "redacted" &&
|
|
155
182
|
props.messages.length > 0 ? (
|
|
156
183
|
<RedactedTranscriptView
|
|
184
|
+
{...placement}
|
|
157
185
|
onOpenSubagentTranscript={props.onOpenSubagentTranscript}
|
|
158
186
|
conversation={props.conversation}
|
|
159
187
|
messages={props.messages}
|
|
160
188
|
/>
|
|
161
189
|
) : props.messages.length > 0 ? (
|
|
162
190
|
<VisibleTranscriptEntries
|
|
191
|
+
{...placement}
|
|
163
192
|
onOpenSubagentTranscript={props.onOpenSubagentTranscript}
|
|
164
193
|
transcript={props.messages}
|
|
165
194
|
conversation={props.conversation}
|
|
@@ -214,15 +243,17 @@ function ExpiredTranscriptView(props: {
|
|
|
214
243
|
);
|
|
215
244
|
}
|
|
216
245
|
|
|
217
|
-
const VisibleTranscriptEntries = memo(function VisibleTranscriptEntries(
|
|
218
|
-
|
|
219
|
-
|
|
246
|
+
const VisibleTranscriptEntries = memo(function VisibleTranscriptEntries(
|
|
247
|
+
props: TranscriptListPlacement & {
|
|
248
|
+
onOpenSubagentTranscript?: (args: {
|
|
249
|
+
part: TranscriptViewSubagentPart;
|
|
250
|
+
conversation: ConversationTranscript;
|
|
251
|
+
}) => void;
|
|
252
|
+
transcript: TranscriptViewMessage[];
|
|
220
253
|
conversation: ConversationTranscript;
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
unread?: TranscriptUnreadRange;
|
|
225
|
-
}) {
|
|
254
|
+
unread?: TranscriptUnreadRange;
|
|
255
|
+
},
|
|
256
|
+
) {
|
|
226
257
|
const entries = useMemo(
|
|
227
258
|
() => groupTranscriptMessages(props.transcript),
|
|
228
259
|
[props.transcript],
|
|
@@ -230,7 +261,11 @@ const VisibleTranscriptEntries = memo(function VisibleTranscriptEntries(props: {
|
|
|
230
261
|
return (
|
|
231
262
|
<TranscriptEntryList
|
|
232
263
|
entries={entries}
|
|
264
|
+
// Open rows and row sizes belong to one Conversation.
|
|
265
|
+
key={props.conversation.conversationId}
|
|
233
266
|
keyPrefix={props.conversation.conversationId}
|
|
267
|
+
revealSeq={props.revealSeq}
|
|
268
|
+
scrollAnchorKey={props.scrollAnchorKey}
|
|
234
269
|
unread={props.unread}
|
|
235
270
|
renderContext={(entry) => (
|
|
236
271
|
<TranscriptRailEvent kind="compaction">
|
|
@@ -264,7 +299,7 @@ const VisibleTranscriptEntries = memo(function VisibleTranscriptEntries(props: {
|
|
|
264
299
|
kind="event"
|
|
265
300
|
objectType={entry.message.eventObjectType}
|
|
266
301
|
>
|
|
267
|
-
<TranscriptEventView message={entry.message} />
|
|
302
|
+
<TranscriptEventView message={entry.message} openKey={entry.key} />
|
|
268
303
|
<TranscriptRecalledMemories
|
|
269
304
|
className="mt-1"
|
|
270
305
|
message={entry.message}
|
|
@@ -341,9 +376,7 @@ const VisibleTranscriptEntries = memo(function VisibleTranscriptEntries(props: {
|
|
|
341
376
|
);
|
|
342
377
|
});
|
|
343
378
|
|
|
344
|
-
|
|
345
|
-
entries: TranscriptEntry[];
|
|
346
|
-
keyPrefix: string;
|
|
379
|
+
type TranscriptEntryRenderers = {
|
|
347
380
|
renderAttachmentsDelivered: (
|
|
348
381
|
entry: TranscriptAttachmentsDeliveredEntry,
|
|
349
382
|
) => ReactNode;
|
|
@@ -354,179 +387,194 @@ function TranscriptEntryList(props: {
|
|
|
354
387
|
renderReasoning: (entry: TranscriptReasoningEntry) => ReactNode;
|
|
355
388
|
renderSubagent: (entry: TranscriptSubagentEntry) => ReactNode;
|
|
356
389
|
renderTool: (entry: TranscriptToolEntry) => ReactNode;
|
|
357
|
-
|
|
358
|
-
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Render transcript entries as list rows. Only the rows near the viewport
|
|
394
|
+
* mount. These rows also stay mounted, because the scroll owner and the
|
|
395
|
+
* page find them in the DOM: the row that holds the reader's place, the
|
|
396
|
+
* "New" marker and the row after it, and the rows around `revealSeq`.
|
|
397
|
+
*/
|
|
398
|
+
function TranscriptEntryList(
|
|
399
|
+
props: TranscriptEntryRenderers &
|
|
400
|
+
TranscriptListPlacement & {
|
|
401
|
+
entries: TranscriptEntry[];
|
|
402
|
+
keyPrefix: string;
|
|
403
|
+
unread?: TranscriptUnreadRange;
|
|
404
|
+
},
|
|
405
|
+
) {
|
|
359
406
|
const search = useTranscriptSearch();
|
|
360
407
|
const activityKeys = useRef(new Map<string, string>());
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
408
|
+
const [openRows] = useState(() => new Map<string, boolean>());
|
|
409
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
410
|
+
const searchQuery = search.active ? search.normalizedQuery : undefined;
|
|
411
|
+
const rows = useMemo(
|
|
412
|
+
() =>
|
|
413
|
+
transcriptListRows({
|
|
414
|
+
entries: props.entries,
|
|
415
|
+
keyPrefix: props.keyPrefix,
|
|
416
|
+
knownActivityKeys: activityKeys.current,
|
|
417
|
+
search: searchQuery,
|
|
418
|
+
unread: props.unread,
|
|
419
|
+
}),
|
|
420
|
+
[props.entries, props.keyPrefix, props.unread, searchQuery],
|
|
364
421
|
);
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
)
|
|
408
|
-
|
|
409
|
-
|
|
422
|
+
const indexByKey = useMemo(
|
|
423
|
+
() => new Map(rows.map((row, index) => [row.key, index])),
|
|
424
|
+
[rows],
|
|
425
|
+
);
|
|
426
|
+
const anchorKey = props.scrollAnchorKey?.();
|
|
427
|
+
const markerIndex = indexByKey.get(UNREAD_MARKER_KEY);
|
|
428
|
+
// A memory row can sit at its event or on the message before it.
|
|
429
|
+
const revealIndex =
|
|
430
|
+
props.revealSeq === undefined
|
|
431
|
+
? undefined
|
|
432
|
+
: rowIndexForSeq(rows, props.revealSeq);
|
|
433
|
+
const virtualizer = useVirtualRows({
|
|
434
|
+
count: rows.length,
|
|
435
|
+
defaultSize: defaultTranscriptRowSize,
|
|
436
|
+
// The gap between rows, like the gap of the transcript stack.
|
|
437
|
+
gap: 4,
|
|
438
|
+
getItemKey: (index) => rows[index]!.key,
|
|
439
|
+
keptIndexes: [
|
|
440
|
+
anchorKey === undefined ? undefined : indexByKey.get(anchorKey),
|
|
441
|
+
// The scroll owner opens at the marker and holds the reader's place
|
|
442
|
+
// at the first unread row after it.
|
|
443
|
+
markerIndex,
|
|
444
|
+
markerIndex === undefined ? undefined : markerIndex + 1,
|
|
445
|
+
revealIndex,
|
|
446
|
+
revealIndex === undefined ? undefined : revealIndex - 1,
|
|
447
|
+
],
|
|
448
|
+
listRef,
|
|
449
|
+
sizeClass: (index) => transcriptRowSizeClass(rows[index]!),
|
|
450
|
+
});
|
|
451
|
+
// Rows render again only when the renderers change, not on each scroll.
|
|
452
|
+
const {
|
|
453
|
+
renderAttachmentsDelivered,
|
|
454
|
+
renderContext,
|
|
455
|
+
renderFailure,
|
|
456
|
+
renderMessage,
|
|
457
|
+
renderReasoning,
|
|
458
|
+
renderStructuredEvent,
|
|
459
|
+
renderSubagent,
|
|
460
|
+
renderTool,
|
|
461
|
+
} = props;
|
|
462
|
+
const renderEntry = useCallback(
|
|
463
|
+
(entry: TranscriptEntry): ReactNode => {
|
|
464
|
+
if (entry.kind === "subagent") return renderSubagent(entry);
|
|
465
|
+
if (entry.kind === "context") return renderContext(entry);
|
|
466
|
+
if (entry.kind === "attachments_delivered") {
|
|
467
|
+
return renderAttachmentsDelivered(entry);
|
|
410
468
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
entryMatchesSearch(candidate, search.normalizedQuery),
|
|
414
|
-
)
|
|
415
|
-
: activityEntries;
|
|
416
|
-
if (visibleEntries.length > 0) {
|
|
417
|
-
const activityKey = stableActivityGroupKey({
|
|
418
|
-
claimedKeys: claimedActivityKeys,
|
|
419
|
-
entries: activityEntries,
|
|
420
|
-
keyPrefix: props.keyPrefix,
|
|
421
|
-
knownKeys: activityKeys.current,
|
|
422
|
-
});
|
|
423
|
-
const lastSeq = lastEntrySeq(activityEntries);
|
|
424
|
-
// The marker goes before the group when any of it is unread.
|
|
425
|
-
pushRow(
|
|
426
|
-
lastSeq,
|
|
427
|
-
<TranscriptRow
|
|
428
|
-
anchorKey={activityKey}
|
|
429
|
-
indent
|
|
430
|
-
key={activityKey}
|
|
431
|
-
seq={lastSeq}
|
|
432
|
-
>
|
|
433
|
-
<TranscriptActivityGroup
|
|
434
|
-
entries={visibleEntries}
|
|
435
|
-
renderEntry={renderEntry}
|
|
436
|
-
/>
|
|
437
|
-
</TranscriptRow>,
|
|
438
|
-
);
|
|
469
|
+
if (entry.kind === "structured_event") {
|
|
470
|
+
return renderStructuredEvent(entry);
|
|
439
471
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
472
|
+
if (entry.kind === "failure") return renderFailure(entry);
|
|
473
|
+
if (entry.kind === "reasoning") return renderReasoning(entry);
|
|
474
|
+
if (entry.kind === "tool") return renderTool(entry);
|
|
475
|
+
return renderMessage(entry);
|
|
476
|
+
},
|
|
477
|
+
[
|
|
478
|
+
renderAttachmentsDelivered,
|
|
479
|
+
renderContext,
|
|
480
|
+
renderFailure,
|
|
481
|
+
renderMessage,
|
|
482
|
+
renderReasoning,
|
|
483
|
+
renderStructuredEvent,
|
|
484
|
+
renderSubagent,
|
|
485
|
+
renderTool,
|
|
486
|
+
],
|
|
487
|
+
);
|
|
454
488
|
|
|
455
489
|
if (search.active && rows.length === 0) {
|
|
456
490
|
return <EmptyTelemetry>No events match your search.</EmptyTelemetry>;
|
|
457
491
|
}
|
|
458
492
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
493
|
+
return (
|
|
494
|
+
<TranscriptOpenRows value={openRows}>
|
|
495
|
+
<div
|
|
496
|
+
className="relative min-w-0"
|
|
497
|
+
ref={listRef}
|
|
498
|
+
style={{ height: virtualizer.getTotalSize() }}
|
|
499
|
+
>
|
|
500
|
+
{virtualizer.getVirtualItems().map((item) => (
|
|
501
|
+
<VirtualTranscriptRow
|
|
502
|
+
index={item.index}
|
|
503
|
+
key={item.key}
|
|
504
|
+
measure={virtualizer.measureElement}
|
|
505
|
+
offset={item.start - virtualizer.options.scrollMargin}
|
|
506
|
+
renderEntry={renderEntry}
|
|
507
|
+
row={rows[item.index]!}
|
|
508
|
+
/>
|
|
509
|
+
))}
|
|
510
|
+
</div>
|
|
511
|
+
</TranscriptOpenRows>
|
|
512
|
+
);
|
|
462
513
|
}
|
|
463
514
|
|
|
515
|
+
/** Where the list keeps rows mounted outside the viewport. */
|
|
516
|
+
type TranscriptListPlacement = {
|
|
517
|
+
/** Keep the rows around this event seq mounted, to show it. */
|
|
518
|
+
revealSeq?: number;
|
|
519
|
+
/** The row that holds the reader's place, from the scroll owner. */
|
|
520
|
+
scrollAnchorKey?: () => string | undefined;
|
|
521
|
+
};
|
|
522
|
+
|
|
464
523
|
/**
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
* the read position. Rows after the range arrived after open, so they get no
|
|
468
|
-
* marker.
|
|
524
|
+
* Place one list row at its offset. Rows render again only when their row
|
|
525
|
+
* or offset changes, not when the mounted range changes.
|
|
469
526
|
*/
|
|
470
|
-
function
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
keyPrefix: string;
|
|
502
|
-
knownKeys: Map<string, string>;
|
|
503
|
-
}): string {
|
|
504
|
-
const entryKeys = args.entries.map(
|
|
505
|
-
(entry) => `${args.keyPrefix}:${entry.key}`,
|
|
527
|
+
const VirtualTranscriptRow = memo(function VirtualTranscriptRow(props: {
|
|
528
|
+
index: number;
|
|
529
|
+
measure: (element: HTMLElement | null) => void;
|
|
530
|
+
offset: number;
|
|
531
|
+
renderEntry: (entry: TranscriptEntry) => ReactNode;
|
|
532
|
+
row: TranscriptListRow;
|
|
533
|
+
}) {
|
|
534
|
+
const { row } = props;
|
|
535
|
+
return (
|
|
536
|
+
<div
|
|
537
|
+
className="absolute left-0 top-0 w-full"
|
|
538
|
+
data-index={props.index}
|
|
539
|
+
ref={props.measure}
|
|
540
|
+
style={{ transform: `translateY(${props.offset}px)` }}
|
|
541
|
+
>
|
|
542
|
+
{row.kind === "unread_marker" ? (
|
|
543
|
+
<TranscriptUnreadMarker />
|
|
544
|
+
) : row.kind === "activity" ? (
|
|
545
|
+
<TranscriptRow anchorKey={row.key} indent seq={row.seq}>
|
|
546
|
+
<TranscriptActivityGroup
|
|
547
|
+
entries={row.entries}
|
|
548
|
+
openKey={row.key}
|
|
549
|
+
renderEntry={props.renderEntry}
|
|
550
|
+
/>
|
|
551
|
+
</TranscriptRow>
|
|
552
|
+
) : (
|
|
553
|
+
<TranscriptRow anchorKey={row.key} seq={row.seq}>
|
|
554
|
+
{props.renderEntry(row.entry)}
|
|
555
|
+
</TranscriptRow>
|
|
556
|
+
)}
|
|
557
|
+
</div>
|
|
506
558
|
);
|
|
507
|
-
|
|
508
|
-
.map((entryKey) => args.knownKeys.get(entryKey))
|
|
509
|
-
.find((key) => key !== undefined && !args.claimedKeys.has(key));
|
|
510
|
-
const groupKey =
|
|
511
|
-
knownKey ?? `${args.keyPrefix}:activity:${args.entries[0]!.key}`;
|
|
512
|
-
|
|
513
|
-
args.claimedKeys.add(groupKey);
|
|
514
|
-
entryKeys.forEach((entryKey) => args.knownKeys.set(entryKey, groupKey));
|
|
515
|
-
return groupKey;
|
|
516
|
-
}
|
|
559
|
+
});
|
|
517
560
|
|
|
518
|
-
function RedactedTranscriptView(
|
|
519
|
-
|
|
520
|
-
|
|
561
|
+
function RedactedTranscriptView(
|
|
562
|
+
props: TranscriptListPlacement & {
|
|
563
|
+
onOpenSubagentTranscript?: (args: {
|
|
564
|
+
part: TranscriptViewSubagentPart;
|
|
565
|
+
conversation: ConversationTranscript;
|
|
566
|
+
}) => void;
|
|
521
567
|
conversation: ConversationTranscript;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}) {
|
|
568
|
+
messages: TranscriptViewMessage[];
|
|
569
|
+
},
|
|
570
|
+
) {
|
|
526
571
|
return (
|
|
527
572
|
<TranscriptEntryList
|
|
528
573
|
entries={groupTranscriptMessages(props.messages)}
|
|
574
|
+
key={props.conversation.conversationId}
|
|
529
575
|
keyPrefix={`${props.conversation.conversationId}:redacted`}
|
|
576
|
+
revealSeq={props.revealSeq}
|
|
577
|
+
scrollAnchorKey={props.scrollAnchorKey}
|
|
530
578
|
renderContext={(entry) => (
|
|
531
579
|
<TranscriptRailEvent kind="compaction">
|
|
532
580
|
<TranscriptContextEventView
|
|
@@ -556,7 +604,7 @@ function RedactedTranscriptView(props: {
|
|
|
556
604
|
kind="event"
|
|
557
605
|
objectType={entry.message.eventObjectType}
|
|
558
606
|
>
|
|
559
|
-
<TranscriptEventView message={entry.message} />
|
|
607
|
+
<TranscriptEventView message={entry.message} openKey={entry.key} />
|
|
560
608
|
</TranscriptRailEvent>
|
|
561
609
|
) : entry.message.context ? (
|
|
562
610
|
<TranscriptRailEvent kind="message_context">
|