@nextclaw/ui 0.11.21 → 0.11.23
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 +24 -0
- package/dist/assets/{ChannelsList-ByHWHkQS.js → ChannelsList-DVDu1xvz.js} +6 -6
- package/dist/assets/ChatPage-Z9tRzm_n.js +43 -0
- package/dist/assets/DocBrowser-B9OaZjmg.js +1 -0
- package/dist/assets/{DocBrowser-3y_NHZ71.js → DocBrowser-BmtBLFU0.js} +1 -1
- package/dist/assets/{DocBrowserContext-CVJuwCcw.js → DocBrowserContext-YIKkPb76.js} +1 -1
- package/dist/assets/{LogoBadge-D8fyilO-.js → LogoBadge-F7ZWdxLT.js} +1 -1
- package/dist/assets/{MarketplacePage-CmhsZXr1.js → MarketplacePage-Buo9HrOz.js} +2 -2
- package/dist/assets/MarketplacePage-D6rVQEQR.js +1 -0
- package/dist/assets/{McpMarketplacePage-C7PkCYbp.js → McpMarketplacePage-JnkYwK7p.js} +2 -2
- package/dist/assets/ModelConfig-BYRhgp0c.js +1 -0
- package/dist/assets/ProvidersList-DmLyyHvX.js +1 -0
- package/dist/assets/RemoteAccessPage-CDSSvH7Z.js +1 -0
- package/dist/assets/RuntimeConfig-v7a7Fe3x.js +1 -0
- package/dist/assets/{SearchConfig-Dm7r2yfp.js → SearchConfig-D5f1EkLE.js} +1 -1
- package/dist/assets/{SecretsConfig-BBP_mbQh.js → SecretsConfig-D61IKcYt.js} +2 -2
- package/dist/assets/{SessionsConfig-6wNJloZN.js → SessionsConfig-BRIxVTEv.js} +2 -2
- package/dist/assets/{book-open-B26jGBjY.js → book-open-CXoF5nQC.js} +1 -1
- package/dist/assets/chat-session-display-D0WpnuRZ.js +1 -0
- package/dist/assets/{chunk-JZWAC4HX-B-4B29RN.js → chunk-JZWAC4HX-CvRWvTy5.js} +1 -1
- package/dist/assets/{config-BaC29Qf-.js → config-DJswxxE8.js} +1 -1
- package/dist/assets/{createLucideIcon-DiFAvXmK.js → createLucideIcon-CjGHOWb6.js} +1 -1
- package/dist/assets/{dist-pCfWPG1A.js → dist-Cl2QB-2y.js} +1 -1
- package/dist/assets/{dist-kW_O3kyZ.js → dist-nqTTbVdA.js} +1 -1
- package/dist/assets/{external-link-D5-p-Gmm.js → external-link-tIO7zING.js} +1 -1
- package/dist/assets/{hash-BlwrSV0q.js → hash-JWUyl1pT.js} +1 -1
- package/dist/assets/i18n-CDHMXlRZ.js +1 -0
- package/dist/assets/{index-DvKS3L9j.js → index-BuwbBgmT.js} +3 -3
- package/dist/assets/index-bZ8cqQIS.css +1 -0
- package/dist/assets/{label-RyXfZqkP.js → label-BIpeNu4r.js} +1 -1
- package/dist/assets/loader-circle-Cs8XVFTw.js +1 -0
- package/dist/assets/{logos-Bpl8QTgI.js → logos-DThdM9lk.js} +1 -1
- package/dist/assets/{page-layout--S0YBU0W.js → page-layout-D3Xo605Z.js} +1 -1
- package/dist/assets/plus-PHf8q-Ct.js +1 -0
- package/dist/assets/{popover-BEjfbEwy.js → popover-BJRUGA_H.js} +1 -1
- package/dist/assets/provider-models-bz5y28rq.js +1 -0
- package/dist/assets/{react-BuSP2-8B.js → react-7ZHqQtEV.js} +1 -1
- package/dist/assets/refresh-ccw-CC6-_QuL.js +1 -0
- package/dist/assets/{save-DPPPpD_c.js → save-DJM5RRWW.js} +1 -1
- package/dist/assets/search-C91yH_6y.js +1 -0
- package/dist/assets/{security-config-6t78Ph-I.js → security-config-DbUyWcQz.js} +1 -1
- package/dist/assets/{select-CT50pzod.js → select-DSkTc61S.js} +1 -1
- package/dist/assets/skeleton-Dzg-HOiN.js +1 -0
- package/dist/assets/{status-dot-BbBqRHfh.js → status-dot-LNBlDu3q.js} +1 -1
- package/dist/assets/{switch-D3l6AcCk.js → switch-Bo-Y46HZ.js} +1 -1
- package/dist/assets/tabs-custom-DXv507_2.js +1 -0
- package/dist/assets/{trash-2-B2_AGVE3.js → trash-2-DFZmW6Gg.js} +1 -1
- package/dist/assets/useConfirmDialog-COwYXDKm.js +1 -0
- package/dist/assets/{useMutation-BzCrO8j-.js → useMutation-DrZrOgVL.js} +1 -1
- package/dist/assets/x-D7Q1yqSF.js +1 -0
- package/dist/index.html +18 -18
- package/package.json +6 -6
- package/src/api/ncp-session.test.ts +37 -0
- package/src/api/ncp-session.ts +29 -1
- package/src/api/server-path.ts +23 -0
- package/src/api/types.ts +45 -0
- package/src/components/chat/ChatConversationPanel.test.tsx +53 -9
- package/src/components/chat/ChatConversationPanel.tsx +122 -79
- package/src/components/chat/ChatSidebar.test.tsx +2 -2
- package/src/components/chat/ChatSidebar.tsx +2 -2
- package/src/components/chat/adapters/chat-input-bar.adapter.test.ts +1 -0
- package/src/components/chat/adapters/chat-input-bar.adapter.ts +7 -2
- package/src/components/chat/adapters/chat-message-part.adapter.ts +26 -14
- package/src/components/chat/adapters/chat-message.adapter.test.ts +159 -13
- package/src/components/chat/adapters/chat-message.session-request-tool-card.ts +191 -0
- package/src/components/chat/adapters/{chat-message.file-operation-card.ts → file-operation/card.ts} +74 -181
- package/src/components/chat/adapters/{chat-message.file-operation-diff.ts → file-operation/diff.ts} +178 -188
- package/src/components/chat/adapters/file-operation/line-builder.ts +249 -0
- package/src/components/chat/adapters/file-operation/record-readers.ts +233 -0
- package/src/components/chat/chat-child-session-panel.tsx +100 -0
- package/src/components/chat/chat-composer-state.ts +3 -3
- package/src/components/chat/chat-page-runtime.test.ts +1 -0
- package/src/components/chat/chat-session-display.test.ts +22 -0
- package/src/components/chat/chat-session-display.ts +6 -1
- package/src/components/chat/containers/chat-input-bar.container.tsx +21 -24
- package/src/components/chat/containers/chat-message-list.container.tsx +4 -0
- package/src/components/chat/hooks/use-chat-session-label.ts +19 -0
- package/src/components/chat/hooks/use-chat-session-project.test.tsx +117 -0
- package/src/components/chat/hooks/use-chat-session-project.ts +40 -0
- package/src/components/chat/{chat-session-label.service.ts → hooks/use-chat-session-update.ts} +11 -7
- package/src/components/chat/managers/chat-session-list.manager.ts +5 -1
- package/src/components/chat/ncp/NcpChatPage.tsx +219 -116
- package/src/components/chat/ncp/ncp-chat-page-data.test.ts +33 -0
- package/src/components/chat/ncp/ncp-chat-page-data.ts +21 -15
- package/src/components/chat/ncp/ncp-chat-thread.manager.ts +49 -0
- package/src/components/chat/ncp/ncp-session-adapter.test.ts +24 -0
- package/src/components/chat/ncp/ncp-session-adapter.ts +47 -0
- package/src/components/chat/ncp/use-ncp-session-list-view.ts +10 -1
- package/src/components/chat/presenter/chat-presenter-context.tsx +4 -1
- package/src/components/chat/session-header/chat-session-header-actions.test.tsx +63 -0
- package/src/components/chat/session-header/chat-session-header-actions.tsx +95 -0
- package/src/components/chat/session-header/chat-session-header-menu-item.tsx +35 -0
- package/src/components/chat/session-header/chat-session-project-badge.test.tsx +66 -0
- package/src/components/chat/session-header/chat-session-project-badge.tsx +102 -0
- package/src/components/chat/session-header/chat-session-project-dialog.tsx +34 -0
- package/src/components/chat/stores/chat-input.store.ts +6 -3
- package/src/components/chat/stores/chat-thread.store.ts +17 -3
- package/src/components/chat/useHydratedNcpAgent.test.tsx +30 -23
- package/src/components/path-picker/server-path-picker-dialog.test.tsx +92 -0
- package/src/components/path-picker/server-path-picker-dialog.tsx +282 -0
- package/src/hooks/server-path/use-server-path-browse.ts +19 -0
- package/src/hooks/useConfig.ts +26 -1
- package/src/lib/i18n/i18n-language-owner.ts +94 -0
- package/src/lib/i18n/i18n.path-picker.ts +12 -0
- package/src/lib/i18n.chat.ts +23 -0
- package/src/lib/i18n.ts +21 -84
- package/src/lib/session-project/session-project.utils.ts +30 -0
- package/dist/assets/ChatPage-FdT3pDnw.js +0 -42
- package/dist/assets/DocBrowser-CMdPdbZj.js +0 -1
- package/dist/assets/MarketplacePage-9oKmxN2n.js +0 -1
- package/dist/assets/ModelConfig-DmCY6jWM.js +0 -1
- package/dist/assets/ProvidersList-ClT-34aX.js +0 -1
- package/dist/assets/RemoteAccessPage-B6hUZl1O.js +0 -1
- package/dist/assets/RuntimeConfig-C5aqliGk.js +0 -1
- package/dist/assets/chat-session-display-Bjmn4aIZ.js +0 -1
- package/dist/assets/i18n-CSytxMFI.js +0 -1
- package/dist/assets/index-CUy6doWo.css +0 -1
- package/dist/assets/loader-circle-B2J777gj.js +0 -1
- package/dist/assets/plus-CM9XJ0Tf.js +0 -1
- package/dist/assets/provider-models-C8JQUd1E.js +0 -1
- package/dist/assets/search-Ctaw34Kp.js +0 -1
- package/dist/assets/skeleton-Bycyb0zU.js +0 -1
- package/dist/assets/tabs-custom-TZQ5WPWP.js +0 -1
- package/dist/assets/useConfirmDialog-BDpdjfIO.js +0 -1
- package/dist/assets/x-CHOBE-63.js +0 -1
- package/src/components/chat/adapters/chat-message.subagent-tool-card.ts +0 -154
- /package/dist/assets/{config-hints-fGnUjDe9.js → config-hints-WtpHP_DW.js} +0 -0
- /package/dist/assets/{config-layout-B-7erZRN.js → config-layout-LQ10ozRC.js} +0 -0
- /package/dist/assets/{marketplace-localization-CXeGRf6E.js → marketplace-localization-CxSTG9wr.js} +0 -0
|
@@ -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
|
|
226
|
+
it("renders session request tool cards from structured child-session status updates", () => {
|
|
227
227
|
const adapted = adapt([
|
|
228
228
|
{
|
|
229
229
|
id: "assistant-subagent",
|
|
@@ -237,12 +237,15 @@ it("renders spawn tool cards from structured subagent status updates", () => {
|
|
|
237
237
|
toolName: "spawn",
|
|
238
238
|
args: '{"label":"Verifier","task":"Verify 1+1=2"}',
|
|
239
239
|
result: {
|
|
240
|
-
kind: "nextclaw.
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
kind: "nextclaw.session_request",
|
|
241
|
+
requestId: "request-1",
|
|
242
|
+
sessionId: "child-session-1",
|
|
243
|
+
isChildSession: true,
|
|
244
|
+
title: "Verifier",
|
|
243
245
|
task: "Verify 1+1=2",
|
|
244
246
|
status: "completed",
|
|
245
|
-
|
|
247
|
+
finalResponseText: "Verified 1+1=2.",
|
|
248
|
+
parentSessionId: "parent-session-1",
|
|
246
249
|
},
|
|
247
250
|
},
|
|
248
251
|
},
|
|
@@ -254,21 +257,92 @@ it("renders spawn tool cards from structured subagent status updates", () => {
|
|
|
254
257
|
type: "tool-card",
|
|
255
258
|
card: {
|
|
256
259
|
toolName: "spawn",
|
|
257
|
-
summary: "
|
|
260
|
+
summary: "title: Verifier · session: child-session-1 · task: Verify 1+1=2",
|
|
258
261
|
output: [
|
|
259
|
-
"
|
|
262
|
+
"Request ID: request-1",
|
|
260
263
|
"",
|
|
261
|
-
"
|
|
264
|
+
"Session ID: child-session-1",
|
|
265
|
+
"",
|
|
266
|
+
"Target: child",
|
|
267
|
+
"",
|
|
268
|
+
"Title: Verifier",
|
|
262
269
|
"",
|
|
263
270
|
"Task:",
|
|
264
271
|
"Verify 1+1=2",
|
|
265
272
|
"",
|
|
266
|
-
"
|
|
273
|
+
"Final Response:",
|
|
267
274
|
"Verified 1+1=2.",
|
|
268
275
|
].join("\n"),
|
|
269
276
|
statusTone: "success",
|
|
270
277
|
statusLabel: "Completed",
|
|
271
278
|
titleLabel: "Tool Result",
|
|
279
|
+
action: {
|
|
280
|
+
kind: "open-session",
|
|
281
|
+
sessionId: "child-session-1",
|
|
282
|
+
sessionKind: "child",
|
|
283
|
+
label: "Verifier",
|
|
284
|
+
parentSessionId: "parent-session-1",
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("renders regular session request tool cards with session navigation instead of child navigation", () => {
|
|
291
|
+
const adapted = adapt([
|
|
292
|
+
{
|
|
293
|
+
id: "assistant-session-request",
|
|
294
|
+
role: "assistant",
|
|
295
|
+
parts: [
|
|
296
|
+
{
|
|
297
|
+
type: "tool-invocation",
|
|
298
|
+
toolInvocation: {
|
|
299
|
+
status: ToolInvocationStatus.RESULT,
|
|
300
|
+
toolCallId: "session-request-call-1",
|
|
301
|
+
toolName: "sessions_request",
|
|
302
|
+
args: '{"sessionId":"session-2","task":"Summarize the latest findings"}',
|
|
303
|
+
result: {
|
|
304
|
+
kind: "nextclaw.session_request",
|
|
305
|
+
requestId: "request-2",
|
|
306
|
+
sessionId: "session-2",
|
|
307
|
+
isChildSession: false,
|
|
308
|
+
title: "Research thread",
|
|
309
|
+
task: "Summarize the latest findings",
|
|
310
|
+
status: "completed",
|
|
311
|
+
finalResponseText: "Here is the summary.",
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
},
|
|
317
|
+
] as unknown as ChatMessageSource[]);
|
|
318
|
+
|
|
319
|
+
expect(adapted[0]?.parts[0]).toMatchObject({
|
|
320
|
+
type: "tool-card",
|
|
321
|
+
card: {
|
|
322
|
+
toolName: "sessions_request",
|
|
323
|
+
summary: "title: Research thread · session: session-2 · task: Summarize the latest findings",
|
|
324
|
+
output: [
|
|
325
|
+
"Request ID: request-2",
|
|
326
|
+
"",
|
|
327
|
+
"Session ID: session-2",
|
|
328
|
+
"",
|
|
329
|
+
"Target: session",
|
|
330
|
+
"",
|
|
331
|
+
"Title: Research thread",
|
|
332
|
+
"",
|
|
333
|
+
"Task:",
|
|
334
|
+
"Summarize the latest findings",
|
|
335
|
+
"",
|
|
336
|
+
"Final Response:",
|
|
337
|
+
"Here is the summary.",
|
|
338
|
+
].join("\n"),
|
|
339
|
+
statusTone: "success",
|
|
340
|
+
action: {
|
|
341
|
+
kind: "open-session",
|
|
342
|
+
sessionId: "session-2",
|
|
343
|
+
sessionKind: "session",
|
|
344
|
+
label: "Research thread",
|
|
345
|
+
},
|
|
272
346
|
},
|
|
273
347
|
});
|
|
274
348
|
});
|
|
@@ -488,6 +562,11 @@ it("builds edit-file previews from structured args before the tool finishes", ()
|
|
|
488
562
|
},
|
|
489
563
|
] as unknown as ChatMessageSource[]);
|
|
490
564
|
|
|
565
|
+
const editLines =
|
|
566
|
+
adapted[0]?.parts[0]?.type === "tool-card"
|
|
567
|
+
? (adapted[0].parts[0].card.fileOperation?.blocks[0]?.lines ?? [])
|
|
568
|
+
: [];
|
|
569
|
+
|
|
491
570
|
expect(adapted[0]?.parts[0]).toMatchObject({
|
|
492
571
|
type: "tool-card",
|
|
493
572
|
card: {
|
|
@@ -513,6 +592,71 @@ it("builds edit-file previews from structured args before the tool finishes", ()
|
|
|
513
592
|
},
|
|
514
593
|
},
|
|
515
594
|
});
|
|
595
|
+
expect(editLines[0]).not.toHaveProperty("oldLineNumber");
|
|
596
|
+
expect(editLines[1]).not.toHaveProperty("newLineNumber");
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
it("uses structured edit-file result line numbers after the tool finishes", () => {
|
|
600
|
+
const adapted = adapt([
|
|
601
|
+
{
|
|
602
|
+
id: "assistant-edit-result",
|
|
603
|
+
role: "assistant",
|
|
604
|
+
parts: [
|
|
605
|
+
{
|
|
606
|
+
type: "tool-invocation",
|
|
607
|
+
toolInvocation: {
|
|
608
|
+
status: ToolInvocationStatus.RESULT,
|
|
609
|
+
toolCallId: "edit-result-1",
|
|
610
|
+
toolName: "edit_file",
|
|
611
|
+
args: JSON.stringify({
|
|
612
|
+
path: "src/app.ts",
|
|
613
|
+
oldText: "const color = 'red';",
|
|
614
|
+
newText: "const color = 'blue';",
|
|
615
|
+
}),
|
|
616
|
+
parsedArgs: {
|
|
617
|
+
path: "src/app.ts",
|
|
618
|
+
oldText: "const color = 'red';",
|
|
619
|
+
newText: "const color = 'blue';",
|
|
620
|
+
},
|
|
621
|
+
result: {
|
|
622
|
+
path: "src/app.ts",
|
|
623
|
+
oldStartLine: 27,
|
|
624
|
+
newStartLine: 27,
|
|
625
|
+
message: "Edited src/app.ts",
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
],
|
|
630
|
+
},
|
|
631
|
+
] as unknown as ChatMessageSource[]);
|
|
632
|
+
|
|
633
|
+
expect(adapted[0]?.parts[0]).toMatchObject({
|
|
634
|
+
type: "tool-card",
|
|
635
|
+
card: {
|
|
636
|
+
toolName: "edit_file",
|
|
637
|
+
summary: "src/app.ts",
|
|
638
|
+
statusTone: "success",
|
|
639
|
+
fileOperation: {
|
|
640
|
+
blocks: [
|
|
641
|
+
{
|
|
642
|
+
path: "src/app.ts",
|
|
643
|
+
lines: [
|
|
644
|
+
{
|
|
645
|
+
kind: "remove",
|
|
646
|
+
text: "const color = 'red';",
|
|
647
|
+
oldLineNumber: 27,
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
kind: "add",
|
|
651
|
+
text: "const color = 'blue';",
|
|
652
|
+
newLineNumber: 27,
|
|
653
|
+
},
|
|
654
|
+
],
|
|
655
|
+
},
|
|
656
|
+
],
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
});
|
|
516
660
|
});
|
|
517
661
|
|
|
518
662
|
it("builds write-file previews from partial native args before the JSON is complete", () => {
|
|
@@ -577,7 +721,7 @@ it("keeps completed write-file cards in preview mode instead of falling back to
|
|
|
577
721
|
toolName: "write_file",
|
|
578
722
|
args: JSON.stringify({
|
|
579
723
|
path: "games/snake.html",
|
|
580
|
-
content:
|
|
724
|
+
content: '<!DOCTYPE html>\n<canvas id="game"></canvas>',
|
|
581
725
|
}),
|
|
582
726
|
result: "Wrote 3906 bytes to games/snake.html",
|
|
583
727
|
},
|
|
@@ -605,7 +749,7 @@ it("keeps completed write-file cards in preview mode instead of falling back to
|
|
|
605
749
|
},
|
|
606
750
|
{
|
|
607
751
|
kind: "add",
|
|
608
|
-
text:
|
|
752
|
+
text: '<canvas id="game"></canvas>',
|
|
609
753
|
newLineNumber: 2,
|
|
610
754
|
},
|
|
611
755
|
],
|
|
@@ -641,7 +785,7 @@ it("renders codex file_change results as structured diff previews", () => {
|
|
|
641
785
|
diff: [
|
|
642
786
|
"--- a/src/main.ts",
|
|
643
787
|
"+++ b/src/main.ts",
|
|
644
|
-
"@@",
|
|
788
|
+
"@@ -109,1 +109,1 @@",
|
|
645
789
|
"-console.log('old');",
|
|
646
790
|
"+console.log('new');",
|
|
647
791
|
].join("\n"),
|
|
@@ -656,7 +800,7 @@ it("renders codex file_change results as structured diff previews", () => {
|
|
|
656
800
|
diff: [
|
|
657
801
|
"--- a/src/main.ts",
|
|
658
802
|
"+++ b/src/main.ts",
|
|
659
|
-
"@@",
|
|
803
|
+
"@@ -109,1 +109,1 @@",
|
|
660
804
|
"-console.log('old');",
|
|
661
805
|
"+console.log('new');",
|
|
662
806
|
].join("\n"),
|
|
@@ -683,10 +827,12 @@ it("renders codex file_change results as structured diff previews", () => {
|
|
|
683
827
|
{
|
|
684
828
|
kind: "remove",
|
|
685
829
|
text: "console.log('old');",
|
|
830
|
+
oldLineNumber: 109,
|
|
686
831
|
},
|
|
687
832
|
{
|
|
688
833
|
kind: "add",
|
|
689
834
|
text: "console.log('new');",
|
|
835
|
+
newLineNumber: 109,
|
|
690
836
|
},
|
|
691
837
|
],
|
|
692
838
|
},
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import {
|
|
2
|
+
stringifyUnknown,
|
|
3
|
+
summarizeToolArgs,
|
|
4
|
+
type ToolCard,
|
|
5
|
+
} from "@/lib/chat-message";
|
|
6
|
+
import type { ChatToolPartViewModel } from "@nextclaw/agent-chat-ui";
|
|
7
|
+
|
|
8
|
+
type ToolCardViewSource = ToolCard & {
|
|
9
|
+
statusTone: ChatToolPartViewModel["statusTone"];
|
|
10
|
+
statusLabel: string;
|
|
11
|
+
action?: ChatToolPartViewModel["action"];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type SessionRequestInvocation = {
|
|
15
|
+
toolName: string;
|
|
16
|
+
toolCallId?: string;
|
|
17
|
+
args?: unknown;
|
|
18
|
+
result?: unknown;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type SessionRequestToolCardTexts = {
|
|
22
|
+
toolStatusRunningLabel: string;
|
|
23
|
+
toolStatusCompletedLabel: string;
|
|
24
|
+
toolStatusFailedLabel: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type SessionRequestResult = {
|
|
28
|
+
kind: string;
|
|
29
|
+
requestId?: string;
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
isChildSession?: boolean;
|
|
32
|
+
title?: string;
|
|
33
|
+
task?: string;
|
|
34
|
+
status?: string;
|
|
35
|
+
message?: unknown;
|
|
36
|
+
finalResponseText?: unknown;
|
|
37
|
+
error?: unknown;
|
|
38
|
+
parentSessionId?: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
42
|
+
return typeof value === "object" && value !== null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function readOptionalString(value: unknown): string | null {
|
|
46
|
+
if (typeof value !== "string") {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const trimmed = value.trim();
|
|
50
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function readSessionRequestResult(value: unknown): SessionRequestResult | null {
|
|
54
|
+
if (!isRecord(value) || value.kind !== "nextclaw.session_request") {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return value as SessionRequestResult;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function buildSessionRequestDetail(
|
|
61
|
+
result: SessionRequestResult,
|
|
62
|
+
fallbackArgs: unknown,
|
|
63
|
+
): string | undefined {
|
|
64
|
+
const detailParts = [
|
|
65
|
+
readOptionalString(result.title)
|
|
66
|
+
? `title: ${result.title?.trim()}`
|
|
67
|
+
: null,
|
|
68
|
+
readOptionalString(result.sessionId)
|
|
69
|
+
? `session: ${result.sessionId?.trim()}`
|
|
70
|
+
: null,
|
|
71
|
+
readOptionalString(result.task)
|
|
72
|
+
? `task: ${result.task?.trim()}`
|
|
73
|
+
: null,
|
|
74
|
+
].filter((value): value is string => Boolean(value));
|
|
75
|
+
|
|
76
|
+
return detailParts.join(" · ") || summarizeToolArgs(fallbackArgs);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function buildSessionRequestOutput(result: SessionRequestResult): string | undefined {
|
|
80
|
+
const requestId = readOptionalString(result.requestId);
|
|
81
|
+
const sessionId = readOptionalString(result.sessionId);
|
|
82
|
+
const title = readOptionalString(result.title);
|
|
83
|
+
const task = readOptionalString(result.task);
|
|
84
|
+
const messageText =
|
|
85
|
+
typeof result.message !== "undefined"
|
|
86
|
+
? stringifyUnknown(result.message).trim()
|
|
87
|
+
: "";
|
|
88
|
+
const finalResponseText =
|
|
89
|
+
typeof result.finalResponseText !== "undefined"
|
|
90
|
+
? stringifyUnknown(result.finalResponseText).trim()
|
|
91
|
+
: "";
|
|
92
|
+
const errorText =
|
|
93
|
+
typeof result.error !== "undefined"
|
|
94
|
+
? stringifyUnknown(result.error).trim()
|
|
95
|
+
: "";
|
|
96
|
+
|
|
97
|
+
const sections = [
|
|
98
|
+
requestId ? `Request ID: ${requestId}` : null,
|
|
99
|
+
sessionId ? `Session ID: ${sessionId}` : null,
|
|
100
|
+
typeof result.isChildSession === "boolean"
|
|
101
|
+
? `Target: ${result.isChildSession ? "child" : "session"}`
|
|
102
|
+
: null,
|
|
103
|
+
title ? `Title: ${title}` : null,
|
|
104
|
+
task ? `Task:\n${task}` : null,
|
|
105
|
+
finalResponseText
|
|
106
|
+
? `Final Response:\n${finalResponseText}`
|
|
107
|
+
: errorText
|
|
108
|
+
? `Error:\n${errorText}`
|
|
109
|
+
: messageText
|
|
110
|
+
? `Status:\n${messageText}`
|
|
111
|
+
: null,
|
|
112
|
+
].filter((value): value is string => Boolean(value));
|
|
113
|
+
|
|
114
|
+
return sections.length > 0 ? sections.join("\n\n") : undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function buildSessionRequestToolCard(params: {
|
|
118
|
+
invocation: SessionRequestInvocation;
|
|
119
|
+
texts: SessionRequestToolCardTexts;
|
|
120
|
+
}): ToolCardViewSource | null {
|
|
121
|
+
if (
|
|
122
|
+
params.invocation.toolName !== "spawn" &&
|
|
123
|
+
params.invocation.toolName !== "sessions_request"
|
|
124
|
+
) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const sessionRequest = readSessionRequestResult(params.invocation.result);
|
|
129
|
+
if (!sessionRequest) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const normalizedStatus = readOptionalString(sessionRequest.status)?.toLowerCase();
|
|
134
|
+
const detail = buildSessionRequestDetail(sessionRequest, params.invocation.args);
|
|
135
|
+
const output = buildSessionRequestOutput(sessionRequest);
|
|
136
|
+
const targetSessionId = readOptionalString(sessionRequest.sessionId);
|
|
137
|
+
const action =
|
|
138
|
+
targetSessionId
|
|
139
|
+
? {
|
|
140
|
+
kind: "open-session" as const,
|
|
141
|
+
sessionId: targetSessionId,
|
|
142
|
+
sessionKind: sessionRequest.isChildSession === true ? ("child" as const) : ("session" as const),
|
|
143
|
+
...(readOptionalString(sessionRequest.title)
|
|
144
|
+
? { label: sessionRequest.title!.trim() }
|
|
145
|
+
: {}),
|
|
146
|
+
...(readOptionalString(sessionRequest.parentSessionId)
|
|
147
|
+
? { parentSessionId: sessionRequest.parentSessionId!.trim() }
|
|
148
|
+
: {}),
|
|
149
|
+
}
|
|
150
|
+
: undefined;
|
|
151
|
+
|
|
152
|
+
if (normalizedStatus === "failed") {
|
|
153
|
+
return {
|
|
154
|
+
kind: "result",
|
|
155
|
+
name: params.invocation.toolName,
|
|
156
|
+
detail,
|
|
157
|
+
text: output,
|
|
158
|
+
callId: params.invocation.toolCallId || undefined,
|
|
159
|
+
hasResult: Boolean(output),
|
|
160
|
+
statusTone: "error",
|
|
161
|
+
statusLabel: params.texts.toolStatusFailedLabel,
|
|
162
|
+
...(action ? { action } : {}),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (normalizedStatus === "completed") {
|
|
167
|
+
return {
|
|
168
|
+
kind: "result",
|
|
169
|
+
name: params.invocation.toolName,
|
|
170
|
+
detail,
|
|
171
|
+
text: output,
|
|
172
|
+
callId: params.invocation.toolCallId || undefined,
|
|
173
|
+
hasResult: Boolean(output),
|
|
174
|
+
statusTone: "success",
|
|
175
|
+
statusLabel: params.texts.toolStatusCompletedLabel,
|
|
176
|
+
...(action ? { action } : {}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
kind: "result",
|
|
182
|
+
name: params.invocation.toolName,
|
|
183
|
+
detail,
|
|
184
|
+
text: output,
|
|
185
|
+
callId: params.invocation.toolCallId || undefined,
|
|
186
|
+
hasResult: Boolean(output),
|
|
187
|
+
statusTone: "running",
|
|
188
|
+
statusLabel: params.texts.toolStatusRunningLabel,
|
|
189
|
+
...(action ? { action } : {}),
|
|
190
|
+
};
|
|
191
|
+
}
|