@sentry/junior-dashboard 0.248.0 → 0.250.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/README.md +3 -0
- package/dist/app.js +2 -2
- package/dist/client.js +40 -38
- package/dist/index.js +2 -2
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
- package/src/client/App.tsx +19 -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 +17 -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/ConnectionsPage.tsx +207 -0
- 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/ChartFixtures.tsx +265 -21
- 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
|
@@ -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}
|
|
@@ -1,65 +1,90 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChevronRight } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
import { StatusChip } from "../components/StatusChip";
|
|
4
|
+
import { formatElapsedDuration, formatMessageTimestamp } from "../format";
|
|
5
|
+
import { cn } from "../styles";
|
|
2
6
|
import type { TranscriptViewSubagentPart } from "../types";
|
|
3
|
-
import {
|
|
7
|
+
import { subagentStatusTone } from "./ConversationChildAgents";
|
|
4
8
|
import { HighlightText } from "./transcriptSearch";
|
|
5
9
|
|
|
6
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Render a child agent as a compact card in the transcript stream. The card
|
|
12
|
+
* matches the child agent rows in the details drawer: name, status, and run
|
|
13
|
+
* time first, then the task title. It opens the child transcript.
|
|
14
|
+
*/
|
|
7
15
|
export function TranscriptSubagentView(props: {
|
|
8
16
|
onOpenTranscript?: (part: TranscriptViewSubagentPart) => void;
|
|
9
17
|
part: TranscriptViewSubagentPart;
|
|
10
18
|
timestamp?: number;
|
|
11
19
|
}) {
|
|
12
20
|
const label = props.part.agentName ?? props.part.subagentKind;
|
|
13
|
-
const
|
|
21
|
+
const headline = props.part.title ?? props.part.task;
|
|
14
22
|
const status = props.part.status;
|
|
15
|
-
const
|
|
16
|
-
|
|
23
|
+
const duration = formatElapsedDuration(
|
|
24
|
+
props.timestamp,
|
|
25
|
+
props.part.finishedTimestamp,
|
|
26
|
+
);
|
|
27
|
+
const started =
|
|
17
28
|
typeof props.timestamp === "number"
|
|
18
|
-
? formatMessageTimestamp(props.timestamp)
|
|
19
|
-
: undefined
|
|
20
|
-
|
|
29
|
+
? `Started ${formatMessageTimestamp(props.timestamp)}`
|
|
30
|
+
: undefined;
|
|
31
|
+
const interactive = Boolean(props.onOpenTranscript);
|
|
21
32
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
const content = (
|
|
34
|
+
<>
|
|
35
|
+
<span className="flex min-w-0 items-center gap-2 text-xs leading-5">
|
|
36
|
+
<span className="min-w-0 truncate font-sans text-sm font-semibold text-dashboard-text">
|
|
37
|
+
<HighlightText text={label} />
|
|
38
|
+
</span>
|
|
39
|
+
<StatusChip
|
|
40
|
+
className={cn("shrink-0", status === "running" && "animate-pulse")}
|
|
41
|
+
size="compact"
|
|
42
|
+
tone={subagentStatusTone(status)}
|
|
43
|
+
>
|
|
44
|
+
{status}
|
|
45
|
+
</StatusChip>
|
|
46
|
+
{duration ? (
|
|
47
|
+
<span className="shrink-0 tabular-nums text-dashboard-text-muted">
|
|
48
|
+
{duration}
|
|
49
|
+
</span>
|
|
50
|
+
) : null}
|
|
51
|
+
{interactive ? (
|
|
52
|
+
<ChevronRight
|
|
53
|
+
aria-hidden="true"
|
|
54
|
+
className="ml-auto size-4 shrink-0 text-dashboard-text-faint transition-colors group-hover/subagent:text-dashboard-text"
|
|
55
|
+
/>
|
|
56
|
+
) : null}
|
|
57
|
+
</span>
|
|
58
|
+
{headline ? (
|
|
59
|
+
<span className="block min-w-0 truncate text-sm leading-snug text-dashboard-text-subtle">
|
|
60
|
+
<HighlightText text={headline} />
|
|
61
|
+
</span>
|
|
62
|
+
) : null}
|
|
63
|
+
</>
|
|
45
64
|
);
|
|
65
|
+
const frameClass =
|
|
66
|
+
"group/subagent grid w-full min-w-0 max-w-[37.5rem] gap-0.5 rounded-lg border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2 text-left text-inherit";
|
|
46
67
|
|
|
47
68
|
if (!props.onOpenTranscript) {
|
|
48
|
-
return
|
|
69
|
+
return (
|
|
70
|
+
<div className={frameClass} title={started}>
|
|
71
|
+
{content}
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
49
74
|
}
|
|
50
75
|
|
|
51
76
|
return (
|
|
52
77
|
<button
|
|
53
78
|
aria-label={`Open ${label} transcript`}
|
|
54
|
-
className=
|
|
79
|
+
className={cn(
|
|
80
|
+
frameClass,
|
|
81
|
+
"cursor-pointer transition-colors hover:border-dashboard-border-emphasis hover:bg-dashboard-surface-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus",
|
|
82
|
+
)}
|
|
55
83
|
onClick={() => props.onOpenTranscript?.(props.part)}
|
|
84
|
+
title={started}
|
|
56
85
|
type="button"
|
|
57
86
|
>
|
|
58
|
-
{
|
|
87
|
+
{content}
|
|
59
88
|
</button>
|
|
60
89
|
);
|
|
61
90
|
}
|
|
62
|
-
|
|
63
|
-
function isString(value: string | undefined): value is string {
|
|
64
|
-
return typeof value === "string" && value.length > 0;
|
|
65
|
-
}
|
|
@@ -26,11 +26,12 @@ export const TranscriptText = memo(function TranscriptText(props: {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
|
-
<
|
|
30
|
-
|
|
29
|
+
<div
|
|
30
|
+
className="min-w-0 overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-surface-panel px-3 py-2.5"
|
|
31
31
|
key={index}
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
>
|
|
33
|
+
<HighlightedCode code={block.code} language={block.language} />
|
|
34
|
+
</div>
|
|
34
35
|
);
|
|
35
36
|
})}
|
|
36
37
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { memo, useMemo } from "react";
|
|
2
|
-
import { TriangleAlert } from "lucide-react";
|
|
2
|
+
import { TriangleAlert, Wrench } from "lucide-react";
|
|
3
3
|
|
|
4
4
|
import { HighlightedCode } from "../code";
|
|
5
5
|
import {
|
|
@@ -45,6 +45,12 @@ export const TranscriptToolView = memo(function TranscriptToolView(props: {
|
|
|
45
45
|
const frame = (
|
|
46
46
|
<ToolFrame
|
|
47
47
|
expandable={hasDetails}
|
|
48
|
+
icon={props.part.status === "error" ? TriangleAlert : Wrench}
|
|
49
|
+
iconClassName={
|
|
50
|
+
props.part.status === "error"
|
|
51
|
+
? "text-rose-300"
|
|
52
|
+
: "text-dashboard-text-faint"
|
|
53
|
+
}
|
|
48
54
|
meta={meta}
|
|
49
55
|
mobileSummaryMeta={mobileSummary}
|
|
50
56
|
signature={signature}
|
|
@@ -78,14 +84,6 @@ function ToolSignature(props: {
|
|
|
78
84
|
|
|
79
85
|
return (
|
|
80
86
|
<>
|
|
81
|
-
{failed ? (
|
|
82
|
-
<TriangleAlert
|
|
83
|
-
aria-hidden="true"
|
|
84
|
-
className="shrink-0 !text-rose-300"
|
|
85
|
-
size={12}
|
|
86
|
-
strokeWidth={2.2}
|
|
87
|
-
/>
|
|
88
|
-
) : null}
|
|
89
87
|
<ShimmerText
|
|
90
88
|
active={shimmering}
|
|
91
89
|
aria-label={statusLabel}
|
|
@@ -109,8 +107,8 @@ function ToolSignature(props: {
|
|
|
109
107
|
function ToolPayload(props: { label: string; value: unknown }) {
|
|
110
108
|
const code = useMemo(() => stringifyPartValue(props.value), [props.value]);
|
|
111
109
|
return (
|
|
112
|
-
<div className="min-w-0 max-w-full overflow-hidden
|
|
113
|
-
<div className="pb-1.5 font-
|
|
110
|
+
<div className="min-w-0 max-w-full overflow-hidden border-dashboard-border-subtle px-3 py-2.5 [&+&]:border-t">
|
|
111
|
+
<div className="pb-1.5 font-sans text-xs font-medium leading-none text-dashboard-text-muted">
|
|
114
112
|
{props.label}
|
|
115
113
|
</div>
|
|
116
114
|
<HighlightedCode code={code} language="json" />
|
|
@@ -24,7 +24,7 @@ export function TranscriptTurnContextView(props: {
|
|
|
24
24
|
aria-expanded={open}
|
|
25
25
|
aria-label="View turn context"
|
|
26
26
|
className={cn(
|
|
27
|
-
"inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded text-dashboard-text-muted transition-colors hover:bg-dashboard-fill-hover hover:text-dashboard-text focus-visible:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus",
|
|
27
|
+
"inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md text-dashboard-text-muted transition-colors hover:bg-dashboard-fill-hover hover:text-dashboard-text focus-visible:bg-dashboard-fill-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-dashboard-focus",
|
|
28
28
|
open && "bg-dashboard-fill-hover text-dashboard-text",
|
|
29
29
|
)}
|
|
30
30
|
onClick={() => setOpen(true)}
|
|
@@ -80,13 +80,13 @@ function TurnContext(props: { context: TranscriptViewTurnContext }) {
|
|
|
80
80
|
{memory ? (
|
|
81
81
|
<Brain
|
|
82
82
|
aria-hidden="true"
|
|
83
|
-
className="shrink-0 text-
|
|
83
|
+
className="shrink-0 text-dashboard-accent-text/60"
|
|
84
84
|
size={15}
|
|
85
85
|
/>
|
|
86
86
|
) : (
|
|
87
87
|
<Braces
|
|
88
88
|
aria-hidden="true"
|
|
89
|
-
className="shrink-0 text-
|
|
89
|
+
className="shrink-0 text-dashboard-accent-text/60"
|
|
90
90
|
size={15}
|
|
91
91
|
/>
|
|
92
92
|
)}
|
|
@@ -72,10 +72,10 @@ export function Transcript(props: {
|
|
|
72
72
|
) : null}
|
|
73
73
|
{props.hasPreviousPage || props.loadingPreviousPage ? (
|
|
74
74
|
<div className="mb-3 flex items-center gap-3">
|
|
75
|
-
<span className="h-px min-w-4 flex-1 bg-
|
|
75
|
+
<span className="h-px min-w-4 flex-1 bg-dashboard-fill-strong" />
|
|
76
76
|
<button
|
|
77
77
|
aria-label="Load earlier events"
|
|
78
|
-
className="shrink-0 cursor-pointer border-0 bg-transparent px-1 py-0.5 font-sans text-xs font-medium text-dashboard-text-muted transition-colors hover:text-dashboard-text focus-visible:outline focus-visible:outline-1 focus-visible:outline-
|
|
78
|
+
className="shrink-0 cursor-pointer border-0 bg-transparent px-1 py-0.5 font-sans text-xs font-medium text-dashboard-text-muted transition-colors hover:text-dashboard-text focus-visible:outline focus-visible:outline-1 focus-visible:outline-dashboard-focus/55 disabled:cursor-not-allowed disabled:opacity-50"
|
|
79
79
|
disabled={props.loadingPreviousPage}
|
|
80
80
|
onClick={() => {
|
|
81
81
|
bottomPinning.preserveViewportForPrepend();
|
|
@@ -88,7 +88,7 @@ export function Transcript(props: {
|
|
|
88
88
|
? `Loading earlier ${historyLabel}…`
|
|
89
89
|
: `Show earlier ${historyLabel}`}
|
|
90
90
|
</button>
|
|
91
|
-
<span className="h-px min-w-4 flex-1 bg-
|
|
91
|
+
<span className="h-px min-w-4 flex-1 bg-dashboard-fill-strong" />
|
|
92
92
|
</div>
|
|
93
93
|
) : null}
|
|
94
94
|
{props.historyError ? (
|
|
@@ -118,7 +118,7 @@ export function UsageCard(props: UsageCardProps) {
|
|
|
118
118
|
className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-3 gap-y-2"
|
|
119
119
|
key={section.title}
|
|
120
120
|
>
|
|
121
|
-
<span className="col-span-2 font-
|
|
121
|
+
<span className="col-span-2 font-sans font-medium text-dashboard-text-faint">
|
|
122
122
|
{section.title}
|
|
123
123
|
{section.total ? ` · ${section.total}` : null}
|
|
124
124
|
</span>
|
|
@@ -352,8 +352,12 @@ export function transcriptMessagesFromEvents(
|
|
|
352
352
|
if (data.type === "subagent") {
|
|
353
353
|
const subagentId = `${data.childConversationId}:${data.startedSeq}`;
|
|
354
354
|
const existing = subagents.get(subagentId);
|
|
355
|
+
const finishedTimestamp =
|
|
356
|
+
data.status === "running" ? undefined : eventTimestamp(event);
|
|
355
357
|
if (existing) {
|
|
356
358
|
existing.status = data.status;
|
|
359
|
+
if (finishedTimestamp === undefined) delete existing.finishedTimestamp;
|
|
360
|
+
else existing.finishedTimestamp = finishedTimestamp;
|
|
357
361
|
continue;
|
|
358
362
|
}
|
|
359
363
|
const part = {
|
|
@@ -362,6 +366,9 @@ export function transcriptMessagesFromEvents(
|
|
|
362
366
|
childConversationId: data.childConversationId,
|
|
363
367
|
subagentKind: data.subagentKind,
|
|
364
368
|
status: data.status,
|
|
369
|
+
...(finishedTimestamp === undefined
|
|
370
|
+
? undefined
|
|
371
|
+
: { finishedTimestamp }),
|
|
365
372
|
...(data.agentName ? { agentName: data.agentName } : undefined),
|
|
366
373
|
...(data.task ? { task: data.task } : undefined),
|
|
367
374
|
...(data.title ? { title: data.title } : undefined),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const TRANSCRIPT_ANCHOR_CLASS =
|
|
2
|
-
"font-medium text-
|
|
2
|
+
"font-medium text-dashboard-accent-text underline decoration-dashboard-accent/35 underline-offset-2 transition-colors hover:text-dashboard-text hover:decoration-dashboard-text-solid";
|
|
3
3
|
|
|
4
4
|
export type TranscriptMarkdownLink = {
|
|
5
5
|
end: number;
|
|
@@ -36,9 +36,7 @@ export function findTranscriptMarkdownLinks(
|
|
|
36
36
|
...markdownLinks,
|
|
37
37
|
...autolinks,
|
|
38
38
|
...findBareLinks(text, bareRanges),
|
|
39
|
-
].sort(
|
|
40
|
-
(left, right) => left.start - right.start || left.end - right.end,
|
|
41
|
-
);
|
|
39
|
+
].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
42
40
|
}
|
|
43
41
|
|
|
44
42
|
function findMarkdownLinks(
|
|
@@ -5,6 +5,6 @@ export function transcriptEmptyClass(
|
|
|
5
5
|
const colors =
|
|
6
6
|
tone === "error"
|
|
7
7
|
? "border-rose-300/25 bg-rose-300/[0.07] text-rose-100"
|
|
8
|
-
: "border-
|
|
8
|
+
: "border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted";
|
|
9
9
|
return `rounded-lg border p-5 text-sm leading-relaxed ${colors}`;
|
|
10
10
|
}
|