@stigmer/react 0.0.56 → 0.0.58
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/execution/ApprovalCard.d.ts.map +1 -1
- package/execution/ApprovalCard.js +1 -1
- package/execution/ApprovalCard.js.map +1 -1
- package/execution/ArtifactsWidget.d.ts +1 -1
- package/execution/ArtifactsWidget.js +1 -1
- package/execution/ExecutionProgress.d.ts.map +1 -1
- package/execution/ExecutionProgress.js +2 -59
- package/execution/ExecutionProgress.js.map +1 -1
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +31 -6
- package/execution/MessageThread.js.map +1 -1
- package/execution/SubAgentSection.d.ts +25 -4
- package/execution/SubAgentSection.d.ts.map +1 -1
- package/execution/SubAgentSection.js +70 -11
- package/execution/SubAgentSection.js.map +1 -1
- package/execution/TodoList.d.ts +42 -0
- package/execution/TodoList.d.ts.map +1 -0
- package/execution/TodoList.js +108 -0
- package/execution/TodoList.js.map +1 -0
- package/execution/ToolCallItem.js +1 -1
- package/execution/ToolCallItem.js.map +1 -1
- package/execution/UsageWidget.d.ts +57 -0
- package/execution/UsageWidget.d.ts.map +1 -0
- package/execution/UsageWidget.js +72 -0
- package/execution/UsageWidget.js.map +1 -0
- package/execution/index.d.ts +4 -4
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +2 -2
- package/execution/index.js.map +1 -1
- package/execution/useExecutionArtifacts.d.ts +1 -1
- package/execution/useExecutionArtifacts.js +1 -1
- package/index.d.ts +4 -4
- package/index.d.ts.map +1 -1
- package/index.js +2 -2
- package/index.js.map +1 -1
- package/package.json +4 -4
- package/session/index.d.ts +2 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js +1 -0
- package/session/index.js.map +1 -1
- package/session/useSessionUsage.d.ts +65 -0
- package/session/useSessionUsage.d.ts.map +1 -0
- package/session/useSessionUsage.js +107 -0
- package/session/useSessionUsage.js.map +1 -0
- package/src/execution/ApprovalCard.tsx +7 -13
- package/src/execution/ArtifactsWidget.tsx +1 -1
- package/src/execution/ExecutionProgress.tsx +2 -134
- package/src/execution/MessageThread.tsx +39 -6
- package/src/execution/SubAgentSection.tsx +323 -16
- package/src/execution/TodoList.tsx +202 -0
- package/src/execution/ToolCallItem.tsx +1 -1
- package/src/execution/{ExecutionCostSummary.tsx → UsageWidget.tsx} +43 -50
- package/src/execution/index.ts +10 -4
- package/src/execution/useExecutionArtifacts.ts +1 -1
- package/src/index.ts +12 -5
- package/src/session/index.ts +6 -0
- package/src/session/useSessionUsage.ts +159 -0
- package/styles.css +1 -1
- package/execution/ExecutionCostSummary.d.ts +0 -47
- package/execution/ExecutionCostSummary.d.ts.map +0 -1
- package/execution/ExecutionCostSummary.js +0 -77
- package/execution/ExecutionCostSummary.js.map +0 -1
- package/execution/__tests__/ExecutionCostSummary.test.d.ts +0 -2
- package/execution/__tests__/ExecutionCostSummary.test.d.ts.map +0 -1
- package/execution/__tests__/ExecutionCostSummary.test.js +0 -255
- package/execution/__tests__/ExecutionCostSummary.test.js.map +0 -1
- package/execution/__tests__/useExecutionUsage.test.d.ts +0 -2
- package/execution/__tests__/useExecutionUsage.test.d.ts.map +0 -1
- package/execution/__tests__/useExecutionUsage.test.js +0 -303
- package/execution/__tests__/useExecutionUsage.test.js.map +0 -1
- package/execution/useExecutionUsage.d.ts +0 -45
- package/execution/useExecutionUsage.d.ts.map +0 -1
- package/execution/useExecutionUsage.js +0 -157
- package/execution/useExecutionUsage.js.map +0 -1
- package/src/execution/__tests__/ExecutionCostSummary.test.tsx +0 -416
- package/src/execution/__tests__/useExecutionUsage.test.tsx +0 -408
- package/src/execution/useExecutionUsage.ts +0 -213
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
2
|
+
/**
|
|
3
|
+
* Per-model cost breakdown computed from per-message {@link LlmCallMetrics}.
|
|
4
|
+
*/
|
|
5
|
+
export interface ModelCostEntry {
|
|
6
|
+
readonly model: string;
|
|
7
|
+
readonly provider: string;
|
|
8
|
+
readonly estimatedCostUsd: number;
|
|
9
|
+
readonly inputTokens: number;
|
|
10
|
+
readonly outputTokens: number;
|
|
11
|
+
readonly cacheCreationTokens: number;
|
|
12
|
+
readonly cacheReadTokens: number;
|
|
13
|
+
readonly callCount: number;
|
|
14
|
+
}
|
|
15
|
+
export interface UseSessionUsageReturn {
|
|
16
|
+
/** Total estimated cost across all executions in the session. */
|
|
17
|
+
readonly totalCostUsd: number;
|
|
18
|
+
/** Total tokens (all types) across all executions. */
|
|
19
|
+
readonly totalTokens: number;
|
|
20
|
+
/** Total input tokens (non-cached) across all executions. */
|
|
21
|
+
readonly inputTokens: number;
|
|
22
|
+
/** Total output tokens across all executions. */
|
|
23
|
+
readonly outputTokens: number;
|
|
24
|
+
/** Total cache read tokens across all executions. */
|
|
25
|
+
readonly cacheReadTokens: number;
|
|
26
|
+
/** Total cache creation tokens across all executions. */
|
|
27
|
+
readonly cacheCreationTokens: number;
|
|
28
|
+
/** Total number of LLM calls across all executions. */
|
|
29
|
+
readonly llmCallCount: number;
|
|
30
|
+
/** Per-model breakdown, sorted by cost descending. */
|
|
31
|
+
readonly modelBreakdown: readonly ModelCostEntry[];
|
|
32
|
+
/** Primary model (first model encountered). */
|
|
33
|
+
readonly primaryModel: string;
|
|
34
|
+
/** Primary provider (first provider encountered). */
|
|
35
|
+
readonly primaryProvider: string;
|
|
36
|
+
/** `true` when at least one execution has cost data. */
|
|
37
|
+
readonly hasUsage: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Pure derivation hook that aggregates usage data across all executions
|
|
41
|
+
* in a session from per-message {@link LlmCallMetrics}.
|
|
42
|
+
*
|
|
43
|
+
* Follows the same pattern as {@link useSessionArtifacts} and
|
|
44
|
+
* {@link useSessionWriteBacks}: `useMemo`-based derivation, no side
|
|
45
|
+
* effects, no data fetching. Takes the same `executions` array input.
|
|
46
|
+
*
|
|
47
|
+
* Per-message `llm_metrics` on `AgentMessage` (type == MESSAGE_AI) is
|
|
48
|
+
* the single source of truth for cost data. This hook walks all messages
|
|
49
|
+
* (main agent + sub-agents) across all executions and sums the fields.
|
|
50
|
+
*
|
|
51
|
+
* @param executions - All executions for a session, in chronological
|
|
52
|
+
* order. Pass both completed and active-stream executions.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* const conv = useSessionConversation(sessionId, org);
|
|
57
|
+
* const allExecutions = [
|
|
58
|
+
* ...conv.completedExecutions,
|
|
59
|
+
* ...(conv.activeStreamExecution ? [conv.activeStreamExecution] : []),
|
|
60
|
+
* ];
|
|
61
|
+
* const { totalCostUsd, totalTokens, hasUsage } = useSessionUsage(allExecutions);
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function useSessionUsage(executions: readonly AgentExecution[]): UseSessionUsageReturn;
|
|
65
|
+
//# sourceMappingURL=useSessionUsage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSessionUsage.d.ts","sourceRoot":"","sources":["../../src/session/useSessionUsage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAIlG;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,yDAAyD;IACzD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,uDAAuD;IACvD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,cAAc,EAAE,SAAS,cAAc,EAAE,CAAC;IACnD,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,SAAS,cAAc,EAAE,GACpC,qBAAqB,CAqFvB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Pure derivation hook that aggregates usage data across all executions
|
|
5
|
+
* in a session from per-message {@link LlmCallMetrics}.
|
|
6
|
+
*
|
|
7
|
+
* Follows the same pattern as {@link useSessionArtifacts} and
|
|
8
|
+
* {@link useSessionWriteBacks}: `useMemo`-based derivation, no side
|
|
9
|
+
* effects, no data fetching. Takes the same `executions` array input.
|
|
10
|
+
*
|
|
11
|
+
* Per-message `llm_metrics` on `AgentMessage` (type == MESSAGE_AI) is
|
|
12
|
+
* the single source of truth for cost data. This hook walks all messages
|
|
13
|
+
* (main agent + sub-agents) across all executions and sums the fields.
|
|
14
|
+
*
|
|
15
|
+
* @param executions - All executions for a session, in chronological
|
|
16
|
+
* order. Pass both completed and active-stream executions.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* const conv = useSessionConversation(sessionId, org);
|
|
21
|
+
* const allExecutions = [
|
|
22
|
+
* ...conv.completedExecutions,
|
|
23
|
+
* ...(conv.activeStreamExecution ? [conv.activeStreamExecution] : []),
|
|
24
|
+
* ];
|
|
25
|
+
* const { totalCostUsd, totalTokens, hasUsage } = useSessionUsage(allExecutions);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function useSessionUsage(executions) {
|
|
29
|
+
return useMemo(() => {
|
|
30
|
+
let totalCostUsd = 0;
|
|
31
|
+
let totalTokens = 0;
|
|
32
|
+
let inputTokens = 0;
|
|
33
|
+
let outputTokens = 0;
|
|
34
|
+
let cacheReadTokens = 0;
|
|
35
|
+
let cacheCreationTokens = 0;
|
|
36
|
+
let llmCallCount = 0;
|
|
37
|
+
let primaryModel = "";
|
|
38
|
+
let primaryProvider = "";
|
|
39
|
+
const modelMap = new Map();
|
|
40
|
+
const processMessage = (msg) => {
|
|
41
|
+
const m = msg.llmMetrics;
|
|
42
|
+
if (!m)
|
|
43
|
+
return;
|
|
44
|
+
totalCostUsd += m.estimatedCostUsd;
|
|
45
|
+
totalTokens += m.totalTokens;
|
|
46
|
+
inputTokens += m.inputTokens;
|
|
47
|
+
outputTokens += m.outputTokens;
|
|
48
|
+
cacheReadTokens += m.cacheReadTokens;
|
|
49
|
+
cacheCreationTokens += m.cacheCreationTokens;
|
|
50
|
+
llmCallCount++;
|
|
51
|
+
if (!primaryModel && m.model) {
|
|
52
|
+
primaryModel = m.model;
|
|
53
|
+
primaryProvider = m.provider;
|
|
54
|
+
}
|
|
55
|
+
const key = `${m.model}\0${m.provider}`;
|
|
56
|
+
const existing = modelMap.get(key);
|
|
57
|
+
if (existing) {
|
|
58
|
+
modelMap.set(key, {
|
|
59
|
+
...existing,
|
|
60
|
+
estimatedCostUsd: existing.estimatedCostUsd + m.estimatedCostUsd,
|
|
61
|
+
inputTokens: existing.inputTokens + m.inputTokens,
|
|
62
|
+
outputTokens: existing.outputTokens + m.outputTokens,
|
|
63
|
+
cacheCreationTokens: existing.cacheCreationTokens + m.cacheCreationTokens,
|
|
64
|
+
cacheReadTokens: existing.cacheReadTokens + m.cacheReadTokens,
|
|
65
|
+
callCount: existing.callCount + 1,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
modelMap.set(key, {
|
|
70
|
+
model: m.model,
|
|
71
|
+
provider: m.provider,
|
|
72
|
+
estimatedCostUsd: m.estimatedCostUsd,
|
|
73
|
+
inputTokens: m.inputTokens,
|
|
74
|
+
outputTokens: m.outputTokens,
|
|
75
|
+
cacheCreationTokens: m.cacheCreationTokens,
|
|
76
|
+
cacheReadTokens: m.cacheReadTokens,
|
|
77
|
+
callCount: 1,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
for (const execution of executions) {
|
|
82
|
+
for (const msg of execution.status?.messages ?? []) {
|
|
83
|
+
processMessage(msg);
|
|
84
|
+
}
|
|
85
|
+
for (const sub of execution.status?.subAgentExecutions ?? []) {
|
|
86
|
+
for (const msg of sub.messages) {
|
|
87
|
+
processMessage(msg);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const modelBreakdown = Array.from(modelMap.values()).sort((a, b) => b.estimatedCostUsd - a.estimatedCostUsd);
|
|
92
|
+
return {
|
|
93
|
+
totalCostUsd,
|
|
94
|
+
totalTokens,
|
|
95
|
+
inputTokens,
|
|
96
|
+
outputTokens,
|
|
97
|
+
cacheReadTokens,
|
|
98
|
+
cacheCreationTokens,
|
|
99
|
+
llmCallCount,
|
|
100
|
+
modelBreakdown,
|
|
101
|
+
primaryModel,
|
|
102
|
+
primaryProvider,
|
|
103
|
+
hasUsage: llmCallCount > 0,
|
|
104
|
+
};
|
|
105
|
+
}, [executions]);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=useSessionUsage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSessionUsage.js","sourceRoot":"","sources":["../../src/session/useSessionUsage.ts"],"names":[],"mappings":"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"}
|
|
@@ -134,6 +134,12 @@ export function ApprovalCard({
|
|
|
134
134
|
)}
|
|
135
135
|
</span>
|
|
136
136
|
|
|
137
|
+
{pendingApproval.fromSubAgent && pendingApproval.subAgentName && (
|
|
138
|
+
<span className="shrink-0 rounded bg-muted px-1 py-0.5 font-mono text-muted-foreground">
|
|
139
|
+
via {pendingApproval.subAgentSubject || pendingApproval.subAgentName}
|
|
140
|
+
</span>
|
|
141
|
+
)}
|
|
142
|
+
|
|
137
143
|
<WaitingDuration requestedAt={pendingApproval.requestedAt} />
|
|
138
144
|
|
|
139
145
|
<span className="shrink-0 text-warning" aria-hidden="true">
|
|
@@ -143,19 +149,7 @@ export function ApprovalCard({
|
|
|
143
149
|
|
|
144
150
|
{/* Body */}
|
|
145
151
|
<div className="px-3 py-2.5 space-y-2">
|
|
146
|
-
{
|
|
147
|
-
{pendingApproval.fromSubAgent && pendingApproval.subAgentName && (
|
|
148
|
-
<p className="text-xs text-muted-foreground">
|
|
149
|
-
Sub-agent{" "}
|
|
150
|
-
<span className="font-medium text-foreground">
|
|
151
|
-
{pendingApproval.subAgentName}
|
|
152
|
-
</span>{" "}
|
|
153
|
-
wants to execute this tool
|
|
154
|
-
</p>
|
|
155
|
-
)}
|
|
156
|
-
|
|
157
|
-
{/* Approval message */}
|
|
158
|
-
{pendingApproval.message && (
|
|
152
|
+
{pendingApproval.message && categoryInfo.category !== "shell" && (
|
|
159
153
|
<p className="text-xs text-foreground">
|
|
160
154
|
{pendingApproval.message}
|
|
161
155
|
</p>
|
|
@@ -51,7 +51,7 @@ export interface ArtifactsWidgetProps {
|
|
|
51
51
|
*
|
|
52
52
|
* Returns `null` when the executions list is empty or no execution
|
|
53
53
|
* has artifacts, matching the conditional-render pattern of
|
|
54
|
-
* {@link ExecutionProgress} and {@link
|
|
54
|
+
* {@link ExecutionProgress} and {@link UsageWidget}.
|
|
55
55
|
*
|
|
56
56
|
* Renders without card chrome — each {@link ArtifactCard} provides its
|
|
57
57
|
* own border and padding. The consumer controls the container styling
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useMemo } from "react";
|
|
4
3
|
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
5
|
-
import type { TodoItem } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
6
|
-
import { TodoStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
7
4
|
import { cn } from "@stigmer/theme";
|
|
8
5
|
import { ExecutionPhaseBadge } from "./ExecutionPhaseBadge";
|
|
6
|
+
import { TodoList } from "./TodoList";
|
|
9
7
|
|
|
10
8
|
export interface ExecutionProgressProps {
|
|
11
9
|
/** The execution to display progress for. Renders nothing when null. */
|
|
@@ -13,17 +11,6 @@ export interface ExecutionProgressProps {
|
|
|
13
11
|
readonly className?: string;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
|
-
const STATUS_SORT_ORDER: ReadonlyMap<TodoStatus, number> = new Map([
|
|
17
|
-
[TodoStatus.TODO_IN_PROGRESS, 0],
|
|
18
|
-
[TodoStatus.TODO_PENDING, 1],
|
|
19
|
-
[TodoStatus.TODO_COMPLETED, 2],
|
|
20
|
-
[TodoStatus.TODO_CANCELLED, 3],
|
|
21
|
-
]);
|
|
22
|
-
|
|
23
|
-
function todoSortKey(item: TodoItem): number {
|
|
24
|
-
return STATUS_SORT_ORDER.get(item.status) ?? 4;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
14
|
/**
|
|
28
15
|
* Displays execution lifecycle phase and, when present, the agent's
|
|
29
16
|
* todo checklist showing multi-step task progress.
|
|
@@ -59,13 +46,6 @@ export function ExecutionProgress({
|
|
|
59
46
|
|
|
60
47
|
const todos = execution.status?.todos;
|
|
61
48
|
|
|
62
|
-
const sortedTodos = useMemo(() => {
|
|
63
|
-
if (!todos) return [];
|
|
64
|
-
const items = Object.values(todos);
|
|
65
|
-
if (items.length === 0) return [];
|
|
66
|
-
return items.slice().sort((a, b) => todoSortKey(a) - todoSortKey(b));
|
|
67
|
-
}, [todos]);
|
|
68
|
-
|
|
69
49
|
return (
|
|
70
50
|
<div
|
|
71
51
|
className={cn("flex flex-col gap-2", className)}
|
|
@@ -73,119 +53,7 @@ export function ExecutionProgress({
|
|
|
73
53
|
aria-label="Execution progress"
|
|
74
54
|
>
|
|
75
55
|
<ExecutionPhaseBadge phase={phase} />
|
|
76
|
-
{
|
|
77
|
-
<ul role="list" className="flex flex-col gap-1" aria-label="Tasks">
|
|
78
|
-
{sortedTodos.map((item) => (
|
|
79
|
-
<TodoRow key={item.id} item={item} />
|
|
80
|
-
))}
|
|
81
|
-
</ul>
|
|
82
|
-
)}
|
|
56
|
+
{todos && <TodoList todos={todos} />}
|
|
83
57
|
</div>
|
|
84
58
|
);
|
|
85
59
|
}
|
|
86
|
-
|
|
87
|
-
// ---------------------------------------------------------------------------
|
|
88
|
-
// Internal sub-components
|
|
89
|
-
// ---------------------------------------------------------------------------
|
|
90
|
-
|
|
91
|
-
function TodoRow({ item }: { item: TodoItem }) {
|
|
92
|
-
const Icon = TODO_ICONS[item.status] ?? TodoPendingIcon;
|
|
93
|
-
const colorClass = TODO_COLORS[item.status] ?? "text-muted-foreground";
|
|
94
|
-
const cancelled = item.status === TodoStatus.TODO_CANCELLED;
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<li className="flex items-start gap-1.5 text-xs">
|
|
98
|
-
<span className={cn("mt-0.5 shrink-0", colorClass)} aria-hidden="true">
|
|
99
|
-
<Icon />
|
|
100
|
-
</span>
|
|
101
|
-
<span
|
|
102
|
-
className={cn(
|
|
103
|
-
"min-w-0 break-words",
|
|
104
|
-
cancelled ? "text-muted-foreground line-through" : "text-foreground",
|
|
105
|
-
)}
|
|
106
|
-
>
|
|
107
|
-
{item.content}
|
|
108
|
-
</span>
|
|
109
|
-
</li>
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// ---------------------------------------------------------------------------
|
|
114
|
-
// Status icon mapping
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
|
|
117
|
-
const TODO_ICONS: Partial<Record<TodoStatus, () => React.JSX.Element>> = {
|
|
118
|
-
[TodoStatus.TODO_PENDING]: TodoPendingIcon,
|
|
119
|
-
[TodoStatus.TODO_IN_PROGRESS]: TodoInProgressIcon,
|
|
120
|
-
[TodoStatus.TODO_COMPLETED]: TodoCompletedIcon,
|
|
121
|
-
[TodoStatus.TODO_CANCELLED]: TodoCancelledIcon,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const TODO_COLORS: Partial<Record<TodoStatus, string>> = {
|
|
125
|
-
[TodoStatus.TODO_PENDING]: "text-muted-foreground",
|
|
126
|
-
[TodoStatus.TODO_IN_PROGRESS]: "text-foreground",
|
|
127
|
-
[TodoStatus.TODO_COMPLETED]: "text-success",
|
|
128
|
-
[TodoStatus.TODO_CANCELLED]: "text-muted-foreground",
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
// Inline SVG icons — no external icon dependency in SDK
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
|
|
135
|
-
function TodoPendingIcon() {
|
|
136
|
-
return (
|
|
137
|
-
<svg
|
|
138
|
-
width="12"
|
|
139
|
-
height="12"
|
|
140
|
-
viewBox="0 0 12 12"
|
|
141
|
-
fill="none"
|
|
142
|
-
stroke="currentColor"
|
|
143
|
-
strokeWidth="1.5"
|
|
144
|
-
>
|
|
145
|
-
<circle cx="6" cy="6" r="4.5" />
|
|
146
|
-
</svg>
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function TodoInProgressIcon() {
|
|
151
|
-
return (
|
|
152
|
-
<span className="relative flex h-3 w-3 items-center justify-center">
|
|
153
|
-
<span className="absolute inline-flex h-2 w-2 animate-ping rounded-full bg-current opacity-75" />
|
|
154
|
-
<span className="relative inline-flex h-2 w-2 rounded-full bg-current" />
|
|
155
|
-
</span>
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function TodoCompletedIcon() {
|
|
160
|
-
return (
|
|
161
|
-
<svg
|
|
162
|
-
width="12"
|
|
163
|
-
height="12"
|
|
164
|
-
viewBox="0 0 12 12"
|
|
165
|
-
fill="none"
|
|
166
|
-
stroke="currentColor"
|
|
167
|
-
strokeWidth="2"
|
|
168
|
-
strokeLinecap="round"
|
|
169
|
-
strokeLinejoin="round"
|
|
170
|
-
>
|
|
171
|
-
<path d="M2.5 6L5 8.5L9.5 3.5" />
|
|
172
|
-
</svg>
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function TodoCancelledIcon() {
|
|
177
|
-
return (
|
|
178
|
-
<svg
|
|
179
|
-
width="12"
|
|
180
|
-
height="12"
|
|
181
|
-
viewBox="0 0 12 12"
|
|
182
|
-
fill="none"
|
|
183
|
-
stroke="currentColor"
|
|
184
|
-
strokeWidth="2"
|
|
185
|
-
strokeLinecap="round"
|
|
186
|
-
strokeLinejoin="round"
|
|
187
|
-
>
|
|
188
|
-
<path d="M3 3L9 9M9 3L3 9" />
|
|
189
|
-
</svg>
|
|
190
|
-
);
|
|
191
|
-
}
|
|
@@ -17,6 +17,7 @@ import { cn } from "@stigmer/theme";
|
|
|
17
17
|
import { isTerminalPhase } from "./execution-phases";
|
|
18
18
|
import { MessageEntry } from "./MessageEntry";
|
|
19
19
|
import { ToolCallGroup } from "./ToolCallGroup";
|
|
20
|
+
import { SubAgentSection } from "./SubAgentSection";
|
|
20
21
|
import { ExecutionPhaseBadge } from "./ExecutionPhaseBadge";
|
|
21
22
|
import { SetupProgress } from "./SetupProgress";
|
|
22
23
|
import { ApprovalCard } from "./ApprovalCard";
|
|
@@ -110,6 +111,7 @@ const AUTO_SCROLL_THRESHOLD_PX = 80;
|
|
|
110
111
|
type ThreadItem =
|
|
111
112
|
| { readonly kind: "message"; readonly message: AgentMessage; readonly key: string }
|
|
112
113
|
| { readonly kind: "tool-group"; readonly toolCalls: readonly ToolCall[]; readonly subAgentExecutions: readonly SubAgentExecution[]; readonly key: string }
|
|
114
|
+
| { readonly kind: "sub-agent"; readonly subAgentExecution: SubAgentExecution; readonly key: string }
|
|
113
115
|
| { readonly kind: "phase-badge"; readonly phase: ExecutionPhase; readonly key: string }
|
|
114
116
|
| { readonly kind: "pending-message"; readonly content: string; readonly key: string }
|
|
115
117
|
| { readonly kind: "approval-request"; readonly pendingApproval: PendingApproval; readonly key: string }
|
|
@@ -176,12 +178,35 @@ function buildThreadItems(
|
|
|
176
178
|
msg.type === MessageType.MESSAGE_AI &&
|
|
177
179
|
msg.toolCalls.length > 0
|
|
178
180
|
) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
181
|
+
const regularTools: ToolCall[] = [];
|
|
182
|
+
const taskTools: ToolCall[] = [];
|
|
183
|
+
for (const tc of msg.toolCalls) {
|
|
184
|
+
if (tc.name === "task") {
|
|
185
|
+
taskTools.push(tc);
|
|
186
|
+
} else {
|
|
187
|
+
regularTools.push(tc);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (regularTools.length > 0) {
|
|
192
|
+
items.push({
|
|
193
|
+
kind: "tool-group",
|
|
194
|
+
toolCalls: regularTools,
|
|
195
|
+
subAgentExecutions: subAgents,
|
|
196
|
+
key: `e${ei}-m${mi}-tc`,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (let ti = 0; ti < taskTools.length; ti++) {
|
|
201
|
+
const matched = subAgents.find((sa) => sa.id === taskTools[ti].id);
|
|
202
|
+
if (matched) {
|
|
203
|
+
items.push({
|
|
204
|
+
kind: "sub-agent",
|
|
205
|
+
subAgentExecution: matched,
|
|
206
|
+
key: `e${ei}-m${mi}-sa${ti}`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
185
210
|
}
|
|
186
211
|
}
|
|
187
212
|
}
|
|
@@ -349,6 +374,14 @@ export function MessageThread({
|
|
|
349
374
|
className="mx-4"
|
|
350
375
|
/>
|
|
351
376
|
);
|
|
377
|
+
case "sub-agent":
|
|
378
|
+
return (
|
|
379
|
+
<SubAgentSection
|
|
380
|
+
key={item.key}
|
|
381
|
+
subAgentExecution={item.subAgentExecution}
|
|
382
|
+
className="mx-4"
|
|
383
|
+
/>
|
|
384
|
+
);
|
|
352
385
|
case "phase-badge":
|
|
353
386
|
return (
|
|
354
387
|
<div key={item.key} className="flex justify-center py-3">
|