@townco/ui 0.1.50 → 0.1.52
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/index.d.ts +1 -0
- package/dist/core/hooks/index.js +1 -0
- package/dist/core/hooks/use-chat-messages.d.ts +84 -0
- package/dist/core/hooks/use-chat-session.js +20 -3
- package/dist/core/hooks/use-subagent-stream.d.ts +28 -0
- package/dist/core/hooks/use-subagent-stream.js +254 -0
- package/dist/core/hooks/use-tool-calls.d.ts +84 -0
- package/dist/core/schemas/chat.d.ts +188 -0
- package/dist/core/schemas/tool-call.d.ts +286 -0
- package/dist/core/schemas/tool-call.js +53 -0
- package/dist/gui/components/ChatEmptyState.d.ts +2 -0
- package/dist/gui/components/ChatEmptyState.js +2 -2
- package/dist/gui/components/ChatLayout.d.ts +2 -0
- package/dist/gui/components/ChatLayout.js +70 -1
- package/dist/gui/components/ChatPanelTabContent.js +2 -2
- package/dist/gui/components/ChatSecondaryPanel.js +1 -1
- package/dist/gui/components/ChatView.js +85 -12
- package/dist/gui/components/PanelTabsHeader.js +1 -1
- package/dist/gui/components/SubAgentDetails.d.ts +27 -0
- package/dist/gui/components/SubAgentDetails.js +121 -0
- package/dist/gui/components/TodoList.js +12 -2
- package/dist/gui/components/ToolCall.js +41 -8
- package/dist/gui/components/index.d.ts +1 -0
- package/dist/gui/components/index.js +1 -0
- package/dist/sdk/client/acp-client.d.ts +9 -1
- package/dist/sdk/client/acp-client.js +10 -0
- package/dist/sdk/schemas/message.d.ts +2 -2
- package/dist/sdk/schemas/session.d.ts +96 -0
- package/dist/sdk/transports/http.d.ts +12 -1
- package/dist/sdk/transports/http.js +77 -1
- package/dist/sdk/transports/stdio.d.ts +3 -0
- package/dist/sdk/transports/types.d.ts +34 -0
- package/package.json +3 -3
package/dist/core/hooks/index.js
CHANGED
|
@@ -69,6 +69,90 @@ export declare function useChatMessages(client: AcpClient | null, startSession:
|
|
|
69
69
|
originalTokens?: number | undefined;
|
|
70
70
|
finalTokens?: number | undefined;
|
|
71
71
|
} | undefined;
|
|
72
|
+
subagentPort?: number | undefined;
|
|
73
|
+
subagentSessionId?: string | undefined;
|
|
74
|
+
subagentMessages?: {
|
|
75
|
+
id: string;
|
|
76
|
+
content: string;
|
|
77
|
+
toolCalls?: {
|
|
78
|
+
id: string;
|
|
79
|
+
title: string;
|
|
80
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
81
|
+
prettyName?: string | undefined;
|
|
82
|
+
icon?: string | undefined;
|
|
83
|
+
content?: ({
|
|
84
|
+
type: "content";
|
|
85
|
+
content: {
|
|
86
|
+
type: "text";
|
|
87
|
+
text: string;
|
|
88
|
+
};
|
|
89
|
+
} | {
|
|
90
|
+
type: "text";
|
|
91
|
+
text: string;
|
|
92
|
+
} | {
|
|
93
|
+
type: "image";
|
|
94
|
+
data: string;
|
|
95
|
+
mimeType?: string | undefined;
|
|
96
|
+
alt?: string | undefined;
|
|
97
|
+
} | {
|
|
98
|
+
type: "image";
|
|
99
|
+
url: string;
|
|
100
|
+
alt?: string | undefined;
|
|
101
|
+
} | {
|
|
102
|
+
type: "diff";
|
|
103
|
+
path: string;
|
|
104
|
+
oldText: string;
|
|
105
|
+
newText: string;
|
|
106
|
+
line?: number | null | undefined;
|
|
107
|
+
} | {
|
|
108
|
+
type: "terminal";
|
|
109
|
+
terminalId: string;
|
|
110
|
+
})[] | undefined;
|
|
111
|
+
}[] | undefined;
|
|
112
|
+
contentBlocks?: ({
|
|
113
|
+
type: "text";
|
|
114
|
+
text: string;
|
|
115
|
+
} | {
|
|
116
|
+
type: "tool_call";
|
|
117
|
+
toolCall: {
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
121
|
+
prettyName?: string | undefined;
|
|
122
|
+
icon?: string | undefined;
|
|
123
|
+
content?: ({
|
|
124
|
+
type: "content";
|
|
125
|
+
content: {
|
|
126
|
+
type: "text";
|
|
127
|
+
text: string;
|
|
128
|
+
};
|
|
129
|
+
} | {
|
|
130
|
+
type: "text";
|
|
131
|
+
text: string;
|
|
132
|
+
} | {
|
|
133
|
+
type: "image";
|
|
134
|
+
data: string;
|
|
135
|
+
mimeType?: string | undefined;
|
|
136
|
+
alt?: string | undefined;
|
|
137
|
+
} | {
|
|
138
|
+
type: "image";
|
|
139
|
+
url: string;
|
|
140
|
+
alt?: string | undefined;
|
|
141
|
+
} | {
|
|
142
|
+
type: "diff";
|
|
143
|
+
path: string;
|
|
144
|
+
oldText: string;
|
|
145
|
+
newText: string;
|
|
146
|
+
line?: number | null | undefined;
|
|
147
|
+
} | {
|
|
148
|
+
type: "terminal";
|
|
149
|
+
terminalId: string;
|
|
150
|
+
})[] | undefined;
|
|
151
|
+
};
|
|
152
|
+
})[] | undefined;
|
|
153
|
+
isStreaming?: boolean | undefined;
|
|
154
|
+
}[] | undefined;
|
|
155
|
+
subagentStreaming?: boolean | undefined;
|
|
72
156
|
}[] | undefined;
|
|
73
157
|
tokenUsage?: {
|
|
74
158
|
inputTokens?: number | undefined;
|
|
@@ -112,6 +112,18 @@ export function useChatSession(client, initialSessionId) {
|
|
|
112
112
|
setConnectionStatus("connecting");
|
|
113
113
|
setError(null);
|
|
114
114
|
await client.connect();
|
|
115
|
+
// Get the session ID from the transport after connecting
|
|
116
|
+
// (the transport creates a session during connect)
|
|
117
|
+
const currentSession = client.getCurrentSession();
|
|
118
|
+
if (currentSession?.id) {
|
|
119
|
+
setSessionId(currentSession.id);
|
|
120
|
+
// Update URL with session ID
|
|
121
|
+
if (typeof window !== "undefined") {
|
|
122
|
+
const url = new URL(window.location.href);
|
|
123
|
+
url.searchParams.set("session", currentSession.id);
|
|
124
|
+
window.history.replaceState({}, "", url.toString());
|
|
125
|
+
}
|
|
126
|
+
}
|
|
115
127
|
setConnectionStatus("connected");
|
|
116
128
|
}
|
|
117
129
|
catch (error) {
|
|
@@ -122,7 +134,7 @@ export function useChatSession(client, initialSessionId) {
|
|
|
122
134
|
setError(message);
|
|
123
135
|
setConnectionStatus("error");
|
|
124
136
|
}
|
|
125
|
-
}, [client, setConnectionStatus, setError]);
|
|
137
|
+
}, [client, setConnectionStatus, setSessionId, setError]);
|
|
126
138
|
/**
|
|
127
139
|
* Load an existing session
|
|
128
140
|
*/
|
|
@@ -197,8 +209,13 @@ export function useChatSession(client, initialSessionId) {
|
|
|
197
209
|
try {
|
|
198
210
|
const id = await client.startSession();
|
|
199
211
|
setSessionId(id);
|
|
200
|
-
|
|
201
|
-
|
|
212
|
+
// Only clear messages if there are no messages from initial message
|
|
213
|
+
// (initial messages are added before startSession is called)
|
|
214
|
+
const currentMessages = useChatStore.getState().messages;
|
|
215
|
+
if (currentMessages.length === 0) {
|
|
216
|
+
clearMessages();
|
|
217
|
+
resetTokens();
|
|
218
|
+
}
|
|
202
219
|
// Update URL with new session ID
|
|
203
220
|
if (typeof window !== "undefined") {
|
|
204
221
|
const url = new URL(window.location.href);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SubagentMessage } from "../schemas/tool-call.js";
|
|
2
|
+
export interface UseSubagentStreamOptions {
|
|
3
|
+
/** Sub-agent HTTP port */
|
|
4
|
+
port: number;
|
|
5
|
+
/** Sub-agent session ID */
|
|
6
|
+
sessionId: string;
|
|
7
|
+
/** Base host (defaults to localhost) */
|
|
8
|
+
host?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface UseSubagentStreamReturn {
|
|
11
|
+
/** Accumulated messages from the sub-agent */
|
|
12
|
+
messages: SubagentMessage[];
|
|
13
|
+
/** Whether the stream is currently active */
|
|
14
|
+
isStreaming: boolean;
|
|
15
|
+
/** Error message if connection failed */
|
|
16
|
+
error: string | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Hook to connect directly to a sub-agent's SSE endpoint and stream messages.
|
|
20
|
+
*
|
|
21
|
+
* This hook:
|
|
22
|
+
* - Connects to the sub-agent's HTTP server at the given port
|
|
23
|
+
* - Subscribes to the /events SSE endpoint with the session ID
|
|
24
|
+
* - Parses incoming session/update notifications
|
|
25
|
+
* - Extracts text chunks and tool calls
|
|
26
|
+
* - Returns accumulated messages for display
|
|
27
|
+
*/
|
|
28
|
+
export declare function useSubagentStream(options: UseSubagentStreamOptions | null): UseSubagentStreamReturn;
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { createLogger } from "@townco/core";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
const logger = createLogger("subagent-stream");
|
|
4
|
+
/**
|
|
5
|
+
* Hook to connect directly to a sub-agent's SSE endpoint and stream messages.
|
|
6
|
+
*
|
|
7
|
+
* This hook:
|
|
8
|
+
* - Connects to the sub-agent's HTTP server at the given port
|
|
9
|
+
* - Subscribes to the /events SSE endpoint with the session ID
|
|
10
|
+
* - Parses incoming session/update notifications
|
|
11
|
+
* - Extracts text chunks and tool calls
|
|
12
|
+
* - Returns accumulated messages for display
|
|
13
|
+
*/
|
|
14
|
+
export function useSubagentStream(options) {
|
|
15
|
+
const [messages, setMessages] = useState([]);
|
|
16
|
+
// Start as streaming=true if options provided, since we're about to connect
|
|
17
|
+
const [isStreaming, setIsStreaming] = useState(!!options);
|
|
18
|
+
const [hasCompleted, setHasCompleted] = useState(false);
|
|
19
|
+
const [error, setError] = useState(null);
|
|
20
|
+
const abortControllerRef = useRef(null);
|
|
21
|
+
const currentMessageRef = useRef(null);
|
|
22
|
+
const updateTimeoutRef = useRef(null);
|
|
23
|
+
// Throttled update to prevent excessive re-renders
|
|
24
|
+
const scheduleUpdate = useCallback(() => {
|
|
25
|
+
// If there's already a pending timeout, let it handle the update
|
|
26
|
+
// (it will read the latest currentMessageRef value)
|
|
27
|
+
if (updateTimeoutRef.current)
|
|
28
|
+
return;
|
|
29
|
+
updateTimeoutRef.current = setTimeout(() => {
|
|
30
|
+
updateTimeoutRef.current = null;
|
|
31
|
+
if (currentMessageRef.current) {
|
|
32
|
+
setMessages([{ ...currentMessageRef.current }]);
|
|
33
|
+
}
|
|
34
|
+
}, 250); // Batch updates every 250ms
|
|
35
|
+
}, []);
|
|
36
|
+
// Process incoming SSE message from sub-agent
|
|
37
|
+
// Defined BEFORE connectToSubagent so it's available in the closure
|
|
38
|
+
const processSSEMessage = useCallback((data) => {
|
|
39
|
+
try {
|
|
40
|
+
const message = JSON.parse(data);
|
|
41
|
+
logger.debug("Processing SSE message", {
|
|
42
|
+
method: message.method,
|
|
43
|
+
hasParams: !!message.params,
|
|
44
|
+
});
|
|
45
|
+
// Check if this is a session/update notification
|
|
46
|
+
if (message.method === "session/update" && message.params?.update) {
|
|
47
|
+
const update = message.params.update;
|
|
48
|
+
logger.debug("Got session update", {
|
|
49
|
+
sessionUpdate: update.sessionUpdate,
|
|
50
|
+
});
|
|
51
|
+
if (update.sessionUpdate === "agent_message_chunk") {
|
|
52
|
+
// Handle text chunk
|
|
53
|
+
const content = update.content;
|
|
54
|
+
if (content?.type === "text" && typeof content.text === "string") {
|
|
55
|
+
if (currentMessageRef.current) {
|
|
56
|
+
currentMessageRef.current.content += content.text;
|
|
57
|
+
// Add to contentBlocks - append to last text block or create new one
|
|
58
|
+
const blocks = currentMessageRef.current.contentBlocks ?? [];
|
|
59
|
+
const lastBlock = blocks[blocks.length - 1];
|
|
60
|
+
if (lastBlock && lastBlock.type === "text") {
|
|
61
|
+
lastBlock.text += content.text;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
blocks.push({ type: "text", text: content.text });
|
|
65
|
+
}
|
|
66
|
+
currentMessageRef.current.contentBlocks = blocks;
|
|
67
|
+
scheduleUpdate();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (update.sessionUpdate === "tool_call") {
|
|
72
|
+
// Handle new tool call
|
|
73
|
+
const toolCall = {
|
|
74
|
+
id: update.toolCallId ?? `tc-${Date.now()}`,
|
|
75
|
+
title: update.title ?? "Tool call",
|
|
76
|
+
prettyName: update._meta?.prettyName,
|
|
77
|
+
icon: update._meta?.icon,
|
|
78
|
+
status: update.status ?? "pending",
|
|
79
|
+
content: [],
|
|
80
|
+
};
|
|
81
|
+
if (currentMessageRef.current) {
|
|
82
|
+
currentMessageRef.current.toolCalls = [
|
|
83
|
+
...(currentMessageRef.current.toolCalls ?? []),
|
|
84
|
+
toolCall,
|
|
85
|
+
];
|
|
86
|
+
// Add to contentBlocks for interleaved display
|
|
87
|
+
const blocks = currentMessageRef.current.contentBlocks ?? [];
|
|
88
|
+
blocks.push({ type: "tool_call", toolCall });
|
|
89
|
+
currentMessageRef.current.contentBlocks = blocks;
|
|
90
|
+
scheduleUpdate();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else if (update.sessionUpdate === "tool_call_update") {
|
|
94
|
+
// Handle tool call update (status change, completion)
|
|
95
|
+
if (currentMessageRef.current?.toolCalls) {
|
|
96
|
+
const toolCallId = update.toolCallId;
|
|
97
|
+
const updateToolCall = (tc) => tc.id === toolCallId
|
|
98
|
+
? {
|
|
99
|
+
...tc,
|
|
100
|
+
status: update.status ?? tc.status,
|
|
101
|
+
content: update.content ?? tc.content,
|
|
102
|
+
}
|
|
103
|
+
: tc;
|
|
104
|
+
currentMessageRef.current.toolCalls =
|
|
105
|
+
currentMessageRef.current.toolCalls.map(updateToolCall);
|
|
106
|
+
// Also update in contentBlocks
|
|
107
|
+
if (currentMessageRef.current.contentBlocks) {
|
|
108
|
+
currentMessageRef.current.contentBlocks =
|
|
109
|
+
currentMessageRef.current.contentBlocks.map((block) => block.type === "tool_call"
|
|
110
|
+
? { ...block, toolCall: updateToolCall(block.toolCall) }
|
|
111
|
+
: block);
|
|
112
|
+
}
|
|
113
|
+
scheduleUpdate();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
logger.error("Failed to parse sub-agent SSE message", {
|
|
120
|
+
error: err instanceof Error ? err.message : String(err),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}, [scheduleUpdate]);
|
|
124
|
+
const connectToSubagent = useCallback(async (port, sessionId, host) => {
|
|
125
|
+
const baseUrl = `http://${host}:${port}`;
|
|
126
|
+
logger.info("Connecting to sub-agent SSE", { baseUrl, sessionId });
|
|
127
|
+
setIsStreaming(true);
|
|
128
|
+
setError(null);
|
|
129
|
+
// Create abort controller for cleanup
|
|
130
|
+
const abortController = new AbortController();
|
|
131
|
+
abortControllerRef.current = abortController;
|
|
132
|
+
try {
|
|
133
|
+
logger.info("Fetching SSE endpoint", {
|
|
134
|
+
url: `${baseUrl}/events`,
|
|
135
|
+
sessionId,
|
|
136
|
+
});
|
|
137
|
+
const response = await fetch(`${baseUrl}/events`, {
|
|
138
|
+
method: "GET",
|
|
139
|
+
headers: {
|
|
140
|
+
"X-Session-ID": sessionId,
|
|
141
|
+
},
|
|
142
|
+
signal: abortController.signal,
|
|
143
|
+
});
|
|
144
|
+
logger.info("SSE response received", {
|
|
145
|
+
status: response.status,
|
|
146
|
+
ok: response.ok,
|
|
147
|
+
});
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
throw new Error(`SSE connection failed: HTTP ${response.status}`);
|
|
150
|
+
}
|
|
151
|
+
if (!response.body) {
|
|
152
|
+
throw new Error("Response body is null");
|
|
153
|
+
}
|
|
154
|
+
logger.info("Sub-agent SSE connection opened, starting to read stream");
|
|
155
|
+
// Read the SSE stream
|
|
156
|
+
const reader = response.body.getReader();
|
|
157
|
+
const decoder = new TextDecoder();
|
|
158
|
+
let buffer = "";
|
|
159
|
+
// Initialize current message
|
|
160
|
+
currentMessageRef.current = {
|
|
161
|
+
id: `subagent-${Date.now()}`,
|
|
162
|
+
content: "",
|
|
163
|
+
toolCalls: [],
|
|
164
|
+
contentBlocks: [],
|
|
165
|
+
isStreaming: true,
|
|
166
|
+
};
|
|
167
|
+
setMessages([currentMessageRef.current]);
|
|
168
|
+
while (true) {
|
|
169
|
+
const { done, value } = await reader.read();
|
|
170
|
+
if (done) {
|
|
171
|
+
logger.debug("Sub-agent SSE stream closed");
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
// Decode the chunk and add to buffer
|
|
175
|
+
buffer += decoder.decode(value, { stream: true });
|
|
176
|
+
// Process complete SSE messages
|
|
177
|
+
const lines = buffer.split("\n");
|
|
178
|
+
buffer = lines.pop() || ""; // Keep incomplete line in buffer
|
|
179
|
+
let currentEvent = { event: "message", data: "" };
|
|
180
|
+
for (const line of lines) {
|
|
181
|
+
if (line.startsWith("event:")) {
|
|
182
|
+
currentEvent.event = line.substring(6).trim();
|
|
183
|
+
}
|
|
184
|
+
else if (line.startsWith("data:")) {
|
|
185
|
+
currentEvent.data = line.substring(5).trim();
|
|
186
|
+
}
|
|
187
|
+
else if (line === "") {
|
|
188
|
+
// Empty line signals end of event
|
|
189
|
+
if (currentEvent.event === "message" && currentEvent.data) {
|
|
190
|
+
processSSEMessage(currentEvent.data);
|
|
191
|
+
}
|
|
192
|
+
// Reset for next event
|
|
193
|
+
currentEvent = { event: "message", data: "" };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
200
|
+
logger.debug("Sub-agent SSE stream aborted");
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
const errorMessage = err instanceof Error
|
|
204
|
+
? err.message
|
|
205
|
+
: "Failed to connect to sub-agent";
|
|
206
|
+
logger.error("Sub-agent SSE error", { error: errorMessage });
|
|
207
|
+
setError(errorMessage);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
// Mark streaming as complete
|
|
212
|
+
if (currentMessageRef.current) {
|
|
213
|
+
currentMessageRef.current.isStreaming = false;
|
|
214
|
+
setMessages((prev) => prev.map((m) => m.id === currentMessageRef.current?.id
|
|
215
|
+
? { ...m, isStreaming: false }
|
|
216
|
+
: m));
|
|
217
|
+
}
|
|
218
|
+
setHasCompleted(true);
|
|
219
|
+
setIsStreaming(false);
|
|
220
|
+
abortControllerRef.current = null;
|
|
221
|
+
logger.debug("Sub-agent stream completed");
|
|
222
|
+
}
|
|
223
|
+
}, [processSSEMessage]);
|
|
224
|
+
// Connect when options change
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
if (!options) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const { port, sessionId, host = "localhost" } = options;
|
|
230
|
+
if (!port || !sessionId) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// Reset state for new connection
|
|
234
|
+
setMessages([]);
|
|
235
|
+
setError(null);
|
|
236
|
+
setHasCompleted(false);
|
|
237
|
+
setIsStreaming(true);
|
|
238
|
+
connectToSubagent(port, sessionId, host);
|
|
239
|
+
// Cleanup on unmount or options change
|
|
240
|
+
return () => {
|
|
241
|
+
if (abortControllerRef.current) {
|
|
242
|
+
abortControllerRef.current.abort();
|
|
243
|
+
abortControllerRef.current = null;
|
|
244
|
+
}
|
|
245
|
+
if (updateTimeoutRef.current) {
|
|
246
|
+
clearTimeout(updateTimeoutRef.current);
|
|
247
|
+
updateTimeoutRef.current = null;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}, [options?.port, options?.sessionId, options?.host, connectToSubagent]);
|
|
251
|
+
// Derive streaming status: streaming if we haven't completed yet
|
|
252
|
+
const effectiveIsStreaming = !hasCompleted;
|
|
253
|
+
return { messages, isStreaming: effectiveIsStreaming, error };
|
|
254
|
+
}
|
|
@@ -67,6 +67,90 @@ export declare function useToolCalls(client: AcpClient | null): {
|
|
|
67
67
|
originalTokens?: number | undefined;
|
|
68
68
|
finalTokens?: number | undefined;
|
|
69
69
|
} | undefined;
|
|
70
|
+
subagentPort?: number | undefined;
|
|
71
|
+
subagentSessionId?: string | undefined;
|
|
72
|
+
subagentMessages?: {
|
|
73
|
+
id: string;
|
|
74
|
+
content: string;
|
|
75
|
+
toolCalls?: {
|
|
76
|
+
id: string;
|
|
77
|
+
title: string;
|
|
78
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
79
|
+
prettyName?: string | undefined;
|
|
80
|
+
icon?: string | undefined;
|
|
81
|
+
content?: ({
|
|
82
|
+
type: "content";
|
|
83
|
+
content: {
|
|
84
|
+
type: "text";
|
|
85
|
+
text: string;
|
|
86
|
+
};
|
|
87
|
+
} | {
|
|
88
|
+
type: "text";
|
|
89
|
+
text: string;
|
|
90
|
+
} | {
|
|
91
|
+
type: "image";
|
|
92
|
+
data: string;
|
|
93
|
+
mimeType?: string | undefined;
|
|
94
|
+
alt?: string | undefined;
|
|
95
|
+
} | {
|
|
96
|
+
type: "image";
|
|
97
|
+
url: string;
|
|
98
|
+
alt?: string | undefined;
|
|
99
|
+
} | {
|
|
100
|
+
type: "diff";
|
|
101
|
+
path: string;
|
|
102
|
+
oldText: string;
|
|
103
|
+
newText: string;
|
|
104
|
+
line?: number | null | undefined;
|
|
105
|
+
} | {
|
|
106
|
+
type: "terminal";
|
|
107
|
+
terminalId: string;
|
|
108
|
+
})[] | undefined;
|
|
109
|
+
}[] | undefined;
|
|
110
|
+
contentBlocks?: ({
|
|
111
|
+
type: "text";
|
|
112
|
+
text: string;
|
|
113
|
+
} | {
|
|
114
|
+
type: "tool_call";
|
|
115
|
+
toolCall: {
|
|
116
|
+
id: string;
|
|
117
|
+
title: string;
|
|
118
|
+
status: "pending" | "in_progress" | "completed" | "failed";
|
|
119
|
+
prettyName?: string | undefined;
|
|
120
|
+
icon?: string | undefined;
|
|
121
|
+
content?: ({
|
|
122
|
+
type: "content";
|
|
123
|
+
content: {
|
|
124
|
+
type: "text";
|
|
125
|
+
text: string;
|
|
126
|
+
};
|
|
127
|
+
} | {
|
|
128
|
+
type: "text";
|
|
129
|
+
text: string;
|
|
130
|
+
} | {
|
|
131
|
+
type: "image";
|
|
132
|
+
data: string;
|
|
133
|
+
mimeType?: string | undefined;
|
|
134
|
+
alt?: string | undefined;
|
|
135
|
+
} | {
|
|
136
|
+
type: "image";
|
|
137
|
+
url: string;
|
|
138
|
+
alt?: string | undefined;
|
|
139
|
+
} | {
|
|
140
|
+
type: "diff";
|
|
141
|
+
path: string;
|
|
142
|
+
oldText: string;
|
|
143
|
+
newText: string;
|
|
144
|
+
line?: number | null | undefined;
|
|
145
|
+
} | {
|
|
146
|
+
type: "terminal";
|
|
147
|
+
terminalId: string;
|
|
148
|
+
})[] | undefined;
|
|
149
|
+
};
|
|
150
|
+
})[] | undefined;
|
|
151
|
+
isStreaming?: boolean | undefined;
|
|
152
|
+
}[] | undefined;
|
|
153
|
+
subagentStreaming?: boolean | undefined;
|
|
70
154
|
}[]>;
|
|
71
155
|
getToolCallsForSession: (sessionId: string) => ToolCall[];
|
|
72
156
|
};
|