@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.
Files changed (249) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/dist/assets/{abnfDiagram-VRR7QNED-DvTjgVMf.js → abnfDiagram-VRR7QNED-DrbfiNNF.js} +1 -1
  3. package/dist/assets/{aiden0z-pptx-renderer.es-C1nfBAXR.js → aiden0z-pptx-renderer.es-DdLb2IVc.js} +1 -1
  4. package/dist/assets/{api-BH6Oslx4.js → api-CUSlBpt_.js} +3 -3
  5. package/dist/assets/{appearance-settings-page-zhgfcGgW.js → appearance-settings-page-cTuZdROP.js} +1 -1
  6. package/dist/assets/{arc-BvhODBXv.js → arc-BXlMc9B0.js} +1 -1
  7. package/dist/assets/architecture-TIHT7OUA-Bq0i9WiE.js +1 -0
  8. package/dist/assets/{architectureDiagram-ZJ3FMSHR-BKO9RgNS.js → architectureDiagram-ZJ3FMSHR-DXAJxxO0.js} +1 -1
  9. package/dist/assets/{blockDiagram-677ZJIJ3-DHpDXy7D.js → blockDiagram-677ZJIJ3-i4Kz7zU0.js} +1 -1
  10. package/dist/assets/{book-open-DGTS6oEO.js → book-open-BJ-xAIp9.js} +1 -1
  11. package/dist/assets/{c4Diagram-LMCZKHZV-BG_iQnDr.js → c4Diagram-LMCZKHZV-BDc0TkPd.js} +1 -1
  12. package/dist/assets/channel-iCaZQ87u.js +1 -0
  13. package/dist/assets/{channels-list-page-3D5lhZoT.js → channels-list-page-nRHOasWA.js} +2 -2
  14. package/dist/assets/chunk-2Q5K7J3B-DFQtlnJS.js +1 -0
  15. package/dist/assets/{chunk-32BRIVSS-DR9M0LLx.js → chunk-32BRIVSS-DuReei0Z.js} +1 -1
  16. package/dist/assets/{chunk-52WLFC77-698iC3BB.js → chunk-52WLFC77-D8APq0tm.js} +1 -1
  17. package/dist/assets/{chunk-5FCAYU7R-DikTj9Ey.js → chunk-5FCAYU7R-BsPrNXNS.js} +1 -1
  18. package/dist/assets/{chunk-5HE753X5-ko0o7_q0.js → chunk-5HE753X5-BRtkOPoJ.js} +1 -1
  19. package/dist/assets/{chunk-5JV3BV7I-CEHufhgo.js → chunk-5JV3BV7I-ChPc8e8U.js} +1 -1
  20. package/dist/assets/{chunk-5TONJI2A-CGgno1cu.js → chunk-5TONJI2A-CzTjlJGb.js} +1 -1
  21. package/dist/assets/{chunk-5VM5RSS4-DkiB4cUQ.js → chunk-5VM5RSS4-xsv_22jR.js} +1 -1
  22. package/dist/assets/{chunk-7BUUIJ7U-DzptcytQ.js → chunk-7BUUIJ7U-CwECujme.js} +1 -1
  23. package/dist/assets/{chunk-BIQX33UG-DMRSQJvT.js → chunk-BIQX33UG-DQAm173p.js} +1 -1
  24. package/dist/assets/{chunk-C7G6YPKG-Bw1BwwuY.js → chunk-C7G6YPKG-BkpajeQb.js} +1 -1
  25. package/dist/assets/{chunk-CQNSW5MT-C0z6eHBk.js → chunk-CQNSW5MT-ND65pWRA.js} +1 -1
  26. package/dist/assets/{chunk-CYSBUYHQ-ByPyAouO.js → chunk-CYSBUYHQ-vMu6ijxG.js} +1 -1
  27. package/dist/assets/{chunk-EMLP6XTP-CJlAXWZg.js → chunk-EMLP6XTP-CEaeW3gH.js} +1 -1
  28. package/dist/assets/{chunk-EX3LRPZG-Dqq4zKJu.js → chunk-EX3LRPZG-a4ER-HDr.js} +1 -1
  29. package/dist/assets/{chunk-FWX5IMBZ-B0SNoCmi.js → chunk-FWX5IMBZ-C_8fQssn.js} +2 -2
  30. package/dist/assets/{chunk-HOUHSVGY-DG_GJih_.js → chunk-HOUHSVGY-CEvw-PEd.js} +1 -1
  31. package/dist/assets/{chunk-ICXQ74PX-Drxk_6bE.js → chunk-ICXQ74PX-BEtF0fGY.js} +1 -1
  32. package/dist/assets/{chunk-JG7HCLWE-DdLFPpnd.js → chunk-JG7HCLWE-DGRrVp8-.js} +1 -1
  33. package/dist/assets/{chunk-JWPE2WC7-B8M4G76F.js → chunk-JWPE2WC7-DRqpp_nM.js} +1 -1
  34. package/dist/assets/{chunk-MOJQB5TN-XP6FJHY_.js → chunk-MOJQB5TN-BDEriOXs.js} +1 -1
  35. package/dist/assets/{chunk-MOZMSUNE-C_6x18Qw.js → chunk-MOZMSUNE-JWRNzdnw.js} +1 -1
  36. package/dist/assets/{chunk-OGEWGWER-N25BzCmG.js → chunk-OGEWGWER-DS2VTgCx.js} +1 -1
  37. package/dist/assets/{chunk-OSBZ3O6U-ASDEm7y0.js → chunk-OSBZ3O6U-3LiYTBUB.js} +1 -1
  38. package/dist/assets/{chunk-PUDLZKDR-CTlvAcn7.js → chunk-PUDLZKDR-o9M2s_SO.js} +1 -1
  39. package/dist/assets/{chunk-Q4XR5HBZ-Da9BWfB6.js → chunk-Q4XR5HBZ-DTB7Ma2N.js} +1 -1
  40. package/dist/assets/{chunk-QBLGF6JB-Bi6RpTJO.js → chunk-QBLGF6JB-DpkxZJL5.js} +1 -1
  41. package/dist/assets/{chunk-R7FJI6CG-DkMsSPvK.js → chunk-R7FJI6CG-CRejkHJU.js} +1 -1
  42. package/dist/assets/{chunk-RYQCIY6F-DZp0eU-j.js → chunk-RYQCIY6F-B1boBjLt.js} +1 -1
  43. package/dist/assets/{chunk-U6XO7XAA-vfinDSrj.js → chunk-U6XO7XAA-DgKa97bj.js} +1 -1
  44. package/dist/assets/{chunk-V7JOEXUC-C9Nksccs.js → chunk-V7JOEXUC-DE56eh0N.js} +1 -1
  45. package/dist/assets/chunk-VAUOI2AC-CF9A-TeE.js +1 -0
  46. package/dist/assets/{chunk-VR4S4FIN-Xv6zfwXs.js → chunk-VR4S4FIN-BzomPZq2.js} +1 -1
  47. package/dist/assets/{chunk-WYO6CB5R-mOJNzbWl.js → chunk-WYO6CB5R-C6gy8rSd.js} +2 -2
  48. package/dist/assets/chunk-XXDRQBXY-BRxdfVCU.js +1 -0
  49. package/dist/assets/{chunk-YOTPTUD7-1-aKSu4o.js → chunk-YOTPTUD7-BK98yfl9.js} +1 -1
  50. package/dist/assets/{chunk-ZGVPDNZ5-OJ8veMpK.js → chunk-ZGVPDNZ5-DFXAhwUT.js} +1 -1
  51. package/dist/assets/{chunk-ZIRB5QZD-SR_Nq_PP.js → chunk-ZIRB5QZD-Bbu6BiNC.js} +1 -1
  52. package/dist/assets/classDiagram-OUVF2IWQ-Bo28fPi-.js +1 -0
  53. package/dist/assets/classDiagram-v2-EOCWNBFH-BOVN9wUz.js +1 -0
  54. package/dist/assets/{config-split-page-B55XD_ZY.js → config-split-page-DO1Oyb-r.js} +1 -1
  55. package/dist/assets/{confirm-dialog-BCCreI_f.js → confirm-dialog-CCae9Fr4.js} +1 -1
  56. package/dist/assets/{cose-bilkent-JH36ORCC-NjVgz2Bw.js → cose-bilkent-JH36ORCC-BV8KR4uF.js} +1 -1
  57. package/dist/assets/cynefin-VYW2F7L2-B7rF3JRp.js +1 -0
  58. package/dist/assets/{cynefinDiagram-TSTJHNR4-B_17LDqD.js → cynefinDiagram-TSTJHNR4-Ckd6nU9t.js} +1 -1
  59. package/dist/assets/{dagre-CMe101gk.js → dagre-D_T-FW5i.js} +1 -1
  60. package/dist/assets/{dagre-VKFMJZFB-qo8nLb3B.js → dagre-VKFMJZFB-CyDaQpD4.js} +1 -1
  61. package/dist/assets/desktop-update-config-XSV-DjJW.js +1 -0
  62. package/dist/assets/{diagram-FQU43EPY-Ba3XIklC.js → diagram-FQU43EPY-CghnwS0H.js} +1 -1
  63. package/dist/assets/{diagram-G47NLZAW-CG45TcUx.js → diagram-G47NLZAW-DK4DJ3Kx.js} +1 -1
  64. package/dist/assets/{diagram-NH7WQ7WH-2F2HrwV-.js → diagram-NH7WQ7WH-CUgDkZCJ.js} +1 -1
  65. package/dist/assets/{diagram-OA4YK3LP-CXfWH9NZ.js → diagram-OA4YK3LP-vO2gyH6n.js} +1 -1
  66. package/dist/assets/{diagram-WEI45ONY-CH_4yepc.js → diagram-WEI45ONY-DbSBRDSr.js} +1 -1
  67. package/dist/assets/{dist-IRWcJpfm.js → dist-1N9UpL3c.js} +1 -1
  68. package/dist/assets/{dist-BYSUQaO2.js → dist-C-2H76Cv.js} +1 -1
  69. package/dist/assets/doc-browser-BHFCZIoL.js +1 -0
  70. package/dist/assets/{doc-browser-D8rNrWHk.js → doc-browser-CRlpqMwH.js} +1 -1
  71. package/dist/assets/{doc-browser-context-DjTbIbQc.js → doc-browser-context-C0Bns1J6.js} +1 -1
  72. package/dist/assets/{docx-preview-CoM4JK7_.js → docx-preview-DfxIm9IB.js} +1 -1
  73. package/dist/assets/{ebnfDiagram-CCIWWBDH-BwiG4Ea1.js → ebnfDiagram-CCIWWBDH-W7CAcK7r.js} +1 -1
  74. package/dist/assets/{erDiagram-Q63AITRT-BML3hpnQ.js → erDiagram-Q63AITRT-LA0JWL8-.js} +1 -1
  75. package/dist/assets/eventmodeling-45OFAUF4-DzQLXa3s.js +1 -0
  76. package/dist/assets/flowDiagram-23GEKE2U-C81eexJZ.js +1 -0
  77. package/dist/assets/{form-actions-C8hazgNP.js → form-actions-CMxhPact.js} +1 -1
  78. package/dist/assets/{ganttDiagram-NO4QXBWP-80enfWbD.js → ganttDiagram-NO4QXBWP-_PiTPavJ.js} +1 -1
  79. package/dist/assets/gitGraph-TEB2WS4Q-Dt3ZqpFD.js +1 -0
  80. package/dist/assets/{gitGraphDiagram-IHSO6WYX-CVLqXr-b.js → gitGraphDiagram-IHSO6WYX-DsRB1ZMU.js} +1 -1
  81. package/dist/assets/index-DdYOaKm7.js +109 -0
  82. package/dist/assets/index-DxCGKhAw.css +1 -0
  83. package/dist/assets/info-DKCQHKI2-CCCE7dXC.js +1 -0
  84. package/dist/assets/{infoDiagram-FWYZ7A6U-Dyvs2t0i.js → infoDiagram-FWYZ7A6U-wIRraYx5.js} +1 -1
  85. package/dist/assets/{ishikawaDiagram-FXEZZL3T-sSnxDKfh.js → ishikawaDiagram-FXEZZL3T-CNzsrcrh.js} +1 -1
  86. package/dist/assets/{journeyDiagram-5HDEW3XC-D22V71Mf.js → journeyDiagram-5HDEW3XC-Dy9huHxy.js} +1 -1
  87. package/dist/assets/{kanban-definition-HUTT4EX6-D3ds0p-g.js → kanban-definition-HUTT4EX6-BOCIN365.js} +1 -1
  88. package/dist/assets/{line-CbyFs065.js → line-BxsizOTs.js} +1 -1
  89. package/dist/assets/{linear-4DKtnZBS.js → linear-C_YHf92I.js} +1 -1
  90. package/dist/assets/loader-circle-B-UdXjl4.js +1 -0
  91. package/dist/assets/{map-CcZzEoz6.js → map-CobcjgZ8.js} +1 -1
  92. package/dist/assets/mcp-marketplace-page-BUIGtSda.js +1 -0
  93. package/dist/assets/mcp-marketplace-page-CStb8ml2.js +9 -0
  94. package/dist/assets/{mermaid-parser.core-DPmMOjXD.js → mermaid-parser.core-D7lu2RbA.js} +2 -2
  95. package/dist/assets/{mermaid.core-BSf-ddRa.js → mermaid.core-CbfW2Rk8.js} +3 -3
  96. package/dist/assets/{mindmap-definition-LN4V7U3C-BUTwWPyx.js → mindmap-definition-LN4V7U3C-DUjGXlIC.js} +1 -1
  97. package/dist/assets/model-config-page-BkfUYm95.js +1 -0
  98. package/dist/assets/{navigation-link-kGAcL2N2.js → navigation-link-v3FaWcIr.js} +1 -1
  99. package/dist/assets/{ordinal-BgLYtOZE.js → ordinal-CjoUCHto.js} +1 -1
  100. package/dist/assets/packet-7NZHBO7P-D19yoxFV.js +1 -0
  101. package/dist/assets/{pegDiagram-2B236MQR-BEu_ZBjc.js → pegDiagram-2B236MQR-BQY2DgiP.js} +1 -1
  102. package/dist/assets/pie-RZYD4A2V-hMaJbLrn.js +1 -0
  103. package/dist/assets/{pieDiagram-ENE6RG2P-CAwAwuBd.js → pieDiagram-ENE6RG2P-D18owe4D.js} +1 -1
  104. package/dist/assets/plus-Dw9QFnKr.js +1 -0
  105. package/dist/assets/{privacy-settings-page-v9LTFvJe.js → privacy-settings-page-CYM1Dxwo.js} +1 -1
  106. package/dist/assets/providers-config-page-fxL4I4bz.js +1 -0
  107. package/dist/assets/{quadrantDiagram-ABIIQ3AL-CwE6F-_2.js → quadrantDiagram-ABIIQ3AL-B8F7YoTA.js} +1 -1
  108. package/dist/assets/radar-I7S5WNFK-C8BkvScA.js +1 -0
  109. package/dist/assets/railroad-3IZDKUUU-CozZOitC.js +1 -0
  110. package/dist/assets/railroad-abnf-AHOZXSZD-BqIoFXFi.js +1 -0
  111. package/dist/assets/railroad-ebnf-EBAXGLYW-CD2e3dng.js +1 -0
  112. package/dist/assets/railroad-peg-LSFZ7HO6-DoKlRUOF.js +1 -0
  113. package/dist/assets/{railroadDiagram-RFXS5EU6-xgLekU3B.js → railroadDiagram-RFXS5EU6-RU8GpxN5.js} +1 -1
  114. package/dist/assets/{react-Dwvp5yeX.js → react-Dlz_IxoP.js} +1 -1
  115. package/dist/assets/{refresh-cw-C_oj_h_s.js → refresh-cw-CK4I5UFv.js} +1 -1
  116. package/dist/assets/remote-B0pPgtC6.js +1 -0
  117. package/dist/assets/{requirementDiagram-TGXJPOKE-CyVUzEX5.js → requirementDiagram-TGXJPOKE-ubPOmmNi.js} +1 -1
  118. package/dist/assets/rotate-cw-Z48dmh13.js +1 -0
  119. package/dist/assets/runtime-config-page-C7vksFVD.js +1 -0
  120. package/dist/assets/{sankeyDiagram-HTMAVEWB-JK6bFmYB.js → sankeyDiagram-HTMAVEWB-8L_hXJWW.js} +1 -1
  121. package/dist/assets/{save-BZE6H02N.js → save-Bo37cIFb.js} +1 -1
  122. package/dist/assets/{search-C7Tj40kC.js → search-CZiEm7YD.js} +1 -1
  123. package/dist/assets/search-config-page-DKdEf7m9.js +1 -0
  124. package/dist/assets/{secrets-config-page-B__VLAEQ.js → secrets-config-page-COlMqSfL.js} +2 -2
  125. package/dist/assets/security-config-CitLihXA.js +1 -0
  126. package/dist/assets/{select-fZ5tifar.js → select-BACzapV3.js} +1 -1
  127. package/dist/assets/{sequenceDiagram-DBY2YBRQ-BR5IokXV.js → sequenceDiagram-DBY2YBRQ-Dom6Qor5.js} +1 -1
  128. package/dist/assets/{sizeCapture-X5ZJPWSS-SxG_YnMA.js → sizeCapture-X5ZJPWSS-cZcFSpLJ.js} +1 -1
  129. package/dist/assets/skeleton-B2PCAZJG.js +1 -0
  130. package/dist/assets/{src-vgz8E_-O.js → src-BE9E1xcR.js} +1 -1
  131. package/dist/assets/{stateDiagram-2N3HPSRC-DD4OoYhn.js → stateDiagram-2N3HPSRC-CHrpxmGO.js} +1 -1
  132. package/dist/assets/stateDiagram-v2-6OUMAXLB-b1pZQlDD.js +1 -0
  133. package/dist/assets/{swimlanes-5IMT3BWC-BWkFeyCT.js → swimlanes-5IMT3BWC-D6nJS2xQ.js} +2 -2
  134. package/dist/assets/swimlanesDiagram-G3AALYLV-CowxgWVn.js +8 -0
  135. package/dist/assets/{tag-chip-CwYZcRoe.js → tag-chip-BnamTQVX.js} +1 -1
  136. package/dist/assets/{timeline-definition-FHXFAJF6-VTRPy6KA.js → timeline-definition-FHXFAJF6-DJNn-HQO.js} +1 -1
  137. package/dist/assets/treeView-QDETBFTQ-BQlYkJbz.js +1 -0
  138. package/dist/assets/treemap-6X3UGDF4-DzTOd1bd.js +1 -0
  139. package/dist/assets/{vennDiagram-L72KCM5P-Bvk42Pek.js → vennDiagram-L72KCM5P-CCEzHoXt.js} +1 -1
  140. package/dist/assets/wardley-OPB4EBWU-D80jQc0y.js +1 -0
  141. package/dist/assets/{wardleyDiagram-EHGQE667-DOFjx2s3.js → wardleyDiagram-EHGQE667-BhyVxVXt.js} +1 -1
  142. package/dist/assets/x-BzYEzkLA.js +1 -0
  143. package/dist/assets/{xychartDiagram-FW5EYKEG-DY5yRTUc.js → xychartDiagram-FW5EYKEG-CacW_246.js} +1 -1
  144. package/dist/index.html +70 -22
  145. package/index.html +49 -1
  146. package/package.json +8 -8
  147. package/src/app/index.tsx +1 -3
  148. package/src/app/managers/__tests__/viewport-layout.manager.test.ts +12 -0
  149. package/src/app/managers/viewport-layout.manager.ts +12 -0
  150. package/src/app/stores/viewport-layout.store.ts +23 -11
  151. package/src/features/apps/components/__tests__/app-marketplace-catalog.test.tsx +161 -0
  152. package/src/features/apps/components/app-marketplace-catalog.tsx +36 -7
  153. package/src/features/apps/components/app-marketplace-detail.tsx +29 -6
  154. package/src/features/apps/components/app-marketplace-dialog.tsx +71 -55
  155. package/src/features/apps/components/app-marketplace-operation.tsx +128 -16
  156. package/src/features/apps/components/app-packages-panel.tsx +1 -0
  157. package/src/features/apps/utils/app-marketplace-platform.utils.test.ts +59 -0
  158. package/src/features/apps/utils/app-marketplace-platform.utils.ts +33 -0
  159. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +6 -0
  160. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +6 -2
  161. package/src/features/chat/features/conversation/components/__tests__/session-queued-input-rows.test.tsx +46 -0
  162. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +15 -2
  163. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +5 -3
  164. package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +59 -5
  165. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +35 -1
  166. package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx +25 -19
  167. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +148 -134
  168. package/src/features/chat/features/conversation/hooks/use-session-pending-input-actions.ts +135 -0
  169. package/src/features/chat/features/conversation/hooks/use-session-run-queue.ts +19 -4
  170. package/src/features/chat/features/conversation/utils/__tests__/session-queued-input.utils.test.ts +52 -2
  171. package/src/features/chat/features/conversation/utils/session-queued-input.utils.ts +46 -5
  172. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +1 -0
  173. package/src/features/chat/features/ncp/hooks/__tests__/use-hydrated-ncp-agent.test.tsx +102 -0
  174. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-conversation.test.tsx +117 -1
  175. package/src/features/chat/features/ncp/hooks/use-ncp-session-conversation.ts +2 -2
  176. package/src/features/chat/features/ncp/hooks/use-ncp-session-message-history.ts +31 -81
  177. package/src/features/chat/features/ncp/hooks/use-ncp-session-seed-loader.ts +134 -0
  178. package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +1 -6
  179. package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +8 -0
  180. package/src/features/panel-apps/components/__tests__/panel-app-main-sidebar-nav.test.tsx +99 -13
  181. package/src/features/panel-apps/components/panel-app-main-sidebar-menu-item.tsx +4 -0
  182. package/src/features/panel-apps/components/panel-app-main-sidebar-nav.tsx +166 -31
  183. package/src/shared/lib/api/utils/ncp-attachments.utils.ts +8 -1
  184. package/src/shared/lib/api/utils/ncp-session.utils.ts +1 -0
  185. package/src/shared/lib/i18n/locales/en-US/chat.json +3 -0
  186. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +11 -1
  187. package/src/shared/lib/i18n/locales/zh-CN/chat.json +3 -0
  188. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +11 -1
  189. package/src/vite-env.d.ts +9 -0
  190. package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +0 -1
  191. package/dist/assets/channel-5T3pdR-s.js +0 -1
  192. package/dist/assets/chat-page-BXu3hnOK.js +0 -1
  193. package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +0 -1
  194. package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +0 -1
  195. package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +0 -1
  196. package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +0 -1
  197. package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +0 -1
  198. package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +0 -1
  199. package/dist/assets/desktop-update-config-Blol-Umu.js +0 -1
  200. package/dist/assets/doc-browser-BExPq1Hk.js +0 -1
  201. package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +0 -1
  202. package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +0 -1
  203. package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +0 -1
  204. package/dist/assets/index-Btj8yN4T.css +0 -1
  205. package/dist/assets/index-CHcGqqBe.js +0 -109
  206. package/dist/assets/info-DKCQHKI2-DNlNGH90.js +0 -1
  207. package/dist/assets/loader-circle-C75DUmmm.js +0 -1
  208. package/dist/assets/mcp-marketplace-page-CIMRYgOY.js +0 -9
  209. package/dist/assets/mcp-marketplace-page-D2NlhG1k.js +0 -1
  210. package/dist/assets/model-config-page-ChR-ENjp.js +0 -1
  211. package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +0 -1
  212. package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +0 -1
  213. package/dist/assets/plus-TzSIMKWW.js +0 -1
  214. package/dist/assets/provider-scoped-model-input-DiSpKSk0.js +0 -1
  215. package/dist/assets/providers-config-page-BvXa03cp.js +0 -1
  216. package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +0 -1
  217. package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +0 -1
  218. package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +0 -1
  219. package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +0 -1
  220. package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +0 -1
  221. package/dist/assets/remote-BgYduCQR.js +0 -1
  222. package/dist/assets/rotate-cw-BT8HxlcB.js +0 -1
  223. package/dist/assets/runtime-config-page-BuYof2Ty.js +0 -1
  224. package/dist/assets/search-config-page-CQTJOsOf.js +0 -1
  225. package/dist/assets/security-config-CtJqaPVL.js +0 -1
  226. package/dist/assets/settings-2-BHGgNlOH.js +0 -1
  227. package/dist/assets/skeleton-CJLc1CWn.js +0 -1
  228. package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +0 -1
  229. package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +0 -8
  230. package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +0 -1
  231. package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +0 -1
  232. package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +0 -1
  233. package/dist/assets/x-BMl7cucN.js +0 -1
  234. /package/dist/assets/{array-NADKd9aU.js → array-COEOjKUv.js} +0 -0
  235. /package/dist/assets/{chunk-KEIR6QF5-BuyuzJJL.js → chunk-KEIR6QF5-D7oHAcry.js} +0 -0
  236. /package/dist/assets/{chunk-Y2CYZVJY-D_B2ZRNt.js → chunk-Y2CYZVJY-08IUpgTP.js} +0 -0
  237. /package/dist/assets/{config-hints-BcfVUMij.js → config-hints-BoE41XDI.js} +0 -0
  238. /package/dist/assets/{cytoscape.esm-BANTlgza.js → cytoscape.esm-HifWufkp.js} +0 -0
  239. /package/dist/assets/{defaultLocale-C4_L0aEs.js → defaultLocale-CA-_SsC1.js} +0 -0
  240. /package/dist/assets/{dist-DAPEIJbz.js → dist-C60rvfy8.js} +0 -0
  241. /package/dist/assets/{graphlib-ChqXg0dI.js → graphlib-CGYCNsoJ.js} +0 -0
  242. /package/dist/assets/{host-capabilities-D9C4CBK5.js → host-capabilities-DPNRAjIj.js} +0 -0
  243. /package/dist/assets/{init-D8wZg9xq.js → init-C3plFVsG.js} +0 -0
  244. /package/dist/assets/{jszip.min-CkbBfwAQ.js → jszip.min-CeYs17Gn.js} +0 -0
  245. /package/dist/assets/{katex-TZJFa0J_.js → katex-DRThweSG.js} +0 -0
  246. /package/dist/assets/{middleware-B3k-TSmZ.js → middleware-D05fK5Sb.js} +0 -0
  247. /package/dist/assets/{path-DodfxcX7.js → path-BKtKxQ6Y.js} +0 -0
  248. /package/dist/assets/{rough.esm-CUaa1Rbe.js → rough.esm-DurL7-u7.js} +0 -0
  249. /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] });
