@sentry/junior-dashboard 0.243.0 → 0.245.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 +73 -7
- package/dist/client.js +34 -34
- package/dist/index.js +73 -7
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
- package/src/client/App.tsx +3 -2
- package/src/client/components/SegmentedTabs.tsx +11 -9
- package/src/client/conversations/ConversationAgentTree.tsx +42 -0
- package/src/client/conversations/ConversationChildAgents.tsx +134 -53
- package/src/client/conversations/ConversationDetailsDrawer.tsx +29 -9
- package/src/client/conversations/ConversationHeader.tsx +13 -1
- package/src/client/conversations/ConversationMemories.tsx +10 -5
- package/src/client/conversations/ConversationPage.tsx +16 -3
- package/src/client/conversations/SubagentTranscriptDrawer.tsx +31 -21
- package/src/client/conversations/TranscriptSubagentView.tsx +8 -2
- package/src/client/conversations/eventLog.ts +1 -1
- package/src/client/conversations/eventTranscript.ts +3 -0
- package/src/client/conversations/transcriptRenderModel.ts +6 -1
- package/src/client/conversations/transcriptSearch.tsx +6 -1
- package/src/client/format.ts +15 -0
- package/src/client/markdownExport.ts +6 -1
- package/src/client/pages/dev/SegmentedFixtures.tsx +1 -1
- package/src/client/types.ts +3 -0
- package/src/mock-reporting/fixtures.ts +77 -2
|
@@ -94,7 +94,7 @@ export function eventLogSummary(data: ConversationReportEventData): string {
|
|
|
94
94
|
case "handoff":
|
|
95
95
|
return "Handoff · New configuration applied";
|
|
96
96
|
case "subagent":
|
|
97
|
-
return `${data.subagentKind} · ${data.status} · ${data.childConversationId}`;
|
|
97
|
+
return `${data.agentName ?? data.subagentKind} · ${data.status} · ${data.childConversationId}`;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -362,6 +362,9 @@ export function transcriptMessagesFromEvents(
|
|
|
362
362
|
childConversationId: data.childConversationId,
|
|
363
363
|
subagentKind: data.subagentKind,
|
|
364
364
|
status: data.status,
|
|
365
|
+
...(data.agentName ? { agentName: data.agentName } : undefined),
|
|
366
|
+
...(data.task ? { task: data.task } : undefined),
|
|
367
|
+
...(data.title ? { title: data.title } : undefined),
|
|
365
368
|
};
|
|
366
369
|
subagents.set(subagentId, part);
|
|
367
370
|
messages.push({
|
|
@@ -194,7 +194,12 @@ export function messageRawText(message: TranscriptViewMessage): string {
|
|
|
194
194
|
if (part.type === "reasoning") return part.text ?? "reasoning redacted";
|
|
195
195
|
if (part.type === "tool_call") return `tool_call ${part.name}`;
|
|
196
196
|
if (part.type === "subagent") {
|
|
197
|
-
return
|
|
197
|
+
return [
|
|
198
|
+
`subagent ${part.agentName ?? part.subagentKind}`,
|
|
199
|
+
...(part.title ? [`title ${part.title}`] : []),
|
|
200
|
+
...(part.task ? [`task ${part.task}`] : []),
|
|
201
|
+
`status ${part.status}`,
|
|
202
|
+
].join("\n");
|
|
198
203
|
}
|
|
199
204
|
if (part.type === "structured_event") {
|
|
200
205
|
return [
|
|
@@ -160,7 +160,12 @@ export function entryMatchesSearch(
|
|
|
160
160
|
|
|
161
161
|
if (entry.kind === "subagent") {
|
|
162
162
|
return (
|
|
163
|
-
textContains(
|
|
163
|
+
textContains(
|
|
164
|
+
entry.part.agentName ?? entry.part.subagentKind,
|
|
165
|
+
normalizedQuery,
|
|
166
|
+
) ||
|
|
167
|
+
textContains(entry.part.title, normalizedQuery) ||
|
|
168
|
+
textContains(entry.part.task, normalizedQuery) ||
|
|
164
169
|
textContains(entry.part.status, normalizedQuery)
|
|
165
170
|
);
|
|
166
171
|
}
|
package/src/client/format.ts
CHANGED
|
@@ -660,6 +660,21 @@ function compareTimeDesc(a: string | undefined, b: string | undefined): number {
|
|
|
660
660
|
return (parseTime(b) ?? 0) - (parseTime(a) ?? 0);
|
|
661
661
|
}
|
|
662
662
|
|
|
663
|
+
/**
|
|
664
|
+
* Return the title of a loaded Conversation. A child agent Conversation uses
|
|
665
|
+
* its agent label from the agent tree, because it has no title of its own.
|
|
666
|
+
*/
|
|
667
|
+
export function conversationDetailTitle(
|
|
668
|
+
detail:
|
|
669
|
+
| Pick<ConversationTranscript, "agentTree" | "displayTitle">
|
|
670
|
+
| undefined,
|
|
671
|
+
): string | undefined {
|
|
672
|
+
return (
|
|
673
|
+
detail?.agentTree?.at(-1)?.label ??
|
|
674
|
+
(detail?.displayTitle?.trim() || undefined)
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
|
|
663
678
|
/** Return the display title prepared by the reporting API. */
|
|
664
679
|
export function conversationDisplayTitle(
|
|
665
680
|
conversation: Conversation | undefined,
|
|
@@ -396,9 +396,14 @@ function appendSubagent(
|
|
|
396
396
|
part: TranscriptViewSubagentPart,
|
|
397
397
|
timestamp: number | undefined,
|
|
398
398
|
): void {
|
|
399
|
-
lines.push(
|
|
399
|
+
lines.push(
|
|
400
|
+
"",
|
|
401
|
+
`### Subagent: ${headingText(part.agentName ?? part.subagentKind)}`,
|
|
402
|
+
);
|
|
400
403
|
addEventMeta(lines, conversationTranscript, timestamp);
|
|
401
404
|
addMetaLine(lines, "Status", part.status);
|
|
405
|
+
addMetaLine(lines, "Title", part.title);
|
|
406
|
+
addMetaLine(lines, "Task", part.task);
|
|
402
407
|
}
|
|
403
408
|
|
|
404
409
|
function appendTool(
|
|
@@ -11,7 +11,7 @@ export function SegmentedTabsFixture() {
|
|
|
11
11
|
<SegmentedTabs
|
|
12
12
|
items={[
|
|
13
13
|
{ label: "Details", value: "details" },
|
|
14
|
-
{ label: "Memories", value: "memories" },
|
|
14
|
+
{ count: 3, label: "Memories", value: "memories" },
|
|
15
15
|
{ label: "Usage", value: "usage" },
|
|
16
16
|
]}
|
|
17
17
|
label="Conversation panels"
|
package/src/client/types.ts
CHANGED
|
@@ -38,10 +38,13 @@ export type TranscriptViewToolCallPart = {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
export type TranscriptViewSubagentPart = {
|
|
41
|
+
agentName?: string;
|
|
41
42
|
childConversationId: string;
|
|
42
43
|
id: string;
|
|
43
44
|
status: "aborted" | "blocked" | "completed" | "error" | "running";
|
|
44
45
|
subagentKind: string;
|
|
46
|
+
task?: string;
|
|
47
|
+
title?: string;
|
|
45
48
|
type: "subagent";
|
|
46
49
|
};
|
|
47
50
|
|
|
@@ -719,6 +719,9 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
719
719
|
startedAt: iso(Date.parse(startedAt), 4_000),
|
|
720
720
|
childConversationId: DASHBOARD_QA_PLAN_ID,
|
|
721
721
|
subagentKind: "agent",
|
|
722
|
+
agentName: "planner",
|
|
723
|
+
task: "Review the dashboard plan before editing.",
|
|
724
|
+
title: "Review the dashboard plan",
|
|
722
725
|
parentToolCallId: "qa-advisor",
|
|
723
726
|
status: "running",
|
|
724
727
|
}),
|
|
@@ -728,6 +731,9 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
728
731
|
startedAt: iso(Date.parse(startedAt), 4_000),
|
|
729
732
|
childConversationId: DASHBOARD_QA_PLAN_ID,
|
|
730
733
|
subagentKind: "agent",
|
|
734
|
+
agentName: "planner",
|
|
735
|
+
task: "Review the dashboard plan before editing.",
|
|
736
|
+
title: "Review the dashboard plan",
|
|
731
737
|
parentToolCallId: "qa-advisor",
|
|
732
738
|
status: "completed",
|
|
733
739
|
}),
|
|
@@ -750,6 +756,7 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
750
756
|
startedAt: iso(Date.parse(startedAt), 25_000),
|
|
751
757
|
childConversationId: DASHBOARD_QA_REVIEW_ID,
|
|
752
758
|
subagentKind: "agent",
|
|
759
|
+
agentName: "reviewer",
|
|
753
760
|
status: "running",
|
|
754
761
|
}),
|
|
755
762
|
reportEvent(7, iso(Date.parse(startedAt), 44_000), {
|
|
@@ -758,6 +765,7 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
758
765
|
startedAt: iso(Date.parse(startedAt), 25_000),
|
|
759
766
|
childConversationId: DASHBOARD_QA_REVIEW_ID,
|
|
760
767
|
subagentKind: "agent",
|
|
768
|
+
agentName: "reviewer",
|
|
761
769
|
status: "blocked",
|
|
762
770
|
}),
|
|
763
771
|
reportEvent(8, iso(Date.parse(startedAt), 50_000), {
|
|
@@ -963,6 +971,10 @@ function advisorConversation(
|
|
|
963
971
|
nowMs: number,
|
|
964
972
|
conversationId: string,
|
|
965
973
|
text: string,
|
|
974
|
+
metrics: Pick<
|
|
975
|
+
ConversationDetailReport,
|
|
976
|
+
"cumulativeDurationMs" | "cumulativeUsage"
|
|
977
|
+
>,
|
|
966
978
|
): MockConversation {
|
|
967
979
|
const startedAt = iso(nowMs, -10 * 60_000);
|
|
968
980
|
const conversation = detail(nowMs, {
|
|
@@ -971,7 +983,7 @@ function advisorConversation(
|
|
|
971
983
|
startedAt,
|
|
972
984
|
lastSeenAt: iso(Date.parse(startedAt), 18_000),
|
|
973
985
|
lastProgressAt: iso(Date.parse(startedAt), 18_000),
|
|
974
|
-
|
|
986
|
+
...metrics,
|
|
975
987
|
events: [
|
|
976
988
|
reportEvent(0, startedAt, {
|
|
977
989
|
type: "message",
|
|
@@ -1391,11 +1403,28 @@ function mockConversations(nowMs: number): MockConversation[] {
|
|
|
1391
1403
|
nowMs,
|
|
1392
1404
|
DASHBOARD_QA_PLAN_ID,
|
|
1393
1405
|
"Review the dashboard plan before editing.",
|
|
1406
|
+
{
|
|
1407
|
+
cumulativeDurationMs: 72_400,
|
|
1408
|
+
cumulativeUsage: {
|
|
1409
|
+
inputTokens: 38_400,
|
|
1410
|
+
outputTokens: 2_150,
|
|
1411
|
+
cachedInputTokens: 21_600,
|
|
1412
|
+
cost: { input: 0.094, output: 0.048, total: 0.142 },
|
|
1413
|
+
},
|
|
1414
|
+
},
|
|
1394
1415
|
),
|
|
1395
1416
|
advisorConversation(
|
|
1396
1417
|
nowMs,
|
|
1397
1418
|
DASHBOARD_QA_REVIEW_ID,
|
|
1398
1419
|
"Review the implementation after the first advisor pass.",
|
|
1420
|
+
{
|
|
1421
|
+
cumulativeDurationMs: 9_800,
|
|
1422
|
+
cumulativeUsage: {
|
|
1423
|
+
inputTokens: 6_200,
|
|
1424
|
+
outputTokens: 310,
|
|
1425
|
+
cost: { input: 0.015, output: 0.004, total: 0.019 },
|
|
1426
|
+
},
|
|
1427
|
+
},
|
|
1399
1428
|
),
|
|
1400
1429
|
longConversation(nowMs),
|
|
1401
1430
|
incidentConversation(nowMs),
|
|
@@ -1821,7 +1850,8 @@ export function readMockConversationPendingMessages(
|
|
|
1821
1850
|
export function readMockConversationChildAgents(
|
|
1822
1851
|
conversationId: string,
|
|
1823
1852
|
): ConversationChildAgentsReport | undefined {
|
|
1824
|
-
const
|
|
1853
|
+
const conversations = mockConversations(NOW_MS);
|
|
1854
|
+
const conversation = conversations.find(
|
|
1825
1855
|
(candidate) => candidate.conversationId === conversationId,
|
|
1826
1856
|
);
|
|
1827
1857
|
if (!conversation) return undefined;
|
|
@@ -1829,9 +1859,20 @@ export function readMockConversationChildAgents(
|
|
|
1829
1859
|
return { agents: [], conversationId };
|
|
1830
1860
|
}
|
|
1831
1861
|
const startedAtMs = NOW_MS - 5 * 60 * 60_000;
|
|
1862
|
+
// Match the API: each row has the usage of its own child Conversation.
|
|
1863
|
+
const childMetrics = (childConversationId: string) => {
|
|
1864
|
+
const child = conversations.find(
|
|
1865
|
+
(candidate) => candidate.conversationId === childConversationId,
|
|
1866
|
+
)!;
|
|
1867
|
+
return {
|
|
1868
|
+
cumulativeDurationMs: child.cumulativeDurationMs,
|
|
1869
|
+
cumulativeUsage: child.cumulativeUsage,
|
|
1870
|
+
};
|
|
1871
|
+
};
|
|
1832
1872
|
return {
|
|
1833
1873
|
agents: [
|
|
1834
1874
|
{
|
|
1875
|
+
...childMetrics(DASHBOARD_QA_REVIEW_ID),
|
|
1835
1876
|
conversationId: DASHBOARD_QA_REVIEW_ID,
|
|
1836
1877
|
error: "GitHub access is needed to read the pull request.",
|
|
1837
1878
|
name: "reviewer",
|
|
@@ -1840,9 +1881,11 @@ export function readMockConversationChildAgents(
|
|
|
1840
1881
|
updatedAt: iso(startedAtMs, 44_000),
|
|
1841
1882
|
},
|
|
1842
1883
|
{
|
|
1884
|
+
...childMetrics(DASHBOARD_QA_PLAN_ID),
|
|
1843
1885
|
conversationId: DASHBOARD_QA_PLAN_ID,
|
|
1844
1886
|
status: "completed",
|
|
1845
1887
|
task: "Review the dashboard plan before editing.",
|
|
1888
|
+
title: "Review the dashboard plan",
|
|
1846
1889
|
updatedAt: iso(startedAtMs, 20_000),
|
|
1847
1890
|
},
|
|
1848
1891
|
],
|
|
@@ -1850,6 +1893,36 @@ export function readMockConversationChildAgents(
|
|
|
1850
1893
|
};
|
|
1851
1894
|
}
|
|
1852
1895
|
|
|
1896
|
+
/** Build the agent tree of a mock child Conversation, like the API. */
|
|
1897
|
+
function mockAgentTree(
|
|
1898
|
+
conversation: MockConversation,
|
|
1899
|
+
): ConversationDetailReport["agentTree"] {
|
|
1900
|
+
if (!conversation.parentConversationId) return undefined;
|
|
1901
|
+
const conversations = mockConversations(NOW_MS);
|
|
1902
|
+
const chain = [conversation];
|
|
1903
|
+
let current = conversation;
|
|
1904
|
+
while (current.parentConversationId) {
|
|
1905
|
+
const parent = conversations.find(
|
|
1906
|
+
(candidate) => candidate.conversationId === current.parentConversationId,
|
|
1907
|
+
);
|
|
1908
|
+
if (!parent) break;
|
|
1909
|
+
chain.unshift(parent);
|
|
1910
|
+
current = parent;
|
|
1911
|
+
}
|
|
1912
|
+
return chain.map((item) => {
|
|
1913
|
+
if (!item.parentConversationId) {
|
|
1914
|
+
return { conversationId: item.conversationId, label: item.displayTitle };
|
|
1915
|
+
}
|
|
1916
|
+
const agent = readMockConversationChildAgents(
|
|
1917
|
+
item.parentConversationId,
|
|
1918
|
+
)?.agents.find((child) => child.conversationId === item.conversationId);
|
|
1919
|
+
return {
|
|
1920
|
+
conversationId: item.conversationId,
|
|
1921
|
+
label: agent?.title ?? agent?.name ?? "Subagent",
|
|
1922
|
+
};
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1853
1926
|
/** Return one canonical-event visual-QA conversation detail fixture. */
|
|
1854
1927
|
export function readMockConversationDetail(
|
|
1855
1928
|
conversationId: string,
|
|
@@ -1860,9 +1933,11 @@ export function readMockConversationDetail(
|
|
|
1860
1933
|
);
|
|
1861
1934
|
if (!conversation) return undefined;
|
|
1862
1935
|
const { parentConversationId, ...conversationDetail } = conversation;
|
|
1936
|
+
const agentTree = mockAgentTree(conversation);
|
|
1863
1937
|
// Match the API: only readable root Conversations can be forked.
|
|
1864
1938
|
const detail = {
|
|
1865
1939
|
...conversationDetail,
|
|
1940
|
+
...(agentTree ? { agentTree } : undefined),
|
|
1866
1941
|
canFork:
|
|
1867
1942
|
!parentConversationId &&
|
|
1868
1943
|
conversationDetail.eventHistory.status !== "redacted",
|