@sentry/junior-dashboard 0.242.0 → 0.244.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 +59 -12
- package/dist/client.js +49 -49
- package/dist/index.js +59 -12
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
- package/src/client/conversations/ConversationChildAgents.tsx +112 -0
- package/src/client/conversations/ConversationDetailsDrawer.tsx +8 -1
- package/src/client/conversations/SubagentTranscriptDrawer.tsx +5 -2
- package/src/client/conversations/TranscriptSubagentView.tsx +8 -2
- package/src/client/conversations/eventLog.ts +3 -2
- 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/markdownExport.ts +6 -1
- package/src/client/types.ts +4 -1
- package/src/mock-reporting/fixtures.ts +53 -10
- package/src/mock-reporting/routes.ts +12 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
import { Bot } from "lucide-react";
|
|
3
|
+
import { Link } from "react-router";
|
|
4
|
+
import {
|
|
5
|
+
conversationChildAgentsReportSchema,
|
|
6
|
+
type ConversationChildAgent,
|
|
7
|
+
} from "@sentry/junior/api/schema";
|
|
8
|
+
|
|
9
|
+
import { StatusChip, type StatusChipTone } from "../components/StatusChip";
|
|
10
|
+
import { formatMessageTimestamp } from "../format";
|
|
11
|
+
import { fetchDashboardJson } from "../http";
|
|
12
|
+
import { conversationPath } from "./conversationRoutes";
|
|
13
|
+
|
|
14
|
+
const statusTone: Record<ConversationChildAgent["status"], StatusChipTone> = {
|
|
15
|
+
blocked: "warning",
|
|
16
|
+
completed: "success",
|
|
17
|
+
failed: "danger",
|
|
18
|
+
paused: "info",
|
|
19
|
+
pending: "neutral",
|
|
20
|
+
running: "info",
|
|
21
|
+
stopped: "neutral",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Load and show the child agents of one Conversation with runtime status. */
|
|
25
|
+
export function ConversationChildAgents(props: {
|
|
26
|
+
conversationId: string;
|
|
27
|
+
/** Called before a child link leaves the current Conversation. */
|
|
28
|
+
onNavigate(): void;
|
|
29
|
+
}) {
|
|
30
|
+
const query = useQuery({
|
|
31
|
+
queryFn: ({ signal }) =>
|
|
32
|
+
fetchDashboardJson(
|
|
33
|
+
conversationChildAgentsReportSchema,
|
|
34
|
+
`/api/conversations/${encodeURIComponent(props.conversationId)}/agents`,
|
|
35
|
+
signal,
|
|
36
|
+
),
|
|
37
|
+
queryKey: ["conversation", props.conversationId, "agents"],
|
|
38
|
+
retry: false,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (query.isPending) {
|
|
42
|
+
return (
|
|
43
|
+
<p className="m-0 text-sm text-dashboard-text-muted" role="status">
|
|
44
|
+
Loading subagents…
|
|
45
|
+
</p>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
if (query.error) {
|
|
49
|
+
return (
|
|
50
|
+
<p className="m-0 text-sm text-red-300/80">
|
|
51
|
+
Could not load subagents from this Conversation.
|
|
52
|
+
</p>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
if (query.data.agents.length === 0) {
|
|
56
|
+
return (
|
|
57
|
+
<div className="grid justify-items-center gap-2 py-10 text-center text-dashboard-text-muted">
|
|
58
|
+
<Bot aria-hidden="true" className="size-5 opacity-60" />
|
|
59
|
+
<p className="m-0 text-sm">No subagents were started.</p>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<ol aria-label="Subagents" className="m-0 grid list-none gap-3 p-0">
|
|
66
|
+
{query.data.agents.map((agent) => (
|
|
67
|
+
<li
|
|
68
|
+
className="grid gap-2 rounded-lg border border-dashboard-border-subtle bg-dashboard-surface px-3 py-3"
|
|
69
|
+
key={agent.conversationId}
|
|
70
|
+
>
|
|
71
|
+
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
|
72
|
+
<Link
|
|
73
|
+
className="min-w-0 truncate font-mono text-xs font-semibold text-dashboard-text no-underline hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
|
|
74
|
+
onClick={props.onNavigate}
|
|
75
|
+
to={conversationPath(agent.conversationId)}
|
|
76
|
+
>
|
|
77
|
+
{agent.redacted ? "Private subagent" : (agent.name ?? "agent")}
|
|
78
|
+
</Link>
|
|
79
|
+
<StatusChip
|
|
80
|
+
className="ml-auto"
|
|
81
|
+
size="compact"
|
|
82
|
+
tone={statusTone[agent.status]}
|
|
83
|
+
>
|
|
84
|
+
{agent.status}
|
|
85
|
+
</StatusChip>
|
|
86
|
+
</div>
|
|
87
|
+
{agent.title ? (
|
|
88
|
+
<p className="m-0 break-words text-sm font-semibold text-dashboard-text">
|
|
89
|
+
{agent.title}
|
|
90
|
+
</p>
|
|
91
|
+
) : null}
|
|
92
|
+
{agent.task ? (
|
|
93
|
+
<p className="m-0 line-clamp-4 whitespace-pre-wrap break-words text-sm leading-relaxed text-dashboard-text">
|
|
94
|
+
{agent.task}
|
|
95
|
+
</p>
|
|
96
|
+
) : null}
|
|
97
|
+
{agent.error ? (
|
|
98
|
+
<p className="m-0 whitespace-pre-wrap break-words text-xs leading-relaxed text-dashboard-text-muted">
|
|
99
|
+
{agent.error}
|
|
100
|
+
</p>
|
|
101
|
+
) : null}
|
|
102
|
+
<time
|
|
103
|
+
className="font-mono text-xs text-dashboard-text-muted"
|
|
104
|
+
dateTime={agent.updatedAt}
|
|
105
|
+
>
|
|
106
|
+
{formatMessageTimestamp(Date.parse(agent.updatedAt), true)}
|
|
107
|
+
</time>
|
|
108
|
+
</li>
|
|
109
|
+
))}
|
|
110
|
+
</ol>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
@@ -5,12 +5,14 @@ import { formatRelativeTime, formatTime } from "../format";
|
|
|
5
5
|
import { ButtonLink } from "../components/Button";
|
|
6
6
|
import { Drawer } from "../components/Drawer";
|
|
7
7
|
import { SegmentedTabs } from "../components/SegmentedTabs";
|
|
8
|
+
import { ConversationChildAgents } from "./ConversationChildAgents";
|
|
8
9
|
import { ConversationMemories } from "./ConversationMemories";
|
|
9
10
|
import { ShareConversationButton } from "./ShareConversationButton";
|
|
10
11
|
|
|
11
12
|
const tabs = [
|
|
12
13
|
{ label: "Details", value: "details" },
|
|
13
14
|
{ label: "Memories", value: "memories" },
|
|
15
|
+
{ label: "Subagents", value: "agents" },
|
|
14
16
|
] as const;
|
|
15
17
|
|
|
16
18
|
/** Put conversation context before usage and diagnostic links. */
|
|
@@ -26,7 +28,7 @@ export function ConversationDetailsDrawer(props: {
|
|
|
26
28
|
stats: ReactNode;
|
|
27
29
|
title: string;
|
|
28
30
|
}) {
|
|
29
|
-
const [tab, setTab] = useState<
|
|
31
|
+
const [tab, setTab] = useState<(typeof tabs)[number]["value"]>("details");
|
|
30
32
|
const titleId = "conversation-details-drawer-title";
|
|
31
33
|
const sections = [
|
|
32
34
|
{ content: props.brief, title: "Summary" },
|
|
@@ -65,6 +67,11 @@ export function ConversationDetailsDrawer(props: {
|
|
|
65
67
|
>
|
|
66
68
|
{tab === "memories" ? (
|
|
67
69
|
<ConversationMemories conversationId={props.conversationId} />
|
|
70
|
+
) : tab === "agents" ? (
|
|
71
|
+
<ConversationChildAgents
|
|
72
|
+
conversationId={props.conversationId}
|
|
73
|
+
onNavigate={props.onClose}
|
|
74
|
+
/>
|
|
68
75
|
) : sections.length > 0 ? (
|
|
69
76
|
<div className="grid min-w-0 gap-5">
|
|
70
77
|
{sections.map((section) => (
|
|
@@ -50,7 +50,10 @@ function SubagentTranscriptDrawerContent(props: {
|
|
|
50
50
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
51
51
|
|
|
52
52
|
const detail = query.data;
|
|
53
|
-
const label =
|
|
53
|
+
const label =
|
|
54
|
+
props.target.part.title ||
|
|
55
|
+
detail?.displayTitle ||
|
|
56
|
+
props.target.part.subagentKind;
|
|
54
57
|
const meta = [
|
|
55
58
|
statusLabel(props.target.part, detail?.status),
|
|
56
59
|
detail ? formatMessageTimestamp(Date.parse(detail.startedAt)) : undefined,
|
|
@@ -169,7 +172,7 @@ function statusLabel(
|
|
|
169
172
|
part: TranscriptViewSubagentPart,
|
|
170
173
|
detailStatus?: string,
|
|
171
174
|
): string {
|
|
172
|
-
if (part.status
|
|
175
|
+
if (part.status !== "running" && part.status !== "completed") {
|
|
173
176
|
return part.status;
|
|
174
177
|
}
|
|
175
178
|
return detailStatus ?? part.status;
|
|
@@ -9,7 +9,8 @@ export function TranscriptSubagentView(props: {
|
|
|
9
9
|
part: TranscriptViewSubagentPart;
|
|
10
10
|
timestamp?: number;
|
|
11
11
|
}) {
|
|
12
|
-
const label = props.part.subagentKind;
|
|
12
|
+
const label = props.part.agentName ?? props.part.subagentKind;
|
|
13
|
+
const summary = props.part.title ?? props.part.task;
|
|
13
14
|
const status = props.part.status;
|
|
14
15
|
const meta = [
|
|
15
16
|
status,
|
|
@@ -27,6 +28,11 @@ export function TranscriptSubagentView(props: {
|
|
|
27
28
|
<strong className="min-w-0 break-words font-bold text-cyan-100">
|
|
28
29
|
<HighlightText text={label} />
|
|
29
30
|
</strong>
|
|
31
|
+
{summary ? (
|
|
32
|
+
<span className="min-w-0 truncate text-dashboard-text-muted">
|
|
33
|
+
<HighlightText text={summary} />
|
|
34
|
+
</span>
|
|
35
|
+
) : null}
|
|
30
36
|
{props.part.status === "running" ? (
|
|
31
37
|
<span
|
|
32
38
|
aria-hidden="true"
|
|
@@ -44,7 +50,7 @@ export function TranscriptSubagentView(props: {
|
|
|
44
50
|
|
|
45
51
|
return (
|
|
46
52
|
<button
|
|
47
|
-
aria-label={`Open ${
|
|
53
|
+
aria-label={`Open ${label} transcript`}
|
|
48
54
|
className="block w-full min-w-0 cursor-pointer text-left transition-colors hover:bg-white/[0.035] focus-visible:outline focus-visible:outline-1 focus-visible:outline-cyan-300/55"
|
|
49
55
|
onClick={() => props.onOpenTranscript?.(props.part)}
|
|
50
56
|
type="button"
|
|
@@ -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
|
|
|
@@ -111,7 +111,8 @@ export function eventLogTone(data: ConversationReportEventData): string {
|
|
|
111
111
|
}
|
|
112
112
|
if (
|
|
113
113
|
(data.type === "guardian_action_reviewed" && data.decision === "ask") ||
|
|
114
|
-
(data.type === "subagent" &&
|
|
114
|
+
(data.type === "subagent" &&
|
|
115
|
+
(data.status === "aborted" || data.status === "blocked"))
|
|
115
116
|
) {
|
|
116
117
|
return "text-amber-200";
|
|
117
118
|
}
|
|
@@ -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
|
}
|
|
@@ -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(
|
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
|
-
status: "aborted" | "completed" | "error" | "running";
|
|
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
|
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
ActorProfileReport,
|
|
9
9
|
ActorSummaryReport,
|
|
10
10
|
ActorWindowMetrics,
|
|
11
|
+
ConversationChildAgentsReport,
|
|
11
12
|
ConversationDetailReport,
|
|
12
13
|
ConversationEventPage,
|
|
13
14
|
ConversationFeed,
|
|
@@ -694,7 +695,7 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
694
695
|
calls: [
|
|
695
696
|
{
|
|
696
697
|
toolCallId: "qa-advisor",
|
|
697
|
-
name: "
|
|
698
|
+
name: "spawnAgent",
|
|
698
699
|
status: "running",
|
|
699
700
|
},
|
|
700
701
|
],
|
|
@@ -704,11 +705,11 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
704
705
|
calls: [
|
|
705
706
|
{
|
|
706
707
|
toolCallId: "qa-advisor",
|
|
707
|
-
name: "
|
|
708
|
+
name: "spawnAgent",
|
|
708
709
|
status: "running",
|
|
709
710
|
startedSeq: 1,
|
|
710
711
|
startedAt: iso(Date.parse(startedAt), 2_000),
|
|
711
|
-
input: {
|
|
712
|
+
input: { task: "Review the dashboard plan before editing." },
|
|
712
713
|
},
|
|
713
714
|
],
|
|
714
715
|
}),
|
|
@@ -717,7 +718,10 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
717
718
|
startedSeq: 3,
|
|
718
719
|
startedAt: iso(Date.parse(startedAt), 4_000),
|
|
719
720
|
childConversationId: DASHBOARD_QA_PLAN_ID,
|
|
720
|
-
subagentKind: "
|
|
721
|
+
subagentKind: "agent",
|
|
722
|
+
agentName: "planner",
|
|
723
|
+
task: "Review the dashboard plan before editing.",
|
|
724
|
+
title: "Review the dashboard plan",
|
|
721
725
|
parentToolCallId: "qa-advisor",
|
|
722
726
|
status: "running",
|
|
723
727
|
}),
|
|
@@ -726,7 +730,10 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
726
730
|
startedSeq: 3,
|
|
727
731
|
startedAt: iso(Date.parse(startedAt), 4_000),
|
|
728
732
|
childConversationId: DASHBOARD_QA_PLAN_ID,
|
|
729
|
-
subagentKind: "
|
|
733
|
+
subagentKind: "agent",
|
|
734
|
+
agentName: "planner",
|
|
735
|
+
task: "Review the dashboard plan before editing.",
|
|
736
|
+
title: "Review the dashboard plan",
|
|
730
737
|
parentToolCallId: "qa-advisor",
|
|
731
738
|
status: "completed",
|
|
732
739
|
}),
|
|
@@ -735,11 +742,11 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
735
742
|
calls: [
|
|
736
743
|
{
|
|
737
744
|
toolCallId: "qa-advisor",
|
|
738
|
-
name: "
|
|
745
|
+
name: "spawnAgent",
|
|
739
746
|
status: "completed",
|
|
740
747
|
startedSeq: 1,
|
|
741
748
|
startedAt: iso(Date.parse(startedAt), 2_000),
|
|
742
|
-
output: {
|
|
749
|
+
output: { conversation_id: DASHBOARD_QA_PLAN_ID },
|
|
743
750
|
},
|
|
744
751
|
],
|
|
745
752
|
}),
|
|
@@ -748,7 +755,8 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
748
755
|
startedSeq: 6,
|
|
749
756
|
startedAt: iso(Date.parse(startedAt), 25_000),
|
|
750
757
|
childConversationId: DASHBOARD_QA_REVIEW_ID,
|
|
751
|
-
subagentKind: "
|
|
758
|
+
subagentKind: "agent",
|
|
759
|
+
agentName: "reviewer",
|
|
752
760
|
status: "running",
|
|
753
761
|
}),
|
|
754
762
|
reportEvent(7, iso(Date.parse(startedAt), 44_000), {
|
|
@@ -756,8 +764,9 @@ function dashboardQaConversation(nowMs: number): ConversationDetailReport {
|
|
|
756
764
|
startedSeq: 6,
|
|
757
765
|
startedAt: iso(Date.parse(startedAt), 25_000),
|
|
758
766
|
childConversationId: DASHBOARD_QA_REVIEW_ID,
|
|
759
|
-
subagentKind: "
|
|
760
|
-
|
|
767
|
+
subagentKind: "agent",
|
|
768
|
+
agentName: "reviewer",
|
|
769
|
+
status: "blocked",
|
|
761
770
|
}),
|
|
762
771
|
reportEvent(8, iso(Date.parse(startedAt), 50_000), {
|
|
763
772
|
type: "tool_calls",
|
|
@@ -1816,6 +1825,40 @@ export function readMockConversationPendingMessages(
|
|
|
1816
1825
|
};
|
|
1817
1826
|
}
|
|
1818
1827
|
|
|
1828
|
+
/** Return the child agents of one mock Conversation, matching its transcript. */
|
|
1829
|
+
export function readMockConversationChildAgents(
|
|
1830
|
+
conversationId: string,
|
|
1831
|
+
): ConversationChildAgentsReport | undefined {
|
|
1832
|
+
const conversation = mockConversations(NOW_MS).find(
|
|
1833
|
+
(candidate) => candidate.conversationId === conversationId,
|
|
1834
|
+
);
|
|
1835
|
+
if (!conversation) return undefined;
|
|
1836
|
+
if (conversationId !== DASHBOARD_QA_CONVERSATION_ID) {
|
|
1837
|
+
return { agents: [], conversationId };
|
|
1838
|
+
}
|
|
1839
|
+
const startedAtMs = NOW_MS - 5 * 60 * 60_000;
|
|
1840
|
+
return {
|
|
1841
|
+
agents: [
|
|
1842
|
+
{
|
|
1843
|
+
conversationId: DASHBOARD_QA_REVIEW_ID,
|
|
1844
|
+
error: "GitHub access is needed to read the pull request.",
|
|
1845
|
+
name: "reviewer",
|
|
1846
|
+
status: "blocked",
|
|
1847
|
+
task: "Review the open dashboard pull requests and list risky changes.",
|
|
1848
|
+
updatedAt: iso(startedAtMs, 44_000),
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
conversationId: DASHBOARD_QA_PLAN_ID,
|
|
1852
|
+
status: "completed",
|
|
1853
|
+
task: "Review the dashboard plan before editing.",
|
|
1854
|
+
title: "Review the dashboard plan",
|
|
1855
|
+
updatedAt: iso(startedAtMs, 20_000),
|
|
1856
|
+
},
|
|
1857
|
+
],
|
|
1858
|
+
conversationId,
|
|
1859
|
+
};
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1819
1862
|
/** Return one canonical-event visual-QA conversation detail fixture. */
|
|
1820
1863
|
export function readMockConversationDetail(
|
|
1821
1864
|
conversationId: string,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
actorProfileReportSchema,
|
|
8
8
|
archiveConversationBodySchema,
|
|
9
9
|
archiveConversationResponseSchema,
|
|
10
|
+
conversationChildAgentsReportSchema,
|
|
10
11
|
conversationDetailQuerySchema,
|
|
11
12
|
conversationDetailReportSchema,
|
|
12
13
|
conversationEventPageSchema,
|
|
@@ -38,6 +39,7 @@ import {
|
|
|
38
39
|
readMockCodeRepository,
|
|
39
40
|
} from "./code-repository";
|
|
40
41
|
import {
|
|
42
|
+
readMockConversationChildAgents,
|
|
41
43
|
readMockConversationDetail,
|
|
42
44
|
readMockConversationEvents,
|
|
43
45
|
readMockConversationFeed,
|
|
@@ -193,6 +195,16 @@ export function createMockReportingApi(): Hono<{
|
|
|
193
195
|
? jsonResponse(conversationEventPageSchema, report)
|
|
194
196
|
: errorResponse("Invalid conversation cursor.", 400);
|
|
195
197
|
});
|
|
198
|
+
app.get("/conversations/:conversationId/agents", (c) => {
|
|
199
|
+
const params = conversationParamsSchema.safeParse(c.req.param());
|
|
200
|
+
if (!params.success) {
|
|
201
|
+
return errorResponse("Invalid route parameters.", 400);
|
|
202
|
+
}
|
|
203
|
+
const report = readMockConversationChildAgents(params.data.conversationId);
|
|
204
|
+
return report
|
|
205
|
+
? jsonResponse(conversationChildAgentsReportSchema, report)
|
|
206
|
+
: errorResponse("Conversation not found.", 404);
|
|
207
|
+
});
|
|
196
208
|
app.get("/conversations/:conversationId/pending-messages", (c) => {
|
|
197
209
|
const params = conversationParamsSchema.safeParse(c.req.param());
|
|
198
210
|
if (!params.success) {
|