@@ -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 { eventKeys, type UiNcpSessionQueuedInputsView } from '@nextclaw/client-sdk';
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): UiNcpSessionQueuedInputsView {
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
- metadata: {},
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, 'listQueuedInputs').mockImplementation(async (sessionId) =>
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.listQueuedInputs).toHaveBeenCalledWith('session-1');
57
- expect(nextclawClient.sessions.listQueuedInputs).toHaveBeenCalledWith('session-2');
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 listQueuedInputs = vi.spyOn(nextclawClient.sessions, 'listQueuedInputs')
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(listQueuedInputs).toHaveBeenCalledTimes(1));
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(listQueuedInputs).toHaveBeenCalledTimes(1);
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(listQueuedInputs).toHaveBeenCalledTimes(2));
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 listQueuedInputs = vi.spyOn(nextclawClient.sessions, 'listQueuedInputs')
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(listQueuedInputs).toHaveBeenCalledTimes(1));
99
+ await waitFor(() => expect(listPendingInputs).toHaveBeenCalledTimes(1));
94
100
 
95
- let refreshed: UiNcpSessionQueuedInputsView['inputs'] = [];
101
+ let refreshed: UiNcpSessionQueuedInputView[] = [];
96
102
  await act(async () => {
97
103
  refreshed = [...await result.current.refreshQueuedInputs()];
98
104
  });
