@sentry/junior-dashboard 0.248.0 → 0.249.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 +2 -2
- package/dist/client.js +36 -35
- package/dist/index.js +2 -2
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
- package/src/client/App.tsx +1 -5
- package/src/client/components/ActorAvatar.tsx +7 -4
- package/src/client/components/AutomationCard.tsx +2 -2
- package/src/client/components/Button.tsx +12 -11
- package/src/client/components/ConversationList.tsx +3 -3
- package/src/client/components/ConversationSummary.tsx +2 -1
- package/src/client/components/DetailList.tsx +3 -3
- package/src/client/components/Drawer.tsx +2 -2
- package/src/client/components/EmptyTelemetry.tsx +1 -1
- package/src/client/components/Field.tsx +1 -2
- package/src/client/components/FilterBar.tsx +6 -6
- package/src/client/components/Metric.tsx +4 -4
- package/src/client/components/Notice.tsx +7 -7
- package/src/client/components/PageContentSkeleton.tsx +2 -2
- package/src/client/components/Pagination.tsx +2 -2
- package/src/client/components/ParticipantAvatarStack.tsx +4 -4
- package/src/client/components/ProfileMenu.tsx +5 -7
- package/src/client/components/README.md +122 -58
- package/src/client/components/SearchInput.tsx +4 -3
- package/src/client/components/SegmentedNav.tsx +10 -17
- package/src/client/components/SegmentedTabs.tsx +3 -3
- package/src/client/components/Select.tsx +1 -1
- package/src/client/components/SelectableRow.tsx +2 -2
- package/src/client/components/Skeleton.tsx +1 -1
- package/src/client/components/StatusChip.tsx +1 -1
- package/src/client/components/StatusDot.tsx +1 -1
- package/src/client/components/TextInput.tsx +1 -1
- package/src/client/components/Tooltip.tsx +2 -2
- package/src/client/components/VersionDriftBanner.tsx +2 -2
- package/src/client/components/charts/ActivityChart.tsx +5 -6
- package/src/client/components/charts/CacheWrites.tsx +3 -3
- package/src/client/components/charts/ChartHeader.tsx +4 -4
- package/src/client/components/charts/ChartLegend.tsx +1 -1
- package/src/client/components/charts/InputCacheChart.tsx +5 -5
- package/src/client/components/charts/WorkspaceUsageChart.tsx +4 -11
- package/src/client/components/controls/DirectorySortSelect.tsx +2 -2
- package/src/client/components/directory/DirectoryMetric.tsx +2 -2
- package/src/client/components/directory/DirectoryRowsSkeleton.tsx +5 -5
- package/src/client/components/directory/DirectoryTable.tsx +3 -3
- package/src/client/components/layout/CardHeader.tsx +4 -4
- package/src/client/components/layout/DashboardChrome.tsx +9 -3
- package/src/client/components/layout/DashboardHeader.tsx +7 -7
- package/src/client/components/layout/PageHeader.tsx +2 -2
- package/src/client/components/layout/SecondaryNavigation.tsx +7 -14
- package/src/client/components/layout/SectionIntro.tsx +1 -1
- package/src/client/components/layout/SectionTitle.tsx +1 -1
- package/src/client/components/metrics/StatCard.tsx +2 -2
- package/src/client/conversations/ConversationArchiveNotices.tsx +1 -1
- package/src/client/conversations/ConversationBrief.tsx +4 -4
- package/src/client/conversations/ConversationChildAgents.tsx +7 -4
- package/src/client/conversations/ConversationComposer.tsx +8 -7
- package/src/client/conversations/ConversationHeader.tsx +5 -5
- package/src/client/conversations/ConversationHeaderActions.tsx +9 -9
- package/src/client/conversations/ConversationHomeList.tsx +3 -3
- package/src/client/conversations/ConversationListStatusIcon.tsx +1 -1
- package/src/client/conversations/ConversationMemories.tsx +4 -4
- package/src/client/conversations/ConversationMeta.tsx +10 -10
- package/src/client/conversations/ConversationPage.tsx +2 -1
- package/src/client/conversations/ConversationSidebar.tsx +6 -6
- package/src/client/conversations/ConversationUsageBreakdown.tsx +4 -4
- package/src/client/conversations/ConversationWorkspace.tsx +1 -1
- package/src/client/conversations/ConversationWorkspaceLoading.tsx +4 -4
- package/src/client/conversations/CopyMarkdownButton.tsx +1 -1
- package/src/client/conversations/EventUsage.tsx +2 -2
- package/src/client/conversations/PendingMailboxStack.tsx +5 -5
- package/src/client/conversations/README.md +9 -0
- package/src/client/conversations/SubagentTranscriptDrawer.tsx +39 -23
- package/src/client/conversations/ToolFrame.tsx +36 -14
- package/src/client/conversations/TranscriptActivityGroup.tsx +10 -3
- package/src/client/conversations/TranscriptAttachmentsDeliveredView.tsx +4 -6
- package/src/client/conversations/TranscriptContextEventView.tsx +2 -2
- package/src/client/conversations/TranscriptEventView.tsx +1 -1
- package/src/client/conversations/TranscriptMarkdown.tsx +3 -3
- package/src/client/conversations/TranscriptMessageContextView.tsx +7 -7
- package/src/client/conversations/TranscriptMessageView.tsx +2 -6
- package/src/client/conversations/TranscriptRailEvent.tsx +20 -8
- package/src/client/conversations/TranscriptReasoningView.tsx +12 -12
- package/src/client/conversations/TranscriptStructuredEventView.tsx +16 -11
- package/src/client/conversations/TranscriptSubagentView.tsx +64 -39
- package/src/client/conversations/TranscriptText.tsx +5 -4
- package/src/client/conversations/TranscriptToolView.tsx +9 -11
- package/src/client/conversations/TranscriptTurnContextView.tsx +3 -3
- package/src/client/conversations/TranscriptView.tsx +3 -3
- package/src/client/conversations/UsageCard.tsx +1 -1
- package/src/client/conversations/eventTranscript.ts +7 -0
- package/src/client/conversations/transcriptMarkdownLinks.ts +2 -4
- package/src/client/conversations/transcriptStyles.ts +1 -1
- package/src/client/pages/PersonalTokensPage.tsx +4 -4
- package/src/client/pages/admin/AdminPage.tsx +2 -2
- package/src/client/pages/automations/AutomationCostChart.tsx +2 -2
- package/src/client/pages/automations/AutomationDetailsDrawer.tsx +5 -10
- package/src/client/pages/automations/AutomationEditor.tsx +1 -1
- package/src/client/pages/automations/AutomationExecutionChart.tsx +2 -2
- package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +2 -2
- package/src/client/pages/automations/AutomationExecutionsPage.tsx +4 -4
- package/src/client/pages/automations/AutomationRow.tsx +4 -4
- package/src/client/pages/automations/AutomationRunsPage.tsx +3 -3
- package/src/client/pages/automations/AutomationScheduleFields.tsx +1 -1
- package/src/client/pages/automations/AutomationVersionsPage.tsx +1 -1
- package/src/client/pages/code/CodeActivityChart.tsx +7 -6
- package/src/client/pages/code/CodeChangeRow.tsx +1 -1
- package/src/client/pages/code/CodePage.tsx +5 -5
- package/src/client/pages/code/RepositoryPage.tsx +2 -2
- package/src/client/pages/dev/ComponentsPage.tsx +40 -146
- package/src/client/pages/dev/TranscriptActivityFixtures.tsx +206 -0
- package/src/client/pages/locations/LocationDetailPage.tsx +4 -4
- package/src/client/pages/locations/LocationDirectory.tsx +1 -1
- package/src/client/pages/locations/PrivateActivityCard.tsx +3 -3
- package/src/client/pages/memory/MemoryCostChart.tsx +3 -5
- package/src/client/pages/memory/MemoryDetailsDrawer.tsx +5 -5
- package/src/client/pages/memory/MemoryPage.tsx +15 -15
- package/src/client/pages/memory/MemoryTimeline.tsx +3 -5
- package/src/client/pages/people/ContributionGrid.tsx +8 -5
- package/src/client/pages/people/PersonProfilePage.tsx +3 -6
- package/src/client/pages/people/ProfilePluginReports.tsx +2 -2
- package/src/client/pages/system/GuardianActivity.tsx +9 -9
- package/src/client/pages/system/PluginBarChart.tsx +4 -6
- package/src/client/pages/system/PluginDetails.tsx +11 -7
- package/src/client/pages/system/PluginPanels.tsx +8 -8
- package/src/client/pages/system/PluginReportRecordSet.tsx +14 -14
- package/src/client/pages/system/PluginReports.tsx +7 -11
- package/src/client/pages/system/SkillInventory.tsx +9 -9
- package/src/client/pages/system/SystemActivity.tsx +1 -1
- package/src/client/pages/system/SystemPage.tsx +3 -6
- package/src/client/pages/system/WorkspaceDetails.tsx +2 -5
- package/src/client/pages/system/WorkspaceEditor.tsx +2 -2
- package/src/client/pages/system/WorkspaceList.tsx +2 -2
- package/src/client/pages/user/PluginUserPage.tsx +3 -3
- package/src/client/styles.ts +5 -4
- package/src/client/types.ts +2 -0
- package/src/tailwind.css +36 -38
|
@@ -16,6 +16,15 @@ shared controls and overlays.
|
|
|
16
16
|
`flush` when the text already sits on the transcript edge. It extends the
|
|
17
17
|
padded control around that text. Do not repeat negative margins at call sites.
|
|
18
18
|
The caller owns the native `details` element and its content.
|
|
19
|
+
- Activity rows (tools, reasoning, and grouped rail events) share one
|
|
20
|
+
layout: a 1rem icon column, an 8px gap, then the title and metadata.
|
|
21
|
+
Expanded content sits in `transcriptActivityBodyClass` under the title.
|
|
22
|
+
`TranscriptActivityNesting` tells a rail event that it is inside an activity
|
|
23
|
+
group. Outside a group, the rail icon sits in the avatar column so the text
|
|
24
|
+
lines up with message text.
|
|
25
|
+
- `TranscriptSubagentView` renders a child agent as a card with its name,
|
|
26
|
+
status, run time, and title. It matches the child agent rows in the details
|
|
27
|
+
drawer and opens the child transcript.
|
|
19
28
|
- `TranscriptAttachments` owns wrapping for both message attachments and file
|
|
20
29
|
deliveries. `ImageAttachment` owns image previews.
|
|
21
30
|
- `TranscriptTurnContextView` owns context content. The shared `Drawer` owns
|
|
@@ -4,7 +4,11 @@ import { Link } from "react-router";
|
|
|
4
4
|
|
|
5
5
|
import { useConversationData } from "./queries";
|
|
6
6
|
import { conversationPath } from "./conversationRoutes";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
conversationDetailTitle,
|
|
9
|
+
formatMessageTimestamp,
|
|
10
|
+
formatRelativeMessageTimestamp,
|
|
11
|
+
} from "../format";
|
|
8
12
|
import { buildConversationMarkdown } from "../markdownExport";
|
|
9
13
|
import { Drawer } from "../components/Drawer";
|
|
10
14
|
import { SearchInput } from "../components/SearchInput";
|
|
@@ -22,6 +26,8 @@ import { transcriptEmptyClass } from "./transcriptStyles";
|
|
|
22
26
|
|
|
23
27
|
/** One child Conversation to show, with what its parent already knows. */
|
|
24
28
|
export interface SubagentTranscriptTarget {
|
|
29
|
+
/** Agent name, such as "planner". Shown beside the status. */
|
|
30
|
+
agentName?: string;
|
|
25
31
|
conversationId: string;
|
|
26
32
|
/** Task title or agent name, shown before the child loads. */
|
|
27
33
|
label?: string;
|
|
@@ -58,6 +64,11 @@ function SubagentTranscriptDrawerContent(props: {
|
|
|
58
64
|
const label =
|
|
59
65
|
props.target.label ?? conversationDetailTitle(detail) ?? "Subagent";
|
|
60
66
|
const status = statusLabel(props.target.status, detail?.status);
|
|
67
|
+
const agentName =
|
|
68
|
+
props.target.agentName && props.target.agentName !== label
|
|
69
|
+
? props.target.agentName
|
|
70
|
+
: undefined;
|
|
71
|
+
const startedAt = detail ? Date.parse(detail.startedAt) : undefined;
|
|
61
72
|
const searchOpenVisible = searchOpen || search.length > 0;
|
|
62
73
|
|
|
63
74
|
const titleId = "subagent-transcript-drawer-title";
|
|
@@ -100,42 +111,47 @@ function SubagentTranscriptDrawerContent(props: {
|
|
|
100
111
|
aria-hidden="true"
|
|
101
112
|
className="shrink-0 text-cyan-300"
|
|
102
113
|
size={16}
|
|
103
|
-
strokeWidth={2
|
|
114
|
+
strokeWidth={2}
|
|
104
115
|
/>
|
|
105
116
|
<h2
|
|
106
|
-
className="m-0 min-w-0 break-words text-lg font-
|
|
117
|
+
className="m-0 min-w-0 break-words font-display text-lg font-medium leading-tight tracking-tight text-dashboard-text"
|
|
107
118
|
id={titleId}
|
|
108
119
|
>
|
|
109
120
|
{label}
|
|
110
121
|
</h2>
|
|
111
122
|
</div>
|
|
112
|
-
<div className="mt-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
<div className="mt-1.5 flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs leading-5 text-dashboard-text-muted">
|
|
124
|
+
{agentName ? (
|
|
125
|
+
<span className="font-medium text-dashboard-text">
|
|
126
|
+
{agentName}
|
|
127
|
+
</span>
|
|
128
|
+
) : null}
|
|
129
|
+
{status ? (
|
|
130
|
+
<StatusChip size="compact" tone={subagentStatusTone(status)}>
|
|
131
|
+
{status}
|
|
132
|
+
</StatusChip>
|
|
133
|
+
) : null}
|
|
134
|
+
{detail && startedAt !== undefined ? (
|
|
135
|
+
<time
|
|
136
|
+
className="tabular-nums"
|
|
137
|
+
dateTime={detail.startedAt}
|
|
138
|
+
title={formatMessageTimestamp(startedAt, true)}
|
|
139
|
+
>
|
|
140
|
+
Started {formatRelativeMessageTimestamp(startedAt)}
|
|
141
|
+
</time>
|
|
142
|
+
) : null}
|
|
116
143
|
<Link
|
|
117
|
-
className="inline-flex w-fit items-center gap-1 font-
|
|
144
|
+
className="inline-flex w-fit items-center gap-1 font-medium text-dashboard-accent-text no-underline hover:underline"
|
|
118
145
|
onClick={props.onClose}
|
|
119
146
|
to={conversationPath(props.target.conversationId)}
|
|
120
147
|
>
|
|
121
148
|
Open conversation
|
|
122
|
-
<ExternalLink aria-hidden="true" size={12} strokeWidth={2
|
|
149
|
+
<ExternalLink aria-hidden="true" size={12} strokeWidth={2} />
|
|
123
150
|
</Link>
|
|
124
151
|
</div>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
<StatusChip size="compact" tone={subagentStatusTone(status)}>
|
|
129
|
-
{status}
|
|
130
|
-
</StatusChip>
|
|
131
|
-
) : null}
|
|
132
|
-
{detail ? (
|
|
133
|
-
<time className="font-mono" dateTime={detail.startedAt}>
|
|
134
|
-
{formatMessageTimestamp(Date.parse(detail.startedAt))}
|
|
135
|
-
</time>
|
|
136
|
-
) : null}
|
|
137
|
-
</div>
|
|
138
|
-
) : null}
|
|
152
|
+
<code className="mt-1 block min-w-0 break-all font-mono text-xs text-dashboard-text-faint">
|
|
153
|
+
{props.target.conversationId}
|
|
154
|
+
</code>
|
|
139
155
|
{searchOpenVisible ? (
|
|
140
156
|
<div className="mt-3 min-w-0">
|
|
141
157
|
<SearchInput
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useState, type ReactNode } from "react";
|
|
2
|
+
import type { LucideIcon } from "lucide-react";
|
|
2
3
|
|
|
3
4
|
import { cn } from "../styles";
|
|
4
5
|
import {
|
|
@@ -8,10 +9,17 @@ import {
|
|
|
8
9
|
import { useTranscriptSearch } from "./transcriptSearch";
|
|
9
10
|
import { TranscriptSummary } from "./TranscriptSummary";
|
|
10
11
|
|
|
12
|
+
/** Frame expanded transcript activity content below its row title. */
|
|
13
|
+
export const transcriptActivityBodyClass =
|
|
14
|
+
"ml-6 mt-1.5 min-w-0 overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-surface-panel";
|
|
15
|
+
|
|
11
16
|
/** Render the shared expandable/non-expandable frame for transcript tools. */
|
|
12
17
|
export function ToolFrame(props: {
|
|
13
18
|
children?: ReactNode;
|
|
14
19
|
expandable?: boolean;
|
|
20
|
+
/** Icon in the activity icon column. Rail events pass their own icon. */
|
|
21
|
+
icon?: LucideIcon;
|
|
22
|
+
iconClassName?: string;
|
|
15
23
|
meta: string[];
|
|
16
24
|
mobileSummaryMeta?: string;
|
|
17
25
|
signature: ReactNode;
|
|
@@ -21,7 +29,8 @@ export function ToolFrame(props: {
|
|
|
21
29
|
const metaText = props.meta.join(" · ");
|
|
22
30
|
const interactive = props.expandable ?? Boolean(props.children);
|
|
23
31
|
const staticFrame = searchActive || !interactive;
|
|
24
|
-
const
|
|
32
|
+
const Icon = props.icon;
|
|
33
|
+
const row = (
|
|
25
34
|
<TranscriptHeadingRow
|
|
26
35
|
left={
|
|
27
36
|
<>
|
|
@@ -62,42 +71,55 @@ export function ToolFrame(props: {
|
|
|
62
71
|
rightClassName="ml-3 min-w-0 max-md:hidden"
|
|
63
72
|
/>
|
|
64
73
|
);
|
|
74
|
+
const header = Icon ? (
|
|
75
|
+
<div className="grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] items-center gap-2">
|
|
76
|
+
<Icon
|
|
77
|
+
aria-hidden="true"
|
|
78
|
+
className={cn("size-3.5 justify-self-center", props.iconClassName)}
|
|
79
|
+
strokeWidth={2}
|
|
80
|
+
/>
|
|
81
|
+
{row}
|
|
82
|
+
</div>
|
|
83
|
+
) : (
|
|
84
|
+
row
|
|
85
|
+
);
|
|
65
86
|
const mobileMeta =
|
|
66
87
|
metaText && props.children ? (
|
|
67
|
-
<div className="hidden min-w-0 break-words
|
|
88
|
+
<div className="hidden min-w-0 break-words border-b border-dashboard-border-subtle px-2.5 py-1.5 font-sans text-xs tabular-nums leading-snug text-dashboard-text-muted max-md:block">
|
|
68
89
|
{metaText}
|
|
69
90
|
</div>
|
|
70
91
|
) : null;
|
|
71
92
|
|
|
93
|
+
const body = props.children ? (
|
|
94
|
+
<div className={transcriptActivityBodyClass}>
|
|
95
|
+
{mobileMeta}
|
|
96
|
+
{props.children}
|
|
97
|
+
</div>
|
|
98
|
+
) : null;
|
|
99
|
+
|
|
72
100
|
// Force-expand tool details during search so highlighted matches are visible.
|
|
73
101
|
if (staticFrame) {
|
|
74
102
|
return (
|
|
75
|
-
<div className="min-w-0 max-w-full
|
|
76
|
-
<div className="block
|
|
103
|
+
<div className="min-w-0 max-w-full">
|
|
104
|
+
<div className="block py-1.5 font-mono text-xs leading-tight text-dashboard-text-muted">
|
|
77
105
|
{header}
|
|
78
106
|
</div>
|
|
79
|
-
{
|
|
80
|
-
{props.children}
|
|
107
|
+
{body}
|
|
81
108
|
</div>
|
|
82
109
|
);
|
|
83
110
|
}
|
|
84
111
|
|
|
85
112
|
return (
|
|
86
113
|
<details
|
|
87
|
-
className="group min-w-0 max-w-full
|
|
114
|
+
className="group min-w-0 max-w-full"
|
|
88
115
|
open={open}
|
|
89
116
|
onToggle={(event) => setOpen(event.currentTarget.open)}
|
|
90
117
|
>
|
|
91
|
-
<TranscriptSummary className="block font-mono text-xs leading-tight text-dashboard-text-muted">
|
|
118
|
+
<TranscriptSummary className="-mx-2 block font-mono text-xs leading-tight text-dashboard-text-muted">
|
|
92
119
|
{header}
|
|
93
120
|
</TranscriptSummary>
|
|
94
121
|
{/* Closed details hide DOM, but still mount React children and run Shiki. */}
|
|
95
|
-
{open ?
|
|
96
|
-
<>
|
|
97
|
-
{mobileMeta}
|
|
98
|
-
{props.children}
|
|
99
|
-
</>
|
|
100
|
-
) : null}
|
|
122
|
+
{open ? body : null}
|
|
101
123
|
</details>
|
|
102
124
|
);
|
|
103
125
|
}
|
|
@@ -7,6 +7,7 @@ import { formatMs } from "../format";
|
|
|
7
7
|
import type { RenderedTranscriptEntry } from "./transcriptRenderModel";
|
|
8
8
|
import { cn } from "../styles";
|
|
9
9
|
import { useTranscriptSearch } from "./transcriptSearch";
|
|
10
|
+
import { TranscriptActivityNesting } from "./TranscriptRailEvent";
|
|
10
11
|
import { TranscriptSummary } from "./TranscriptSummary";
|
|
11
12
|
|
|
12
13
|
function countLabel(count: number, singular: string, plural: string): string {
|
|
@@ -156,7 +157,11 @@ export function TranscriptActivityGroup(props: {
|
|
|
156
157
|
const live = hasLiveActivity(props.entries);
|
|
157
158
|
|
|
158
159
|
if (searchActive) {
|
|
159
|
-
return
|
|
160
|
+
return (
|
|
161
|
+
<TranscriptActivityNesting.Provider value>
|
|
162
|
+
<div className="grid min-w-0 gap-1">{rows}</div>
|
|
163
|
+
</TranscriptActivityNesting.Provider>
|
|
164
|
+
);
|
|
160
165
|
}
|
|
161
166
|
|
|
162
167
|
const open = activityGroupOpen(userOpen);
|
|
@@ -167,7 +172,7 @@ export function TranscriptActivityGroup(props: {
|
|
|
167
172
|
flush
|
|
168
173
|
className={cn(
|
|
169
174
|
"flex items-center gap-1 text-left text-xs leading-tight text-dashboard-text-muted",
|
|
170
|
-
live && "text-
|
|
175
|
+
live && "text-dashboard-accent-text/80",
|
|
171
176
|
)}
|
|
172
177
|
onClick={(event) => {
|
|
173
178
|
event.preventDefault();
|
|
@@ -190,7 +195,9 @@ export function TranscriptActivityGroup(props: {
|
|
|
190
195
|
</span>
|
|
191
196
|
</Tooltip>
|
|
192
197
|
</TranscriptSummary>
|
|
193
|
-
<
|
|
198
|
+
<TranscriptActivityNesting.Provider value>
|
|
199
|
+
<div className="mt-1.5 grid min-w-0 gap-1">{rows}</div>
|
|
200
|
+
</TranscriptActivityNesting.Provider>
|
|
194
201
|
</details>
|
|
195
202
|
);
|
|
196
203
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { TranscriptAttachments } from "./TranscriptAttachment";
|
|
2
2
|
|
|
3
3
|
import { getDashboardAgentName } from "../agentName";
|
|
4
|
-
import { formatMessageTimestamp } from "../format";
|
|
5
4
|
import type {
|
|
6
5
|
ConversationTranscript,
|
|
7
6
|
TranscriptViewAttachmentsDeliveredPart,
|
|
8
7
|
} from "../types";
|
|
9
8
|
import { TranscriptMessageHeading } from "./TranscriptHeadingRow";
|
|
10
9
|
import { TranscriptMessageShell } from "./TranscriptMessageShell";
|
|
10
|
+
import { TranscriptTimestamp } from "./TranscriptTimestamp";
|
|
11
11
|
|
|
12
12
|
/** Render host-delivered conversation attachments as first-class transcript media. */
|
|
13
13
|
export function TranscriptAttachmentsDeliveredView(props: {
|
|
@@ -15,17 +15,15 @@ export function TranscriptAttachmentsDeliveredView(props: {
|
|
|
15
15
|
part: TranscriptViewAttachmentsDeliveredPart;
|
|
16
16
|
timestamp?: number;
|
|
17
17
|
}) {
|
|
18
|
-
const timestamp = formatMessageTimestamp(props.timestamp);
|
|
19
|
-
|
|
20
18
|
return (
|
|
21
19
|
<TranscriptMessageShell role="assistant" actor={getDashboardAgentName()}>
|
|
22
20
|
<TranscriptMessageHeading>
|
|
23
|
-
<span className="max-w-full truncate font-sans text-sm font-semibold leading-6 text-
|
|
21
|
+
<span className="max-w-full truncate font-sans text-sm font-semibold leading-6 text-dashboard-accent-text">
|
|
24
22
|
{getDashboardAgentName()}
|
|
25
23
|
</span>
|
|
26
|
-
{timestamp ? (
|
|
24
|
+
{typeof props.timestamp === "number" ? (
|
|
27
25
|
<span className="text-xs leading-6 text-dashboard-text-muted">
|
|
28
|
-
{timestamp}
|
|
26
|
+
<TranscriptTimestamp value={props.timestamp} />
|
|
29
27
|
</span>
|
|
30
28
|
) : null}
|
|
31
29
|
</TranscriptMessageHeading>
|
|
@@ -18,10 +18,10 @@ export function TranscriptContextEventView(props: {
|
|
|
18
18
|
? ` using the ${event.modelProfile} profile (${event.modelId})`
|
|
19
19
|
: "";
|
|
20
20
|
return (
|
|
21
|
-
<article className="min-w-0
|
|
21
|
+
<article className="min-w-0 py-0.5">
|
|
22
22
|
<div className="flex min-w-0 flex-wrap items-center justify-between gap-x-3 gap-y-1">
|
|
23
23
|
<strong
|
|
24
|
-
className={`font-
|
|
24
|
+
className={`font-sans text-xs font-semibold ${
|
|
25
25
|
handoff ? "text-sky-100" : "text-amber-100"
|
|
26
26
|
}`}
|
|
27
27
|
>
|
|
@@ -41,7 +41,7 @@ export function TranscriptEventView(props: { message: TranscriptViewMessage }) {
|
|
|
41
41
|
strokeWidth={2.2}
|
|
42
42
|
/>
|
|
43
43
|
</TranscriptSummary>
|
|
44
|
-
<pre className="mt-2 max-h-80 overflow-auto whitespace-pre-wrap break-words rounded-lg border border-dashboard-border bg-dashboard-surface px-3 py-2 font-
|
|
44
|
+
<pre className="mt-2 max-h-80 overflow-auto whitespace-pre-wrap break-words rounded-lg border border-dashboard-border bg-dashboard-surface-panel px-3 py-2 font-sans text-xs leading-relaxed text-dashboard-text-muted">
|
|
45
45
|
<HighlightText text={text} />
|
|
46
46
|
</pre>
|
|
47
47
|
</details>
|
|
@@ -177,7 +177,7 @@ function MarkdownTable(props: {
|
|
|
177
177
|
|
|
178
178
|
return (
|
|
179
179
|
<div className="min-w-0 max-w-full overflow-x-auto rounded-md border border-dashboard-border bg-dashboard-fill-faint">
|
|
180
|
-
<table className="w-max border-collapse text-left text-sm">
|
|
180
|
+
<table className="w-max min-w-full border-collapse text-left text-sm">
|
|
181
181
|
<thead className="bg-dashboard-overlay-soft">
|
|
182
182
|
<tr>
|
|
183
183
|
{Array.from({ length: columnCount }, (_, index) => {
|
|
@@ -185,7 +185,7 @@ function MarkdownTable(props: {
|
|
|
185
185
|
return (
|
|
186
186
|
<th
|
|
187
187
|
className={cn(
|
|
188
|
-
"whitespace-nowrap border-b border-dashboard-border px-2.5 py-1.5 font-
|
|
188
|
+
"whitespace-nowrap border-b border-dashboard-border px-2.5 py-1.5 font-sans text-xs font-medium text-dashboard-text-muted",
|
|
189
189
|
tableCellAlignClass(alignment),
|
|
190
190
|
)}
|
|
191
191
|
key={`h-${index}`}
|
|
@@ -365,7 +365,7 @@ function renderInlineCode(text: string, keyBase: number): ReactNode[] {
|
|
|
365
365
|
}
|
|
366
366
|
nodes.push(
|
|
367
367
|
<code
|
|
368
|
-
className="rounded-[0.25rem] bg-
|
|
368
|
+
className="rounded-[0.25rem] bg-dashboard-fill-strong px-1 py-0.5 font-mono text-[0.9em] text-dashboard-text"
|
|
369
369
|
key={`code-${keyBase}-${part++}`}
|
|
370
370
|
>
|
|
371
371
|
<HighlightText text={match[2] ?? ""} />
|
|
@@ -31,12 +31,12 @@ export function TranscriptMessageContextView(props: {
|
|
|
31
31
|
return (
|
|
32
32
|
<>
|
|
33
33
|
<details
|
|
34
|
-
className="group/message-context min-w-0 rounded-lg bg-
|
|
34
|
+
className="group/message-context min-w-0 rounded-lg border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5 md:hidden"
|
|
35
35
|
data-transcript-message-context
|
|
36
36
|
>
|
|
37
37
|
<TranscriptSummary
|
|
38
38
|
flush
|
|
39
|
-
className="flex items-center justify-between gap-2 font-
|
|
39
|
+
className="flex items-center justify-between gap-2 font-sans text-xs font-medium text-dashboard-text-muted"
|
|
40
40
|
>
|
|
41
41
|
<span className="min-w-0 truncate">Context from {actor}</span>
|
|
42
42
|
<ChevronRight
|
|
@@ -45,7 +45,7 @@ export function TranscriptMessageContextView(props: {
|
|
|
45
45
|
size={14}
|
|
46
46
|
/>
|
|
47
47
|
</TranscriptSummary>
|
|
48
|
-
<div className="mt-2 whitespace-pre-wrap pt-2 text-sm leading-relaxed text-dashboard-text
|
|
48
|
+
<div className="mt-2 whitespace-pre-wrap pt-2 text-sm leading-relaxed text-dashboard-text-subtle">
|
|
49
49
|
{content}
|
|
50
50
|
</div>
|
|
51
51
|
{!props.redacted && props.message.contexts?.length ? (
|
|
@@ -55,25 +55,25 @@ export function TranscriptMessageContextView(props: {
|
|
|
55
55
|
) : null}
|
|
56
56
|
</details>
|
|
57
57
|
<article
|
|
58
|
-
className="hidden min-w-0 rounded-lg bg-
|
|
58
|
+
className="hidden min-w-0 rounded-lg border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5 md:block"
|
|
59
59
|
data-transcript-message-context
|
|
60
60
|
>
|
|
61
61
|
<TranscriptHeadingRow
|
|
62
62
|
left={
|
|
63
|
-
<span className="font-
|
|
63
|
+
<span className="font-sans text-xs font-medium text-dashboard-text-muted">
|
|
64
64
|
Context from {actor}
|
|
65
65
|
</span>
|
|
66
66
|
}
|
|
67
67
|
leftClassName="min-w-0"
|
|
68
68
|
right={
|
|
69
69
|
timestamp ? (
|
|
70
|
-
<TranscriptHeadingMeta className="
|
|
70
|
+
<TranscriptHeadingMeta className="text-xs tabular-nums text-dashboard-text-muted">
|
|
71
71
|
{timestamp}
|
|
72
72
|
</TranscriptHeadingMeta>
|
|
73
73
|
) : undefined
|
|
74
74
|
}
|
|
75
75
|
/>
|
|
76
|
-
<div className="mt-1 whitespace-pre-wrap text-sm leading-relaxed text-dashboard-text
|
|
76
|
+
<div className="mt-1 whitespace-pre-wrap text-sm leading-relaxed text-dashboard-text-subtle">
|
|
77
77
|
{content}
|
|
78
78
|
</div>
|
|
79
79
|
{!props.redacted && props.message.contexts?.length ? (
|
|
@@ -160,11 +160,7 @@ function TranscriptMessageHeader(props: {
|
|
|
160
160
|
</span>
|
|
161
161
|
) : null}
|
|
162
162
|
{showSlack && timestamp ? <span aria-hidden="true">·</span> : null}
|
|
163
|
-
{props.message.
|
|
164
|
-
<TranscriptTimestamp value={props.message.timestamp} />
|
|
165
|
-
) : (
|
|
166
|
-
timestamp
|
|
167
|
-
)}
|
|
163
|
+
<TranscriptTimestamp value={props.message.timestamp} />
|
|
168
164
|
</span>
|
|
169
165
|
) : null}
|
|
170
166
|
</TranscriptMessageHeading>
|
|
@@ -176,7 +172,7 @@ function transcriptRoleLabelClass(role: string): string {
|
|
|
176
172
|
|
|
177
173
|
return cn(
|
|
178
174
|
"inline-block max-w-full truncate font-sans text-sm font-semibold leading-6",
|
|
179
|
-
kind === "assistant" && "text-
|
|
175
|
+
kind === "assistant" && "text-dashboard-accent-text",
|
|
180
176
|
kind === "user" && "text-dashboard-text",
|
|
181
177
|
kind === "system" && "text-amber-200",
|
|
182
178
|
kind === "tool" && "text-dashboard-text-muted",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { createContext, useContext, type ReactNode } from "react";
|
|
2
2
|
import type { ObjectType } from "@sentry/junior-plugin-api";
|
|
3
3
|
import { ObjectIcon } from "../components/ObjectIcon";
|
|
4
4
|
import {
|
|
@@ -33,6 +33,13 @@ type TranscriptRailEventKind =
|
|
|
33
33
|
| "structured_event"
|
|
34
34
|
| "subagent";
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* True inside an activity group. Grouped rows use the narrow activity icon
|
|
38
|
+
* column. Top-level rows put the icon in the avatar column, so their text
|
|
39
|
+
* lines up with message text.
|
|
40
|
+
*/
|
|
41
|
+
export const TranscriptActivityNesting = createContext(false);
|
|
42
|
+
|
|
36
43
|
/** Mark noteworthy transcript events with an inline status icon. */
|
|
37
44
|
export function TranscriptRailEvent(props: {
|
|
38
45
|
children: ReactNode;
|
|
@@ -42,30 +49,35 @@ export function TranscriptRailEvent(props: {
|
|
|
42
49
|
}) {
|
|
43
50
|
const marker = transcriptRailMarker(props.kind);
|
|
44
51
|
const Icon = props.icon ?? marker.icon;
|
|
52
|
+
const nested = useContext(TranscriptActivityNesting);
|
|
45
53
|
|
|
46
54
|
return (
|
|
47
55
|
<div
|
|
48
56
|
className={cn(
|
|
49
57
|
"grid min-w-0 items-start",
|
|
50
|
-
|
|
51
|
-
? "grid-cols-[
|
|
52
|
-
: "grid-cols-[
|
|
58
|
+
nested
|
|
59
|
+
? "grid-cols-[1rem_minmax(0,1fr)] gap-2"
|
|
60
|
+
: "grid-cols-[2rem_minmax(0,1fr)] gap-3",
|
|
53
61
|
)}
|
|
54
62
|
data-transcript-rail-event={props.kind}
|
|
55
63
|
>
|
|
56
64
|
<span
|
|
57
65
|
aria-hidden="true"
|
|
58
66
|
className={cn(
|
|
59
|
-
|
|
60
|
-
? "
|
|
61
|
-
: "
|
|
67
|
+
nested
|
|
68
|
+
? "grid h-6 w-4 place-items-center"
|
|
69
|
+
: "grid h-6 w-8 place-items-center",
|
|
70
|
+
// Card rows: center the icon on the card's first line.
|
|
71
|
+
!nested &&
|
|
72
|
+
(props.kind === "subagent" || props.kind === "message_context") &&
|
|
73
|
+
"mt-1.5",
|
|
62
74
|
marker.className,
|
|
63
75
|
)}
|
|
64
76
|
>
|
|
65
77
|
{props.objectType ? (
|
|
66
78
|
<ObjectIcon objectType={props.objectType} size={14} decorative />
|
|
67
79
|
) : (
|
|
68
|
-
<Icon size={
|
|
80
|
+
<Icon size={nested ? 14 : 15} strokeWidth={2} />
|
|
69
81
|
)}
|
|
70
82
|
</span>
|
|
71
83
|
<div className="min-w-0">{props.children}</div>
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "./TranscriptHeadingRow";
|
|
10
10
|
import { HighlightText, useTranscriptSearch } from "./transcriptSearch";
|
|
11
11
|
import { TranscriptSummary } from "./TranscriptSummary";
|
|
12
|
+
import { transcriptActivityBodyClass } from "./ToolFrame";
|
|
12
13
|
|
|
13
14
|
/** Render reasoning collapsed with a short preview until expanded or searched. */
|
|
14
15
|
export function TranscriptReasoningView(props: {
|
|
@@ -22,23 +23,23 @@ export function TranscriptReasoningView(props: {
|
|
|
22
23
|
<>
|
|
23
24
|
<span
|
|
24
25
|
aria-label="Reasoning"
|
|
25
|
-
className="
|
|
26
|
+
className="inline-flex size-4 shrink-0 items-center justify-center text-violet-200/80"
|
|
26
27
|
title="Reasoning"
|
|
27
28
|
>
|
|
28
|
-
<Lightbulb aria-hidden="true" size={
|
|
29
|
+
<Lightbulb aria-hidden="true" size={14} strokeWidth={2} />
|
|
29
30
|
</span>
|
|
30
31
|
<TranscriptHeadingRow
|
|
31
32
|
left={
|
|
32
33
|
searchActive ? (
|
|
33
|
-
<span className="block min-w-0
|
|
34
|
+
<span className="block min-w-0 text-dashboard-text-muted">
|
|
34
35
|
Reasoning
|
|
35
36
|
</span>
|
|
36
37
|
) : (
|
|
37
38
|
<>
|
|
38
|
-
<span className="block min-w-0 truncate italic text-
|
|
39
|
+
<span className="block min-w-0 truncate italic text-dashboard-text-muted group-open/reasoning:hidden">
|
|
39
40
|
{rendered}
|
|
40
41
|
</span>
|
|
41
|
-
<span className="hidden min-w-0
|
|
42
|
+
<span className="hidden min-w-0 text-dashboard-text-muted group-open/reasoning:inline">
|
|
42
43
|
Reasoning
|
|
43
44
|
</span>
|
|
44
45
|
</>
|
|
@@ -46,7 +47,7 @@ export function TranscriptReasoningView(props: {
|
|
|
46
47
|
}
|
|
47
48
|
right={
|
|
48
49
|
timestamp ? (
|
|
49
|
-
<TranscriptHeadingMeta className="min-w-0 break-words text-
|
|
50
|
+
<TranscriptHeadingMeta className="min-w-0 break-words text-xs tabular-nums text-dashboard-text-muted max-md:hidden">
|
|
50
51
|
{timestamp}
|
|
51
52
|
</TranscriptHeadingMeta>
|
|
52
53
|
) : undefined
|
|
@@ -56,9 +57,8 @@ export function TranscriptReasoningView(props: {
|
|
|
56
57
|
</>
|
|
57
58
|
);
|
|
58
59
|
const content = (
|
|
59
|
-
<div className=
|
|
60
|
-
<
|
|
61
|
-
<div className="min-w-0 whitespace-pre-wrap break-words text-xs leading-relaxed italic text-violet-100/65">
|
|
60
|
+
<div className={cn(transcriptActivityBodyClass, "px-3 py-2.5")}>
|
|
61
|
+
<div className="min-w-0 whitespace-pre-wrap break-words text-sm leading-relaxed text-dashboard-text-subtle">
|
|
62
62
|
<HighlightText text={rendered} />
|
|
63
63
|
</div>
|
|
64
64
|
</div>
|
|
@@ -67,7 +67,7 @@ export function TranscriptReasoningView(props: {
|
|
|
67
67
|
if (searchActive) {
|
|
68
68
|
return (
|
|
69
69
|
<div className={reasoningFrameClass()}>
|
|
70
|
-
<div className="grid list-none grid-cols-[1rem_minmax(0,1fr)] items-
|
|
70
|
+
<div className="grid list-none grid-cols-[1rem_minmax(0,1fr)] items-center gap-2 py-1.5">
|
|
71
71
|
{summary}
|
|
72
72
|
</div>
|
|
73
73
|
{content}
|
|
@@ -77,7 +77,7 @@ export function TranscriptReasoningView(props: {
|
|
|
77
77
|
|
|
78
78
|
return (
|
|
79
79
|
<details className={cn("group/reasoning", reasoningFrameClass())}>
|
|
80
|
-
<TranscriptSummary className="grid grid-cols-[1rem_minmax(0,1fr)] items-
|
|
80
|
+
<TranscriptSummary className="-mx-2 grid grid-cols-[1rem_minmax(0,1fr)] items-center gap-2">
|
|
81
81
|
{summary}
|
|
82
82
|
</TranscriptSummary>
|
|
83
83
|
{content}
|
|
@@ -86,5 +86,5 @@ export function TranscriptReasoningView(props: {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
function reasoningFrameClass(): string {
|
|
89
|
-
return "min-w-0
|
|
89
|
+
return "min-w-0 text-xs leading-tight";
|
|
90
90
|
}
|
|
@@ -14,24 +14,29 @@ export function TranscriptStructuredEventView(props: {
|
|
|
14
14
|
const presentation = props.part.presentation;
|
|
15
15
|
const timestamp = formatMessageTimestamp(props.timestamp);
|
|
16
16
|
const details = presentation.details ?? [];
|
|
17
|
-
//
|
|
18
|
-
const surfaceClass =
|
|
19
|
-
|
|
17
|
+
// The rail icon box is h-6. A leading-6 title shares its center line.
|
|
18
|
+
const surfaceClass = "min-w-0 font-sans text-xs";
|
|
19
|
+
// A lone detail often repeats the event title, such as "Loaded AGENTS.md"
|
|
20
|
+
// over "AGENTS.md". Skip that repeated title.
|
|
21
|
+
const repeatsTitle = (title: string) =>
|
|
22
|
+
details.length === 1 && presentation.title.includes(title);
|
|
20
23
|
const body =
|
|
21
24
|
details.length > 0 ? (
|
|
22
|
-
<div className="grid gap-4 pb-1 pt-
|
|
25
|
+
<div className="grid gap-4 pb-1 pt-2">
|
|
23
26
|
{details.map((detail, index) => (
|
|
24
27
|
<section key={`${detail.title}:${index}`}>
|
|
25
|
-
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
+
{repeatsTitle(detail.title) ? null : (
|
|
29
|
+
<div className="whitespace-pre-wrap break-words font-sans text-sm font-medium text-dashboard-text">
|
|
30
|
+
<HighlightText text={detail.title} />
|
|
31
|
+
</div>
|
|
32
|
+
)}
|
|
28
33
|
{detail.description ? (
|
|
29
34
|
<div className="mt-1 whitespace-pre-wrap break-words text-xs leading-relaxed text-dashboard-text-muted">
|
|
30
35
|
<HighlightText text={detail.description} />
|
|
31
36
|
</div>
|
|
32
37
|
) : null}
|
|
33
38
|
{detail.content ? (
|
|
34
|
-
<pre className="mt-2 max-h-[32rem] overflow-auto whitespace-pre-wrap break-words font-mono text-xs leading-
|
|
39
|
+
<pre className="mt-2 max-h-[32rem] overflow-auto whitespace-pre-wrap break-words rounded-md border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5 font-mono text-xs leading-normal text-dashboard-text-muted first:mt-0">
|
|
35
40
|
<HighlightText text={detail.content} />
|
|
36
41
|
</pre>
|
|
37
42
|
) : null}
|
|
@@ -39,7 +44,7 @@ export function TranscriptStructuredEventView(props: {
|
|
|
39
44
|
<div className="mt-2 flex flex-wrap gap-1.5">
|
|
40
45
|
{detail.metadata.map((value) => (
|
|
41
46
|
<span
|
|
42
|
-
className="
|
|
47
|
+
className="text-xs text-dashboard-text-muted"
|
|
43
48
|
key={value}
|
|
44
49
|
>
|
|
45
50
|
<HighlightText text={value} />
|
|
@@ -54,7 +59,7 @@ export function TranscriptStructuredEventView(props: {
|
|
|
54
59
|
const header = (
|
|
55
60
|
<div className="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-2 max-md:grid-cols-[minmax(0,1fr)]">
|
|
56
61
|
<div className="min-w-0">
|
|
57
|
-
<div className="
|
|
62
|
+
<div className="text-sm font-medium leading-6 text-dashboard-text">
|
|
58
63
|
<HighlightText text={presentation.title} />
|
|
59
64
|
</div>
|
|
60
65
|
{presentation.preview ? (
|
|
@@ -64,7 +69,7 @@ export function TranscriptStructuredEventView(props: {
|
|
|
64
69
|
) : null}
|
|
65
70
|
</div>
|
|
66
71
|
{timestamp ? (
|
|
67
|
-
<span className="
|
|
72
|
+
<span className="text-xs leading-6 tabular-nums text-dashboard-text-muted max-md:hidden">
|
|
68
73
|
{timestamp}
|
|
69
74
|
</span>
|
|
70
75
|
) : null}
|