@nextclaw/ui 0.27.0 → 0.27.1
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 +29 -0
- package/dist/.vite/manifest.json +1242 -1171
- package/dist/assets/{abnfDiagram-VRR7QNED-DmeCRAkd.js → abnfDiagram-VRR7QNED-BT0_ycaq.js} +1 -1
- package/dist/assets/account-panel-BVNV8XqM.js +1 -0
- package/dist/assets/agents-CfpN8PQc.js +1 -0
- package/dist/assets/agents-E4nu-17c.js +1 -0
- package/dist/assets/{aiden0z-pptx-renderer.es-ChX5DHqP.js → aiden0z-pptx-renderer.es-ClCaf_Wh.js} +1 -1
- package/dist/assets/api-CI6_8Qt1.js +20 -0
- package/dist/assets/app-presenter-provider-2DwHRRle.js +28 -0
- package/dist/assets/appearance-settings-page-Cn9w3F-K.js +1 -0
- package/dist/assets/apps-YFlJirpx.js +1 -0
- package/dist/assets/{arc-Cu6Ols44.js → arc-cmSdpq1Z.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-BImoGh10.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-DrNB0eLE.js → architectureDiagram-ZJ3FMSHR-aYglVeoS.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-08rHt6DJ.js → blockDiagram-677ZJIJ3-Di_PBl5q.js} +1 -1
- package/dist/assets/{book-open-ClbJmmxP.js → book-open-i_BjUBqL.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-CCVgRG-u.js → c4Diagram-LMCZKHZV-CfuxybOL.js} +1 -1
- package/dist/assets/{card-BdC01NFF.js → card-DokH7OBp.js} +1 -1
- package/dist/assets/channel-BDQry0ob.js +1 -0
- package/dist/assets/{channels-list-page-BrIvJlop.js → channels-list-page-B7G9lHUm.js} +2 -2
- package/dist/assets/chunk-2Q5K7J3B-DkgSFfIy.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-BeCaI-JN.js → chunk-32BRIVSS-CCGc4qg4.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-ZXIcYPYs.js → chunk-52WLFC77-aJoxU2Ow.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-DDwTPcy8.js → chunk-5FCAYU7R-CGwtZSax.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-WygrMYPL.js → chunk-5HE753X5-DqaMSMeS.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-o8T3KZgk.js → chunk-5JV3BV7I-DnabINcd.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-BKFbUT7J.js → chunk-5TONJI2A-BhpKv1k2.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DYxCRV86.js → chunk-5VM5RSS4-DvkRPit_.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-CvSeJlKZ.js → chunk-7BUUIJ7U-CgDQOLnC.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-BhH3RHCY.js → chunk-BIQX33UG-9FEv5b7T.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-BTL0-xL3.js → chunk-C7G6YPKG-CNGFAFYL.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-DWAU4QaD.js → chunk-CQNSW5MT-DovTZx0M.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-B7ZBMXTx.js → chunk-CYSBUYHQ-DpLEgYa1.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-D92HvnHE.js → chunk-EMLP6XTP-D4NuN01W.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-DfOGKwW8.js → chunk-EX3LRPZG-D8Jf4kc2.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-DUuJUrXJ.js → chunk-FWX5IMBZ-BdHymAs0.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-i3MDyUY5.js → chunk-HOUHSVGY-Dd_Ycn9Z.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-F_pmNX6t.js → chunk-ICXQ74PX-BRPUu3ff.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DygOelrU.js → chunk-JG7HCLWE-DnCasQja.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-BpiZMeRl.js → chunk-JWPE2WC7-C3CkbEj1.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-CV10sB1I.js → chunk-MOJQB5TN-Pi--K4-1.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-Cf1WZNm0.js → chunk-MOZMSUNE-3VTspvlh.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-DuSw54VR.js → chunk-OGEWGWER-BetLLyJt.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-_rt_XKSZ.js → chunk-OSBZ3O6U-D1VcupAj.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-BFPaAGNW.js → chunk-PUDLZKDR-Cy4G8SjV.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-GE0v_E5y.js → chunk-Q4XR5HBZ-UYxXzi7_.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-BK_FpnlJ.js → chunk-QBLGF6JB-CHiGeRY1.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-CpYh6rGo.js → chunk-R7FJI6CG-C5kVJus8.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-htnxL_Cl.js → chunk-RYQCIY6F-C6cuuEBn.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-wDbE4BZ7.js → chunk-U6XO7XAA-CM0EK7Y0.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-DDRSVFTB.js → chunk-V7JOEXUC-DWJZIsME.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-CsTIB8qD.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-COdhHR1o.js → chunk-VR4S4FIN-CY5KYeEi.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-DPDGhyF6.js → chunk-WYO6CB5R-B30N3ZP8.js} +3 -3
- package/dist/assets/chunk-XXDRQBXY-DK6dz0Q3.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-D8ir9Nx5.js → chunk-YOTPTUD7-CBu82JpO.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-BuNKD836.js → chunk-ZGVPDNZ5-BN5NX5qA.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-DyHzq8jH.js → chunk-ZIRB5QZD-DcDXK29L.js} +1 -1
- package/dist/assets/{circle-dashed-nDaMRmP-.js → circle-dashed-Cx8CIEbg.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-BYygHCrp.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-BgQ0XKYz.js +1 -0
- package/dist/assets/{client-DlFB5dW5.js → client-CUJUci3r.js} +1 -1
- package/dist/assets/{config-split-page-C06fU9OQ.js → config-split-page-hY1xug28.js} +1 -1
- package/dist/assets/{confirm-dialog-DpcmlXhd.js → confirm-dialog-B-ejV666.js} +1 -1
- package/dist/assets/{context-menu-DKIEaY7f.js → context-menu-dGVv8klA.js} +9 -9
- package/dist/assets/{cose-bilkent-JH36ORCC-B1I1_P6a.js → cose-bilkent-JH36ORCC-CmeJVoTw.js} +1 -1
- package/dist/assets/{createLucideIcon-Lnt-4LMC.js → createLucideIcon-reFMl-W-.js} +1 -1
- package/dist/assets/cron-CH5c55CR.js +1 -0
- package/dist/assets/cynefin-VYW2F7L2-DKbotNWS.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-DcOnhnCo.js → cynefinDiagram-TSTJHNR4-DGOUMgPP.js} +1 -1
- package/dist/assets/{dagre-nSYhf9yY.js → dagre-CMxSkbJJ.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-hAX89lg3.js → dagre-VKFMJZFB-3YUBEXwo.js} +1 -1
- package/dist/assets/{desktop-capabilities-page-DPORyZAu.js → desktop-capabilities-page-CYJTQ3nC.js} +1 -1
- package/dist/assets/{desktop-update-config-BMTeWZmn.js → desktop-update-config-guKAozXO.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-C1mRMD2k.js → diagram-FQU43EPY-Br1g--ww.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-D2XBn5al.js → diagram-G47NLZAW-D1wJCBgr.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-3LmRsmkC.js → diagram-NH7WQ7WH-Cgg2auLH.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CFWn-osC.js → diagram-OA4YK3LP-R-wHiWqh.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-BqNRbUvU.js → diagram-WEI45ONY-CsNnKV0P.js} +1 -1
- package/dist/assets/{dialog-BNXSPMX_.js → dialog-DLOwdjT1.js} +1 -1
- package/dist/assets/{dist-Cuiqqp1O.js → dist-ZaFFmAGl.js} +1 -1
- package/dist/assets/doc-browser-ClDUWo9V.js +1 -0
- package/dist/assets/doc-browser-context-CTmOmuqa.js +1 -0
- package/dist/assets/{docx-preview-CunAATyC.js → docx-preview-kPn_EtAr.js} +1 -1
- package/dist/assets/{download-f_sPcoLZ.js → download-DovI3Yvf.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CYb8IwqD.js → ebnfDiagram-CCIWWBDH-DCyhIPdi.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-H47mUoeK.js → erDiagram-Q63AITRT-D0ZJYAUf.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-SIhbIFIw.js +1 -0
- package/dist/assets/{extensions-B-0xQz3L.js → extensions-BZ3qrM8M.js} +1 -1
- package/dist/assets/{external-link-CbVlnlNy.js → external-link-DUD3AbsF.js} +1 -1
- package/dist/assets/flowDiagram-23GEKE2U-DdAjkU7I.js +1 -0
- package/dist/assets/{form-actions-BoTqELHB.js → form-actions-B8VniHts.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-hSX45zfV.js → ganttDiagram-NO4QXBWP-CiXDcXZD.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-DnMNpESZ.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-Br0UW2qg.js → gitGraphDiagram-IHSO6WYX-BSiIV48S.js} +1 -1
- package/dist/assets/{i18n-B0V5NkFj.js → i18n-IGQbjBqS.js} +2 -2
- package/dist/assets/inbox-BjBZIbgx.js +1 -0
- package/dist/assets/{inbox-Bna8iUy0.js → inbox-ClAG7SI_.js} +1 -1
- package/dist/assets/info-DKCQHKI2-BSm-69p_.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-DQmP_67w.js → infoDiagram-FWYZ7A6U-CCIgBCVq.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-BHAV2oes.js → ishikawaDiagram-FXEZZL3T-nQ_baN5u.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-CFHax4_d.js → journeyDiagram-5HDEW3XC-ABueIPzj.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-B4ZA9rp5.js → kanban-definition-HUTT4EX6-8FKS3fmQ.js} +1 -1
- package/dist/assets/katex-DPgHtix3.js +1 -0
- package/dist/assets/keyboard-shortcuts-settings-page-BqfbbKir.js +1 -0
- package/dist/assets/{line-BboM0HLF.js → line-Biw8iEUz.js} +1 -1
- package/dist/assets/{linear-4K_M1oYM.js → linear-D7CWUHTF.js} +1 -1
- package/dist/assets/login-page-BxSMwUsc.js +1 -0
- package/dist/assets/{login-page-JNr5JCEw.js → login-page-DYaozpzz.js} +1 -1
- package/dist/assets/main-CWYF9QU_.js +2 -0
- package/dist/assets/main-D_zmSVS1.css +1 -0
- package/dist/assets/main-i18n-catalog.config-itg3Gvzp.js +1 -0
- package/dist/assets/{map-26GpO1wn.js → map-CDu47gTf.js} +1 -1
- package/dist/assets/marketplace-CnQ5USfr.js +1 -0
- package/dist/assets/mcp-marketplace-page-Dor6H9IC.js +1 -0
- package/dist/assets/{mermaid-parser.core-BTJFnvRC.js → mermaid-parser.core-Cc9wjl82.js} +2 -2
- package/dist/assets/{mermaid.core-B7ufoXgq.js → mermaid.core-GWlaVWz1.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BHyru6KE.js → mindmap-definition-LN4V7U3C-oqnKsz-R.js} +1 -1
- package/dist/assets/{model-config-page-C-wbM6Fe.js → model-config-page-Cduyz2Hy.js} +1 -1
- package/dist/assets/{navigation-link-DFLSVIut.js → navigation-link-D-JSWFxj.js} +1 -1
- package/dist/assets/{ordinal-BqFe2ePF.js → ordinal-DImbxqBz.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-1YQvC6mT.js +1 -0
- package/dist/assets/panel-app-i18n-catalog.config-BfLHr1tc.js +1 -0
- package/dist/assets/panel-apps-C-izvtu9.js +1 -0
- package/dist/assets/panelStandalone-oHxbXvYt.js +2 -0
- package/dist/assets/{pegDiagram-2B236MQR-PVTatU5j.js → pegDiagram-2B236MQR-DYAB8CEz.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-BGoNOSwu.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-CGc-QCc7.js → pieDiagram-ENE6RG2P-DGsH0Kk5.js} +1 -1
- package/dist/assets/plus-DUdl68Eo.js +1 -0
- package/dist/assets/{privacy-settings-page-CPdEiouE.js → privacy-settings-page-DG9E8N-F.js} +1 -1
- package/dist/assets/projects-CzBaTOTL.js +1 -0
- package/dist/assets/{provider-models-XRArsply.js → provider-models-COzjYl29.js} +1 -1
- package/dist/assets/{provider-scoped-model-input-C8JI-hus.js → provider-scoped-model-input-Cvy74uj8.js} +1 -1
- package/dist/assets/{providers-config-page-fyMlVgvq.js → providers-config-page-7rCwVnhh.js} +1 -1
- package/dist/assets/{puzzle-Bk3ud1KI.js → puzzle-C5Wfpjk_.js} +1 -1
- package/dist/assets/{pwa-Cx6Fnox4.js → pwa-CAg_9zFs.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-DGL36riv.js → quadrantDiagram-ABIIQ3AL-BegGcT3l.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-uPku9RRq.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-DHnmbuIo.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-DiZs--Iw.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-Nr53gnNE.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-Cm_PuwJS.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-CyNwvhSb.js → railroadDiagram-RFXS5EU6-B3yJ2yxE.js} +1 -1
- package/dist/assets/{refresh-cw-Ca2napNx.js → refresh-cw-OhwaPDn1.js} +1 -1
- package/dist/assets/remote-DvCdHjzA.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-C31NMKJ0.js → requirementDiagram-TGXJPOKE-DtEyoEXG.js} +1 -1
- package/dist/assets/{rotate-cw-DXg7sNUE.js → rotate-cw-aBponvp7.js} +1 -1
- package/dist/assets/runtime-config-page-BF1wxvzR.js +1 -0
- package/dist/assets/{sankeyDiagram-HTMAVEWB-CwrQ_7PA.js → sankeyDiagram-HTMAVEWB-h9AYS2UB.js} +1 -1
- package/dist/assets/{save-DNigywZ9.js → save-394QCMXn.js} +1 -1
- package/dist/assets/{search-U9C0oTQJ.js → search-BG2qAlNZ.js} +1 -1
- package/dist/assets/{search-config-page-Bdx_RR1q.js → search-config-page-D4LeiB9y.js} +1 -1
- package/dist/assets/{secrets-config-page-CvMIcsfJ.js → secrets-config-page-BzGcr5Vw.js} +2 -2
- package/dist/assets/security-config-vD_V0BQF.js +1 -0
- package/dist/assets/{select-DxwDeKUR.js → select-xUXYV0Gr.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-EFD482_y.js → sequenceDiagram-DBY2YBRQ-D-uxCkob.js} +1 -1
- package/dist/assets/service-apps-panel-D3wwPRzV.js +1 -0
- package/dist/assets/{settings-2-BrBUdRoY.js → settings-2-CWOGRRaA.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-TDvULTE1.js → sizeCapture-X5ZJPWSS-DBzZytQo.js} +1 -1
- package/dist/assets/{src-CI2AvEMj.js → src-zrGbZsfc.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-JdPsIYHo.js → stateDiagram-2N3HPSRC-DyDy7AHq.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-CtkpO6aA.js +1 -0
- package/dist/assets/{status-dot-BbGsrkIX.js → status-dot-CYifnSnt.js} +1 -1
- package/dist/assets/{swimlanes-5IMT3BWC-BnxpKeK_.js → swimlanes-5IMT3BWC-BzOduS38.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-BSdi6mvi.js +8 -0
- package/dist/assets/{tag-chip-BDbxcf6P.js → tag-chip-CjM6lyeh.js} +1 -1
- package/dist/assets/theme-provider-BToFZGZG.js +1 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-2IL22-uC.js → timeline-definition-FHXFAJF6-CmgnEF2t.js} +1 -1
- package/dist/assets/{trash-2-DwSkRfeB.js → trash-2-DvJ6duOW.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-DBoqypPR.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-BMeL3P0q.js +1 -0
- package/dist/assets/use-config-COusaY5p.js +1 -0
- package/dist/assets/{use-desktop-capabilities-D7odgaTB.js → use-desktop-capabilities-B-u6ojjW.js} +1 -1
- package/dist/assets/{use-viewport-layout-BANU5E1t.js → use-viewport-layout-IKKGpjzF.js} +1 -1
- package/dist/assets/{vennDiagram-L72KCM5P-Cjf6n5Va.js → vennDiagram-L72KCM5P-DwS7D2kg.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-Dqxe7zN6.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-yv4qKbBO.js → wardleyDiagram-EHGQE667-B4X8OOL4.js} +1 -1
- package/dist/assets/{x-BqGj6_Vq.js → x-E9VB4HQx.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-Bmp8Ck8X.js → xychartDiagram-FW5EYKEG-BjRQ_0nx.js} +1 -1
- package/dist/index.html +41 -40
- package/dist/panel-standalone.html +16 -16
- package/package.json +6 -6
- package/src/features/agents/components/__tests__/agents-page.test.tsx +8 -5
- package/src/features/agents/components/agent-details-dialog.tsx +19 -15
- package/src/features/agents/components/agents-page.tsx +27 -38
- package/src/features/app-data/components/app-retained-data-section.tsx +2 -2
- package/src/features/apps/components/app-marketplace-catalog.tsx +5 -5
- package/src/features/apps/components/app-marketplace-detail.tsx +11 -2
- package/src/features/apps/components/app-packages-panel.tsx +4 -4
- package/src/features/apps/components/apps-panel.tsx +3 -1
- package/src/features/chat/components/providers/chat-runtime.provider.tsx +1 -1
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +0 -1
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +13 -2
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +8 -1
- package/src/features/chat/features/conversation/components/session-conversation-input-top-slot.tsx +44 -0
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +4 -38
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +86 -10
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +12 -2
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +85 -73
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +5 -15
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +53 -13
- package/src/features/chat/features/conversation/hooks/use-session-submission-recovery.ts +83 -0
- package/src/features/chat/features/conversation/types/session-conversation-input.types.ts +38 -0
- package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +1 -29
- package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +1 -8
- package/src/features/chat/features/message/components/__tests__/chat-message-list-skill-preview.container.test.tsx +14 -1
- package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +7 -2
- package/src/features/chat/features/session/utils/__tests__/chat-session-route.utils.test.ts +26 -0
- package/src/features/chat/features/session/utils/chat-session-preference-governance.utils.ts +14 -8
- package/src/features/chat/features/session/utils/chat-session-route.utils.ts +9 -12
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.selection.test.tsx +14 -2
- package/src/features/chat/features/workspace/components/__tests__/session-cron-job-content.test.tsx +5 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +1 -1
- package/src/features/chat/features/workspace/components/session-cron-job-content.tsx +6 -22
- package/src/features/chat/index.ts +1 -0
- package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +37 -47
- package/src/features/chat/pages/ncp-chat-page.tsx +3 -3
- package/src/features/chat/stores/__tests__/chat-composer-draft.store.test.ts +67 -1
- package/src/features/chat/stores/chat-composer-draft.store.ts +230 -29
- package/src/features/cron/components/__tests__/cron-config.test.tsx +8 -2
- package/src/features/cron/components/cron-config.tsx +6 -17
- package/src/features/cron/components/cron-job-detail-dialog.tsx +10 -9
- package/src/features/cron/components/cron-job-resource.tsx +51 -0
- package/src/features/cron/index.ts +1 -0
- package/src/features/inbox/pages/inbox-page.tsx +8 -5
- package/src/features/marketplace/components/__tests__/marketplace-page-detail.test.tsx +1 -0
- package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +1 -0
- package/src/features/marketplace/components/mcp/__tests__/mcp-marketplace-page.test.tsx +2 -0
- package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +2 -2
- package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +23 -1
- package/src/features/marketplace/hooks/use-marketplace-item-detail.ts +11 -0
- package/src/features/panel-apps/index.ts +1 -0
- package/src/features/projects/components/work/project-work-item-drawer.tsx +7 -10
- package/src/features/projects/pages/project-home-page.tsx +18 -23
- package/src/features/projects/pages/projects-page.test.tsx +4 -1
- package/src/features/right-panel-resources/components/__tests__/system-object-resource.test.tsx +74 -6
- package/src/features/right-panel-resources/components/native-object-resource.tsx +134 -0
- package/src/features/right-panel-resources/components/page-resource-icon.tsx +1 -1
- package/src/features/right-panel-resources/components/system-object-resource.tsx +66 -1
- package/src/features/right-panel-resources/components/workspace-file-resource.tsx +9 -0
- package/src/features/right-panel-resources/configs/right-panel-resource-routes.config.ts +11 -21
- package/src/features/right-panel-resources/managers/__tests__/page-resource.manager.test.ts +14 -4
- package/src/features/right-panel-resources/managers/page-resource.manager.ts +38 -21
- package/src/features/right-panel-resources/utils/__tests__/right-panel-resource-route-resolver.utils.test.ts +12 -0
- package/src/features/service-apps/components/service-apps-panel.tsx +5 -2
- package/src/shared/components/doc-browser/__tests__/doc-browser-context.test.tsx +16 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +2 -2
- package/src/shared/components/doc-browser/__tests__/resource-link-interceptor.test.tsx +29 -1
- package/src/shared/components/doc-browser/stores/doc-browser.store.ts +13 -7
- package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +2 -1
- package/src/shared/components/ui/skeleton.tsx +16 -2
- package/src/shared/lib/i18n/locales/en-US/chat.json +8 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +8 -0
- package/src/shared/lib/transport/__tests__/local-transport.service.test.ts +24 -0
- package/src/shared/lib/transport/local-transport.service.ts +8 -6
- package/dist/assets/account-panel-BYxGT4m4.js +0 -1
- package/dist/assets/api-CG22BskB.js +0 -20
- package/dist/assets/app-presenter-provider-CJFjhVYI.js +0 -28
- package/dist/assets/appearance-settings-page-BcXr0vHp.js +0 -1
- package/dist/assets/architecture-TIHT7OUA-CLjV_xu4.js +0 -1
- package/dist/assets/channel-BgpbPyEH.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-DjhMPqAC.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-GYimZYx9.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-KKCf0HV5.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-iRMPRR8M.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-BguFy_wj.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-CtbjXuCW.js +0 -1
- package/dist/assets/doc-browser-CDEapjmj.js +0 -1
- package/dist/assets/doc-browser-context-0QDWYorh.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-Djd6id_u.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DUrsM_ZL.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-CU6P_2Cm.js +0 -1
- package/dist/assets/info-DKCQHKI2-Bj2P_7RC.js +0 -1
- package/dist/assets/katex-BprZ-Wwb.js +0 -1
- package/dist/assets/keyboard-shortcuts-settings-page-BluWKrSo.js +0 -1
- package/dist/assets/login-page-BMHW0Hh0.js +0 -1
- package/dist/assets/main-BCX_Untx.css +0 -1
- package/dist/assets/main-C5kbmGUV.js +0 -2
- package/dist/assets/main-i18n-catalog.config-DO4wNT7T.js +0 -1
- package/dist/assets/mcp-marketplace-page-CV-PHKTN.js +0 -1
- package/dist/assets/packet-7NZHBO7P-ti5ge2jr.js +0 -1
- package/dist/assets/panel-app-i18n-catalog.config-Bo52dPuF.js +0 -1
- package/dist/assets/panelStandalone-PuuMF65O.js +0 -2
- package/dist/assets/pie-RZYD4A2V-Bnep8TyV.js +0 -1
- package/dist/assets/plus-CywSlIbG.js +0 -1
- package/dist/assets/projects-D_cd_t4G.js +0 -1
- package/dist/assets/radar-I7S5WNFK-BYg-icAP.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-_CHO-Fi1.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-hbQDevHe.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-v4RZkOfi.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-bC9BqkI5.js +0 -1
- package/dist/assets/remote-D5MBQNZE.js +0 -1
- package/dist/assets/runtime-config-page--ivCxBT4.js +0 -1
- package/dist/assets/security-config-CQmMqQ8v.js +0 -1
- package/dist/assets/service-apps-panel-CiYO1Be4.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-4_aAQfB_.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-wCqfwsw-.js +0 -8
- package/dist/assets/theme-provider-D98XGa-c.js +0 -1
- package/dist/assets/treeView-QDETBFTQ-BAyOb14Z.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-DgPDM0zS.js +0 -1
- package/dist/assets/use-config-D3cNzk2k.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-eCElh8z5.js +0 -1
- /package/dist/assets/{array-DstOKG9P.js → array-DsNX3jRj.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-0TA8nwgf.js → chunk-KEIR6QF5-BOAXXeyv.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-rfGCG6pM.js → chunk-Y2CYZVJY-CHjSjwoV.js} +0 -0
- /package/dist/assets/{config-hints-BfGoD7-o.js → config-hints-CaB3I7KP.js} +0 -0
- /package/dist/assets/{cytoscape.esm-DdIcNEda.js → cytoscape.esm-j4J9a91l.js} +0 -0
- /package/dist/assets/{defaultLocale-CzXix2iJ.js → defaultLocale-Bmxjp-V_.js} +0 -0
- /package/dist/assets/{dist-D5dwMwKA.js → dist-DwLj1Wg5.js} +0 -0
- /package/dist/assets/{graphlib-BKOe0eFe.js → graphlib-CC0HTn1v.js} +0 -0
- /package/dist/assets/{host-capabilities-CnSVTaot.js → host-capabilities-B107nwS3.js} +0 -0
- /package/dist/assets/{init-OCFb3zgY.js → init-Biz9Rus1.js} +0 -0
- /package/dist/assets/{jszip.min-B2uhSxvV.js → jszip.min-DQvBVV_R.js} +0 -0
- /package/dist/assets/{katex-dBrYsE7B.js → katex-BzT-4KBu.js} +0 -0
- /package/dist/assets/{middleware-CAXxl-af.js → middleware-B--6mAUM.js} +0 -0
- /package/dist/assets/{navigation-history-CzErJuPG.js → navigation-history-CCnxsAKR.js} +0 -0
- /package/dist/assets/{panel-app-CSQmm_7E.js → panel-app-BBTg0tVp.js} +0 -0
- /package/dist/assets/{path-T5eoIRSJ.js → path-4azsBPZv.js} +0 -0
- /package/dist/assets/{rough.esm-DmGXmZEB.js → rough.esm-w1lBArN6.js} +0 -0
- /package/dist/assets/{xlsx-CoYacou7.js → xlsx--SB9KlFl.js} +0 -0
|
@@ -2,8 +2,13 @@ import { act, renderHook, waitFor } from '@testing-library/react';
|
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest';
|
|
3
3
|
import { NextClawClientError, type UiNcpSessionQueuedInputView } from '@nextclaw/client-sdk';
|
|
4
4
|
import type { NcpAgentSendEnvelope, NcpMessage, NcpRunHandle } from '@nextclaw/ncp';
|
|
5
|
+
import { NcpHttpSendError } from '@nextclaw/ncp-http-agent-client';
|
|
6
|
+
|
|
7
|
+
const fetchNcpSessionMessages = vi.hoisted(() => vi.fn());
|
|
8
|
+
vi.mock('@/shared/lib/api', () => ({ fetchNcpSessionMessages }));
|
|
5
9
|
|
|
6
10
|
import { useSessionConversationController } from '@/features/chat/features/conversation/hooks/use-session-conversation-controller';
|
|
11
|
+
import type { ChatComposerSubmission } from '@/features/chat/stores/chat-composer-draft.store';
|
|
7
12
|
|
|
8
13
|
type TestAgentSend = (envelope: NcpAgentSendEnvelope) => Promise<NcpRunHandle | null>;
|
|
9
14
|
|
|
@@ -107,6 +112,7 @@ function createControllerParams(params: {
|
|
|
107
112
|
composerFocusRequestId: 0,
|
|
108
113
|
nodes: [createTextNode('next task')],
|
|
109
114
|
pendingProjectRoot: null,
|
|
115
|
+
pendingSubmission: null as ChatComposerSubmission | null,
|
|
110
116
|
pendingSessionType: 'default',
|
|
111
117
|
selectedModel: undefined,
|
|
112
118
|
selectedSessionType: 'default',
|
|
@@ -126,8 +132,12 @@ function createControllerParams(params: {
|
|
|
126
132
|
},
|
|
127
133
|
selectedAgentId: 'main',
|
|
128
134
|
sessionKey: 'session-1',
|
|
129
|
-
resetComposer: vi.fn(),
|
|
130
135
|
restoreComposer: vi.fn(),
|
|
136
|
+
beginSubmission: vi.fn(),
|
|
137
|
+
acceptSubmission: vi.fn(),
|
|
138
|
+
failSubmission: vi.fn(),
|
|
139
|
+
restoreSubmission: vi.fn(),
|
|
140
|
+
discardSubmission: vi.fn(),
|
|
131
141
|
onSessionMaterialized: vi.fn(),
|
|
132
142
|
setSendError: vi.fn(),
|
|
133
143
|
};
|
|
@@ -162,6 +172,7 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
162
172
|
const envelope = send.mock.calls[0]?.[0];
|
|
163
173
|
expect(envelope?.sessionId).toMatch(/^ncp-/);
|
|
164
174
|
expect(envelope?.message.sessionId).toBe(envelope?.sessionId);
|
|
175
|
+
expect(envelope?.idempotencyKey).toBe(envelope?.message.id);
|
|
165
176
|
expect(params.onSessionMaterialized).toHaveBeenCalledWith(envelope?.sessionId);
|
|
166
177
|
});
|
|
167
178
|
|
|
@@ -182,7 +193,21 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
182
193
|
parts: [{ type: 'text', text: 'next task' }],
|
|
183
194
|
}),
|
|
184
195
|
});
|
|
185
|
-
expect(params.
|
|
196
|
+
expect(params.beginSubmission).toHaveBeenCalledTimes(1);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('attempts a send when a nonempty draft has a stale blocked runtime status', async () => {
|
|
200
|
+
const send = createSendMock();
|
|
201
|
+
const params = { ...createControllerParams({ isRunning: false, send }), isRuntimeBlocked: true };
|
|
202
|
+
const { result } = renderHook(() => useSessionConversationController(params));
|
|
203
|
+
|
|
204
|
+
expect(result.current.sendDisabled).toBe(false);
|
|
205
|
+
await act(async () => {
|
|
206
|
+
await result.current.send();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
expect(send).toHaveBeenCalledTimes(1);
|
|
210
|
+
expect(params.setSendError).toHaveBeenLastCalledWith(null);
|
|
186
211
|
});
|
|
187
212
|
|
|
188
213
|
it('uses prefer-steer for command/control-enter submission without changing the send button path', async () => {
|
|
@@ -241,7 +266,7 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
241
266
|
}),
|
|
242
267
|
});
|
|
243
268
|
expect(envelope?.metadata).not.toHaveProperty('ui_inline_tokens');
|
|
244
|
-
expect(params.
|
|
269
|
+
expect(params.beginSubmission).not.toHaveBeenCalled();
|
|
245
270
|
expect(params.restoreComposer).not.toHaveBeenCalled();
|
|
246
271
|
});
|
|
247
272
|
|
|
@@ -257,7 +282,7 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
257
282
|
await expect(result.current.sendPresetMessage('Update title')).rejects.toThrow(sendError);
|
|
258
283
|
});
|
|
259
284
|
|
|
260
|
-
expect(params.
|
|
285
|
+
expect(params.beginSubmission).not.toHaveBeenCalled();
|
|
261
286
|
expect(params.restoreComposer).not.toHaveBeenCalled();
|
|
262
287
|
expect(params.setSendError).toHaveBeenLastCalledWith(sendError.message);
|
|
263
288
|
});
|
|
@@ -275,7 +300,7 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
275
300
|
submission = result.current.send();
|
|
276
301
|
});
|
|
277
302
|
|
|
278
|
-
expect(params.
|
|
303
|
+
expect(params.beginSubmission).toHaveBeenCalledTimes(1);
|
|
279
304
|
expect(result.current.queuedInputs).toEqual([
|
|
280
305
|
expect.objectContaining({
|
|
281
306
|
isSubmitting: true,
|
|
@@ -306,13 +331,64 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
306
331
|
});
|
|
307
332
|
|
|
308
333
|
expect(result.current.queuedInputs).toEqual([]);
|
|
309
|
-
expect(params.
|
|
310
|
-
text: 'next task',
|
|
311
|
-
}));
|
|
312
|
-
expect(params.setSendError).toHaveBeenLastCalledWith(sendError.message);
|
|
334
|
+
expect(params.failSubmission).toHaveBeenCalledWith(expect.any(String), 'uncertain', sendError.message);
|
|
313
335
|
expect(params.runQueue.refreshQueuedInputs).not.toHaveBeenCalled();
|
|
314
336
|
});
|
|
315
337
|
|
|
338
|
+
it('shows a send failure and restores the draft when the client returns no acceptance handle', async () => {
|
|
339
|
+
const send = createSendMock(null);
|
|
340
|
+
const params = createControllerParams({ isRunning: false, send });
|
|
341
|
+
const { result } = renderHook(() => useSessionConversationController(params));
|
|
342
|
+
|
|
343
|
+
await act(async () => {
|
|
344
|
+
await expect(result.current.send()).rejects.toThrow('Failed to send message');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
expect(params.failSubmission).toHaveBeenCalledWith(expect.any(String), 'rejected', 'Failed to send message');
|
|
348
|
+
expect(params.onSessionMaterialized).not.toHaveBeenCalled();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('classifies an explicit HTTP rejection so the draft can be restored', async () => {
|
|
352
|
+
const error = new NcpHttpSendError('invalid request', true);
|
|
353
|
+
const send = vi.fn<TestAgentSend>(async () => { throw error; });
|
|
354
|
+
const params = createControllerParams({ isRunning: false, send });
|
|
355
|
+
const { result } = renderHook(() => useSessionConversationController(params));
|
|
356
|
+
await act(async () => {
|
|
357
|
+
await expect(result.current.send()).rejects.toThrow(error);
|
|
358
|
+
});
|
|
359
|
+
expect(params.failSubmission).toHaveBeenCalledWith(expect.any(String), 'rejected', 'invalid request');
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('rechecks the original message before retrying with the same identity', async () => {
|
|
363
|
+
fetchNcpSessionMessages.mockResolvedValue({ messages: [] });
|
|
364
|
+
const params = createControllerParams({ isRunning: false });
|
|
365
|
+
const envelope: NcpAgentSendEnvelope = {
|
|
366
|
+
sessionId: 'session-1', idempotencyKey: 'user-original',
|
|
367
|
+
message: {
|
|
368
|
+
id: 'user-original', sessionId: 'session-1', role: 'user', status: 'final',
|
|
369
|
+
timestamp: '2026-09-24T00:00:00.000Z', parts: [{ type: 'text', text: 'next task' }],
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
params.inputSnapshot.pendingSubmission = {
|
|
373
|
+
envelope,
|
|
374
|
+
composer: {
|
|
375
|
+
text: 'next task', nodes: [createTextNode('next task')],
|
|
376
|
+
selectedSkills: [], skillRecords: [], attachments: [],
|
|
377
|
+
},
|
|
378
|
+
status: 'uncertain',
|
|
379
|
+
};
|
|
380
|
+
const { result } = renderHook(() => useSessionConversationController(params));
|
|
381
|
+
expect(result.current.sendDisabled).toBe(true);
|
|
382
|
+
await act(async () => {
|
|
383
|
+
await result.current.send();
|
|
384
|
+
await result.current.retryPendingSubmission();
|
|
385
|
+
});
|
|
386
|
+
expect(fetchNcpSessionMessages).toHaveBeenCalledWith('session-1', { limit: 100 });
|
|
387
|
+
expect(params.agent.send).toHaveBeenCalledTimes(1);
|
|
388
|
+
expect(params.agent.send).toHaveBeenCalledWith(envelope);
|
|
389
|
+
expect(params.acceptSubmission).toHaveBeenCalledWith('user-original');
|
|
390
|
+
});
|
|
391
|
+
|
|
316
392
|
it('keeps an existing session bound to its agent instead of the global draft selection', async () => {
|
|
317
393
|
const send = createSendMock();
|
|
318
394
|
const params = createControllerParams({ isRunning: false, send });
|
|
@@ -406,7 +482,7 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
406
482
|
|
|
407
483
|
expect(params.agent.continueRun).toHaveBeenCalledWith({ sessionId: 'session-1' });
|
|
408
484
|
expect(params.agent.send).not.toHaveBeenCalled();
|
|
409
|
-
expect(params.
|
|
485
|
+
expect(params.beginSubmission).not.toHaveBeenCalled();
|
|
410
486
|
});
|
|
411
487
|
|
|
412
488
|
it('keeps continuation available but restores send as primary when the user types', () => {
|
|
@@ -36,7 +36,7 @@ const THINKING_MODEL_OPTIONS: ChatModelOption[] = [
|
|
|
36
36
|
describe('useSessionConversationInputState session preferences', () => {
|
|
37
37
|
beforeEach(() => {
|
|
38
38
|
window.localStorage.clear();
|
|
39
|
-
useChatComposerDraftStore.setState({ drafts: {} });
|
|
39
|
+
useChatComposerDraftStore.setState({ drafts: {}, submissions: {}, recentSubmittedNodes: {} });
|
|
40
40
|
useChatThreadStore.getState().setSnapshot({ draftProjectRoot: null });
|
|
41
41
|
});
|
|
42
42
|
|
|
@@ -213,7 +213,17 @@ describe('useSessionConversationInputState session preferences', () => {
|
|
|
213
213
|
selectedSkills: [],
|
|
214
214
|
skillRecords: [],
|
|
215
215
|
});
|
|
216
|
-
result.current.inputActions.
|
|
216
|
+
result.current.inputActions.beginSubmission({
|
|
217
|
+
sessionId: 'session-sent',
|
|
218
|
+
message: {
|
|
219
|
+
id: 'user-sent', sessionId: 'session-sent', role: 'user', status: 'final',
|
|
220
|
+
timestamp: '2026-09-24T00:00:00.000Z',
|
|
221
|
+
parts: [{ type: 'text', text: '已经发送的消息' }],
|
|
222
|
+
},
|
|
223
|
+
}, {
|
|
224
|
+
text: '已经发送的消息', nodes: [], selectedSkills: [], skillRecords: [], attachments: [],
|
|
225
|
+
});
|
|
226
|
+
result.current.inputActions.acceptSubmission('user-sent');
|
|
217
227
|
});
|
|
218
228
|
rerender({ sessionKey: 'session-unsent' });
|
|
219
229
|
act(() => {
|
package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts
CHANGED
|
@@ -5,12 +5,14 @@ import type {
|
|
|
5
5
|
UiNcpSessionQueuedInputView,
|
|
6
6
|
} from '@nextclaw/client-sdk';
|
|
7
7
|
import type { NcpAgentSendEnvelope, NcpRunHandle } from '@nextclaw/ncp';
|
|
8
|
+
import { NcpHttpSendError } from '@nextclaw/ncp-http-agent-client';
|
|
8
9
|
|
|
9
10
|
import {
|
|
10
11
|
createChatComposerNodesFromDraft,
|
|
11
12
|
deriveNcpMessagePartsFromComposer,
|
|
12
13
|
} from '@/features/chat/features/input/utils/chat-composer-state.utils';
|
|
13
14
|
import { isNcpChatSendDisabled } from '@/features/chat/features/input/utils/ncp-chat-input-availability.utils';
|
|
15
|
+
import { t } from '@/shared/lib/i18n';
|
|
14
16
|
import { buildChatRunMetadata } from '@/features/chat/features/session/utils/chat-run-metadata.utils';
|
|
15
17
|
import { createNcpSessionId } from '@/features/chat/features/session/utils/ncp-session-adapter.utils';
|
|
16
18
|
import type { SessionQueuedInputAttachmentPreview } from '@/features/chat/features/conversation/utils/session-queued-input.utils';
|
|
@@ -25,6 +27,7 @@ import {
|
|
|
25
27
|
useSessionConversationRecoveryActions,
|
|
26
28
|
type SessionConversationRecoveryAgent,
|
|
27
29
|
} from './use-session-conversation-recovery-actions';
|
|
30
|
+
import { useSessionSubmissionRecovery } from './use-session-submission-recovery';
|
|
28
31
|
|
|
29
32
|
type SessionConversationInputQuery = ReturnType<typeof useSessionConversationInputQuery>;
|
|
30
33
|
type ComposerDraftSnapshot = Pick<
|
|
@@ -80,8 +83,12 @@ type UseSessionConversationControllerParams = {
|
|
|
80
83
|
readonly selectedAgentId: string;
|
|
81
84
|
readonly sessionKey: string | null;
|
|
82
85
|
readonly onSessionMaterialized?: (sessionKey: string) => void;
|
|
83
|
-
readonly resetComposer: () => void;
|
|
84
86
|
readonly restoreComposer: (snapshot: ComposerDraftSnapshot) => void;
|
|
87
|
+
readonly beginSubmission: (envelope: NcpAgentSendEnvelope, composer: ComposerDraftSnapshot) => void;
|
|
88
|
+
readonly acceptSubmission: (messageId: string) => void;
|
|
89
|
+
readonly failSubmission: (messageId: string, status: 'uncertain' | 'rejected', message: string) => void;
|
|
90
|
+
readonly restoreSubmission: (messageId: string) => void;
|
|
91
|
+
readonly discardSubmission: (messageId: string) => void;
|
|
85
92
|
readonly setSendError: (message: string | null) => void;
|
|
86
93
|
};
|
|
87
94
|
|
|
@@ -90,7 +97,6 @@ type BuildSubmissionDraftParams = {
|
|
|
90
97
|
readonly composerSnapshot?: ComposerDraftSnapshot;
|
|
91
98
|
readonly inputSnapshot: SessionConversationInputSnapshot;
|
|
92
99
|
readonly inputQuery: SessionConversationInputQuery;
|
|
93
|
-
readonly isRuntimeBlocked: boolean;
|
|
94
100
|
readonly materializationContext?: SessionConversationMaterializationContext | null;
|
|
95
101
|
readonly selectedAgentId: string;
|
|
96
102
|
readonly sessionKey: string | null;
|
|
@@ -111,21 +117,12 @@ const resolveModelForSend = (value: string | null | undefined): string | undefin
|
|
|
111
117
|
return trimmed || undefined;
|
|
112
118
|
};
|
|
113
119
|
|
|
114
|
-
function buildInputAvailabilitySnapshot(inputQuery: SessionConversationInputQuery) {
|
|
115
|
-
return {
|
|
116
|
-
isProviderStateResolved: inputQuery.isProviderStateResolved,
|
|
117
|
-
modelOptions: inputQuery.modelOptions,
|
|
118
|
-
sessionTypeUnavailable: inputQuery.sessionTypeState.sessionTypeUnavailable,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
120
|
function buildSubmissionDraft(params: BuildSubmissionDraftParams): SubmissionDraft | null {
|
|
123
121
|
const {
|
|
124
122
|
agentIsSending,
|
|
125
123
|
composerSnapshot: requestedComposerSnapshot,
|
|
126
124
|
inputQuery,
|
|
127
125
|
inputSnapshot,
|
|
128
|
-
isRuntimeBlocked,
|
|
129
126
|
materializationContext,
|
|
130
127
|
selectedAgentId,
|
|
131
128
|
sessionKey,
|
|
@@ -142,10 +139,9 @@ function buildSubmissionDraft(params: BuildSubmissionDraftParams): SubmissionDra
|
|
|
142
139
|
composerSnapshot.attachments,
|
|
143
140
|
);
|
|
144
141
|
if (
|
|
142
|
+
inputSnapshot.pendingSubmission ||
|
|
145
143
|
isNcpChatSendDisabled({
|
|
146
|
-
snapshot: buildInputAvailabilitySnapshot(inputQuery),
|
|
147
144
|
hasSendableDraft: hasSendableMessagePart(currentParts),
|
|
148
|
-
isRuntimeBlocked,
|
|
149
145
|
}) ||
|
|
150
146
|
agentIsSending
|
|
151
147
|
) {
|
|
@@ -197,6 +193,7 @@ function buildSubmissionEnvelope(
|
|
|
197
193
|
): NcpAgentSendEnvelope | null {
|
|
198
194
|
const envelope = buildNcpRequestEnvelope({
|
|
199
195
|
sessionId: sessionKey ?? undefined,
|
|
196
|
+
messageId: `user-${crypto.randomUUID()}`,
|
|
200
197
|
text: draft.composerSnapshot.text.trim(),
|
|
201
198
|
attachments: [...draft.composerSnapshot.attachments],
|
|
202
199
|
parts: deriveNcpMessagePartsFromComposer(
|
|
@@ -205,7 +202,7 @@ function buildSubmissionEnvelope(
|
|
|
205
202
|
),
|
|
206
203
|
metadata: draft.metadata,
|
|
207
204
|
});
|
|
208
|
-
return envelope ? { ...envelope, delivery } : null;
|
|
205
|
+
return envelope ? { ...envelope, delivery, idempotencyKey: envelope.message.id } : null;
|
|
209
206
|
}
|
|
210
207
|
|
|
211
208
|
function useSubmissionDraftRunner(params: {
|
|
@@ -213,8 +210,9 @@ function useSubmissionDraftRunner(params: {
|
|
|
213
210
|
readonly clearSubmittingInput: (input: SubmittingQueuedInput) => void;
|
|
214
211
|
readonly materializationContext?: SessionConversationMaterializationContext | null;
|
|
215
212
|
readonly onSessionMaterialized?: (sessionKey: string) => void;
|
|
216
|
-
readonly
|
|
217
|
-
readonly
|
|
213
|
+
readonly beginSubmission: (envelope: NcpAgentSendEnvelope, composer: ComposerDraftSnapshot) => void;
|
|
214
|
+
readonly acceptSubmission: (messageId: string) => void;
|
|
215
|
+
readonly failSubmission: (messageId: string, status: 'uncertain' | 'rejected', message: string) => void;
|
|
218
216
|
readonly runQueue: SessionRunQueue;
|
|
219
217
|
readonly sessionKey: string | null;
|
|
220
218
|
readonly setSendError: (message: string | null) => void;
|
|
@@ -225,8 +223,9 @@ function useSubmissionDraftRunner(params: {
|
|
|
225
223
|
clearSubmittingInput,
|
|
226
224
|
materializationContext,
|
|
227
225
|
onSessionMaterialized,
|
|
228
|
-
|
|
229
|
-
|
|
226
|
+
beginSubmission,
|
|
227
|
+
acceptSubmission,
|
|
228
|
+
failSubmission,
|
|
230
229
|
runQueue,
|
|
231
230
|
sessionKey,
|
|
232
231
|
setSendError,
|
|
@@ -244,10 +243,16 @@ function useSubmissionDraftRunner(params: {
|
|
|
244
243
|
const queuedSubmission = agent.isRunning && delivery === 'queue'
|
|
245
244
|
? stageSubmittingInput(envelope)
|
|
246
245
|
: null;
|
|
247
|
-
if (composerBehavior === 'reset-and-restore')
|
|
246
|
+
if (composerBehavior === 'reset-and-restore') beginSubmission(envelope, draft.composerSnapshot);
|
|
248
247
|
setSendError(null);
|
|
248
|
+
let definitelyRejected = false;
|
|
249
249
|
try {
|
|
250
250
|
const handle = await agent.send(envelope);
|
|
251
|
+
if (!handle) {
|
|
252
|
+
definitelyRejected = true;
|
|
253
|
+
throw new Error(t('chatSendFailed'));
|
|
254
|
+
}
|
|
255
|
+
if (composerBehavior === 'reset-and-restore') acceptSubmission(envelope.message.id);
|
|
251
256
|
if (handle?.delivery === 'steered') {
|
|
252
257
|
await runQueue.refreshPendingInputs().catch(() => undefined);
|
|
253
258
|
} else if (handle?.delivery === 'queued') {
|
|
@@ -261,8 +266,12 @@ function useSubmissionDraftRunner(params: {
|
|
|
261
266
|
}
|
|
262
267
|
} catch (error) {
|
|
263
268
|
if (queuedSubmission) clearSubmittingInput(queuedSubmission);
|
|
264
|
-
|
|
265
|
-
|
|
269
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
270
|
+
if (composerBehavior === 'reset-and-restore') {
|
|
271
|
+
failSubmission(envelope.message.id,
|
|
272
|
+
definitelyRejected || (error instanceof NcpHttpSendError && error.sendRejected) ? 'rejected' : 'uncertain',
|
|
273
|
+
message);
|
|
274
|
+
} else setSendError(message);
|
|
266
275
|
throw error;
|
|
267
276
|
}
|
|
268
277
|
}, [
|
|
@@ -270,8 +279,9 @@ function useSubmissionDraftRunner(params: {
|
|
|
270
279
|
clearSubmittingInput,
|
|
271
280
|
materializationContext,
|
|
272
281
|
onSessionMaterialized,
|
|
273
|
-
|
|
274
|
-
|
|
282
|
+
beginSubmission,
|
|
283
|
+
acceptSubmission,
|
|
284
|
+
failSubmission,
|
|
275
285
|
runQueue,
|
|
276
286
|
sessionKey,
|
|
277
287
|
setSendError,
|
|
@@ -283,7 +293,6 @@ function useSteeringSubmission(params: {
|
|
|
283
293
|
readonly agent: SessionConversationAgent;
|
|
284
294
|
readonly inputSnapshot: SessionConversationInputSnapshot;
|
|
285
295
|
readonly inputQuery: SessionConversationInputQuery;
|
|
286
|
-
readonly isRuntimeBlocked: boolean;
|
|
287
296
|
readonly materializationContext?: SessionConversationMaterializationContext | null;
|
|
288
297
|
readonly selectedAgentId: string;
|
|
289
298
|
readonly sessionKey: string | null;
|
|
@@ -297,7 +306,6 @@ function useSteeringSubmission(params: {
|
|
|
297
306
|
agent,
|
|
298
307
|
inputQuery,
|
|
299
308
|
inputSnapshot,
|
|
300
|
-
isRuntimeBlocked,
|
|
301
309
|
materializationContext,
|
|
302
310
|
selectedAgentId,
|
|
303
311
|
sessionKey,
|
|
@@ -308,7 +316,6 @@ function useSteeringSubmission(params: {
|
|
|
308
316
|
agentIsSending: agent.isSending,
|
|
309
317
|
inputSnapshot,
|
|
310
318
|
inputQuery,
|
|
311
|
-
isRuntimeBlocked,
|
|
312
319
|
materializationContext,
|
|
313
320
|
selectedAgentId,
|
|
314
321
|
sessionKey,
|
|
@@ -318,7 +325,6 @@ function useSteeringSubmission(params: {
|
|
|
318
325
|
agent.isSending,
|
|
319
326
|
inputQuery,
|
|
320
327
|
inputSnapshot,
|
|
321
|
-
isRuntimeBlocked,
|
|
322
328
|
materializationContext,
|
|
323
329
|
selectedAgentId,
|
|
324
330
|
sessionKey,
|
|
@@ -331,7 +337,6 @@ function usePrimarySubmission(params: {
|
|
|
331
337
|
readonly continueRun: () => Promise<void>;
|
|
332
338
|
readonly inputSnapshot: SessionConversationInputSnapshot;
|
|
333
339
|
readonly inputQuery: SessionConversationInputQuery;
|
|
334
|
-
readonly isRuntimeBlocked: boolean;
|
|
335
340
|
readonly materializationContext?: SessionConversationMaterializationContext | null;
|
|
336
341
|
readonly primaryAction: 'continue' | 'send';
|
|
337
342
|
readonly selectedAgentId: string;
|
|
@@ -346,7 +351,6 @@ function usePrimarySubmission(params: {
|
|
|
346
351
|
continueRun,
|
|
347
352
|
inputQuery,
|
|
348
353
|
inputSnapshot,
|
|
349
|
-
isRuntimeBlocked,
|
|
350
354
|
materializationContext,
|
|
351
355
|
primaryAction,
|
|
352
356
|
selectedAgentId,
|
|
@@ -359,7 +363,6 @@ function usePrimarySubmission(params: {
|
|
|
359
363
|
agentIsSending: agent.isSending,
|
|
360
364
|
inputSnapshot,
|
|
361
365
|
inputQuery,
|
|
362
|
-
isRuntimeBlocked,
|
|
363
366
|
materializationContext,
|
|
364
367
|
selectedAgentId,
|
|
365
368
|
sessionKey,
|
|
@@ -370,7 +373,6 @@ function usePrimarySubmission(params: {
|
|
|
370
373
|
continueRun,
|
|
371
374
|
inputQuery,
|
|
372
375
|
inputSnapshot,
|
|
373
|
-
isRuntimeBlocked,
|
|
374
376
|
materializationContext,
|
|
375
377
|
primaryAction,
|
|
376
378
|
selectedAgentId,
|
|
@@ -379,6 +381,32 @@ function usePrimarySubmission(params: {
|
|
|
379
381
|
]);
|
|
380
382
|
}
|
|
381
383
|
|
|
384
|
+
function usePresetSubmission(params: {
|
|
385
|
+
readonly agent: SessionConversationAgent;
|
|
386
|
+
readonly inputSnapshot: SessionConversationInputSnapshot;
|
|
387
|
+
readonly inputQuery: SessionConversationInputQuery;
|
|
388
|
+
readonly materializationContext?: SessionConversationMaterializationContext | null;
|
|
389
|
+
readonly selectedAgentId: string;
|
|
390
|
+
readonly sessionKey: string | null;
|
|
391
|
+
readonly submitDraft: (draft: SubmissionDraft, behavior: SubmissionComposerBehavior) => Promise<void>;
|
|
392
|
+
}) {
|
|
393
|
+
const { agent, inputSnapshot, inputQuery, materializationContext, selectedAgentId, sessionKey, submitDraft } = params;
|
|
394
|
+
return useCallback(async (message: string) => {
|
|
395
|
+
const text = message.trim();
|
|
396
|
+
if (!text) return;
|
|
397
|
+
const draft = buildSubmissionDraft({
|
|
398
|
+
agentIsSending: agent.isSending,
|
|
399
|
+
composerSnapshot: {
|
|
400
|
+
text,
|
|
401
|
+
nodes: createChatComposerNodesFromDraft(text),
|
|
402
|
+
selectedSkills: [], skillRecords: [], attachments: [],
|
|
403
|
+
},
|
|
404
|
+
inputSnapshot, inputQuery, materializationContext, selectedAgentId, sessionKey,
|
|
405
|
+
});
|
|
406
|
+
if (draft) await submitDraft(draft, 'preserve');
|
|
407
|
+
}, [agent.isSending, inputQuery, inputSnapshot, materializationContext, selectedAgentId, sessionKey, submitDraft]);
|
|
408
|
+
}
|
|
409
|
+
|
|
382
410
|
export function useSessionConversationController(params: UseSessionConversationControllerParams) {
|
|
383
411
|
const {
|
|
384
412
|
agent,
|
|
@@ -390,8 +418,12 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
390
418
|
selectedAgentId,
|
|
391
419
|
sessionKey,
|
|
392
420
|
onSessionMaterialized,
|
|
393
|
-
resetComposer,
|
|
394
421
|
restoreComposer,
|
|
422
|
+
beginSubmission,
|
|
423
|
+
acceptSubmission,
|
|
424
|
+
failSubmission,
|
|
425
|
+
restoreSubmission,
|
|
426
|
+
discardSubmission,
|
|
395
427
|
setSendError,
|
|
396
428
|
} = params;
|
|
397
429
|
const {
|
|
@@ -421,12 +453,10 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
421
453
|
);
|
|
422
454
|
const primaryAction: 'continue' | 'send' =
|
|
423
455
|
canContinue && !hasSendableDraft ? 'continue' : 'send';
|
|
424
|
-
const sendDisabled = primaryAction === 'continue'
|
|
456
|
+
const sendDisabled = inputSnapshot.pendingSubmission ? true : primaryAction === 'continue'
|
|
425
457
|
? false
|
|
426
458
|
: isNcpChatSendDisabled({
|
|
427
|
-
snapshot: buildInputAvailabilitySnapshot(inputQuery),
|
|
428
459
|
hasSendableDraft,
|
|
429
|
-
isRuntimeBlocked,
|
|
430
460
|
}) || agent.isSending;
|
|
431
461
|
|
|
432
462
|
const { continueRun, editMessage } = useSessionConversationRecoveryActions({
|
|
@@ -440,8 +470,9 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
440
470
|
clearSubmittingInput,
|
|
441
471
|
materializationContext,
|
|
442
472
|
onSessionMaterialized,
|
|
443
|
-
|
|
444
|
-
|
|
473
|
+
beginSubmission,
|
|
474
|
+
acceptSubmission,
|
|
475
|
+
failSubmission,
|
|
445
476
|
runQueue,
|
|
446
477
|
sessionKey,
|
|
447
478
|
setSendError,
|
|
@@ -453,7 +484,6 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
453
484
|
continueRun,
|
|
454
485
|
inputQuery,
|
|
455
486
|
inputSnapshot,
|
|
456
|
-
isRuntimeBlocked,
|
|
457
487
|
materializationContext,
|
|
458
488
|
primaryAction,
|
|
459
489
|
selectedAgentId,
|
|
@@ -465,52 +495,33 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
465
495
|
agent,
|
|
466
496
|
inputQuery,
|
|
467
497
|
inputSnapshot,
|
|
468
|
-
isRuntimeBlocked,
|
|
469
498
|
materializationContext,
|
|
470
499
|
selectedAgentId,
|
|
471
500
|
sessionKey,
|
|
472
501
|
submitDraft,
|
|
473
502
|
});
|
|
474
503
|
|
|
475
|
-
const sendPresetMessage =
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
const draft = buildSubmissionDraft({
|
|
481
|
-
agentIsSending: agent.isSending,
|
|
482
|
-
composerSnapshot: {
|
|
483
|
-
text,
|
|
484
|
-
nodes: createChatComposerNodesFromDraft(text),
|
|
485
|
-
selectedSkills: [],
|
|
486
|
-
skillRecords: [],
|
|
487
|
-
attachments: [],
|
|
488
|
-
},
|
|
489
|
-
inputSnapshot,
|
|
490
|
-
inputQuery,
|
|
491
|
-
isRuntimeBlocked,
|
|
492
|
-
materializationContext,
|
|
493
|
-
selectedAgentId,
|
|
494
|
-
sessionKey,
|
|
495
|
-
});
|
|
496
|
-
if (draft) {
|
|
497
|
-
await submitDraft(draft, 'preserve');
|
|
498
|
-
}
|
|
499
|
-
}, [
|
|
500
|
-
agent.isSending,
|
|
501
|
-
inputQuery,
|
|
502
|
-
inputSnapshot,
|
|
503
|
-
isRuntimeBlocked,
|
|
504
|
-
materializationContext,
|
|
505
|
-
selectedAgentId,
|
|
506
|
-
sessionKey,
|
|
507
|
-
submitDraft,
|
|
508
|
-
]);
|
|
504
|
+
const sendPresetMessage = usePresetSubmission({
|
|
505
|
+
agent, inputSnapshot, inputQuery, materializationContext,
|
|
506
|
+
selectedAgentId, sessionKey, submitDraft,
|
|
507
|
+
});
|
|
509
508
|
|
|
510
509
|
const stop = useCallback(async () => {
|
|
511
510
|
await agent.abort();
|
|
512
511
|
}, [agent]);
|
|
513
512
|
|
|
513
|
+
const submissionRecovery = useSessionSubmissionRecovery({
|
|
514
|
+
agent,
|
|
515
|
+
submission: inputSnapshot.pendingSubmission,
|
|
516
|
+
sessionKey,
|
|
517
|
+
onSessionMaterialized,
|
|
518
|
+
acceptSubmission,
|
|
519
|
+
failSubmission,
|
|
520
|
+
restoreSubmission,
|
|
521
|
+
discardSubmission,
|
|
522
|
+
setSendError,
|
|
523
|
+
});
|
|
524
|
+
|
|
514
525
|
return {
|
|
515
526
|
canContinue,
|
|
516
527
|
canStopGeneration: agent.isRunning,
|
|
@@ -525,6 +536,7 @@ export function useSessionConversationController(params: UseSessionConversationC
|
|
|
525
536
|
send,
|
|
526
537
|
sendSteering,
|
|
527
538
|
sendPresetMessage,
|
|
539
|
+
...submissionRecovery,
|
|
528
540
|
sendDisabled,
|
|
529
541
|
primaryAction,
|
|
530
542
|
stop,
|
package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
filterNcpChatModelOptionsBySessionType,
|
|
13
13
|
} from '@/features/chat/features/ncp/utils/ncp-chat-query-derived.utils';
|
|
14
14
|
import { adaptNcpSessionSummaries } from '@/features/chat/features/session/utils/ncp-session-adapter.utils';
|
|
15
|
-
import {
|
|
15
|
+
import { resolveRecentSessionPreferenceSnapshot } from '@/features/chat/features/session/utils/chat-session-preference-governance.utils';
|
|
16
16
|
import { useChatSessionTypeState } from '@/features/chat/features/session-type/hooks/use-chat-session-type-state';
|
|
17
17
|
import { chatRecentModelsManager } from '@/features/chat/managers/chat-recent-models.manager';
|
|
18
18
|
import { useChatQueryStore } from '@/features/chat/stores/ncp-chat-query.store';
|
|
@@ -112,27 +112,17 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
|
|
|
112
112
|
const recentSessionTypeModel = chatRecentModelsManager
|
|
113
113
|
.read({ namespace: sessionTypeState.selectedSessionType })
|
|
114
114
|
.find((value) => availableModelValueSet.has(value));
|
|
115
|
-
const
|
|
115
|
+
const recentSessionPreferences = useMemo(
|
|
116
116
|
() =>
|
|
117
|
-
|
|
118
|
-
resolveRecentSessionPreferredValue<string>({
|
|
117
|
+
resolveRecentSessionPreferenceSnapshot({
|
|
119
118
|
sessions,
|
|
120
119
|
selectedSessionKey,
|
|
121
120
|
sessionType: sessionTypeState.selectedSessionType,
|
|
122
|
-
readPreference: (session) => session.preferredModel?.trim() || undefined,
|
|
123
|
-
}),
|
|
124
|
-
[recentSessionTypeModel, selectedSessionKey, sessionTypeState.selectedSessionType, sessions],
|
|
125
|
-
);
|
|
126
|
-
const fallbackPreferredThinking = useMemo(
|
|
127
|
-
() =>
|
|
128
|
-
resolveRecentSessionPreferredValue({
|
|
129
|
-
sessions,
|
|
130
|
-
selectedSessionKey,
|
|
131
|
-
sessionType: sessionTypeState.selectedSessionType,
|
|
132
|
-
readPreference: (session) => session.preferredThinking ?? undefined,
|
|
133
121
|
}),
|
|
134
122
|
[selectedSessionKey, sessionTypeState.selectedSessionType, sessions],
|
|
135
123
|
);
|
|
124
|
+
const fallbackPreferredModel = recentSessionPreferences?.model ?? recentSessionTypeModel;
|
|
125
|
+
const fallbackPreferredThinking = recentSessionPreferences?.thinking;
|
|
136
126
|
|
|
137
127
|
const defaultProjectRoot = normalizeSessionProjectRootValue(
|
|
138
128
|
config?.agents.defaults.workspace,
|