@nextclaw/ui 0.12.4 → 0.12.5
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/CHANGELOG.md +41 -0
- package/dist/assets/{ChannelsList-CobWeI2V.js → ChannelsList-C6-lh55g.js} +2 -2
- package/dist/assets/ChatPage-DOW0gPc2.js +45 -0
- package/dist/assets/DocBrowser-CGyeswYP.js +1 -0
- package/dist/assets/{DocBrowser-NSzgVKka.js → DocBrowser-QUZ3nfmH.js} +1 -1
- package/dist/assets/{DocBrowserContext-DpgVdRgk.js → DocBrowserContext-CpiIfhJO.js} +1 -1
- package/dist/assets/{LogoBadge-CHS4YNLw.js → LogoBadge-BUK13xK5.js} +1 -1
- package/dist/assets/MarketplacePage-BDVwhIYE.js +1 -0
- package/dist/assets/MarketplacePage-LnKKL3xK.js +49 -0
- package/dist/assets/McpMarketplacePage-BG4T_Pcx.js +40 -0
- package/dist/assets/ModelConfig-LtWuogIw.js +1 -0
- package/dist/assets/ProviderScopedModelInput-DGn6sFEN.js +1 -0
- package/dist/assets/ProvidersList-ma-_MlLo.js +1 -0
- package/dist/assets/{RemoteAccessPage-yfbrveNQ.js → RemoteAccessPage-ff15qO-c.js} +1 -1
- package/dist/assets/RuntimeConfig-TgPandXF.js +1 -0
- package/dist/assets/SearchConfig-C9iBt7pl.js +1 -0
- package/dist/assets/{SecretsConfig-CLFSSoTl.js → SecretsConfig-Bew4EF2A.js} +2 -2
- package/dist/assets/{SessionsConfig-vYrvc2Fk.js → SessionsConfig-2r2yAGZg.js} +2 -2
- package/dist/assets/{book-open-C7TAghTk.js → book-open-CJG8Yz3U.js} +1 -1
- package/dist/assets/{chat-session-display-5dVFkJyw.js → chat-session-display-DkAC5OMC.js} +1 -1
- package/dist/assets/{chunk-JZWAC4HX-DbL4EmiT.js → chunk-JZWAC4HX-D5b3Iyas.js} +1 -1
- package/dist/assets/{config-CMiW0yaK.js → config-zvnxSXSP.js} +1 -1
- package/dist/assets/{createLucideIcon-BRLFtf-8.js → createLucideIcon-_FMJqZw2.js} +1 -1
- package/dist/assets/{dist-DP-JKR4G.js → dist-B1fpOuON.js} +1 -1
- package/dist/assets/{dist-BFc_H-lY.js → dist-BCXX7FD-.js} +2 -2
- package/dist/assets/{external-link-BkJkiWbH.js → external-link-b7gAJWYY.js} +1 -1
- package/dist/assets/{hash-CbP6-6R9.js → hash-Bhy4TwfZ.js} +1 -1
- package/dist/assets/{i18n-C_2dKw6w.js → i18n-DJg9BPYk.js} +1 -1
- package/dist/assets/index-BoJbxdvZ.css +1 -0
- package/dist/assets/index-CtlT4E9Y.js +6 -0
- package/dist/assets/infiniteQueryBehavior-CTcVlD9s.js +1 -0
- package/dist/assets/loader-circle-B60I0hEk.js +1 -0
- package/dist/assets/{logos-N3dbS6-I.js → logos-GMeYU9vc.js} +1 -1
- package/dist/assets/{page-layout-DyuvlNrg.js → page-layout-C8UbWuMt.js} +1 -1
- package/dist/assets/plus-CR7RfK3H.js +1 -0
- package/dist/assets/{popover-BKKWGUaG.js → popover-8HSx9wQj.js} +1 -1
- package/dist/assets/react-BB4jko2M.js +1 -0
- package/dist/assets/{refresh-ccw-BGMdiNGq.js → refresh-ccw-CA4_C7Zg.js} +1 -1
- package/dist/assets/{save-Dh4GQzzX.js → save-BtvMy4lk.js} +1 -1
- package/dist/assets/search-C60UA27E.js +1 -0
- package/dist/assets/security-config-BkFDYZ6j.js +1 -0
- package/dist/assets/{select-BtIi5fnh.js → select-xp_Ac8ip.js} +1 -1
- package/dist/assets/skeleton-uxz_5h3A.js +1 -0
- package/dist/assets/{status-dot-C4O-2jZP.js → status-dot-Cn4Pp7DZ.js} +1 -1
- package/dist/assets/{switch-DPegGIa_.js → switch-BTi6UOij.js} +1 -1
- package/dist/assets/{tabs-custom-x5GZexrF.js → tabs-custom-BiiN8DME.js} +1 -1
- package/dist/assets/{trash-2-CU3LYIpQ.js → trash-2-BpsF0N-r.js} +1 -1
- package/dist/assets/use-infinite-scroll-loader-C8jBv11-.js +1 -0
- package/dist/assets/{useConfirmDialog-S5WsGOGf.js → useConfirmDialog-BJIwUZjH.js} +1 -1
- package/dist/assets/{useMutation-DSinpgEq.js → useMutation-BjBOKHj_.js} +1 -1
- package/dist/assets/x-BfTu-g7D.js +1 -0
- package/dist/index.html +19 -18
- package/package.json +4 -4
- package/src/account/components/account-panel.tsx +46 -4
- package/src/account/managers/account.manager.ts +19 -4
- package/src/api/remote.ts +9 -0
- package/src/api/remote.types.ts +5 -0
- package/src/components/chat/ChatConversationPanel.test.tsx +183 -141
- package/src/components/chat/adapters/chat-message-tool-agent-id.test.ts +11 -11
- package/src/components/chat/adapters/chat-message.adapter.test.ts +43 -6
- package/src/components/chat/adapters/chat-message.session-request-tool-card.ts +182 -44
- package/src/components/chat/adapters/chat-message.session-spawn-tool-card.test.ts +104 -0
- package/src/components/chat/chat-child-session-panel.tsx +103 -45
- package/src/components/chat/chat-page-runtime.test.ts +16 -19
- package/src/components/chat/chat-session-preference-sync.test.ts +13 -0
- package/src/components/chat/chat-session-preference-sync.ts +9 -7
- package/src/components/chat/hooks/use-chat-session-project.test.tsx +5 -5
- package/src/components/chat/hooks/use-chat-session-project.ts +0 -5
- package/src/components/chat/hooks/use-chat-session-update.test.tsx +75 -0
- package/src/components/chat/hooks/use-chat-session-update.ts +4 -2
- package/src/components/chat/managers/chat-session-list.manager.test.ts +45 -5
- package/src/components/chat/managers/chat-session-list.manager.ts +18 -4
- package/src/components/chat/ncp/NcpChatPage.tsx +32 -51
- package/src/components/chat/ncp/ncp-chat-input.manager.ts +3 -5
- package/src/components/chat/ncp/ncp-chat-page-data.ts +0 -1
- package/src/components/chat/ncp/ncp-chat.presenter.ts +1 -11
- package/src/components/chat/ncp/session-conversation/use-ncp-child-session-tabs-view.ts +20 -7
- package/src/components/chat/stores/chat-session-list.store.ts +3 -0
- package/src/components/chat/useChatSessionTypeState.test.tsx +0 -3
- package/src/components/chat/useChatSessionTypeState.ts +3 -5
- package/src/components/config/ChannelsList.test.tsx +68 -0
- package/src/components/config/ChannelsList.tsx +22 -4
- package/src/components/config/ProvidersList.tsx +17 -3
- package/src/components/config/providers-list.test.tsx +68 -0
- package/src/components/layout/Sidebar.tsx +13 -13
- package/src/components/layout/sidebar.layout.test.tsx +32 -1
- package/src/components/marketplace/MarketplacePage.tsx +30 -30
- package/src/components/marketplace/marketplace-page-parts.tsx +16 -24
- package/src/components/marketplace/mcp/McpMarketplacePage.tsx +28 -26
- package/src/hooks/marketplace-list-pages.ts +27 -0
- package/src/hooks/use-infinite-scroll-loader.ts +88 -0
- package/src/hooks/useMarketplace.ts +14 -3
- package/src/hooks/useMcpMarketplace.ts +14 -3
- package/src/lib/i18n.remote.ts +15 -0
- package/dist/assets/ChatPage-ZIdFFVAv.js +0 -43
- package/dist/assets/DocBrowser-D55C0iyl.js +0 -1
- package/dist/assets/MarketplacePage-BFYsRss_.js +0 -49
- package/dist/assets/MarketplacePage-DII-q-Y1.js +0 -1
- package/dist/assets/McpMarketplacePage-CPqsGJzz.js +0 -40
- package/dist/assets/ModelConfig-Bvuo_IpS.js +0 -1
- package/dist/assets/ProviderScopedModelInput-BfY8rGsf.js +0 -1
- package/dist/assets/ProvidersList-3tlaqwSS.js +0 -1
- package/dist/assets/RuntimeConfig-CAd5Kta3.js +0 -1
- package/dist/assets/SearchConfig-DFwgaAa7.js +0 -1
- package/dist/assets/index-ChUXhq0G.css +0 -1
- package/dist/assets/index-DAE8Srx-.js +0 -6
- package/dist/assets/label-D8yyejJS.js +0 -1
- package/dist/assets/loader-circle-B0sKKO29.js +0 -1
- package/dist/assets/marketplace-localization-CxSTG9wr.js +0 -1
- package/dist/assets/plus-CYXs3JtZ.js +0 -1
- package/dist/assets/react-8EIEQjMP.js +0 -1
- package/dist/assets/search-DOsLw-P9.js +0 -1
- package/dist/assets/security-config-CM_tQRXQ.js +0 -1
- package/dist/assets/skeleton-GbHLjPC0.js +0 -1
- package/dist/assets/x-Bnco_K8b.js +0 -1
|
@@ -223,7 +223,7 @@ it("keeps structured terminal results as structured data instead of raw json out
|
|
|
223
223
|
});
|
|
224
224
|
});
|
|
225
225
|
|
|
226
|
-
it("renders session request
|
|
226
|
+
it("renders child-session request cards for sessions_spawn when the new child starts immediately", () => {
|
|
227
227
|
const adapted = adapt([
|
|
228
228
|
{
|
|
229
229
|
id: "assistant-subagent",
|
|
@@ -233,18 +233,21 @@ it("renders session request tool cards from structured child-session status upda
|
|
|
233
233
|
type: "tool-invocation",
|
|
234
234
|
toolInvocation: {
|
|
235
235
|
status: ToolInvocationStatus.RESULT,
|
|
236
|
-
toolCallId: "spawn-call-1",
|
|
237
|
-
toolName: "
|
|
238
|
-
args: '{"
|
|
236
|
+
toolCallId: "sessions-spawn-call-1",
|
|
237
|
+
toolName: "sessions_spawn",
|
|
238
|
+
args: '{"scope":"child","title":"Verifier","task":"Verify 1+1=2","request":{"notify":"final_reply"}}',
|
|
239
239
|
result: {
|
|
240
240
|
kind: "nextclaw.session_request",
|
|
241
241
|
requestId: "request-1",
|
|
242
242
|
sessionId: "child-session-1",
|
|
243
243
|
agentId: "verifier-agent",
|
|
244
244
|
isChildSession: true,
|
|
245
|
+
lifecycle: "persistent",
|
|
245
246
|
title: "Verifier",
|
|
246
247
|
task: "Verify 1+1=2",
|
|
247
248
|
status: "completed",
|
|
249
|
+
notify: "final_reply",
|
|
250
|
+
spawnedByRequestId: "request-1",
|
|
248
251
|
finalResponseText: "Verified 1+1=2.",
|
|
249
252
|
parentSessionId: "parent-session-1",
|
|
250
253
|
},
|
|
@@ -257,9 +260,17 @@ it("renders session request tool cards from structured child-session status upda
|
|
|
257
260
|
expect(adapted[0]?.parts[0]).toMatchObject({
|
|
258
261
|
type: "tool-card",
|
|
259
262
|
card: {
|
|
260
|
-
toolName: "
|
|
263
|
+
toolName: "sessions_spawn",
|
|
261
264
|
agentId: "verifier-agent",
|
|
262
265
|
summary: "title: Verifier · session: child-session-1 · task: Verify 1+1=2",
|
|
266
|
+
input: `{
|
|
267
|
+
"scope": "child",
|
|
268
|
+
"title": "Verifier",
|
|
269
|
+
"task": "Verify 1+1=2",
|
|
270
|
+
"request": {
|
|
271
|
+
"notify": "final_reply"
|
|
272
|
+
}
|
|
273
|
+
}`,
|
|
263
274
|
output: [
|
|
264
275
|
"Request ID: request-1",
|
|
265
276
|
"",
|
|
@@ -267,6 +278,16 @@ it("renders session request tool cards from structured child-session status upda
|
|
|
267
278
|
"",
|
|
268
279
|
"Target: child",
|
|
269
280
|
"",
|
|
281
|
+
"Status: completed",
|
|
282
|
+
"",
|
|
283
|
+
"Notify: final_reply",
|
|
284
|
+
"",
|
|
285
|
+
"Lifecycle: persistent",
|
|
286
|
+
"",
|
|
287
|
+
"Parent Session ID: parent-session-1",
|
|
288
|
+
"",
|
|
289
|
+
"Spawned By Request ID: request-1",
|
|
290
|
+
"",
|
|
270
291
|
"Title: Verifier",
|
|
271
292
|
"",
|
|
272
293
|
"Task:",
|
|
@@ -302,16 +323,18 @@ it("renders regular session request tool cards with session navigation instead o
|
|
|
302
323
|
status: ToolInvocationStatus.RESULT,
|
|
303
324
|
toolCallId: "session-request-call-1",
|
|
304
325
|
toolName: "sessions_request",
|
|
305
|
-
args: '{"
|
|
326
|
+
args: '{"target":{"session_id":"session-2"},"task":"Summarize the latest findings","notify":"none","title":"Research thread"}',
|
|
306
327
|
result: {
|
|
307
328
|
kind: "nextclaw.session_request",
|
|
308
329
|
requestId: "request-2",
|
|
309
330
|
sessionId: "session-2",
|
|
310
331
|
agentId: "research-agent",
|
|
311
332
|
isChildSession: false,
|
|
333
|
+
lifecycle: "persistent",
|
|
312
334
|
title: "Research thread",
|
|
313
335
|
task: "Summarize the latest findings",
|
|
314
336
|
status: "completed",
|
|
337
|
+
notify: "none",
|
|
315
338
|
finalResponseText: "Here is the summary.",
|
|
316
339
|
},
|
|
317
340
|
},
|
|
@@ -326,6 +349,14 @@ it("renders regular session request tool cards with session navigation instead o
|
|
|
326
349
|
toolName: "sessions_request",
|
|
327
350
|
agentId: "research-agent",
|
|
328
351
|
summary: "title: Research thread · session: session-2 · task: Summarize the latest findings",
|
|
352
|
+
input: `{
|
|
353
|
+
"target": {
|
|
354
|
+
"session_id": "session-2"
|
|
355
|
+
},
|
|
356
|
+
"task": "Summarize the latest findings",
|
|
357
|
+
"notify": "none",
|
|
358
|
+
"title": "Research thread"
|
|
359
|
+
}`,
|
|
329
360
|
output: [
|
|
330
361
|
"Request ID: request-2",
|
|
331
362
|
"",
|
|
@@ -333,6 +364,12 @@ it("renders regular session request tool cards with session navigation instead o
|
|
|
333
364
|
"",
|
|
334
365
|
"Target: session",
|
|
335
366
|
"",
|
|
367
|
+
"Status: completed",
|
|
368
|
+
"",
|
|
369
|
+
"Notify: none",
|
|
370
|
+
"",
|
|
371
|
+
"Lifecycle: persistent",
|
|
372
|
+
"",
|
|
336
373
|
"Title: Research thread",
|
|
337
374
|
"",
|
|
338
375
|
"Task:",
|
|
@@ -9,6 +9,7 @@ import type { ChatToolPartViewModel } from "@nextclaw/agent-chat-ui";
|
|
|
9
9
|
type ToolCardViewSource = ToolCard & {
|
|
10
10
|
statusTone: ChatToolPartViewModel["statusTone"];
|
|
11
11
|
statusLabel: string;
|
|
12
|
+
input?: string;
|
|
12
13
|
action?: ChatToolPartViewModel["action"];
|
|
13
14
|
};
|
|
14
15
|
|
|
@@ -31,15 +32,30 @@ type SessionRequestResult = {
|
|
|
31
32
|
sessionId?: string;
|
|
32
33
|
agentId?: string;
|
|
33
34
|
isChildSession?: boolean;
|
|
35
|
+
lifecycle?: string;
|
|
34
36
|
title?: string;
|
|
35
37
|
task?: string;
|
|
36
38
|
status?: string;
|
|
39
|
+
notify?: string;
|
|
40
|
+
spawnedByRequestId?: string;
|
|
37
41
|
message?: unknown;
|
|
38
42
|
finalResponseText?: unknown;
|
|
39
43
|
error?: unknown;
|
|
40
44
|
parentSessionId?: string;
|
|
41
45
|
};
|
|
42
46
|
|
|
47
|
+
type SessionSpawnResult = {
|
|
48
|
+
kind: string;
|
|
49
|
+
sessionId?: string;
|
|
50
|
+
agentId?: string;
|
|
51
|
+
isChildSession?: boolean;
|
|
52
|
+
title?: string;
|
|
53
|
+
sessionType?: string;
|
|
54
|
+
lifecycle?: string;
|
|
55
|
+
createdAt?: string;
|
|
56
|
+
parentSessionId?: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
43
59
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
44
60
|
return typeof value === "object" && value !== null;
|
|
45
61
|
}
|
|
@@ -59,6 +75,33 @@ function readSessionRequestResult(value: unknown): SessionRequestResult | null {
|
|
|
59
75
|
return value as SessionRequestResult;
|
|
60
76
|
}
|
|
61
77
|
|
|
78
|
+
function readSessionSpawnResult(value: unknown): SessionSpawnResult | null {
|
|
79
|
+
if (!isRecord(value) || value.kind !== "nextclaw.session") {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return value as SessionSpawnResult;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function parseStructuredValue(value: unknown): unknown {
|
|
86
|
+
if (typeof value !== "string") {
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
const trimmed = value.trim();
|
|
90
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(trimmed) as unknown;
|
|
95
|
+
} catch {
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function buildStructuredInput(value: unknown): string | undefined {
|
|
101
|
+
const text = stringifyUnknown(parseStructuredValue(value)).trim();
|
|
102
|
+
return text || undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
62
105
|
function buildSessionRequestDetail(
|
|
63
106
|
result: SessionRequestResult,
|
|
64
107
|
fallbackArgs: unknown,
|
|
@@ -78,11 +121,32 @@ function buildSessionRequestDetail(
|
|
|
78
121
|
return detailParts.join(" · ") || summarizeToolArgs(fallbackArgs);
|
|
79
122
|
}
|
|
80
123
|
|
|
124
|
+
function buildSessionSpawnDetail(
|
|
125
|
+
result: SessionSpawnResult,
|
|
126
|
+
fallbackArgs: unknown,
|
|
127
|
+
): string | undefined {
|
|
128
|
+
const detailParts = [
|
|
129
|
+
readOptionalString(result.title)
|
|
130
|
+
? `title: ${result.title?.trim()}`
|
|
131
|
+
: null,
|
|
132
|
+
readOptionalString(result.sessionId)
|
|
133
|
+
? `session: ${result.sessionId?.trim()}`
|
|
134
|
+
: null,
|
|
135
|
+
].filter((value): value is string => Boolean(value));
|
|
136
|
+
|
|
137
|
+
return detailParts.join(" · ") || summarizeToolArgs(fallbackArgs);
|
|
138
|
+
}
|
|
139
|
+
|
|
81
140
|
function buildSessionRequestOutput(result: SessionRequestResult): string | undefined {
|
|
82
141
|
const requestId = readOptionalString(result.requestId);
|
|
83
142
|
const sessionId = readOptionalString(result.sessionId);
|
|
84
143
|
const title = readOptionalString(result.title);
|
|
85
144
|
const task = readOptionalString(result.task);
|
|
145
|
+
const status = readOptionalString(result.status);
|
|
146
|
+
const notify = readOptionalString(result.notify);
|
|
147
|
+
const lifecycle = readOptionalString(result.lifecycle);
|
|
148
|
+
const parentSessionId = readOptionalString(result.parentSessionId);
|
|
149
|
+
const spawnedByRequestId = readOptionalString(result.spawnedByRequestId);
|
|
86
150
|
const messageText =
|
|
87
151
|
typeof result.message !== "undefined"
|
|
88
152
|
? stringifyUnknown(result.message).trim()
|
|
@@ -102,6 +166,11 @@ function buildSessionRequestOutput(result: SessionRequestResult): string | undef
|
|
|
102
166
|
typeof result.isChildSession === "boolean"
|
|
103
167
|
? `Target: ${result.isChildSession ? "child" : "session"}`
|
|
104
168
|
: null,
|
|
169
|
+
status ? `Status: ${status}` : null,
|
|
170
|
+
notify ? `Notify: ${notify}` : null,
|
|
171
|
+
lifecycle ? `Lifecycle: ${lifecycle}` : null,
|
|
172
|
+
parentSessionId ? `Parent Session ID: ${parentSessionId}` : null,
|
|
173
|
+
spawnedByRequestId ? `Spawned By Request ID: ${spawnedByRequestId}` : null,
|
|
105
174
|
title ? `Title: ${title}` : null,
|
|
106
175
|
task ? `Task:\n${task}` : null,
|
|
107
176
|
finalResponseText
|
|
@@ -116,6 +185,29 @@ function buildSessionRequestOutput(result: SessionRequestResult): string | undef
|
|
|
116
185
|
return sections.length > 0 ? sections.join("\n\n") : undefined;
|
|
117
186
|
}
|
|
118
187
|
|
|
188
|
+
function buildSessionSpawnOutput(result: SessionSpawnResult): string | undefined {
|
|
189
|
+
const sessionId = readOptionalString(result.sessionId);
|
|
190
|
+
const title = readOptionalString(result.title);
|
|
191
|
+
const sessionType = readOptionalString(result.sessionType);
|
|
192
|
+
const lifecycle = readOptionalString(result.lifecycle);
|
|
193
|
+
const parentSessionId = readOptionalString(result.parentSessionId);
|
|
194
|
+
const createdAt = readOptionalString(result.createdAt);
|
|
195
|
+
|
|
196
|
+
const sections = [
|
|
197
|
+
sessionId ? `Session ID: ${sessionId}` : null,
|
|
198
|
+
typeof result.isChildSession === "boolean"
|
|
199
|
+
? `Target: ${result.isChildSession ? "child" : "session"}`
|
|
200
|
+
: null,
|
|
201
|
+
title ? `Title: ${title}` : null,
|
|
202
|
+
sessionType ? `Session Type: ${sessionType}` : null,
|
|
203
|
+
lifecycle ? `Lifecycle: ${lifecycle}` : null,
|
|
204
|
+
parentSessionId ? `Parent Session ID: ${parentSessionId}` : null,
|
|
205
|
+
createdAt ? `Created At: ${createdAt}` : null,
|
|
206
|
+
].filter((value): value is string => Boolean(value));
|
|
207
|
+
|
|
208
|
+
return sections.length > 0 ? sections.join("\n\n") : undefined;
|
|
209
|
+
}
|
|
210
|
+
|
|
119
211
|
export function buildSessionRequestToolCard(params: {
|
|
120
212
|
invocation: SessionRequestInvocation;
|
|
121
213
|
texts: SessionRequestToolCardTexts;
|
|
@@ -123,77 +215,123 @@ export function buildSessionRequestToolCard(params: {
|
|
|
123
215
|
const { invocation, texts } = params;
|
|
124
216
|
const { toolName, toolCallId, args, result } = invocation;
|
|
125
217
|
|
|
126
|
-
if (
|
|
218
|
+
if (
|
|
219
|
+
toolName !== "spawn" &&
|
|
220
|
+
toolName !== "sessions_request" &&
|
|
221
|
+
toolName !== "sessions_spawn"
|
|
222
|
+
) {
|
|
127
223
|
return null;
|
|
128
224
|
}
|
|
129
225
|
|
|
130
226
|
const sessionRequest = readSessionRequestResult(result);
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
|
|
227
|
+
if (sessionRequest) {
|
|
228
|
+
const normalizedStatus = readOptionalString(sessionRequest.status)?.toLowerCase();
|
|
229
|
+
const detail = buildSessionRequestDetail(sessionRequest, args);
|
|
230
|
+
const output = buildSessionRequestOutput(sessionRequest);
|
|
231
|
+
const targetSessionId = readOptionalString(sessionRequest.sessionId);
|
|
232
|
+
const agentId = resolveToolInvocationAgentId({ args, result: sessionRequest });
|
|
233
|
+
const action =
|
|
234
|
+
targetSessionId
|
|
235
|
+
? {
|
|
236
|
+
kind: "open-session" as const,
|
|
237
|
+
sessionId: targetSessionId,
|
|
238
|
+
sessionKind: sessionRequest.isChildSession === true ? ("child" as const) : ("session" as const),
|
|
239
|
+
...(agentId
|
|
240
|
+
? { agentId }
|
|
241
|
+
: {}),
|
|
242
|
+
...(readOptionalString(sessionRequest.title)
|
|
243
|
+
? { label: sessionRequest.title!.trim() }
|
|
244
|
+
: {}),
|
|
245
|
+
...(readOptionalString(sessionRequest.parentSessionId)
|
|
246
|
+
? { parentSessionId: sessionRequest.parentSessionId!.trim() }
|
|
247
|
+
: {}),
|
|
248
|
+
}
|
|
249
|
+
: undefined;
|
|
134
250
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
251
|
+
if (normalizedStatus === "failed") {
|
|
252
|
+
return {
|
|
253
|
+
kind: "result",
|
|
254
|
+
name: toolName,
|
|
255
|
+
detail,
|
|
256
|
+
input: buildStructuredInput(args),
|
|
257
|
+
text: output,
|
|
258
|
+
callId: toolCallId || undefined,
|
|
259
|
+
hasResult: Boolean(output),
|
|
260
|
+
statusTone: "error",
|
|
261
|
+
statusLabel: texts.toolStatusFailedLabel,
|
|
262
|
+
...(agentId ? { agentId } : {}),
|
|
263
|
+
...(action ? { action } : {}),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (normalizedStatus === "completed") {
|
|
268
|
+
return {
|
|
269
|
+
kind: "result",
|
|
270
|
+
name: toolName,
|
|
271
|
+
detail,
|
|
272
|
+
input: buildStructuredInput(args),
|
|
273
|
+
text: output,
|
|
274
|
+
callId: toolCallId || undefined,
|
|
275
|
+
hasResult: Boolean(output),
|
|
276
|
+
statusTone: "success",
|
|
277
|
+
statusLabel: texts.toolStatusCompletedLabel,
|
|
278
|
+
...(agentId ? { agentId } : {}),
|
|
279
|
+
...(action ? { action } : {}),
|
|
280
|
+
};
|
|
281
|
+
}
|
|
157
282
|
|
|
158
|
-
if (normalizedStatus === "failed") {
|
|
159
283
|
return {
|
|
160
284
|
kind: "result",
|
|
161
285
|
name: toolName,
|
|
162
286
|
detail,
|
|
287
|
+
input: buildStructuredInput(args),
|
|
163
288
|
text: output,
|
|
164
289
|
callId: toolCallId || undefined,
|
|
165
290
|
hasResult: Boolean(output),
|
|
166
|
-
statusTone: "
|
|
167
|
-
statusLabel: texts.
|
|
291
|
+
statusTone: "running",
|
|
292
|
+
statusLabel: texts.toolStatusRunningLabel,
|
|
168
293
|
...(agentId ? { agentId } : {}),
|
|
169
294
|
...(action ? { action } : {}),
|
|
170
295
|
};
|
|
171
296
|
}
|
|
172
297
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
name: toolName,
|
|
177
|
-
detail,
|
|
178
|
-
text: output,
|
|
179
|
-
callId: toolCallId || undefined,
|
|
180
|
-
hasResult: Boolean(output),
|
|
181
|
-
statusTone: "success",
|
|
182
|
-
statusLabel: texts.toolStatusCompletedLabel,
|
|
183
|
-
...(agentId ? { agentId } : {}),
|
|
184
|
-
...(action ? { action } : {}),
|
|
185
|
-
};
|
|
298
|
+
const sessionSpawn = readSessionSpawnResult(result);
|
|
299
|
+
if (!sessionSpawn) {
|
|
300
|
+
return null;
|
|
186
301
|
}
|
|
187
302
|
|
|
303
|
+
const detail = buildSessionSpawnDetail(sessionSpawn, args);
|
|
304
|
+
const output = buildSessionSpawnOutput(sessionSpawn);
|
|
305
|
+
const targetSessionId = readOptionalString(sessionSpawn.sessionId);
|
|
306
|
+
const agentId = resolveToolInvocationAgentId({ args, result: sessionSpawn });
|
|
307
|
+
const action =
|
|
308
|
+
targetSessionId
|
|
309
|
+
? {
|
|
310
|
+
kind: "open-session" as const,
|
|
311
|
+
sessionId: targetSessionId,
|
|
312
|
+
sessionKind: sessionSpawn.isChildSession === true ? ("child" as const) : ("session" as const),
|
|
313
|
+
...(agentId
|
|
314
|
+
? { agentId }
|
|
315
|
+
: {}),
|
|
316
|
+
...(readOptionalString(sessionSpawn.title)
|
|
317
|
+
? { label: sessionSpawn.title!.trim() }
|
|
318
|
+
: {}),
|
|
319
|
+
...(readOptionalString(sessionSpawn.parentSessionId)
|
|
320
|
+
? { parentSessionId: sessionSpawn.parentSessionId!.trim() }
|
|
321
|
+
: {}),
|
|
322
|
+
}
|
|
323
|
+
: undefined;
|
|
324
|
+
|
|
188
325
|
return {
|
|
189
326
|
kind: "result",
|
|
190
327
|
name: toolName,
|
|
191
328
|
detail,
|
|
329
|
+
input: buildStructuredInput(args),
|
|
192
330
|
text: output,
|
|
193
331
|
callId: toolCallId || undefined,
|
|
194
332
|
hasResult: Boolean(output),
|
|
195
|
-
statusTone: "
|
|
196
|
-
statusLabel: texts.
|
|
333
|
+
statusTone: "success",
|
|
334
|
+
statusLabel: texts.toolStatusCompletedLabel,
|
|
197
335
|
...(agentId ? { agentId } : {}),
|
|
198
336
|
...(action ? { action } : {}),
|
|
199
337
|
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { ToolInvocationStatus, type UiMessage } from "@nextclaw/agent-chat";
|
|
2
|
+
import { adaptChatMessages } from "@/components/chat/adapters/chat-message.adapter";
|
|
3
|
+
import type { ChatMessageSource } from "@/components/chat/adapters/chat-message.adapter";
|
|
4
|
+
|
|
5
|
+
const defaultTexts = {
|
|
6
|
+
roleLabels: {
|
|
7
|
+
user: "You",
|
|
8
|
+
assistant: "Assistant",
|
|
9
|
+
tool: "Tool",
|
|
10
|
+
system: "System",
|
|
11
|
+
fallback: "Message",
|
|
12
|
+
},
|
|
13
|
+
reasoningLabel: "Reasoning",
|
|
14
|
+
toolCallLabel: "Tool Call",
|
|
15
|
+
toolResultLabel: "Tool Result",
|
|
16
|
+
toolInputLabel: "Input",
|
|
17
|
+
toolNoOutputLabel: "No output",
|
|
18
|
+
toolOutputLabel: "Output",
|
|
19
|
+
toolStatusPreparingLabel: "Preparing",
|
|
20
|
+
toolStatusRunningLabel: "Running",
|
|
21
|
+
toolStatusCompletedLabel: "Completed",
|
|
22
|
+
toolStatusFailedLabel: "Failed",
|
|
23
|
+
toolStatusCancelledLabel: "Cancelled",
|
|
24
|
+
imageAttachmentLabel: "Image attachment",
|
|
25
|
+
fileAttachmentLabel: "File attachment",
|
|
26
|
+
unknownPartLabel: "Unknown Part",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function adapt(uiMessages: UiMessage[]) {
|
|
30
|
+
return adaptChatMessages({
|
|
31
|
+
uiMessages: uiMessages as unknown as ChatMessageSource[],
|
|
32
|
+
formatTimestamp: (value) => `formatted:${value}`,
|
|
33
|
+
texts: defaultTexts,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
it("renders child-session creation cards for sessions_spawn and keeps child-panel navigation", () => {
|
|
38
|
+
const adapted = adapt([
|
|
39
|
+
{
|
|
40
|
+
id: "assistant-child-session-create",
|
|
41
|
+
role: "assistant",
|
|
42
|
+
parts: [
|
|
43
|
+
{
|
|
44
|
+
type: "tool-invocation",
|
|
45
|
+
toolInvocation: {
|
|
46
|
+
status: ToolInvocationStatus.RESULT,
|
|
47
|
+
toolCallId: "sessions-spawn-child-only-1",
|
|
48
|
+
toolName: "sessions_spawn",
|
|
49
|
+
args: '{"scope":"child","title":"Verifier","task":"Prepare a child workspace"}',
|
|
50
|
+
result: {
|
|
51
|
+
kind: "nextclaw.session",
|
|
52
|
+
sessionId: "child-session-2",
|
|
53
|
+
agentId: "verifier-agent",
|
|
54
|
+
isChildSession: true,
|
|
55
|
+
title: "Verifier",
|
|
56
|
+
sessionType: "native",
|
|
57
|
+
lifecycle: "persistent",
|
|
58
|
+
parentSessionId: "parent-session-2",
|
|
59
|
+
createdAt: "2026-04-09T09:00:00.000Z",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
expect(adapted[0]?.parts[0]).toMatchObject({
|
|
68
|
+
type: "tool-card",
|
|
69
|
+
card: {
|
|
70
|
+
toolName: "sessions_spawn",
|
|
71
|
+
agentId: "verifier-agent",
|
|
72
|
+
summary: "title: Verifier · session: child-session-2",
|
|
73
|
+
input: `{
|
|
74
|
+
"scope": "child",
|
|
75
|
+
"title": "Verifier",
|
|
76
|
+
"task": "Prepare a child workspace"
|
|
77
|
+
}`,
|
|
78
|
+
output: [
|
|
79
|
+
"Session ID: child-session-2",
|
|
80
|
+
"",
|
|
81
|
+
"Target: child",
|
|
82
|
+
"",
|
|
83
|
+
"Title: Verifier",
|
|
84
|
+
"",
|
|
85
|
+
"Session Type: native",
|
|
86
|
+
"",
|
|
87
|
+
"Lifecycle: persistent",
|
|
88
|
+
"",
|
|
89
|
+
"Parent Session ID: parent-session-2",
|
|
90
|
+
"",
|
|
91
|
+
"Created At: 2026-04-09T09:00:00.000Z",
|
|
92
|
+
].join("\n"),
|
|
93
|
+
statusTone: "success",
|
|
94
|
+
action: {
|
|
95
|
+
kind: "open-session",
|
|
96
|
+
sessionId: "child-session-2",
|
|
97
|
+
sessionKind: "child",
|
|
98
|
+
agentId: "verifier-agent",
|
|
99
|
+
label: "Verifier",
|
|
100
|
+
parentSessionId: "parent-session-2",
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
});
|