@nextclaw/ui 0.19.2 → 0.19.4
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 +20 -1
- package/dist/assets/{abnfDiagram-VRR7QNED-DvTjgVMf.js → abnfDiagram-VRR7QNED-DrbfiNNF.js} +1 -1
- package/dist/assets/{aiden0z-pptx-renderer.es-C1nfBAXR.js → aiden0z-pptx-renderer.es-DdLb2IVc.js} +1 -1
- package/dist/assets/{api-BH6Oslx4.js → api-CUSlBpt_.js} +3 -3
- package/dist/assets/{appearance-settings-page-zhgfcGgW.js → appearance-settings-page-cTuZdROP.js} +1 -1
- package/dist/assets/{arc-BvhODBXv.js → arc-BXlMc9B0.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-Bq0i9WiE.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-BKO9RgNS.js → architectureDiagram-ZJ3FMSHR-DXAJxxO0.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-DHpDXy7D.js → blockDiagram-677ZJIJ3-i4Kz7zU0.js} +1 -1
- package/dist/assets/{book-open-DGTS6oEO.js → book-open-BJ-xAIp9.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-BG_iQnDr.js → c4Diagram-LMCZKHZV-BDc0TkPd.js} +1 -1
- package/dist/assets/channel-iCaZQ87u.js +1 -0
- package/dist/assets/{channels-list-page-3D5lhZoT.js → channels-list-page-nRHOasWA.js} +2 -2
- package/dist/assets/chunk-2Q5K7J3B-DFQtlnJS.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-DR9M0LLx.js → chunk-32BRIVSS-DuReei0Z.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-698iC3BB.js → chunk-52WLFC77-D8APq0tm.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-DikTj9Ey.js → chunk-5FCAYU7R-BsPrNXNS.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-ko0o7_q0.js → chunk-5HE753X5-BRtkOPoJ.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CEHufhgo.js → chunk-5JV3BV7I-ChPc8e8U.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CGgno1cu.js → chunk-5TONJI2A-CzTjlJGb.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DkiB4cUQ.js → chunk-5VM5RSS4-xsv_22jR.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-DzptcytQ.js → chunk-7BUUIJ7U-CwECujme.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-DMRSQJvT.js → chunk-BIQX33UG-DQAm173p.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-Bw1BwwuY.js → chunk-C7G6YPKG-BkpajeQb.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-C0z6eHBk.js → chunk-CQNSW5MT-ND65pWRA.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-ByPyAouO.js → chunk-CYSBUYHQ-vMu6ijxG.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-CJlAXWZg.js → chunk-EMLP6XTP-CEaeW3gH.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-Dqq4zKJu.js → chunk-EX3LRPZG-a4ER-HDr.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-B0SNoCmi.js → chunk-FWX5IMBZ-C_8fQssn.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-DG_GJih_.js → chunk-HOUHSVGY-CEvw-PEd.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-Drxk_6bE.js → chunk-ICXQ74PX-BEtF0fGY.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DdLFPpnd.js → chunk-JG7HCLWE-DGRrVp8-.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-B8M4G76F.js → chunk-JWPE2WC7-DRqpp_nM.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-XP6FJHY_.js → chunk-MOJQB5TN-BDEriOXs.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-C_6x18Qw.js → chunk-MOZMSUNE-JWRNzdnw.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-N25BzCmG.js → chunk-OGEWGWER-DS2VTgCx.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-ASDEm7y0.js → chunk-OSBZ3O6U-3LiYTBUB.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-CTlvAcn7.js → chunk-PUDLZKDR-o9M2s_SO.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-Da9BWfB6.js → chunk-Q4XR5HBZ-DTB7Ma2N.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-Bi6RpTJO.js → chunk-QBLGF6JB-DpkxZJL5.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-DkMsSPvK.js → chunk-R7FJI6CG-CRejkHJU.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-DZp0eU-j.js → chunk-RYQCIY6F-B1boBjLt.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-vfinDSrj.js → chunk-U6XO7XAA-DgKa97bj.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-C9Nksccs.js → chunk-V7JOEXUC-DE56eh0N.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-CF9A-TeE.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-Xv6zfwXs.js → chunk-VR4S4FIN-BzomPZq2.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-mOJNzbWl.js → chunk-WYO6CB5R-C6gy8rSd.js} +2 -2
- package/dist/assets/chunk-XXDRQBXY-BRxdfVCU.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-1-aKSu4o.js → chunk-YOTPTUD7-BK98yfl9.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-OJ8veMpK.js → chunk-ZGVPDNZ5-DFXAhwUT.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-SR_Nq_PP.js → chunk-ZIRB5QZD-Bbu6BiNC.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Bo28fPi-.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-BOVN9wUz.js +1 -0
- package/dist/assets/{config-split-page-B55XD_ZY.js → config-split-page-DO1Oyb-r.js} +1 -1
- package/dist/assets/{confirm-dialog-BCCreI_f.js → confirm-dialog-CCae9Fr4.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-NjVgz2Bw.js → cose-bilkent-JH36ORCC-BV8KR4uF.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-B7rF3JRp.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-B_17LDqD.js → cynefinDiagram-TSTJHNR4-Ckd6nU9t.js} +1 -1
- package/dist/assets/{dagre-CMe101gk.js → dagre-D_T-FW5i.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-qo8nLb3B.js → dagre-VKFMJZFB-CyDaQpD4.js} +1 -1
- package/dist/assets/desktop-update-config-XSV-DjJW.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-Ba3XIklC.js → diagram-FQU43EPY-CghnwS0H.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-CG45TcUx.js → diagram-G47NLZAW-DK4DJ3Kx.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-2F2HrwV-.js → diagram-NH7WQ7WH-CUgDkZCJ.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CXfWH9NZ.js → diagram-OA4YK3LP-vO2gyH6n.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-CH_4yepc.js → diagram-WEI45ONY-DbSBRDSr.js} +1 -1
- package/dist/assets/{dist-IRWcJpfm.js → dist-1N9UpL3c.js} +1 -1
- package/dist/assets/{dist-BYSUQaO2.js → dist-C-2H76Cv.js} +1 -1
- package/dist/assets/doc-browser-BHFCZIoL.js +1 -0
- package/dist/assets/{doc-browser-D8rNrWHk.js → doc-browser-CRlpqMwH.js} +1 -1
- package/dist/assets/{doc-browser-context-DjTbIbQc.js → doc-browser-context-C0Bns1J6.js} +1 -1
- package/dist/assets/{docx-preview-CoM4JK7_.js → docx-preview-DfxIm9IB.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BwiG4Ea1.js → ebnfDiagram-CCIWWBDH-W7CAcK7r.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-BML3hpnQ.js → erDiagram-Q63AITRT-LA0JWL8-.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-DzQLXa3s.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-C81eexJZ.js +1 -0
- package/dist/assets/{form-actions-C8hazgNP.js → form-actions-CMxhPact.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-80enfWbD.js → ganttDiagram-NO4QXBWP-_PiTPavJ.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-Dt3ZqpFD.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-CVLqXr-b.js → gitGraphDiagram-IHSO6WYX-DsRB1ZMU.js} +1 -1
- package/dist/assets/index-DdYOaKm7.js +109 -0
- package/dist/assets/index-DxCGKhAw.css +1 -0
- package/dist/assets/info-DKCQHKI2-CCCE7dXC.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-Dyvs2t0i.js → infoDiagram-FWYZ7A6U-wIRraYx5.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-sSnxDKfh.js → ishikawaDiagram-FXEZZL3T-CNzsrcrh.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-D22V71Mf.js → journeyDiagram-5HDEW3XC-Dy9huHxy.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-D3ds0p-g.js → kanban-definition-HUTT4EX6-BOCIN365.js} +1 -1
- package/dist/assets/{line-CbyFs065.js → line-BxsizOTs.js} +1 -1
- package/dist/assets/{linear-4DKtnZBS.js → linear-C_YHf92I.js} +1 -1
- package/dist/assets/loader-circle-B-UdXjl4.js +1 -0
- package/dist/assets/{map-CcZzEoz6.js → map-CobcjgZ8.js} +1 -1
- package/dist/assets/mcp-marketplace-page-BUIGtSda.js +1 -0
- package/dist/assets/mcp-marketplace-page-CStb8ml2.js +9 -0
- package/dist/assets/{mermaid-parser.core-DPmMOjXD.js → mermaid-parser.core-D7lu2RbA.js} +2 -2
- package/dist/assets/{mermaid.core-BSf-ddRa.js → mermaid.core-CbfW2Rk8.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BUTwWPyx.js → mindmap-definition-LN4V7U3C-DUjGXlIC.js} +1 -1
- package/dist/assets/model-config-page-BkfUYm95.js +1 -0
- package/dist/assets/{navigation-link-kGAcL2N2.js → navigation-link-v3FaWcIr.js} +1 -1
- package/dist/assets/{ordinal-BgLYtOZE.js → ordinal-CjoUCHto.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-D19yoxFV.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-BEu_ZBjc.js → pegDiagram-2B236MQR-BQY2DgiP.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-hMaJbLrn.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-CAwAwuBd.js → pieDiagram-ENE6RG2P-D18owe4D.js} +1 -1
- package/dist/assets/plus-Dw9QFnKr.js +1 -0
- package/dist/assets/{privacy-settings-page-v9LTFvJe.js → privacy-settings-page-CYM1Dxwo.js} +1 -1
- package/dist/assets/providers-config-page-fxL4I4bz.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-CwE6F-_2.js → quadrantDiagram-ABIIQ3AL-B8F7YoTA.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-C8BkvScA.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-CozZOitC.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-BqIoFXFi.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-CD2e3dng.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-DoKlRUOF.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-xgLekU3B.js → railroadDiagram-RFXS5EU6-RU8GpxN5.js} +1 -1
- package/dist/assets/{react-Dwvp5yeX.js → react-Dlz_IxoP.js} +1 -1
- package/dist/assets/{refresh-cw-C_oj_h_s.js → refresh-cw-CK4I5UFv.js} +1 -1
- package/dist/assets/remote-B0pPgtC6.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-CyVUzEX5.js → requirementDiagram-TGXJPOKE-ubPOmmNi.js} +1 -1
- package/dist/assets/rotate-cw-Z48dmh13.js +1 -0
- package/dist/assets/runtime-config-page-C7vksFVD.js +1 -0
- package/dist/assets/{sankeyDiagram-HTMAVEWB-JK6bFmYB.js → sankeyDiagram-HTMAVEWB-8L_hXJWW.js} +1 -1
- package/dist/assets/{save-BZE6H02N.js → save-Bo37cIFb.js} +1 -1
- package/dist/assets/{search-C7Tj40kC.js → search-CZiEm7YD.js} +1 -1
- package/dist/assets/search-config-page-DKdEf7m9.js +1 -0
- package/dist/assets/{secrets-config-page-B__VLAEQ.js → secrets-config-page-COlMqSfL.js} +2 -2
- package/dist/assets/security-config-CitLihXA.js +1 -0
- package/dist/assets/{select-fZ5tifar.js → select-BACzapV3.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BR5IokXV.js → sequenceDiagram-DBY2YBRQ-Dom6Qor5.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-SxG_YnMA.js → sizeCapture-X5ZJPWSS-cZcFSpLJ.js} +1 -1
- package/dist/assets/skeleton-B2PCAZJG.js +1 -0
- package/dist/assets/{src-vgz8E_-O.js → src-BE9E1xcR.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-DD4OoYhn.js → stateDiagram-2N3HPSRC-CHrpxmGO.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-b1pZQlDD.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-BWkFeyCT.js → swimlanes-5IMT3BWC-D6nJS2xQ.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-CowxgWVn.js +8 -0
- package/dist/assets/{tag-chip-CwYZcRoe.js → tag-chip-BnamTQVX.js} +1 -1
- package/dist/assets/{timeline-definition-FHXFAJF6-VTRPy6KA.js → timeline-definition-FHXFAJF6-DJNn-HQO.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-BQlYkJbz.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-DzTOd1bd.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-Bvk42Pek.js → vennDiagram-L72KCM5P-CCEzHoXt.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-D80jQc0y.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-DOFjx2s3.js → wardleyDiagram-EHGQE667-BhyVxVXt.js} +1 -1
- package/dist/assets/x-BzYEzkLA.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-DY5yRTUc.js → xychartDiagram-FW5EYKEG-CacW_246.js} +1 -1
- package/dist/index.html +70 -22
- package/index.html +49 -1
- package/package.json +8 -8
- package/src/app/index.tsx +1 -3
- package/src/app/managers/__tests__/viewport-layout.manager.test.ts +12 -0
- package/src/app/managers/viewport-layout.manager.ts +12 -0
- package/src/app/stores/viewport-layout.store.ts +23 -11
- package/src/features/apps/components/__tests__/app-marketplace-catalog.test.tsx +161 -0
- package/src/features/apps/components/app-marketplace-catalog.tsx +36 -7
- package/src/features/apps/components/app-marketplace-detail.tsx +29 -6
- package/src/features/apps/components/app-marketplace-dialog.tsx +71 -55
- package/src/features/apps/components/app-marketplace-operation.tsx +128 -16
- package/src/features/apps/components/app-packages-panel.tsx +1 -0
- package/src/features/apps/utils/app-marketplace-platform.utils.test.ts +59 -0
- package/src/features/apps/utils/app-marketplace-platform.utils.ts +33 -0
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +6 -0
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +6 -2
- package/src/features/chat/features/conversation/components/__tests__/session-queued-input-rows.test.tsx +46 -0
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +15 -2
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +5 -3
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +59 -5
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +35 -1
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx +25 -19
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +148 -134
- package/src/features/chat/features/conversation/hooks/use-session-pending-input-actions.ts +135 -0
- package/src/features/chat/features/conversation/hooks/use-session-run-queue.ts +19 -4
- package/src/features/chat/features/conversation/utils/__tests__/session-queued-input.utils.test.ts +52 -2
- package/src/features/chat/features/conversation/utils/session-queued-input.utils.ts +46 -5
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +1 -0
- package/src/features/chat/features/ncp/hooks/__tests__/use-hydrated-ncp-agent.test.tsx +102 -0
- package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-conversation.test.tsx +117 -1
- package/src/features/chat/features/ncp/hooks/use-ncp-session-conversation.ts +2 -2
- package/src/features/chat/features/ncp/hooks/use-ncp-session-message-history.ts +31 -81
- package/src/features/chat/features/ncp/hooks/use-ncp-session-seed-loader.ts +134 -0
- package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +1 -6
- package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +8 -0
- package/src/features/panel-apps/components/__tests__/panel-app-main-sidebar-nav.test.tsx +99 -13
- package/src/features/panel-apps/components/panel-app-main-sidebar-menu-item.tsx +4 -0
- package/src/features/panel-apps/components/panel-app-main-sidebar-nav.tsx +166 -31
- package/src/shared/lib/api/utils/ncp-attachments.utils.ts +8 -1
- package/src/shared/lib/api/utils/ncp-session.utils.ts +1 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +3 -0
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +11 -1
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +3 -0
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +11 -1
- package/src/vite-env.d.ts +9 -0
- package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +0 -1
- package/dist/assets/channel-5T3pdR-s.js +0 -1
- package/dist/assets/chat-page-BXu3hnOK.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +0 -1
- package/dist/assets/desktop-update-config-Blol-Umu.js +0 -1
- package/dist/assets/doc-browser-BExPq1Hk.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +0 -1
- package/dist/assets/index-Btj8yN4T.css +0 -1
- package/dist/assets/index-CHcGqqBe.js +0 -109
- package/dist/assets/info-DKCQHKI2-DNlNGH90.js +0 -1
- package/dist/assets/loader-circle-C75DUmmm.js +0 -1
- package/dist/assets/mcp-marketplace-page-CIMRYgOY.js +0 -9
- package/dist/assets/mcp-marketplace-page-D2NlhG1k.js +0 -1
- package/dist/assets/model-config-page-ChR-ENjp.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +0 -1
- package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +0 -1
- package/dist/assets/plus-TzSIMKWW.js +0 -1
- package/dist/assets/provider-scoped-model-input-DiSpKSk0.js +0 -1
- package/dist/assets/providers-config-page-BvXa03cp.js +0 -1
- package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +0 -1
- package/dist/assets/remote-BgYduCQR.js +0 -1
- package/dist/assets/rotate-cw-BT8HxlcB.js +0 -1
- package/dist/assets/runtime-config-page-BuYof2Ty.js +0 -1
- package/dist/assets/search-config-page-CQTJOsOf.js +0 -1
- package/dist/assets/security-config-CtJqaPVL.js +0 -1
- package/dist/assets/settings-2-BHGgNlOH.js +0 -1
- package/dist/assets/skeleton-CJLc1CWn.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +0 -1
- package/dist/assets/x-BMl7cucN.js +0 -1
- /package/dist/assets/{array-NADKd9aU.js → array-COEOjKUv.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-BuyuzJJL.js → chunk-KEIR6QF5-D7oHAcry.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-D_B2ZRNt.js → chunk-Y2CYZVJY-08IUpgTP.js} +0 -0
- /package/dist/assets/{config-hints-BcfVUMij.js → config-hints-BoE41XDI.js} +0 -0
- /package/dist/assets/{cytoscape.esm-BANTlgza.js → cytoscape.esm-HifWufkp.js} +0 -0
- /package/dist/assets/{defaultLocale-C4_L0aEs.js → defaultLocale-CA-_SsC1.js} +0 -0
- /package/dist/assets/{dist-DAPEIJbz.js → dist-C60rvfy8.js} +0 -0
- /package/dist/assets/{graphlib-ChqXg0dI.js → graphlib-CGYCNsoJ.js} +0 -0
- /package/dist/assets/{host-capabilities-D9C4CBK5.js → host-capabilities-DPNRAjIj.js} +0 -0
- /package/dist/assets/{init-D8wZg9xq.js → init-C3plFVsG.js} +0 -0
- /package/dist/assets/{jszip.min-CkbBfwAQ.js → jszip.min-CeYs17Gn.js} +0 -0
- /package/dist/assets/{katex-TZJFa0J_.js → katex-DRThweSG.js} +0 -0
- /package/dist/assets/{middleware-B3k-TSmZ.js → middleware-D05fK5Sb.js} +0 -0
- /package/dist/assets/{path-DodfxcX7.js → path-BKtKxQ6Y.js} +0 -0
- /package/dist/assets/{rough.esm-CUaa1Rbe.js → rough.esm-DurL7-u7.js} +0 -0
- /package/dist/assets/{xlsx-CxByi7bR.js → xlsx-Sg8fZ6nH.js} +0 -0
|
@@ -60,6 +60,7 @@ function createControllerParams(params: {
|
|
|
60
60
|
queuedInputs.find((item) => item.id === id) ?? null,
|
|
61
61
|
);
|
|
62
62
|
const refreshQueuedInputs = vi.fn(async () => queuedInputs);
|
|
63
|
+
const steerQueuedInput = vi.fn(async () => null);
|
|
63
64
|
return {
|
|
64
65
|
agent: {
|
|
65
66
|
abort: vi.fn(),
|
|
@@ -119,6 +120,7 @@ function createControllerParams(params: {
|
|
|
119
120
|
inputs: queuedInputs,
|
|
120
121
|
refreshQueuedInputs,
|
|
121
122
|
removeQueuedInput,
|
|
123
|
+
steerQueuedInput,
|
|
122
124
|
},
|
|
123
125
|
selectedAgentId: 'main',
|
|
124
126
|
sessionKey: 'session-1',
|
|
@@ -172,6 +174,7 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
172
174
|
|
|
173
175
|
expect(send).toHaveBeenCalledTimes(1);
|
|
174
176
|
expect(send.mock.calls[0]?.[0]).toMatchObject({
|
|
177
|
+
delivery: 'queue',
|
|
175
178
|
sessionId: 'session-1',
|
|
176
179
|
message: expect.objectContaining({
|
|
177
180
|
parts: [{ type: 'text', text: 'next task' }],
|
|
@@ -180,6 +183,22 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
180
183
|
expect(params.resetComposer).toHaveBeenCalledTimes(1);
|
|
181
184
|
});
|
|
182
185
|
|
|
186
|
+
it('uses prefer-steer for command/control-enter submission without changing the send button path', async () => {
|
|
187
|
+
const send = createSendMock(createRunHandle({ delivery: 'steered' }));
|
|
188
|
+
const params = createControllerParams({ isRunning: true, send });
|
|
189
|
+
const { result } = renderHook(() => useSessionConversationController(params));
|
|
190
|
+
|
|
191
|
+
await act(async () => {
|
|
192
|
+
await result.current.sendSteering();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
expect(send.mock.calls[0]?.[0]).toMatchObject({
|
|
196
|
+
delivery: 'prefer-steer',
|
|
197
|
+
message: { parts: [{ type: 'text', text: 'next task' }] },
|
|
198
|
+
});
|
|
199
|
+
expect(result.current.queuedInputs).toEqual([]);
|
|
200
|
+
});
|
|
201
|
+
|
|
183
202
|
it('sends a preset message without clearing the existing composer draft', async () => {
|
|
184
203
|
const send = createSendMock();
|
|
185
204
|
const params = createControllerParams({ isRunning: false, send });
|
|
@@ -249,7 +268,7 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
249
268
|
expect(params.runQueue.refreshQueuedInputs).not.toHaveBeenCalled();
|
|
250
269
|
|
|
251
270
|
await act(async () => {
|
|
252
|
-
resolveSend(createRunHandle({ runId: null }));
|
|
271
|
+
resolveSend(createRunHandle({ delivery: 'queued', runId: null }));
|
|
253
272
|
await submission;
|
|
254
273
|
});
|
|
255
274
|
|
|
@@ -303,6 +322,8 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
303
322
|
it('projects the backend queue and returns a removed item to the composer for editing', async () => {
|
|
304
323
|
const queuedInput = createQueuedInput();
|
|
305
324
|
const params = createControllerParams({ isRunning: true, queuedInputs: [queuedInput] });
|
|
325
|
+
params.inputSnapshot.nodes = [];
|
|
326
|
+
params.inputSnapshot.text = '';
|
|
306
327
|
const { result } = renderHook(() => useSessionConversationController(params));
|
|
307
328
|
|
|
308
329
|
expect(result.current.queuedInputs).toEqual([
|
|
@@ -321,6 +342,19 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
321
342
|
}));
|
|
322
343
|
});
|
|
323
344
|
|
|
345
|
+
it('keeps the queued item unchanged when the composer already contains a draft', () => {
|
|
346
|
+
const queuedInput = createQueuedInput();
|
|
347
|
+
const params = createControllerParams({ isRunning: true, queuedInputs: [queuedInput] });
|
|
348
|
+
const { result } = renderHook(() => useSessionConversationController(params));
|
|
349
|
+
|
|
350
|
+
act(() => result.current.editQueuedInput(queuedInput.id));
|
|
351
|
+
|
|
352
|
+
expect(result.current.canEditQueuedInput).toBe(false);
|
|
353
|
+
expect(params.runQueue.removeQueuedInput).not.toHaveBeenCalled();
|
|
354
|
+
expect(params.restoreComposer).not.toHaveBeenCalled();
|
|
355
|
+
expect(params.setSendError).toHaveBeenCalledWith(expect.any(String));
|
|
356
|
+
});
|
|
357
|
+
|
|
324
358
|
it('deletes through the backend queue owner without restoring the composer', async () => {
|
|
325
359
|
const queuedInput = createQueuedInput();
|
|
326
360
|
const params = createControllerParams({ isRunning: true, queuedInputs: [queuedInput] });
|
package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx
CHANGED
|
@@ -2,19 +2,25 @@ import type { ReactNode } from 'react';
|
|
|
2
2
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
3
3
|
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
4
4
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
eventKeys,
|
|
7
|
+
type UiNcpSessionPendingInputsView,
|
|
8
|
+
type UiNcpSessionQueuedInputView,
|
|
9
|
+
} from '@nextclaw/client-sdk';
|
|
6
10
|
|
|
7
11
|
import { useSessionRunQueue } from '@/features/chat/features/conversation/hooks/use-session-run-queue';
|
|
8
12
|
import { nextclawClient } from '@/shared/lib/api';
|
|
9
13
|
|
|
10
|
-
function createQueue(sessionId: string, text: string):
|
|
14
|
+
function createQueue(sessionId: string, text: string): UiNcpSessionPendingInputsView {
|
|
11
15
|
return {
|
|
12
16
|
sessionId,
|
|
13
17
|
inputs: [{
|
|
14
18
|
id: `queued-${sessionId}`,
|
|
15
19
|
sessionId,
|
|
16
20
|
enqueuedAt: '2026-07-22T10:00:00.000Z',
|
|
17
|
-
|
|
21
|
+
metadata: {},
|
|
22
|
+
placement: 'queued',
|
|
23
|
+
intendedRunId: null,
|
|
18
24
|
message: {
|
|
19
25
|
id: `message-${sessionId}`,
|
|
20
26
|
sessionId,
|
|
@@ -42,7 +48,7 @@ describe('useSessionRunQueue', () => {
|
|
|
42
48
|
});
|
|
43
49
|
|
|
44
50
|
it('keys backend queue data by session instead of sharing one frontend queue', async () => {
|
|
45
|
-
vi.spyOn(nextclawClient.sessions, '
|
|
51
|
+
vi.spyOn(nextclawClient.sessions, 'listPendingInputs').mockImplementation(async (sessionId) =>
|
|
46
52
|
createQueue(sessionId, sessionId === 'session-1' ? 'first session' : 'second session'),
|
|
47
53
|
);
|
|
48
54
|
const { result, rerender } = renderHook(
|
|
@@ -53,18 +59,18 @@ describe('useSessionRunQueue', () => {
|
|
|
53
59
|
await waitFor(() => expect(result.current.inputs[0]?.message.parts[0]).toMatchObject({ text: 'first session' }));
|
|
54
60
|
rerender({ sessionKey: 'session-2' });
|
|
55
61
|
await waitFor(() => expect(result.current.inputs[0]?.message.parts[0]).toMatchObject({ text: 'second session' }));
|
|
56
|
-
expect(nextclawClient.sessions.
|
|
57
|
-
expect(nextclawClient.sessions.
|
|
62
|
+
expect(nextclawClient.sessions.listPendingInputs).toHaveBeenCalledWith('session-1');
|
|
63
|
+
expect(nextclawClient.sessions.listPendingInputs).toHaveBeenCalledWith('session-2');
|
|
58
64
|
});
|
|
59
65
|
|
|
60
66
|
it('refetches only when the matching session queue changes', async () => {
|
|
61
|
-
const
|
|
67
|
+
const listPendingInputs = vi.spyOn(nextclawClient.sessions, 'listPendingInputs')
|
|
62
68
|
.mockResolvedValue(createQueue('session-1', 'queued'));
|
|
63
69
|
const { unmount } = renderHook(
|
|
64
70
|
() => useSessionRunQueue('session-1'),
|
|
65
71
|
{ wrapper: createWrapper() },
|
|
66
72
|
);
|
|
67
|
-
await waitFor(() => expect(
|
|
73
|
+
await waitFor(() => expect(listPendingInputs).toHaveBeenCalledTimes(1));
|
|
68
74
|
|
|
69
75
|
act(() => {
|
|
70
76
|
nextclawClient.eventBus.emit(eventKeys.sessionRunQueueUpdated, {
|
|
@@ -72,55 +78,55 @@ describe('useSessionRunQueue', () => {
|
|
|
72
78
|
});
|
|
73
79
|
});
|
|
74
80
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
75
|
-
expect(
|
|
81
|
+
expect(listPendingInputs).toHaveBeenCalledTimes(1);
|
|
76
82
|
|
|
77
83
|
act(() => {
|
|
78
84
|
nextclawClient.eventBus.emit(eventKeys.sessionRunQueueUpdated, {
|
|
79
85
|
sessionKey: 'session-1',
|
|
80
86
|
});
|
|
81
87
|
});
|
|
82
|
-
await waitFor(() => expect(
|
|
88
|
+
await waitFor(() => expect(listPendingInputs).toHaveBeenCalledTimes(2));
|
|
83
89
|
unmount();
|
|
84
90
|
});
|
|
85
91
|
|
|
86
92
|
it('refreshes the authoritative queue on demand after a submission is accepted', async () => {
|
|
87
|
-
const
|
|
93
|
+
const listPendingInputs = vi.spyOn(nextclawClient.sessions, 'listPendingInputs')
|
|
88
94
|
.mockResolvedValue(createQueue('session-1', 'queued'));
|
|
89
95
|
const { result } = renderHook(
|
|
90
96
|
() => useSessionRunQueue('session-1'),
|
|
91
97
|
{ wrapper: createWrapper() },
|
|
92
98
|
);
|
|
93
|
-
await waitFor(() => expect(
|
|
99
|
+
await waitFor(() => expect(listPendingInputs).toHaveBeenCalledTimes(1));
|
|
94
100
|
|
|
95
|
-
let refreshed:
|
|
101
|
+
let refreshed: UiNcpSessionQueuedInputView[] = [];
|
|
96
102
|
await act(async () => {
|
|
97
103
|
refreshed = [...await result.current.refreshQueuedInputs()];
|
|
98
104
|
});
|
|
99
105
|
|
|
100
|
-
expect(
|
|
106
|
+
expect(listPendingInputs).toHaveBeenCalledTimes(2);
|
|
101
107
|
expect(refreshed[0]?.message.parts[0]).toMatchObject({ text: 'queued' });
|
|
102
108
|
});
|
|
103
109
|
|
|
104
110
|
it('replaces an in-flight stale queue read after the queue changes', async () => {
|
|
105
|
-
let resolveInitialRead!: (queue:
|
|
106
|
-
const initialRead = new Promise<
|
|
111
|
+
let resolveInitialRead!: (queue: UiNcpSessionPendingInputsView) => void;
|
|
112
|
+
const initialRead = new Promise<UiNcpSessionPendingInputsView>((resolve) => {
|
|
107
113
|
resolveInitialRead = resolve;
|
|
108
114
|
});
|
|
109
|
-
const
|
|
115
|
+
const listPendingInputs = vi.spyOn(nextclawClient.sessions, 'listPendingInputs')
|
|
110
116
|
.mockImplementationOnce(async () => await initialRead)
|
|
111
117
|
.mockResolvedValue({ sessionId: 'session-1', inputs: [] });
|
|
112
118
|
const { result } = renderHook(
|
|
113
119
|
() => useSessionRunQueue('session-1'),
|
|
114
120
|
{ wrapper: createWrapper() },
|
|
115
121
|
);
|
|
116
|
-
await waitFor(() => expect(
|
|
122
|
+
await waitFor(() => expect(listPendingInputs).toHaveBeenCalledTimes(1));
|
|
117
123
|
|
|
118
124
|
act(() => {
|
|
119
125
|
nextclawClient.eventBus.emit(eventKeys.sessionRunQueueUpdated, {
|
|
120
126
|
sessionKey: 'session-1',
|
|
121
127
|
});
|
|
122
128
|
});
|
|
123
|
-
await waitFor(() => expect(
|
|
129
|
+
await waitFor(() => expect(listPendingInputs).toHaveBeenCalledTimes(2));
|
|
124
130
|
|
|
125
131
|
await act(async () => {
|
|
126
132
|
resolveInitialRead(createQueue('session-1', 'stale queued input'));
|
package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { useCallback, useMemo
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
2
|
import { buildNcpRequestEnvelope } from '@nextclaw/ncp-react';
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
UiNcpSessionPendingInputView,
|
|
5
|
+
UiNcpSessionQueuedInputView,
|
|
6
|
+
} from '@nextclaw/client-sdk';
|
|
4
7
|
import type { NcpAgentSendEnvelope, NcpRunHandle } from '@nextclaw/ncp';
|
|
5
8
|
|
|
6
9
|
import {
|
|
@@ -10,12 +13,14 @@ import {
|
|
|
10
13
|
import { isNcpChatSendDisabled } from '@/features/chat/features/input/utils/ncp-chat-input-availability.utils';
|
|
11
14
|
import { buildChatRunMetadata } from '@/features/chat/features/session/utils/chat-run-metadata.utils';
|
|
12
15
|
import { createNcpSessionId } from '@/features/chat/features/session/utils/ncp-session-adapter.utils';
|
|
13
|
-
import {
|
|
14
|
-
buildSessionQueuedInputComposerSnapshot,
|
|
15
|
-
buildSessionQueuedInputPreview,
|
|
16
|
-
} from '@/features/chat/features/conversation/utils/session-queued-input.utils';
|
|
16
|
+
import type { SessionQueuedInputAttachmentPreview } from '@/features/chat/features/conversation/utils/session-queued-input.utils';
|
|
17
17
|
import type { SessionConversationInputSnapshot } from './use-session-conversation-input-state';
|
|
18
18
|
import type { useSessionConversationInputQuery } from './use-session-conversation-input-query';
|
|
19
|
+
import {
|
|
20
|
+
useQueuedInputActions,
|
|
21
|
+
useSubmittingQueuedInputProjection,
|
|
22
|
+
type SubmittingQueuedInput,
|
|
23
|
+
} from './use-session-pending-input-actions';
|
|
19
24
|
import {
|
|
20
25
|
useSessionConversationRecoveryActions,
|
|
21
26
|
type SessionConversationRecoveryAgent,
|
|
@@ -41,6 +46,7 @@ type SessionConversationAgent = SessionConversationRecoveryAgent & {
|
|
|
41
46
|
};
|
|
42
47
|
|
|
43
48
|
export type SessionConversationQueuedInput = {
|
|
49
|
+
readonly attachments?: readonly SessionQueuedInputAttachmentPreview[];
|
|
44
50
|
readonly id: string;
|
|
45
51
|
readonly isSubmitting?: boolean;
|
|
46
52
|
readonly preview: string;
|
|
@@ -52,6 +58,9 @@ type SessionRunQueue = {
|
|
|
52
58
|
readonly removeQueuedInput: (
|
|
53
59
|
queuedInputId: string,
|
|
54
60
|
) => Promise<UiNcpSessionQueuedInputView | null>;
|
|
61
|
+
readonly steerQueuedInput: (
|
|
62
|
+
queuedInputId: string,
|
|
63
|
+
) => Promise<UiNcpSessionPendingInputView | null>;
|
|
55
64
|
};
|
|
56
65
|
|
|
57
66
|
export type SessionConversationMaterializationContext = {
|
|
@@ -93,13 +102,6 @@ type SubmissionDraft = {
|
|
|
93
102
|
|
|
94
103
|
type SubmissionComposerBehavior = 'preserve' | 'reset-and-restore';
|
|
95
104
|
|
|
96
|
-
type SubmittingQueuedInput = {
|
|
97
|
-
readonly id: string;
|
|
98
|
-
readonly preview: string;
|
|
99
|
-
readonly sessionId: string;
|
|
100
|
-
readonly userMessageId: string;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
105
|
const hasSendableMessagePart = (parts: ReturnType<typeof deriveNcpMessagePartsFromComposer>): boolean =>
|
|
104
106
|
parts.some((part) => part.type !== 'text' || part.text.trim().length > 0);
|
|
105
107
|
|
|
@@ -191,8 +193,9 @@ function buildSubmissionDraft(params: BuildSubmissionDraftParams): SubmissionDra
|
|
|
191
193
|
function buildSubmissionEnvelope(
|
|
192
194
|
draft: SubmissionDraft,
|
|
193
195
|
sessionKey: string | null,
|
|
196
|
+
delivery: NcpAgentSendEnvelope['delivery'] = 'queue',
|
|
194
197
|
): NcpAgentSendEnvelope | null {
|
|
195
|
-
|
|
198
|
+
const envelope = buildNcpRequestEnvelope({
|
|
196
199
|
sessionId: sessionKey ?? undefined,
|
|
197
200
|
text: draft.composerSnapshot.text.trim(),
|
|
198
201
|
attachments: [...draft.composerSnapshot.attachments],
|
|
@@ -202,97 +205,7 @@ function buildSubmissionEnvelope(
|
|
|
202
205
|
),
|
|
203
206
|
metadata: draft.metadata,
|
|
204
207
|
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function buildSubmittingQueuedInput(
|
|
208
|
-
envelope: NcpAgentSendEnvelope,
|
|
209
|
-
): SubmittingQueuedInput | null {
|
|
210
|
-
const sessionId = envelope.sessionId?.trim();
|
|
211
|
-
if (!sessionId) {
|
|
212
|
-
return null;
|
|
213
|
-
}
|
|
214
|
-
const message = {
|
|
215
|
-
...envelope.message,
|
|
216
|
-
sessionId,
|
|
217
|
-
};
|
|
218
|
-
const enqueuedAt = new Date().toISOString();
|
|
219
|
-
const input: UiNcpSessionQueuedInputView = {
|
|
220
|
-
id: `submitting-${message.id}`,
|
|
221
|
-
sessionId,
|
|
222
|
-
enqueuedAt,
|
|
223
|
-
message,
|
|
224
|
-
metadata: structuredClone(envelope.metadata ?? {}),
|
|
225
|
-
};
|
|
226
|
-
return {
|
|
227
|
-
id: input.id,
|
|
228
|
-
preview: buildSessionQueuedInputPreview(input),
|
|
229
|
-
sessionId,
|
|
230
|
-
userMessageId: message.id,
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function useSubmittingQueuedInputProjection(
|
|
235
|
-
serverInputs: readonly UiNcpSessionQueuedInputView[],
|
|
236
|
-
sessionKey: string | null,
|
|
237
|
-
) {
|
|
238
|
-
const [submittingInput, setSubmittingInput] =
|
|
239
|
-
useState<SubmittingQueuedInput | null>(null);
|
|
240
|
-
const stageSubmittingInput = useCallback((envelope: NcpAgentSendEnvelope) => {
|
|
241
|
-
const input = buildSubmittingQueuedInput(envelope);
|
|
242
|
-
if (input) {
|
|
243
|
-
setSubmittingInput(input);
|
|
244
|
-
}
|
|
245
|
-
return input;
|
|
246
|
-
}, []);
|
|
247
|
-
const clearSubmittingInput = useCallback((input: SubmittingQueuedInput) => {
|
|
248
|
-
setSubmittingInput((current) =>
|
|
249
|
-
current?.userMessageId === input.userMessageId ? null : current
|
|
250
|
-
);
|
|
251
|
-
}, []);
|
|
252
|
-
const queuedInputs = useMemo<SessionConversationQueuedInput[]>(() => {
|
|
253
|
-
const projected: SessionConversationQueuedInput[] = serverInputs.map((input) => ({
|
|
254
|
-
id: input.id,
|
|
255
|
-
preview: buildSessionQueuedInputPreview(input),
|
|
256
|
-
}));
|
|
257
|
-
if (
|
|
258
|
-
submittingInput?.sessionId === sessionKey &&
|
|
259
|
-
!serverInputs.some((input) => input.message.id === submittingInput.userMessageId)
|
|
260
|
-
) {
|
|
261
|
-
projected.push({
|
|
262
|
-
id: submittingInput.id,
|
|
263
|
-
isSubmitting: true,
|
|
264
|
-
preview: submittingInput.preview,
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
return projected;
|
|
268
|
-
}, [serverInputs, sessionKey, submittingInput]);
|
|
269
|
-
return { clearSubmittingInput, queuedInputs, stageSubmittingInput };
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function useQueuedInputActions(params: {
|
|
273
|
-
readonly availableSkills: readonly { ref: string; name: string }[];
|
|
274
|
-
readonly restoreComposer: (snapshot: ComposerDraftSnapshot) => void;
|
|
275
|
-
readonly runQueue: SessionRunQueue;
|
|
276
|
-
readonly setSendError: (message: string | null) => void;
|
|
277
|
-
}) {
|
|
278
|
-
const { availableSkills, restoreComposer, runQueue, setSendError } = params;
|
|
279
|
-
const editQueuedInput = useCallback((id: string) => {
|
|
280
|
-
const input = runQueue.inputs.find((item) => item.id === id);
|
|
281
|
-
if (!input) return;
|
|
282
|
-
void runQueue.removeQueuedInput(id).then((removed) => {
|
|
283
|
-
if (!removed) return;
|
|
284
|
-
restoreComposer(buildSessionQueuedInputComposerSnapshot(removed, availableSkills));
|
|
285
|
-
setSendError(null);
|
|
286
|
-
}).catch((error) => {
|
|
287
|
-
setSendError(error instanceof Error ? error.message : String(error));
|
|
288
|
-
});
|
|
289
|
-
}, [availableSkills, restoreComposer, runQueue, setSendError]);
|
|
290
|
-
const deleteQueuedInput = useCallback((id: string) => {
|
|
291
|
-
void runQueue.removeQueuedInput(id).then(() => setSendError(null)).catch((error) => {
|
|
292
|
-
setSendError(error instanceof Error ? error.message : String(error));
|
|
293
|
-
});
|
|
294
|
-
}, [runQueue, setSendError]);
|
|
295
|
-
return { deleteQueuedInput, editQueuedInput };
|
|
208
|
+
return envelope ? { ...envelope, delivery } : null;
|
|
296
209
|
}
|
|
297
210
|
|
|
298
211
|
function useSubmissionDraftRunner(params: {
|
|
@@ -322,17 +235,20 @@ function useSubmissionDraftRunner(params: {
|
|
|
322
235
|
return useCallback(async (
|
|
323
236
|
draft: SubmissionDraft,
|
|
324
237
|
composerBehavior: SubmissionComposerBehavior,
|
|
238
|
+
delivery: NcpAgentSendEnvelope['delivery'] = 'queue',
|
|
325
239
|
) => {
|
|
326
240
|
const submissionSessionKey =
|
|
327
241
|
sessionKey ?? (materializationContext ? null : createNcpSessionId());
|
|
328
|
-
const envelope = buildSubmissionEnvelope(draft, submissionSessionKey);
|
|
242
|
+
const envelope = buildSubmissionEnvelope(draft, submissionSessionKey, delivery);
|
|
329
243
|
if (!envelope) return;
|
|
330
|
-
const queuedSubmission = agent.isRunning
|
|
244
|
+
const queuedSubmission = agent.isRunning && delivery === 'queue'
|
|
245
|
+
? stageSubmittingInput(envelope)
|
|
246
|
+
: null;
|
|
331
247
|
if (composerBehavior === 'reset-and-restore') resetComposer();
|
|
332
248
|
setSendError(null);
|
|
333
249
|
try {
|
|
334
250
|
const handle = await agent.send(envelope);
|
|
335
|
-
if (queuedSubmission && handle?.
|
|
251
|
+
if (queuedSubmission && handle?.delivery === 'queued') {
|
|
336
252
|
await runQueue.refreshQueuedInputs().catch(() => undefined);
|
|
337
253
|
}
|
|
338
254
|
if (queuedSubmission) clearSubmittingInput(queuedSubmission);
|
|
@@ -361,6 +277,106 @@ function useSubmissionDraftRunner(params: {
|
|
|
361
277
|
]);
|
|
362
278
|
}
|
|
363
279
|
|
|
280
|
+
function useSteeringSubmission(params: {
|
|
281
|
+
readonly agent: SessionConversationAgent;
|
|
282
|
+
readonly inputSnapshot: SessionConversationInputSnapshot;
|
|
283
|
+
readonly inputQuery: SessionConversationInputQuery;
|
|
284
|
+
readonly isRuntimeBlocked: boolean;
|
|
285
|
+
readonly materializationContext?: SessionConversationMaterializationContext | null;
|
|
286
|
+
readonly selectedAgentId: string;
|
|
287
|
+
readonly sessionKey: string | null;
|
|
288
|
+
readonly submitDraft: (
|
|
289
|
+
draft: SubmissionDraft,
|
|
290
|
+
composerBehavior: SubmissionComposerBehavior,
|
|
291
|
+
delivery?: NcpAgentSendEnvelope['delivery'],
|
|
292
|
+
) => Promise<void>;
|
|
293
|
+
}) {
|
|
294
|
+
const {
|
|
295
|
+
agent,
|
|
296
|
+
inputQuery,
|
|
297
|
+
inputSnapshot,
|
|
298
|
+
isRuntimeBlocked,
|
|
299
|
+
materializationContext,
|
|
300
|
+
selectedAgentId,
|
|
301
|
+
sessionKey,
|
|
302
|
+
submitDraft,
|
|
303
|
+
} = params;
|
|
304
|
+
return useCallback(async () => {
|
|
305
|
+
const draft = buildSubmissionDraft({
|
|
306
|
+
agentIsSending: agent.isSending,
|
|
307
|
+
inputSnapshot,
|
|
308
|
+
inputQuery,
|
|
309
|
+
isRuntimeBlocked,
|
|
310
|
+
materializationContext,
|
|
311
|
+
selectedAgentId,
|
|
312
|
+
sessionKey,
|
|
313
|
+
});
|
|
314
|
+
if (draft) await submitDraft(draft, 'reset-and-restore', 'prefer-steer');
|
|
315
|
+
}, [
|
|
316
|
+
agent.isSending,
|
|
317
|
+
inputQuery,
|
|
318
|
+
inputSnapshot,
|
|
319
|
+
isRuntimeBlocked,
|
|
320
|
+
materializationContext,
|
|
321
|
+
selectedAgentId,
|
|
322
|
+
sessionKey,
|
|
323
|
+
submitDraft,
|
|
324
|
+
]);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function usePrimarySubmission(params: {
|
|
328
|
+
readonly agent: SessionConversationAgent;
|
|
329
|
+
readonly continueRun: () => Promise<void>;
|
|
330
|
+
readonly inputSnapshot: SessionConversationInputSnapshot;
|
|
331
|
+
readonly inputQuery: SessionConversationInputQuery;
|
|
332
|
+
readonly isRuntimeBlocked: boolean;
|
|
333
|
+
readonly materializationContext?: SessionConversationMaterializationContext | null;
|
|
334
|
+
readonly primaryAction: 'continue' | 'send';
|
|
335
|
+
readonly selectedAgentId: string;
|
|
336
|
+
readonly sessionKey: string | null;
|
|
337
|
+
readonly submitDraft: (
|
|
338
|
+
draft: SubmissionDraft,
|
|
339
|
+
composerBehavior: SubmissionComposerBehavior,
|
|
340
|
+
) => Promise<void>;
|
|
341
|
+
}) {
|
|
342
|
+
const {
|
|
343
|
+
agent,
|
|
344
|
+
continueRun,
|
|
345
|
+
inputQuery,
|
|
346
|
+
inputSnapshot,
|
|
347
|
+
isRuntimeBlocked,
|
|
348
|
+
materializationContext,
|
|
349
|
+
primaryAction,
|
|
350
|
+
selectedAgentId,
|
|
351
|
+
sessionKey,
|
|
352
|
+
submitDraft,
|
|
353
|
+
} = params;
|
|
354
|
+
return useCallback(async () => {
|
|
355
|
+
if (primaryAction === 'continue') return await continueRun();
|
|
356
|
+
const draft = buildSubmissionDraft({
|
|
357
|
+
agentIsSending: agent.isSending,
|
|
358
|
+
inputSnapshot,
|
|
359
|
+
inputQuery,
|
|
360
|
+
isRuntimeBlocked,
|
|
361
|
+
materializationContext,
|
|
362
|
+
selectedAgentId,
|
|
363
|
+
sessionKey,
|
|
364
|
+
});
|
|
365
|
+
if (draft) await submitDraft(draft, 'reset-and-restore');
|
|
366
|
+
}, [
|
|
367
|
+
agent.isSending,
|
|
368
|
+
continueRun,
|
|
369
|
+
inputQuery,
|
|
370
|
+
inputSnapshot,
|
|
371
|
+
isRuntimeBlocked,
|
|
372
|
+
materializationContext,
|
|
373
|
+
primaryAction,
|
|
374
|
+
selectedAgentId,
|
|
375
|
+
sessionKey,
|
|
376
|
+
submitDraft,
|
|
377
|
+
]);
|
|
378
|
+
}
|
|
379
|
+
|
|
364
380
|
export function useSessionConversationController(params: UseSessionConversationControllerParams) {
|
|
365
381
|
const {
|
|
366
382
|
agent,
|
|
@@ -381,17 +397,18 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
381
397
|
queuedInputs,
|
|
382
398
|
stageSubmittingInput,
|
|
383
399
|
} = useSubmittingQueuedInputProjection(runQueue.inputs, sessionKey);
|
|
384
|
-
const { deleteQueuedInput, editQueuedInput } = useQueuedInputActions({
|
|
385
|
-
availableSkills: inputQuery.skillRecords,
|
|
386
|
-
restoreComposer,
|
|
387
|
-
runQueue,
|
|
388
|
-
setSendError,
|
|
389
|
-
});
|
|
390
400
|
const parts = useMemo(
|
|
391
401
|
() => deriveNcpMessagePartsFromComposer([...inputSnapshot.nodes], inputSnapshot.attachments),
|
|
392
402
|
[inputSnapshot.attachments, inputSnapshot.nodes],
|
|
393
403
|
);
|
|
394
404
|
const hasSendableDraft = hasSendableMessagePart(parts);
|
|
405
|
+
const { deleteQueuedInput, editQueuedInput, steerQueuedInput } = useQueuedInputActions({
|
|
406
|
+
availableSkills: inputQuery.skillRecords,
|
|
407
|
+
hasComposerContent: hasSendableDraft,
|
|
408
|
+
restoreComposer,
|
|
409
|
+
runQueue,
|
|
410
|
+
setSendError,
|
|
411
|
+
});
|
|
395
412
|
const isSending = agent.isSending || agent.isRunning;
|
|
396
413
|
const activityState = inputQuery.selectedSession?.activityPreview?.state;
|
|
397
414
|
const canContinue = Boolean(
|
|
@@ -429,25 +446,8 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
429
446
|
stageSubmittingInput,
|
|
430
447
|
});
|
|
431
448
|
|
|
432
|
-
const send =
|
|
433
|
-
|
|
434
|
-
await continueRun();
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
const draft = buildSubmissionDraft({
|
|
438
|
-
agentIsSending: agent.isSending,
|
|
439
|
-
inputSnapshot,
|
|
440
|
-
inputQuery,
|
|
441
|
-
isRuntimeBlocked,
|
|
442
|
-
materializationContext,
|
|
443
|
-
selectedAgentId,
|
|
444
|
-
sessionKey,
|
|
445
|
-
});
|
|
446
|
-
if (draft) {
|
|
447
|
-
await submitDraft(draft, 'reset-and-restore');
|
|
448
|
-
}
|
|
449
|
-
}, [
|
|
450
|
-
agent.isSending,
|
|
449
|
+
const send = usePrimarySubmission({
|
|
450
|
+
agent,
|
|
451
451
|
continueRun,
|
|
452
452
|
inputQuery,
|
|
453
453
|
inputSnapshot,
|
|
@@ -457,7 +457,18 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
457
457
|
selectedAgentId,
|
|
458
458
|
sessionKey,
|
|
459
459
|
submitDraft,
|
|
460
|
-
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const sendSteering = useSteeringSubmission({
|
|
463
|
+
agent,
|
|
464
|
+
inputQuery,
|
|
465
|
+
inputSnapshot,
|
|
466
|
+
isRuntimeBlocked,
|
|
467
|
+
materializationContext,
|
|
468
|
+
selectedAgentId,
|
|
469
|
+
sessionKey,
|
|
470
|
+
submitDraft,
|
|
471
|
+
});
|
|
461
472
|
|
|
462
473
|
const sendPresetMessage = useCallback(async (message: string) => {
|
|
463
474
|
const text = message.trim();
|
|
@@ -505,14 +516,17 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
505
516
|
deleteQueuedInput,
|
|
506
517
|
editMessage,
|
|
507
518
|
editQueuedInput,
|
|
519
|
+
canEditQueuedInput: !hasSendableDraft,
|
|
508
520
|
hasSendableDraft,
|
|
509
521
|
isSending,
|
|
510
522
|
queuedInputs,
|
|
511
523
|
send,
|
|
524
|
+
sendSteering,
|
|
512
525
|
sendPresetMessage,
|
|
513
526
|
sendDisabled,
|
|
514
527
|
primaryAction,
|
|
515
528
|
stop,
|
|
516
529
|
stopDisabled: !agent.isRunning,
|
|
530
|
+
steerQueuedInput,
|
|
517
531
|
};
|
|
518
532
|
}
|