@townco/ui 0.1.77 → 0.1.79
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 +6 -4
- package/dist/core/hooks/use-chat-messages.js +4 -1
- package/dist/core/hooks/use-chat-session.d.ts +1 -1
- package/dist/core/hooks/use-chat-session.js +5 -1
- package/dist/core/hooks/use-subagent-stream.js +6 -6
- package/dist/core/hooks/use-tool-calls.d.ts +5 -3
- package/dist/core/hooks/use-tool-calls.js +1 -1
- package/dist/core/schemas/chat.d.ts +14 -10
- package/dist/core/schemas/tool-call.d.ts +21 -8
- package/dist/core/schemas/tool-call.js +15 -0
- package/dist/core/store/chat-store.js +1 -0
- package/dist/core/utils/tool-summary.js +8 -3
- package/dist/core/utils/tool-verbiage.js +1 -1
- package/dist/gui/components/AppSidebar.d.ts +1 -1
- package/dist/gui/components/AppSidebar.js +4 -3
- package/dist/gui/components/ChatEmptyState.js +1 -1
- package/dist/gui/components/ChatHeader.d.ts +1 -28
- package/dist/gui/components/ChatHeader.js +4 -71
- package/dist/gui/components/ChatLayout.d.ts +6 -2
- package/dist/gui/components/ChatLayout.js +82 -33
- package/dist/gui/components/ChatView.js +28 -45
- package/dist/gui/components/ContextUsageButton.d.ts +0 -1
- package/dist/gui/components/ContextUsageButton.js +10 -3
- package/dist/gui/components/HookNotification.js +2 -1
- package/dist/gui/components/MessageContent.js +24 -160
- package/dist/gui/components/SessionHistory.js +1 -2
- package/dist/gui/components/SessionHistoryItem.js +1 -1
- package/dist/gui/components/Sidebar.js +27 -42
- package/dist/gui/components/SubAgentDetails.js +10 -14
- package/dist/gui/components/TodoSubline.js +1 -0
- package/dist/gui/components/ToolOperation.js +117 -81
- package/dist/gui/components/WorkProgress.js +5 -3
- package/dist/gui/components/index.d.ts +0 -1
- package/dist/gui/components/resizable.d.ts +1 -1
- package/dist/gui/constants.d.ts +6 -0
- package/dist/gui/constants.js +8 -0
- package/dist/gui/hooks/index.d.ts +1 -0
- package/dist/gui/hooks/index.js +1 -0
- package/dist/gui/hooks/use-lock-body-scroll.d.ts +7 -0
- package/dist/gui/hooks/use-lock-body-scroll.js +29 -0
- package/dist/gui/lib/motion.d.ts +12 -0
- package/dist/gui/lib/motion.js +69 -0
- package/dist/sdk/schemas/session.d.ts +37 -24
- package/dist/sdk/transports/http.d.ts +1 -1
- package/dist/sdk/transports/http.js +99 -1
- package/dist/sdk/transports/stdio.js +2 -2
- package/dist/sdk/transports/types.d.ts +11 -0
- package/dist/sdk/transports/types.js +28 -1
- package/package.json +3 -5
|
@@ -15,7 +15,7 @@ export declare function useChatMessages(client: AcpClient | null, startSession:
|
|
|
15
15
|
id: string;
|
|
16
16
|
title: string;
|
|
17
17
|
kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "switch_mode" | "other";
|
|
18
|
-
status: "
|
|
18
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
19
19
|
batchId?: string | undefined;
|
|
20
20
|
prettyName?: string | undefined;
|
|
21
21
|
icon?: string | undefined;
|
|
@@ -73,6 +73,8 @@ export declare function useChatMessages(client: AcpClient | null, startSession:
|
|
|
73
73
|
compactionAction?: "compacted" | "truncated" | undefined;
|
|
74
74
|
originalTokens?: number | undefined;
|
|
75
75
|
finalTokens?: number | undefined;
|
|
76
|
+
originalContentPreview?: string | undefined;
|
|
77
|
+
originalContentPath?: string | undefined;
|
|
76
78
|
} | undefined;
|
|
77
79
|
subagentPort?: number | undefined;
|
|
78
80
|
subagentSessionId?: string | undefined;
|
|
@@ -82,7 +84,7 @@ export declare function useChatMessages(client: AcpClient | null, startSession:
|
|
|
82
84
|
toolCalls?: {
|
|
83
85
|
id: string;
|
|
84
86
|
title: string;
|
|
85
|
-
status: "
|
|
87
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
86
88
|
prettyName?: string | undefined;
|
|
87
89
|
icon?: string | undefined;
|
|
88
90
|
content?: ({
|
|
@@ -122,7 +124,7 @@ export declare function useChatMessages(client: AcpClient | null, startSession:
|
|
|
122
124
|
toolCall: {
|
|
123
125
|
id: string;
|
|
124
126
|
title: string;
|
|
125
|
-
status: "
|
|
127
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
126
128
|
prettyName?: string | undefined;
|
|
127
129
|
icon?: string | undefined;
|
|
128
130
|
content?: ({
|
|
@@ -163,7 +165,7 @@ export declare function useChatMessages(client: AcpClient | null, startSession:
|
|
|
163
165
|
id: string;
|
|
164
166
|
hookType: "context_size" | "tool_response";
|
|
165
167
|
callback: string;
|
|
166
|
-
status: "
|
|
168
|
+
status: "completed" | "error" | "triggered";
|
|
167
169
|
threshold?: number | undefined;
|
|
168
170
|
currentPercentage?: number | undefined;
|
|
169
171
|
metadata?: {
|
|
@@ -103,8 +103,11 @@ export function useChatMessages(client, startSession) {
|
|
|
103
103
|
if (chunk.type === "content") {
|
|
104
104
|
// Content chunk - text streaming
|
|
105
105
|
// Update context size if provided (check both _meta.context_size and direct context_size)
|
|
106
|
+
// biome-ignore lint/suspicious/noExplicitAny: Accessing dynamic properties from streaming chunks
|
|
106
107
|
const chunkMeta = chunk._meta;
|
|
107
|
-
const contextSizeData =
|
|
108
|
+
const contextSizeData =
|
|
109
|
+
// biome-ignore lint/suspicious/noExplicitAny: Accessing dynamic properties from streaming chunks
|
|
110
|
+
chunkMeta?.context_size || chunk.context_size;
|
|
108
111
|
if (contextSizeData != null) {
|
|
109
112
|
const contextSize = contextSizeData;
|
|
110
113
|
logger.info("✅ Received context_size from backend", {
|
|
@@ -3,7 +3,7 @@ import type { AcpClient } from "../../sdk/client/index.js";
|
|
|
3
3
|
* Hook for managing chat session lifecycle
|
|
4
4
|
*/
|
|
5
5
|
export declare function useChatSession(client: AcpClient | null, initialSessionId?: string | null): {
|
|
6
|
-
connectionStatus: "error" | "
|
|
6
|
+
connectionStatus: "error" | "connecting" | "connected" | "disconnected";
|
|
7
7
|
sessionId: string | null;
|
|
8
8
|
connect: () => Promise<void>;
|
|
9
9
|
loadSession: (sessionIdToLoad: string) => Promise<void>;
|
|
@@ -21,8 +21,11 @@ export function useChatSession(client, initialSessionId) {
|
|
|
21
21
|
return;
|
|
22
22
|
const unsubscribe = client.onSessionUpdate((update) => {
|
|
23
23
|
// Extract context size from update metadata if available
|
|
24
|
+
// biome-ignore lint/suspicious/noExplicitAny: Accessing dynamic metadata properties from session updates
|
|
24
25
|
const updateMeta = update._meta;
|
|
25
|
-
const contextSizeData =
|
|
26
|
+
const contextSizeData =
|
|
27
|
+
// biome-ignore lint/suspicious/noExplicitAny: Accessing dynamic metadata properties from session updates
|
|
28
|
+
updateMeta?.context_size || update.context_size;
|
|
26
29
|
if (contextSizeData != null) {
|
|
27
30
|
const contextSize = contextSizeData;
|
|
28
31
|
logger.info("✅ Received context_size from session update", {
|
|
@@ -52,6 +55,7 @@ export function useChatSession(client, initialSessionId) {
|
|
|
52
55
|
const imageBlocks = [];
|
|
53
56
|
for (const c of update.message.content) {
|
|
54
57
|
if (c.type === "image") {
|
|
58
|
+
// biome-ignore lint/suspicious/noExplicitAny: Image blocks can have various formats (source object or direct properties)
|
|
55
59
|
const imgBlock = c;
|
|
56
60
|
// Handle both formats: direct data/mimeType or source object
|
|
57
61
|
if (imgBlock.source?.data) {
|
|
@@ -14,7 +14,7 @@ const logger = createLogger("subagent-stream");
|
|
|
14
14
|
export function useSubagentStream(options) {
|
|
15
15
|
const [messages, setMessages] = useState([]);
|
|
16
16
|
// Start as streaming=true if options provided, since we're about to connect
|
|
17
|
-
const [
|
|
17
|
+
const [_isStreaming, setIsStreaming] = useState(!!options);
|
|
18
18
|
const [hasCompleted, setHasCompleted] = useState(false);
|
|
19
19
|
const [error, setError] = useState(null);
|
|
20
20
|
const abortControllerRef = useRef(null);
|
|
@@ -221,12 +221,12 @@ export function useSubagentStream(options) {
|
|
|
221
221
|
logger.debug("Sub-agent stream completed");
|
|
222
222
|
}
|
|
223
223
|
}, [processSSEMessage]);
|
|
224
|
+
// Extract values from options (memoized to avoid dependency issues)
|
|
225
|
+
const port = options?.port;
|
|
226
|
+
const sessionId = options?.sessionId;
|
|
227
|
+
const host = options?.host ?? "localhost";
|
|
224
228
|
// Connect when options change
|
|
225
229
|
useEffect(() => {
|
|
226
|
-
if (!options) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
const { port, sessionId, host = "localhost" } = options;
|
|
230
230
|
if (!port || !sessionId) {
|
|
231
231
|
return;
|
|
232
232
|
}
|
|
@@ -247,7 +247,7 @@ export function useSubagentStream(options) {
|
|
|
247
247
|
updateTimeoutRef.current = null;
|
|
248
248
|
}
|
|
249
249
|
};
|
|
250
|
-
}, [
|
|
250
|
+
}, [port, sessionId, host, connectToSubagent]);
|
|
251
251
|
// Derive streaming status: streaming if we haven't completed yet
|
|
252
252
|
const effectiveIsStreaming = !hasCompleted;
|
|
253
253
|
return { messages, isStreaming: effectiveIsStreaming, error };
|
|
@@ -13,7 +13,7 @@ export declare function useToolCalls(client: AcpClient | null): {
|
|
|
13
13
|
id: string;
|
|
14
14
|
title: string;
|
|
15
15
|
kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "switch_mode" | "other";
|
|
16
|
-
status: "
|
|
16
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
17
17
|
batchId?: string | undefined;
|
|
18
18
|
prettyName?: string | undefined;
|
|
19
19
|
icon?: string | undefined;
|
|
@@ -71,6 +71,8 @@ export declare function useToolCalls(client: AcpClient | null): {
|
|
|
71
71
|
compactionAction?: "compacted" | "truncated" | undefined;
|
|
72
72
|
originalTokens?: number | undefined;
|
|
73
73
|
finalTokens?: number | undefined;
|
|
74
|
+
originalContentPreview?: string | undefined;
|
|
75
|
+
originalContentPath?: string | undefined;
|
|
74
76
|
} | undefined;
|
|
75
77
|
subagentPort?: number | undefined;
|
|
76
78
|
subagentSessionId?: string | undefined;
|
|
@@ -80,7 +82,7 @@ export declare function useToolCalls(client: AcpClient | null): {
|
|
|
80
82
|
toolCalls?: {
|
|
81
83
|
id: string;
|
|
82
84
|
title: string;
|
|
83
|
-
status: "
|
|
85
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
84
86
|
prettyName?: string | undefined;
|
|
85
87
|
icon?: string | undefined;
|
|
86
88
|
content?: ({
|
|
@@ -120,7 +122,7 @@ export declare function useToolCalls(client: AcpClient | null): {
|
|
|
120
122
|
toolCall: {
|
|
121
123
|
id: string;
|
|
122
124
|
title: string;
|
|
123
|
-
status: "
|
|
125
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
124
126
|
prettyName?: string | undefined;
|
|
125
127
|
icon?: string | undefined;
|
|
126
128
|
content?: ({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "@townco/core";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import { useChatStore } from "../store/chat-store.js";
|
|
4
|
-
const
|
|
4
|
+
const _logger = createLogger("use-tool-calls", "debug");
|
|
5
5
|
/**
|
|
6
6
|
* Hook to track and manage tool calls from ACP sessions
|
|
7
7
|
*
|
|
@@ -22,9 +22,9 @@ export declare const HookNotificationDisplay: z.ZodObject<{
|
|
|
22
22
|
}>;
|
|
23
23
|
callback: z.ZodString;
|
|
24
24
|
status: z.ZodEnum<{
|
|
25
|
+
completed: "completed";
|
|
25
26
|
error: "error";
|
|
26
27
|
triggered: "triggered";
|
|
27
|
-
completed: "completed";
|
|
28
28
|
}>;
|
|
29
29
|
threshold: z.ZodOptional<z.ZodNumber>;
|
|
30
30
|
currentPercentage: z.ZodOptional<z.ZodNumber>;
|
|
@@ -86,9 +86,9 @@ export declare const DisplayMessage: z.ZodObject<{
|
|
|
86
86
|
other: "other";
|
|
87
87
|
}>;
|
|
88
88
|
status: z.ZodEnum<{
|
|
89
|
-
completed: "completed";
|
|
90
89
|
pending: "pending";
|
|
91
90
|
in_progress: "in_progress";
|
|
91
|
+
completed: "completed";
|
|
92
92
|
failed: "failed";
|
|
93
93
|
}>;
|
|
94
94
|
contentPosition: z.ZodOptional<z.ZodNumber>;
|
|
@@ -142,6 +142,8 @@ export declare const DisplayMessage: z.ZodObject<{
|
|
|
142
142
|
}>>;
|
|
143
143
|
originalTokens: z.ZodOptional<z.ZodNumber>;
|
|
144
144
|
finalTokens: z.ZodOptional<z.ZodNumber>;
|
|
145
|
+
originalContentPreview: z.ZodOptional<z.ZodString>;
|
|
146
|
+
originalContentPath: z.ZodOptional<z.ZodString>;
|
|
145
147
|
}, z.core.$strip>>;
|
|
146
148
|
subagentPort: z.ZodOptional<z.ZodNumber>;
|
|
147
149
|
subagentSessionId: z.ZodOptional<z.ZodString>;
|
|
@@ -154,9 +156,9 @@ export declare const DisplayMessage: z.ZodObject<{
|
|
|
154
156
|
prettyName: z.ZodOptional<z.ZodString>;
|
|
155
157
|
icon: z.ZodOptional<z.ZodString>;
|
|
156
158
|
status: z.ZodEnum<{
|
|
157
|
-
completed: "completed";
|
|
158
159
|
pending: "pending";
|
|
159
160
|
in_progress: "in_progress";
|
|
161
|
+
completed: "completed";
|
|
160
162
|
failed: "failed";
|
|
161
163
|
}>;
|
|
162
164
|
content: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -199,9 +201,9 @@ export declare const DisplayMessage: z.ZodObject<{
|
|
|
199
201
|
prettyName: z.ZodOptional<z.ZodString>;
|
|
200
202
|
icon: z.ZodOptional<z.ZodString>;
|
|
201
203
|
status: z.ZodEnum<{
|
|
202
|
-
completed: "completed";
|
|
203
204
|
pending: "pending";
|
|
204
205
|
in_progress: "in_progress";
|
|
206
|
+
completed: "completed";
|
|
205
207
|
failed: "failed";
|
|
206
208
|
}>;
|
|
207
209
|
content: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -246,9 +248,9 @@ export declare const DisplayMessage: z.ZodObject<{
|
|
|
246
248
|
}>;
|
|
247
249
|
callback: z.ZodString;
|
|
248
250
|
status: z.ZodEnum<{
|
|
251
|
+
completed: "completed";
|
|
249
252
|
error: "error";
|
|
250
253
|
triggered: "triggered";
|
|
251
|
-
completed: "completed";
|
|
252
254
|
}>;
|
|
253
255
|
threshold: z.ZodOptional<z.ZodNumber>;
|
|
254
256
|
currentPercentage: z.ZodOptional<z.ZodNumber>;
|
|
@@ -338,9 +340,9 @@ export declare const ChatSessionState: z.ZodObject<{
|
|
|
338
340
|
other: "other";
|
|
339
341
|
}>;
|
|
340
342
|
status: z.ZodEnum<{
|
|
341
|
-
completed: "completed";
|
|
342
343
|
pending: "pending";
|
|
343
344
|
in_progress: "in_progress";
|
|
345
|
+
completed: "completed";
|
|
344
346
|
failed: "failed";
|
|
345
347
|
}>;
|
|
346
348
|
contentPosition: z.ZodOptional<z.ZodNumber>;
|
|
@@ -394,6 +396,8 @@ export declare const ChatSessionState: z.ZodObject<{
|
|
|
394
396
|
}>>;
|
|
395
397
|
originalTokens: z.ZodOptional<z.ZodNumber>;
|
|
396
398
|
finalTokens: z.ZodOptional<z.ZodNumber>;
|
|
399
|
+
originalContentPreview: z.ZodOptional<z.ZodString>;
|
|
400
|
+
originalContentPath: z.ZodOptional<z.ZodString>;
|
|
397
401
|
}, z.core.$strip>>;
|
|
398
402
|
subagentPort: z.ZodOptional<z.ZodNumber>;
|
|
399
403
|
subagentSessionId: z.ZodOptional<z.ZodString>;
|
|
@@ -406,9 +410,9 @@ export declare const ChatSessionState: z.ZodObject<{
|
|
|
406
410
|
prettyName: z.ZodOptional<z.ZodString>;
|
|
407
411
|
icon: z.ZodOptional<z.ZodString>;
|
|
408
412
|
status: z.ZodEnum<{
|
|
409
|
-
completed: "completed";
|
|
410
413
|
pending: "pending";
|
|
411
414
|
in_progress: "in_progress";
|
|
415
|
+
completed: "completed";
|
|
412
416
|
failed: "failed";
|
|
413
417
|
}>;
|
|
414
418
|
content: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -451,9 +455,9 @@ export declare const ChatSessionState: z.ZodObject<{
|
|
|
451
455
|
prettyName: z.ZodOptional<z.ZodString>;
|
|
452
456
|
icon: z.ZodOptional<z.ZodString>;
|
|
453
457
|
status: z.ZodEnum<{
|
|
454
|
-
completed: "completed";
|
|
455
458
|
pending: "pending";
|
|
456
459
|
in_progress: "in_progress";
|
|
460
|
+
completed: "completed";
|
|
457
461
|
failed: "failed";
|
|
458
462
|
}>;
|
|
459
463
|
content: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -498,9 +502,9 @@ export declare const ChatSessionState: z.ZodObject<{
|
|
|
498
502
|
}>;
|
|
499
503
|
callback: z.ZodString;
|
|
500
504
|
status: z.ZodEnum<{
|
|
505
|
+
completed: "completed";
|
|
501
506
|
error: "error";
|
|
502
507
|
triggered: "triggered";
|
|
503
|
-
completed: "completed";
|
|
504
508
|
}>;
|
|
505
509
|
threshold: z.ZodOptional<z.ZodNumber>;
|
|
506
510
|
currentPercentage: z.ZodOptional<z.ZodNumber>;
|
|
@@ -549,8 +553,8 @@ export type ChatSessionState = z.infer<typeof ChatSessionState>;
|
|
|
549
553
|
*/
|
|
550
554
|
export declare const ConnectionStatus: z.ZodEnum<{
|
|
551
555
|
error: "error";
|
|
552
|
-
disconnected: "disconnected";
|
|
553
556
|
connecting: "connecting";
|
|
554
557
|
connected: "connected";
|
|
558
|
+
disconnected: "disconnected";
|
|
555
559
|
}>;
|
|
556
560
|
export type ConnectionStatus = z.infer<typeof ConnectionStatus>;
|
|
@@ -13,16 +13,16 @@ export type ToolCallStatus = z.infer<typeof ToolCallStatusSchema>;
|
|
|
13
13
|
* Tool call categories for UI presentation
|
|
14
14
|
*/
|
|
15
15
|
export declare const ToolCallKindSchema: z.ZodEnum<{
|
|
16
|
-
search: "search";
|
|
17
|
-
execute: "execute";
|
|
18
|
-
move: "move";
|
|
19
|
-
other: "other";
|
|
20
16
|
read: "read";
|
|
21
17
|
edit: "edit";
|
|
22
18
|
delete: "delete";
|
|
19
|
+
move: "move";
|
|
20
|
+
search: "search";
|
|
21
|
+
execute: "execute";
|
|
23
22
|
think: "think";
|
|
24
23
|
fetch: "fetch";
|
|
25
24
|
switch_mode: "switch_mode";
|
|
25
|
+
other: "other";
|
|
26
26
|
}>;
|
|
27
27
|
export type ToolCallKind = z.infer<typeof ToolCallKindSchema>;
|
|
28
28
|
/**
|
|
@@ -280,16 +280,16 @@ export declare const ToolCallSchema: z.ZodObject<{
|
|
|
280
280
|
}, z.core.$strip>>;
|
|
281
281
|
subline: z.ZodOptional<z.ZodString>;
|
|
282
282
|
kind: z.ZodEnum<{
|
|
283
|
-
search: "search";
|
|
284
|
-
execute: "execute";
|
|
285
|
-
move: "move";
|
|
286
|
-
other: "other";
|
|
287
283
|
read: "read";
|
|
288
284
|
edit: "edit";
|
|
289
285
|
delete: "delete";
|
|
286
|
+
move: "move";
|
|
287
|
+
search: "search";
|
|
288
|
+
execute: "execute";
|
|
290
289
|
think: "think";
|
|
291
290
|
fetch: "fetch";
|
|
292
291
|
switch_mode: "switch_mode";
|
|
292
|
+
other: "other";
|
|
293
293
|
}>;
|
|
294
294
|
status: z.ZodEnum<{
|
|
295
295
|
pending: "pending";
|
|
@@ -348,6 +348,8 @@ export declare const ToolCallSchema: z.ZodObject<{
|
|
|
348
348
|
}>>;
|
|
349
349
|
originalTokens: z.ZodOptional<z.ZodNumber>;
|
|
350
350
|
finalTokens: z.ZodOptional<z.ZodNumber>;
|
|
351
|
+
originalContentPreview: z.ZodOptional<z.ZodString>;
|
|
352
|
+
originalContentPath: z.ZodOptional<z.ZodString>;
|
|
351
353
|
}, z.core.$strip>>;
|
|
352
354
|
subagentPort: z.ZodOptional<z.ZodNumber>;
|
|
353
355
|
subagentSessionId: z.ZodOptional<z.ZodString>;
|
|
@@ -594,6 +596,17 @@ export declare const ToolCallUpdateSchema: z.ZodObject<{
|
|
|
594
596
|
}, z.core.$strip>], "type">>>;
|
|
595
597
|
isStreaming: z.ZodOptional<z.ZodBoolean>;
|
|
596
598
|
}, z.core.$strip>>>;
|
|
599
|
+
_meta: z.ZodOptional<z.ZodObject<{
|
|
600
|
+
truncationWarning: z.ZodOptional<z.ZodString>;
|
|
601
|
+
compactionAction: z.ZodOptional<z.ZodEnum<{
|
|
602
|
+
compacted: "compacted";
|
|
603
|
+
truncated: "truncated";
|
|
604
|
+
}>>;
|
|
605
|
+
originalTokens: z.ZodOptional<z.ZodNumber>;
|
|
606
|
+
finalTokens: z.ZodOptional<z.ZodNumber>;
|
|
607
|
+
originalContentPreview: z.ZodOptional<z.ZodString>;
|
|
608
|
+
originalContentPath: z.ZodOptional<z.ZodString>;
|
|
609
|
+
}, z.core.$strip>>;
|
|
597
610
|
}, z.core.$strip>;
|
|
598
611
|
export type ToolCallUpdate = z.infer<typeof ToolCallUpdateSchema>;
|
|
599
612
|
/**
|
|
@@ -171,6 +171,8 @@ export const ToolCallSchema = z.object({
|
|
|
171
171
|
compactionAction: z.enum(["compacted", "truncated"]).optional(),
|
|
172
172
|
originalTokens: z.number().optional(),
|
|
173
173
|
finalTokens: z.number().optional(),
|
|
174
|
+
originalContentPreview: z.string().optional(),
|
|
175
|
+
originalContentPath: z.string().optional(),
|
|
174
176
|
})
|
|
175
177
|
.optional(),
|
|
176
178
|
/** Sub-agent HTTP port for direct SSE connection (Task tool only) */
|
|
@@ -205,6 +207,17 @@ export const ToolCallUpdateSchema = z.object({
|
|
|
205
207
|
subagentSessionId: z.string().optional(),
|
|
206
208
|
/** Sub-agent messages for replay */
|
|
207
209
|
subagentMessages: z.array(SubagentMessageSchema).optional(),
|
|
210
|
+
/** Internal metadata (e.g., compaction info) */
|
|
211
|
+
_meta: z
|
|
212
|
+
.object({
|
|
213
|
+
truncationWarning: z.string().optional(),
|
|
214
|
+
compactionAction: z.enum(["compacted", "truncated"]).optional(),
|
|
215
|
+
originalTokens: z.number().optional(),
|
|
216
|
+
finalTokens: z.number().optional(),
|
|
217
|
+
originalContentPreview: z.string().optional(),
|
|
218
|
+
originalContentPath: z.string().optional(),
|
|
219
|
+
})
|
|
220
|
+
.optional(),
|
|
208
221
|
});
|
|
209
222
|
/**
|
|
210
223
|
* Helper to merge a tool call update into an existing tool call
|
|
@@ -232,6 +245,8 @@ export function mergeToolCallUpdate(existing, update) {
|
|
|
232
245
|
subagentSessionId: update.subagentSessionId ?? existing.subagentSessionId,
|
|
233
246
|
// Sub-agent messages for replay
|
|
234
247
|
subagentMessages: update.subagentMessages ?? existing.subagentMessages,
|
|
248
|
+
// Internal metadata (compaction info)
|
|
249
|
+
_meta: update._meta ?? existing._meta,
|
|
235
250
|
};
|
|
236
251
|
return merged;
|
|
237
252
|
}
|
|
@@ -359,6 +359,7 @@ export const useChatStore = create((set) => ({
|
|
|
359
359
|
if (existingIndex !== -1) {
|
|
360
360
|
// Merge: preserve triggered data (threshold, currentPercentage, triggeredAt),
|
|
361
361
|
// overlay completion data
|
|
362
|
+
// biome-ignore lint/style/noNonNullAssertion: existingIndex !== -1 ensures element exists
|
|
362
363
|
const existing = existingNotifications[existingIndex];
|
|
363
364
|
updatedNotifications = [...existingNotifications];
|
|
364
365
|
// Use backend timestamp if available, fallback to Date.now()
|
|
@@ -33,14 +33,15 @@ function extractKeyParameter(toolCall) {
|
|
|
33
33
|
function formatItemList(items, maxItems = 3) {
|
|
34
34
|
if (items.length === 0)
|
|
35
35
|
return "";
|
|
36
|
+
// biome-ignore lint/style/noNonNullAssertion: Length check ensures element exists
|
|
36
37
|
if (items.length === 1)
|
|
37
38
|
return items[0];
|
|
38
39
|
if (items.length <= maxItems) {
|
|
39
|
-
return items.slice(0, -1).join(", ")
|
|
40
|
+
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
40
41
|
}
|
|
41
42
|
const shown = items.slice(0, maxItems);
|
|
42
43
|
const remaining = items.length - maxItems;
|
|
43
|
-
return shown.join(", ")
|
|
44
|
+
return `${shown.join(", ")} and ${remaining} more`;
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
46
47
|
* Detect common patterns in file paths
|
|
@@ -49,13 +50,14 @@ function detectFilePattern(paths) {
|
|
|
49
50
|
if (paths.length === 0)
|
|
50
51
|
return null;
|
|
51
52
|
// Extract directory from first path
|
|
53
|
+
// biome-ignore lint/style/noNonNullAssertion: Length check ensures element exists
|
|
52
54
|
const firstPath = paths[0];
|
|
53
55
|
const lastSlash = firstPath.lastIndexOf("/");
|
|
54
56
|
if (lastSlash === -1)
|
|
55
57
|
return null;
|
|
56
58
|
const directory = firstPath.substring(0, lastSlash);
|
|
57
59
|
// Check if all paths are in the same directory
|
|
58
|
-
const allInSameDir = paths.every((p) => p.startsWith(directory
|
|
60
|
+
const allInSameDir = paths.every((p) => p.startsWith(`${directory}/`));
|
|
59
61
|
if (allInSameDir) {
|
|
60
62
|
return directory;
|
|
61
63
|
}
|
|
@@ -68,8 +70,10 @@ function generateSameToolSummary(toolCalls, tense) {
|
|
|
68
70
|
if (toolCalls.length === 0)
|
|
69
71
|
return "";
|
|
70
72
|
if (toolCalls.length === 1) {
|
|
73
|
+
// biome-ignore lint/style/noNonNullAssertion: Length check ensures element exists
|
|
71
74
|
return getToolCallVerbiage(toolCalls[0], tense);
|
|
72
75
|
}
|
|
76
|
+
// biome-ignore lint/style/noNonNullAssertion: Length check ensures element exists
|
|
73
77
|
const firstTool = toolCalls[0];
|
|
74
78
|
const toolName = firstTool.title;
|
|
75
79
|
// Extract parameters from all tool calls
|
|
@@ -144,6 +148,7 @@ export function generateSmartSummary(toolCalls, tense) {
|
|
|
144
148
|
if (toolCalls.length === 0)
|
|
145
149
|
return "";
|
|
146
150
|
if (toolCalls.length === 1) {
|
|
151
|
+
// biome-ignore lint/style/noNonNullAssertion: Length check ensures element exists
|
|
147
152
|
return getToolCallVerbiage(toolCalls[0], tense);
|
|
148
153
|
}
|
|
149
154
|
// Check if all tool calls are of the same type
|
|
@@ -128,7 +128,7 @@ function formatVerbiage(template, params) {
|
|
|
128
128
|
function truncate(text, maxLength) {
|
|
129
129
|
if (text.length <= maxLength)
|
|
130
130
|
return text;
|
|
131
|
-
return text.substring(0, maxLength - 1)
|
|
131
|
+
return `${text.substring(0, maxLength - 1)}…`;
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
134
|
* Get display verbiage for a tool call
|
|
@@ -19,4 +19,4 @@ export interface AppSidebarProps {
|
|
|
19
19
|
/** Additional className for the sidebar */
|
|
20
20
|
className?: string;
|
|
21
21
|
}
|
|
22
|
-
export declare function AppSidebar({ client, currentSessionId, onSessionSelect, onNewSession, onRenameSession, onArchiveSession, onDeleteSession,
|
|
22
|
+
export declare function AppSidebar({ client, currentSessionId, onSessionSelect, onNewSession, onRenameSession, onArchiveSession, onDeleteSession, className, }: AppSidebarProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Plus } from "lucide-react";
|
|
2
|
+
import { Plus, Settings } from "lucide-react";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
4
|
import { IconButton } from "./IconButton.js";
|
|
5
5
|
import { SessionHistory } from "./SessionHistory.js";
|
|
6
6
|
import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, useSidebar, } from "./Sidebar.js";
|
|
7
|
-
|
|
7
|
+
import { ThemeToggle } from "./ThemeToggle.js";
|
|
8
|
+
export function AppSidebar({ client, currentSessionId, onSessionSelect, onNewSession, onRenameSession, onArchiveSession, onDeleteSession, className, }) {
|
|
8
9
|
const { setOpenMobile } = useSidebar();
|
|
9
10
|
const handleNewSession = () => {
|
|
10
11
|
if (onNewSession) {
|
|
@@ -18,5 +19,5 @@ export function AppSidebar({ client, currentSessionId, onSessionSelect, onNewSes
|
|
|
18
19
|
}
|
|
19
20
|
setOpenMobile(false);
|
|
20
21
|
};
|
|
21
|
-
return (_jsxs(Sidebar, { className: cn("group-data-[side=left]:border-r-0", className), children: [_jsx(SidebarHeader, { className: "h-16 py-5
|
|
22
|
+
return (_jsxs(Sidebar, { className: cn("group-data-[side=left]:border-r-0", className), children: [_jsx(SidebarHeader, { className: "h-16 py-5 px-4 justify-center gap-0", children: _jsxs("div", { className: "flex flex-row items-center justify-between w-full pl-2", children: [_jsx("span", { className: "font-semibold text-xl tracking-tight", children: "Sessions" }), _jsx(IconButton, { onClick: handleNewSession, "aria-label": "New Chat", variant: "default", children: _jsx(Plus, { className: "size-4" }) })] }) }), _jsx(SidebarContent, { className: "gap-6", children: _jsx(SessionHistory, { client: client, currentSessionId: currentSessionId, onSessionSelect: onSessionSelect, onRenameSession: onRenameSession, onArchiveSession: onArchiveSession, onDeleteSession: onDeleteSession }) }), _jsx(SidebarFooter, { className: "p-0", children: _jsxs("div", { className: "border-t border-border pl-6 pr-4 py-5 flex justify-end gap-2", children: [_jsx(ThemeToggle, {}), _jsx(IconButton, { "aria-label": "Settings", children: _jsx(Settings, { className: "size-4 text-muted-foreground" }) })] }) })] }));
|
|
22
23
|
}
|
|
@@ -17,6 +17,6 @@ export const ChatEmptyState = React.forwardRef(({ title, titleElement, descripti
|
|
|
17
17
|
for (let i = 0; i < suggestedPrompts.length; i += 2) {
|
|
18
18
|
promptRows.push(suggestedPrompts.slice(i, i + 2));
|
|
19
19
|
}
|
|
20
|
-
return (_jsxs("div", { ref: ref, className: cn("flex flex-col items-start", className), ...props, children: [titleElement ? (_jsx("div", { className: "text-heading-4 text-text-primary mb-6", children: titleElement })) : (_jsx("h3", { className: "text-heading-4 text-text-primary mb-6", children: title })), _jsx("p", { className: "text-subheading text-text-secondary max-w-prose mb-6", children: description }), (onOpenFiles || onOpenSettings) && (_jsxs("div", { className: "flex items-center gap-1 -ml-3 mb-6", children: [onOpenFiles && (_jsxs("button", { type: "button", onClick: onOpenFiles, className: "inline-flex items-center gap-1 py-1.5 pr-3 pl-3 rounded-lg hover:bg-accent transition-colors", children: [_jsx("span", { className: "text-paragraph-sm-medium text-foreground tracking-wide leading-none", children: "View Files" }), _jsx(ChevronRight, { className: "size-4 text-foreground shrink-0" })] })), onOpenSettings && (_jsxs("button", { type: "button", onClick: onOpenSettings, className: "inline-flex items-center gap-1 py-1.5 pr-3 pl-3 rounded-lg hover:bg-accent transition-colors", children: [_jsxs("span", { className: "text-paragraph-sm-medium text-foreground tracking-wide leading-none", children: ["View Tools & MCPs", toolsAndMcpsCount !== undefined && toolsAndMcpsCount > 0 && (_jsxs("span", { className: "ml-1", children: ["(", toolsAndMcpsCount, ")"] }))] }), _jsx(ChevronRight, { className: "size-4 text-foreground shrink-0" })] }))] })), (guideUrl || onGuideClick) && (_jsxs("button", { type: "button", onClick: handleGuideClick, className: "inline-flex items-center gap-1 py-1.5 pr-3 -ml-3 pl-3 rounded-lg hover:bg-accent transition-colors", children: [_jsx("span", { className: "text-paragraph-sm-medium text-foreground tracking-wide leading-none", children: guideText }), _jsx(ChevronRight, { className: "size-4 text-foreground shrink-0" })] })), suggestedPrompts.length > 0 && (_jsxs("div", { className: "flex flex-col gap-3 w-full max-w-prompt-container", children: [_jsx("p", { className: "text-
|
|
20
|
+
return (_jsxs("div", { ref: ref, className: cn("flex flex-col items-start", className), ...props, children: [titleElement ? (_jsx("div", { className: "text-heading-4 text-text-primary mb-6", children: titleElement })) : (_jsx("h3", { className: "text-heading-4 text-text-primary mb-6", children: title })), _jsx("p", { className: "text-subheading text-text-secondary max-w-prose mb-6", children: description }), (onOpenFiles || onOpenSettings) && (_jsxs("div", { className: "flex items-center gap-1 -ml-3 mb-6", children: [onOpenFiles && (_jsxs("button", { type: "button", onClick: onOpenFiles, className: "inline-flex items-center gap-1 py-1.5 pr-3 pl-3 rounded-lg hover:bg-accent transition-colors", children: [_jsx("span", { className: "text-paragraph-sm-medium text-foreground tracking-wide leading-none", children: "View Files" }), _jsx(ChevronRight, { className: "size-4 text-foreground shrink-0" })] })), onOpenSettings && (_jsxs("button", { type: "button", onClick: onOpenSettings, className: "inline-flex items-center gap-1 py-1.5 pr-3 pl-3 rounded-lg hover:bg-accent transition-colors", children: [_jsxs("span", { className: "text-paragraph-sm-medium text-foreground tracking-wide leading-none", children: ["View Tools & MCPs", toolsAndMcpsCount !== undefined && toolsAndMcpsCount > 0 && (_jsxs("span", { className: "ml-1", children: ["(", toolsAndMcpsCount, ")"] }))] }), _jsx(ChevronRight, { className: "size-4 text-foreground shrink-0" })] }))] })), (guideUrl || onGuideClick) && (_jsxs("button", { type: "button", onClick: handleGuideClick, className: "inline-flex items-center gap-1 py-1.5 pr-3 -ml-3 pl-3 rounded-lg hover:bg-accent transition-colors", children: [_jsx("span", { className: "text-paragraph-sm-medium text-foreground tracking-wide leading-none", children: guideText }), _jsx(ChevronRight, { className: "size-4 text-foreground shrink-0" })] })), suggestedPrompts.length > 0 && (_jsxs("div", { className: "flex flex-col gap-3 w-full max-w-prompt-container", children: [_jsx("p", { className: "text-text-tertiary", children: "Suggested Prompts" }), _jsx("div", { className: "flex flex-col gap-2.5", children: promptRows.map((row) => (_jsx("div", { className: "flex gap-2.5 items-center", children: row.map((prompt) => (_jsx("button", { type: "button", onClick: () => handlePromptClick(prompt), onMouseEnter: () => onPromptHover?.(prompt), onMouseLeave: () => onPromptLeave?.(), className: "flex-1 flex items-start gap-2 p-3 bg-secondary hover:bg-secondary/80 rounded-2xl transition-colors min-w-0", children: _jsx("span", { className: "text-paragraph font-normal leading-normal text-text-tertiary truncate", children: prompt }) }, prompt))) }, row.join("-")))) })] }))] }));
|
|
21
21
|
});
|
|
22
22
|
ChatEmptyState.displayName = "ChatEmptyState";
|
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
interface ChatHeaderContextValue {
|
|
3
|
-
isExpanded: boolean;
|
|
4
|
-
setIsExpanded: (expanded: boolean) => void;
|
|
5
|
-
}
|
|
6
|
-
declare const useChatHeaderContext: () => ChatHeaderContextValue;
|
|
7
2
|
export interface ChatHeaderRootProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
8
|
-
/** Initial expanded state */
|
|
9
|
-
defaultExpanded?: boolean;
|
|
10
|
-
/** Controlled expanded state */
|
|
11
|
-
expanded?: boolean;
|
|
12
|
-
/** Callback when expanded state changes */
|
|
13
|
-
onExpandedChange?: (expanded: boolean) => void;
|
|
14
3
|
}
|
|
15
4
|
declare const ChatHeaderRoot: React.ForwardRefExoticComponent<ChatHeaderRootProps & React.RefAttributes<HTMLDivElement>>;
|
|
16
5
|
export interface ChatHeaderTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
|
|
@@ -19,20 +8,4 @@ declare const ChatHeaderTitle: React.ForwardRefExoticComponent<ChatHeaderTitlePr
|
|
|
19
8
|
export interface ChatHeaderActionsProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
20
9
|
}
|
|
21
10
|
declare const ChatHeaderActions: React.ForwardRefExoticComponent<ChatHeaderActionsProps & React.RefAttributes<HTMLDivElement>>;
|
|
22
|
-
export
|
|
23
|
-
export interface ChatHeaderStatusIndicatorProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
24
|
-
/** Connection status */
|
|
25
|
-
status: ConnectionStatus;
|
|
26
|
-
/** Optional status text override */
|
|
27
|
-
statusText?: string;
|
|
28
|
-
}
|
|
29
|
-
declare const ChatHeaderStatusIndicator: React.ForwardRefExoticComponent<ChatHeaderStatusIndicatorProps & React.RefAttributes<HTMLDivElement>>;
|
|
30
|
-
export interface ChatHeaderToggleProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
31
|
-
/** Icon to display (should rotate based on expanded state) */
|
|
32
|
-
icon?: React.ReactNode;
|
|
33
|
-
}
|
|
34
|
-
declare const ChatHeaderToggle: React.ForwardRefExoticComponent<ChatHeaderToggleProps & React.RefAttributes<HTMLButtonElement>>;
|
|
35
|
-
export interface ChatHeaderExpandablePanelProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
36
|
-
}
|
|
37
|
-
declare const ChatHeaderExpandablePanel: React.ForwardRefExoticComponent<ChatHeaderExpandablePanelProps & React.RefAttributes<HTMLDivElement>>;
|
|
38
|
-
export { ChatHeaderRoot as Root, ChatHeaderTitle as Title, ChatHeaderActions as Actions, ChatHeaderStatusIndicator as StatusIndicator, ChatHeaderToggle as Toggle, ChatHeaderExpandablePanel as ExpandablePanel, useChatHeaderContext, };
|
|
11
|
+
export { ChatHeaderRoot as Root, ChatHeaderTitle as Title, ChatHeaderActions as Actions, };
|