99
105
 
100
- expect(listQueuedInputs).toHaveBeenCalledTimes(2);
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: UiNcpSessionQueuedInputsView) => void;
106
- const initialRead = new Promise<UiNcpSessionQueuedInputsView>((resolve) => {
111
+ let resolveInitialRead!: (queue: UiNcpSessionPendingInputsView) => void;
112
+ const initialRead = new Promise<UiNcpSessionPendingInputsView>((resolve) => {
107
113
  resolveInitialRead = resolve;
108
114
  });
109
- const listQueuedInputs = vi.spyOn(nextclawClient.sessions, 'listQueuedInputs')
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(listQueuedInputs).toHaveBeenCalledTimes(1));
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(listQueuedInputs).toHaveBeenCalledTimes(2));
129
+ await waitFor(() => expect(listPendingInputs).toHaveBeenCalledTimes(2));
124
130
 
125
131
  await act(async () => {
126
132
  resolveInitialRead(createQueue('session-1', 'stale queued input'));
@@ -1,6 +1,9 @@
1
- import { useCallback, useMemo, useState } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import { buildNcpRequestEnvelope } from '@nextclaw/ncp-react';
3
- import type { UiNcpSessionQueuedInputView } from '@nextclaw/client-sdk';
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
- return buildNcpRequestEnvelope({
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 ? stageSubmittingInput(envelope) : null;
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?.runId === null) {
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 = useCallback(async () => {
433
- if (primaryAction === 'continue') {
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
  }