@townco/ui 0.1.114 → 0.1.116
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/core/hooks/use-chat-messages.d.ts +25 -0
- package/dist/core/hooks/use-subagent-stream.d.ts +28 -0
- package/dist/core/hooks/use-subagent-stream.js +256 -0
- package/dist/core/hooks/use-tool-calls.d.ts +50 -0
- package/dist/core/schemas/chat.d.ts +50 -2
- package/dist/core/schemas/tool-call.d.ts +91 -3
- package/dist/core/schemas/tool-call.js +22 -0
- package/dist/gui/components/ContextUsageButton.d.ts +16 -12
- package/dist/gui/components/ContextUsageButton.js +85 -45
- package/dist/gui/components/InvokingGroup.d.ts +9 -0
- package/dist/gui/components/InvokingGroup.js +16 -0
- package/dist/gui/components/SubagentStream.d.ts +23 -0
- package/dist/gui/components/SubagentStream.js +98 -0
- package/dist/gui/components/ToolCall.d.ts +8 -0
- package/dist/gui/components/ToolCall.js +234 -0
- package/dist/gui/components/ToolCallGroup.d.ts +8 -0
- package/dist/gui/components/ToolCallGroup.js +29 -0
- package/dist/gui/components/ToolOperation.js +29 -2
- package/dist/gui/components/Tooltip.js +3 -1
- package/dist/sdk/schemas/session.d.ts +50 -2
- package/package.json +3 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronDown, ListVideo } from "lucide-react";
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import { ToolCall } from "./ToolCall.js";
|
|
5
|
+
/**
|
|
6
|
+
* ToolCallGroup component - displays a group of parallel tool calls with collapsible details
|
|
7
|
+
*/
|
|
8
|
+
export function ToolCallGroup({ toolCalls }) {
|
|
9
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
10
|
+
// Calculate group status based on individual tool call statuses
|
|
11
|
+
const getGroupStatus = () => {
|
|
12
|
+
const statuses = toolCalls.map((tc) => tc.status);
|
|
13
|
+
if (statuses.some((s) => s === "failed"))
|
|
14
|
+
return "failed";
|
|
15
|
+
if (statuses.some((s) => s === "in_progress"))
|
|
16
|
+
return "in_progress";
|
|
17
|
+
if (statuses.every((s) => s === "completed"))
|
|
18
|
+
return "completed";
|
|
19
|
+
return "pending";
|
|
20
|
+
};
|
|
21
|
+
const groupStatus = getGroupStatus();
|
|
22
|
+
// Generate summary of tool names
|
|
23
|
+
const toolNames = toolCalls.map((tc) => tc.prettyName || tc.title);
|
|
24
|
+
const uniqueNames = [...new Set(toolNames)];
|
|
25
|
+
const summary = uniqueNames.length <= 2
|
|
26
|
+
? uniqueNames.join(", ")
|
|
27
|
+
: `${uniqueNames.slice(0, 2).join(", ")} +${uniqueNames.length - 2} more`;
|
|
28
|
+
return (_jsxs("div", { className: "flex flex-col my-4", children: [_jsxs("button", { type: "button", className: "flex flex-col items-start gap-0.5 cursor-pointer bg-transparent border-none p-0 text-left group w-fit", onClick: () => setIsExpanded(!isExpanded), "aria-expanded": isExpanded, children: [_jsxs("div", { className: "flex items-center gap-1.5 text-[11px] font-medium text-muted-foreground", children: [_jsx("div", { className: "text-muted-foreground", children: _jsx(ListVideo, { className: "h-3 w-3" }) }), _jsx("span", { className: "text-paragraph-sm text-muted-foreground", children: "Parallel operation" }), _jsx("span", { className: "text-[10px] bg-muted px-1.5 py-0.5 rounded text-muted-foreground/70", children: toolCalls.length }), _jsx(ChevronDown, { className: `h-3 w-3 text-muted-foreground/70 transition-transform duration-200 ${isExpanded ? "rotate-180" : ""}` })] }), !isExpanded && (_jsx("span", { className: "text-paragraph-sm text-muted-foreground/70 pl-4.5", children: summary }))] }), isExpanded && (_jsx("div", { className: "mt-1", children: toolCalls.map((toolCall) => (_jsxs("div", { className: "flex items-start", children: [_jsx("div", { className: "w-2.5 h-4 border-l-2 border-b-2 border-border rounded-bl-[6px] mt-1 mr-0.5 shrink-0" }), _jsx("div", { className: "flex-1 -mt-2", children: _jsx(ToolCall, { toolCall: toolCall }) })] }, toolCall.id))) }))] }));
|
|
29
|
+
}
|
|
@@ -5,6 +5,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|
|
5
5
|
import { getGroupDisplayState, getToolCallDisplayState, getToolCallStateVerbiage, isPreliminaryToolCall, } from "../../core/utils/tool-call-state.js";
|
|
6
6
|
import { generateSmartSummary } from "../../core/utils/tool-summary.js";
|
|
7
7
|
import * as ChatLayout from "./ChatLayout.js";
|
|
8
|
+
import { ContextUsageIndicator } from "./ContextUsageButton.js";
|
|
8
9
|
import { SubAgentDetails } from "./SubAgentDetails.js";
|
|
9
10
|
import { useTheme } from "./ThemeProvider.js";
|
|
10
11
|
import { TodoSubline } from "./TodoSubline.js";
|
|
@@ -141,6 +142,20 @@ export function ToolOperation({ toolCalls, isGrouped = false, autoMinimize = tru
|
|
|
141
142
|
// Detect subagent calls (subagents now run in-process, messages in subagentMessages)
|
|
142
143
|
const isSubagentCall = !!(singleToolCall?.subagentMessages &&
|
|
143
144
|
singleToolCall.subagentMessages.length > 0);
|
|
145
|
+
// Extract latest subagent context size (if provided by backend on subagent messages)
|
|
146
|
+
const subagentContextSize = React.useMemo(() => {
|
|
147
|
+
if (!singleToolCall?.subagentMessages)
|
|
148
|
+
return null;
|
|
149
|
+
const messages = singleToolCall.subagentMessages;
|
|
150
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
151
|
+
const msg = messages[i];
|
|
152
|
+
const cs = msg?._meta?.context_size ?? msg?.context_size;
|
|
153
|
+
if (cs != null)
|
|
154
|
+
return cs;
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}, [singleToolCall?.subagentMessages]);
|
|
158
|
+
const subagentHeaderContextSize = subagentContextSize;
|
|
144
159
|
// State for subagent expansion
|
|
145
160
|
const [isSubagentExpanded, setIsSubagentExpanded] = useState(false);
|
|
146
161
|
// Safely access ChatLayout context
|
|
@@ -253,7 +268,7 @@ export function ToolOperation({ toolCalls, isGrouped = false, autoMinimize = tru
|
|
|
253
268
|
return (_jsxs("div", { className: "flex flex-col my-4", children: [
|
|
254
269
|
_jsxs("button", { type: "button", className: "flex flex-col items-start gap-0.5 cursor-pointer bg-transparent border-none p-0 text-left group w-fit rounded-md px-1 -mx-1", onClick: handleHeaderClick, "aria-expanded": isTodoWrite ? undefined : isExpanded, children: [
|
|
255
270
|
_jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
256
|
-
_jsx("div", { className: "text-text-secondary/70 group-hover:text-text-secondary transition-colors", children: _jsx(IconComponent, { className: "h-3 w-3" }) }), _jsxs("span", { className: "text-paragraph-sm text-text-secondary/70 group-hover:text-text-secondary transition-colors", children: [isGrouped && _jsx("span", { className: "mr-1", children: "Parallel operation" }), !isGrouped && displayText] }), !isGrouped &&
|
|
271
|
+
_jsx("div", { className: "text-text-secondary/70 group-hover:text-text-secondary transition-colors", children: _jsx(IconComponent, { className: "h-3 w-3" }) }), _jsxs("span", { className: "text-paragraph-sm text-text-secondary/70 group-hover:text-text-secondary transition-colors", children: [isGrouped && _jsx("span", { className: "mr-1", children: "Parallel operation" }), !isGrouped && displayText] }), isSubagentCall && (_jsx(ContextUsageIndicator, { contextSize: subagentHeaderContextSize, size: 12, className: "text-text-secondary/70 group-hover:text-text-secondary transition-colors" })), !isGrouped &&
|
|
257
272
|
singleToolCall?.startedAt &&
|
|
258
273
|
displayState === "executing" && (_jsx(RunningDuration, { startTime: singleToolCall.startedAt, isRunning: !singleToolCall.subagentCompleted })), isGrouped &&
|
|
259
274
|
displayState === "executing" &&
|
|
@@ -333,6 +348,18 @@ function GroupedToolCallItem({ toolCall, hookNotification, }) {
|
|
|
333
348
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
334
349
|
// Detect subagent calls (subagents now run in-process, messages in subagentMessages)
|
|
335
350
|
const isSubagentCall = !!(toolCall.subagentMessages && toolCall.subagentMessages.length > 0);
|
|
351
|
+
// Extract latest subagent context size (if provided by backend on subagent messages)
|
|
352
|
+
const subagentContextSize = React.useMemo(() => {
|
|
353
|
+
const messages = toolCall.subagentMessages ?? [];
|
|
354
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
355
|
+
const msg = messages[i];
|
|
356
|
+
const cs = msg?._meta?.context_size ?? msg?.context_size;
|
|
357
|
+
if (cs != null)
|
|
358
|
+
return cs;
|
|
359
|
+
}
|
|
360
|
+
return null;
|
|
361
|
+
}, [toolCall.subagentMessages]);
|
|
362
|
+
const subagentHeaderContextSize = subagentContextSize;
|
|
336
363
|
// Detect compaction for this individual tool call
|
|
337
364
|
const hasCompaction = !!((hookNotification?.status === "completed" &&
|
|
338
365
|
hookNotification.metadata?.action &&
|
|
@@ -351,7 +378,7 @@ function GroupedToolCallItem({ toolCall, hookNotification, }) {
|
|
|
351
378
|
_jsxs("button", { type: "button", className: "flex items-center gap-1.5 cursor-pointer bg-transparent border-none p-0 text-left group w-fit", onClick: () => setIsExpanded(!isExpanded), "aria-expanded": isExpanded, children: [
|
|
352
379
|
_jsx("div", { className: "text-text-secondary/70 group-hover:text-text-secondary transition-colors", children: _jsx(CircleDot, { className: "h-3 w-3" }) }), _jsx("span", { className: "text-paragraph-sm text-text-secondary/70 group-hover:text-text-secondary transition-colors", children: toolCall.subagentMessages?.[0]?._meta?.semanticName ||
|
|
353
380
|
toolCall.rawInput?.agentName ||
|
|
354
|
-
"Subagent" }), toolCall.subagentMessages?.[0]?._meta?.semanticName && (_jsxs("span", { className: "text-muted-foreground text-[10px] ml-1", children: ["(", toolCall.rawInput?.agentName || "subagent", ")"] })), isRunning && toolCall.startedAt && (_jsx(RunningDuration, { startTime: toolCall.startedAt })), isFailed && (_jsx("span", { title: toolCall.error || "Operation failed", children: _jsx(AlertCircle, { className: "h-3 w-3 text-destructive" }) })), hasCompaction && (_jsx(TooltipProvider, { delayDuration: 0, children: _jsxs(Tooltip, { children: [
|
|
381
|
+
"Subagent" }), toolCall.subagentMessages?.[0]?._meta?.semanticName && (_jsxs("span", { className: "text-muted-foreground text-[10px] ml-1", children: ["(", toolCall.rawInput?.agentName || "subagent", ")"] })), _jsx(ContextUsageIndicator, { contextSize: subagentHeaderContextSize, size: 12, className: "text-text-secondary/70 group-hover:text-text-secondary transition-colors" }), isRunning && toolCall.startedAt && (_jsx(RunningDuration, { startTime: toolCall.startedAt })), isFailed && (_jsx("span", { title: toolCall.error || "Operation failed", children: _jsx(AlertCircle, { className: "h-3 w-3 text-destructive" }) })), hasCompaction && (_jsx(TooltipProvider, { delayDuration: 0, children: _jsxs(Tooltip, { children: [
|
|
355
382
|
_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: isTruncation ? (_jsx(ScissorsLineDashed, { className: "h-3 w-3 text-destructive" })) : (_jsx(FoldVertical, { className: "h-3 w-3 text-text-secondary/70" })) }) }), _jsx(TooltipContent, { children: (() => {
|
|
356
383
|
const meta = toolCall._meta;
|
|
357
384
|
const percentage = meta?.originalTokens && meta?.finalTokens
|
|
@@ -5,6 +5,8 @@ import { cn } from "../lib/utils.js";
|
|
|
5
5
|
const TooltipProvider = TooltipPrimitive.Provider;
|
|
6
6
|
const Tooltip = TooltipPrimitive.Root;
|
|
7
7
|
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
8
|
-
const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn(
|
|
8
|
+
const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn(
|
|
9
|
+
// High z-index so tooltips render above overlays/modals in the chat UI.
|
|
10
|
+
"z-[9999] overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props }) })));
|
|
9
11
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
10
12
|
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
|
@@ -348,12 +348,36 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
348
348
|
}, z.core.$strip>;
|
|
349
349
|
}, z.core.$strip>], "type">>>;
|
|
350
350
|
isStreaming: z.ZodOptional<z.ZodBoolean>;
|
|
351
|
+
context_size: z.ZodOptional<z.ZodObject<{
|
|
352
|
+
systemPromptTokens: z.ZodNumber;
|
|
353
|
+
toolOverheadTokens: z.ZodOptional<z.ZodNumber>;
|
|
354
|
+
mcpOverheadTokens: z.ZodOptional<z.ZodNumber>;
|
|
355
|
+
userMessagesTokens: z.ZodNumber;
|
|
356
|
+
assistantMessagesTokens: z.ZodNumber;
|
|
357
|
+
toolInputTokens: z.ZodNumber;
|
|
358
|
+
toolResultsTokens: z.ZodNumber;
|
|
359
|
+
totalEstimated: z.ZodNumber;
|
|
360
|
+
llmReportedInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
361
|
+
modelContextWindow: z.ZodOptional<z.ZodNumber>;
|
|
362
|
+
}, z.core.$strip>>;
|
|
351
363
|
_meta: z.ZodOptional<z.ZodObject<{
|
|
352
364
|
semanticName: z.ZodOptional<z.ZodString>;
|
|
353
365
|
agentDefinitionName: z.ZodOptional<z.ZodString>;
|
|
354
366
|
currentActivity: z.ZodOptional<z.ZodString>;
|
|
355
367
|
statusGenerating: z.ZodOptional<z.ZodBoolean>;
|
|
356
|
-
|
|
368
|
+
context_size: z.ZodOptional<z.ZodObject<{
|
|
369
|
+
systemPromptTokens: z.ZodNumber;
|
|
370
|
+
toolOverheadTokens: z.ZodOptional<z.ZodNumber>;
|
|
371
|
+
mcpOverheadTokens: z.ZodOptional<z.ZodNumber>;
|
|
372
|
+
userMessagesTokens: z.ZodNumber;
|
|
373
|
+
assistantMessagesTokens: z.ZodNumber;
|
|
374
|
+
toolInputTokens: z.ZodNumber;
|
|
375
|
+
toolResultsTokens: z.ZodNumber;
|
|
376
|
+
totalEstimated: z.ZodNumber;
|
|
377
|
+
llmReportedInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
378
|
+
modelContextWindow: z.ZodOptional<z.ZodNumber>;
|
|
379
|
+
}, z.core.$strip>>;
|
|
380
|
+
}, z.core.$loose>>;
|
|
357
381
|
}, z.core.$strip>>>;
|
|
358
382
|
subagentStreaming: z.ZodOptional<z.ZodBoolean>;
|
|
359
383
|
subagentCompleted: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -563,12 +587,36 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
563
587
|
}, z.core.$strip>;
|
|
564
588
|
}, z.core.$strip>], "type">>>;
|
|
565
589
|
isStreaming: z.ZodOptional<z.ZodBoolean>;
|
|
590
|
+
context_size: z.ZodOptional<z.ZodObject<{
|
|
591
|
+
systemPromptTokens: z.ZodNumber;
|
|
592
|
+
toolOverheadTokens: z.ZodOptional<z.ZodNumber>;
|
|
593
|
+
mcpOverheadTokens: z.ZodOptional<z.ZodNumber>;
|
|
594
|
+
userMessagesTokens: z.ZodNumber;
|
|
595
|
+
assistantMessagesTokens: z.ZodNumber;
|
|
596
|
+
toolInputTokens: z.ZodNumber;
|
|
597
|
+
toolResultsTokens: z.ZodNumber;
|
|
598
|
+
totalEstimated: z.ZodNumber;
|
|
599
|
+
llmReportedInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
600
|
+
modelContextWindow: z.ZodOptional<z.ZodNumber>;
|
|
601
|
+
}, z.core.$strip>>;
|
|
566
602
|
_meta: z.ZodOptional<z.ZodObject<{
|
|
567
603
|
semanticName: z.ZodOptional<z.ZodString>;
|
|
568
604
|
agentDefinitionName: z.ZodOptional<z.ZodString>;
|
|
569
605
|
currentActivity: z.ZodOptional<z.ZodString>;
|
|
570
606
|
statusGenerating: z.ZodOptional<z.ZodBoolean>;
|
|
571
|
-
|
|
607
|
+
context_size: z.ZodOptional<z.ZodObject<{
|
|
608
|
+
systemPromptTokens: z.ZodNumber;
|
|
609
|
+
toolOverheadTokens: z.ZodOptional<z.ZodNumber>;
|
|
610
|
+
mcpOverheadTokens: z.ZodOptional<z.ZodNumber>;
|
|
611
|
+
userMessagesTokens: z.ZodNumber;
|
|
612
|
+
assistantMessagesTokens: z.ZodNumber;
|
|
613
|
+
toolInputTokens: z.ZodNumber;
|
|
614
|
+
toolResultsTokens: z.ZodNumber;
|
|
615
|
+
totalEstimated: z.ZodNumber;
|
|
616
|
+
llmReportedInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
617
|
+
modelContextWindow: z.ZodOptional<z.ZodNumber>;
|
|
618
|
+
}, z.core.$strip>>;
|
|
619
|
+
}, z.core.$loose>>;
|
|
572
620
|
}, z.core.$strip>>>;
|
|
573
621
|
subagentCompleted: z.ZodOptional<z.ZodBoolean>;
|
|
574
622
|
_meta: z.ZodOptional<z.ZodObject<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@townco/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.116",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@radix-ui/react-slot": "^1.2.4",
|
|
50
50
|
"@radix-ui/react-tabs": "^1.1.13",
|
|
51
51
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
52
|
-
"@townco/core": "0.0.
|
|
52
|
+
"@townco/core": "0.0.94",
|
|
53
53
|
"@types/mdast": "^4.0.4",
|
|
54
54
|
"@uiw/react-json-view": "^2.0.0-alpha.39",
|
|
55
55
|
"class-variance-authority": "^0.7.1",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"zustand": "^5.0.8"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@townco/tsconfig": "0.1.
|
|
70
|
+
"@townco/tsconfig": "0.1.113",
|
|
71
71
|
"@types/node": "^24.10.0",
|
|
72
72
|
"@types/react": "^19.2.2",
|
|
73
73
|
"@types/unist": "^3.0.3",
|