@nextclaw/ui 0.19.5 → 0.20.0

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 (265) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/assets/{abnfDiagram-VRR7QNED-DrbfiNNF.js → abnfDiagram-VRR7QNED-BcFJp_1X.js} +1 -1
  3. package/dist/assets/{aiden0z-pptx-renderer.es-DdLb2IVc.js → aiden0z-pptx-renderer.es-Dp2ezlQn.js} +1 -1
  4. package/dist/assets/api-C2iYhdTe.js +13 -0
  5. package/dist/assets/{appearance-settings-page-cTuZdROP.js → appearance-settings-page-BwQDQr0n.js} +1 -1
  6. package/dist/assets/{arc-BXlMc9B0.js → arc-CkgyPMyW.js} +1 -1
  7. package/dist/assets/architecture-TIHT7OUA-DO2x53FK.js +1 -0
  8. package/dist/assets/{architectureDiagram-ZJ3FMSHR-DXAJxxO0.js → architectureDiagram-ZJ3FMSHR-CMd4cIjI.js} +1 -1
  9. package/dist/assets/{blockDiagram-677ZJIJ3-i4Kz7zU0.js → blockDiagram-677ZJIJ3-Bz3tbhet.js} +1 -1
  10. package/dist/assets/book-open-C0IlT9zs.js +1 -0
  11. package/dist/assets/{c4Diagram-LMCZKHZV-BDc0TkPd.js → c4Diagram-LMCZKHZV-D9hFNAGv.js} +1 -1
  12. package/dist/assets/channel-nBvMaVyP.js +1 -0
  13. package/dist/assets/channels-list-page-B0z4bh8e.js +8 -0
  14. package/dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +1 -0
  15. package/dist/assets/{chunk-32BRIVSS-DuReei0Z.js → chunk-32BRIVSS-7NrjEITq.js} +1 -1
  16. package/dist/assets/{chunk-52WLFC77-D8APq0tm.js → chunk-52WLFC77-viIcqj9q.js} +1 -1
  17. package/dist/assets/{chunk-5FCAYU7R-BsPrNXNS.js → chunk-5FCAYU7R-Vsu4J-VM.js} +1 -1
  18. package/dist/assets/{chunk-5HE753X5-BRtkOPoJ.js → chunk-5HE753X5-C-w6CQZK.js} +1 -1
  19. package/dist/assets/{chunk-5JV3BV7I-ChPc8e8U.js → chunk-5JV3BV7I-CuKgJQ4W.js} +1 -1
  20. package/dist/assets/{chunk-5TONJI2A-CzTjlJGb.js → chunk-5TONJI2A-CYeiWZKb.js} +1 -1
  21. package/dist/assets/{chunk-5VM5RSS4-xsv_22jR.js → chunk-5VM5RSS4-DRCbfwIn.js} +1 -1
  22. package/dist/assets/{chunk-7BUUIJ7U-CwECujme.js → chunk-7BUUIJ7U-BvydOcm3.js} +1 -1
  23. package/dist/assets/{chunk-BIQX33UG-DQAm173p.js → chunk-BIQX33UG-RlppOXKo.js} +1 -1
  24. package/dist/assets/{chunk-C7G6YPKG-BkpajeQb.js → chunk-C7G6YPKG-DAizzYwr.js} +1 -1
  25. package/dist/assets/{chunk-CQNSW5MT-ND65pWRA.js → chunk-CQNSW5MT-5eChJHca.js} +1 -1
  26. package/dist/assets/{chunk-CYSBUYHQ-vMu6ijxG.js → chunk-CYSBUYHQ-YHPr53fv.js} +1 -1
  27. package/dist/assets/{chunk-EMLP6XTP-CEaeW3gH.js → chunk-EMLP6XTP-CK4D7Hz5.js} +1 -1
  28. package/dist/assets/{chunk-EX3LRPZG-a4ER-HDr.js → chunk-EX3LRPZG-BmlDFIRW.js} +1 -1
  29. package/dist/assets/{chunk-FWX5IMBZ-C_8fQssn.js → chunk-FWX5IMBZ-D0ksHZZ9.js} +2 -2
  30. package/dist/assets/{chunk-HOUHSVGY-CEvw-PEd.js → chunk-HOUHSVGY-DPkq8FCm.js} +1 -1
  31. package/dist/assets/{chunk-ICXQ74PX-BEtF0fGY.js → chunk-ICXQ74PX-FAatv5fC.js} +1 -1
  32. package/dist/assets/{chunk-JG7HCLWE-DGRrVp8-.js → chunk-JG7HCLWE-DLkIi4F7.js} +1 -1
  33. package/dist/assets/{chunk-JWPE2WC7-DRqpp_nM.js → chunk-JWPE2WC7-DawOjNE3.js} +1 -1
  34. package/dist/assets/{chunk-MOJQB5TN-BDEriOXs.js → chunk-MOJQB5TN-Di52TorW.js} +1 -1
  35. package/dist/assets/{chunk-MOZMSUNE-JWRNzdnw.js → chunk-MOZMSUNE-PfyK9w1-.js} +1 -1
  36. package/dist/assets/{chunk-OGEWGWER-DS2VTgCx.js → chunk-OGEWGWER-C3jdH3Ty.js} +1 -1
  37. package/dist/assets/{chunk-OSBZ3O6U-3LiYTBUB.js → chunk-OSBZ3O6U-CecHo-f0.js} +1 -1
  38. package/dist/assets/{chunk-PUDLZKDR-o9M2s_SO.js → chunk-PUDLZKDR-f3IJh3sN.js} +1 -1
  39. package/dist/assets/{chunk-Q4XR5HBZ-DTB7Ma2N.js → chunk-Q4XR5HBZ-DQFeUPxZ.js} +1 -1
  40. package/dist/assets/{chunk-QBLGF6JB-DpkxZJL5.js → chunk-QBLGF6JB-BhUeG0y2.js} +1 -1
  41. package/dist/assets/{chunk-R7FJI6CG-CRejkHJU.js → chunk-R7FJI6CG-C3XpZ-2u.js} +1 -1
  42. package/dist/assets/{chunk-RYQCIY6F-B1boBjLt.js → chunk-RYQCIY6F-CAqa5klQ.js} +1 -1
  43. package/dist/assets/{chunk-U6XO7XAA-DgKa97bj.js → chunk-U6XO7XAA-D_WXezeD.js} +1 -1
  44. package/dist/assets/{chunk-V7JOEXUC-DE56eh0N.js → chunk-V7JOEXUC-CZ70oOtp.js} +1 -1
  45. package/dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +1 -0
  46. package/dist/assets/{chunk-VR4S4FIN-BzomPZq2.js → chunk-VR4S4FIN-B7AHEYYk.js} +1 -1
  47. package/dist/assets/{chunk-WYO6CB5R-C6gy8rSd.js → chunk-WYO6CB5R-Dn9To_OI.js} +2 -2
  48. package/dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +1 -0
  49. package/dist/assets/{chunk-YOTPTUD7-BK98yfl9.js → chunk-YOTPTUD7-BYEgRBk3.js} +1 -1
  50. package/dist/assets/{chunk-ZGVPDNZ5-DFXAhwUT.js → chunk-ZGVPDNZ5-C6YtZDU0.js} +1 -1
  51. package/dist/assets/{chunk-ZIRB5QZD-Bbu6BiNC.js → chunk-ZIRB5QZD-DMuYtnHF.js} +1 -1
  52. package/dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +1 -0
  53. package/dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +1 -0
  54. package/dist/assets/{config-split-page-DO1Oyb-r.js → config-split-page-VDTf3zZb.js} +1 -1
  55. package/dist/assets/confirm-dialog-BI_Vt2s_.js +5 -0
  56. package/dist/assets/{cose-bilkent-JH36ORCC-BV8KR4uF.js → cose-bilkent-JH36ORCC-Bc2Ex5Y3.js} +1 -1
  57. package/dist/assets/createLucideIcon-Bydi9Gc5.js +1 -0
  58. package/dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +1 -0
  59. package/dist/assets/{cynefinDiagram-TSTJHNR4-Ckd6nU9t.js → cynefinDiagram-TSTJHNR4-DVysQoGz.js} +1 -1
  60. package/dist/assets/{dagre-D_T-FW5i.js → dagre-CMhQ1cAG.js} +1 -1
  61. package/dist/assets/{dagre-VKFMJZFB-CyDaQpD4.js → dagre-VKFMJZFB-RYyWpPJZ.js} +1 -1
  62. package/dist/assets/{desktop-update-config-XSV-DjJW.js → desktop-update-config-DVoD6NxG.js} +1 -1
  63. package/dist/assets/{diagram-FQU43EPY-CghnwS0H.js → diagram-FQU43EPY-BD6KONdF.js} +1 -1
  64. package/dist/assets/{diagram-G47NLZAW-DK4DJ3Kx.js → diagram-G47NLZAW-CGB2ptRR.js} +1 -1
  65. package/dist/assets/{diagram-NH7WQ7WH-CUgDkZCJ.js → diagram-NH7WQ7WH-DnkOI6cU.js} +1 -1
  66. package/dist/assets/{diagram-OA4YK3LP-vO2gyH6n.js → diagram-OA4YK3LP-DF82RZ7P.js} +1 -1
  67. package/dist/assets/{diagram-WEI45ONY-DbSBRDSr.js → diagram-WEI45ONY-Be2v7Ck9.js} +1 -1
  68. package/dist/assets/{dist-C-2H76Cv.js → dist-A5btQciA.js} +1 -1
  69. package/dist/assets/dist-CmHtkFbs.js +1 -0
  70. package/dist/assets/doc-browser-Cm_tMZ_C.js +1 -0
  71. package/dist/assets/doc-browser-Dto54tCf.js +1 -0
  72. package/dist/assets/{doc-browser-context-C0Bns1J6.js → doc-browser-context-Bxw0ora-.js} +1 -1
  73. package/dist/assets/{docx-preview-DfxIm9IB.js → docx-preview-BqwAjrj3.js} +1 -1
  74. package/dist/assets/{ebnfDiagram-CCIWWBDH-W7CAcK7r.js → ebnfDiagram-CCIWWBDH-CP98OYk8.js} +1 -1
  75. package/dist/assets/{erDiagram-Q63AITRT-LA0JWL8-.js → erDiagram-Q63AITRT-ZLlx8xfs.js} +1 -1
  76. package/dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +1 -0
  77. package/dist/assets/extensions-CG4voDCh.js +1 -0
  78. package/dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +1 -0
  79. package/dist/assets/{form-actions-CMxhPact.js → form-actions-lv47uGIB.js} +1 -1
  80. package/dist/assets/{ganttDiagram-NO4QXBWP-_PiTPavJ.js → ganttDiagram-NO4QXBWP-DXCDjHR2.js} +1 -1
  81. package/dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +1 -0
  82. package/dist/assets/{gitGraphDiagram-IHSO6WYX-DsRB1ZMU.js → gitGraphDiagram-IHSO6WYX-l2HWrTJp.js} +1 -1
  83. package/dist/assets/index-BTSwNDVi.js +109 -0
  84. package/dist/assets/index-QrdUWHfm.css +1 -0
  85. package/dist/assets/info-DKCQHKI2-BIporNWb.js +1 -0
  86. package/dist/assets/{infoDiagram-FWYZ7A6U-wIRraYx5.js → infoDiagram-FWYZ7A6U-D-DjX-bn.js} +1 -1
  87. package/dist/assets/{ishikawaDiagram-FXEZZL3T-CNzsrcrh.js → ishikawaDiagram-FXEZZL3T-y_Xy128F.js} +1 -1
  88. package/dist/assets/{journeyDiagram-5HDEW3XC-Dy9huHxy.js → journeyDiagram-5HDEW3XC-DJn5xYcQ.js} +1 -1
  89. package/dist/assets/{kanban-definition-HUTT4EX6-BOCIN365.js → kanban-definition-HUTT4EX6-DJVIOR21.js} +1 -1
  90. package/dist/assets/{line-BxsizOTs.js → line-Cos7PIOj.js} +1 -1
  91. package/dist/assets/{linear-C_YHf92I.js → linear-BtDLqtzF.js} +1 -1
  92. package/dist/assets/loader-circle-CkaqeEne.js +1 -0
  93. package/dist/assets/{map-CobcjgZ8.js → map-BKnQyvd0.js} +1 -1
  94. package/dist/assets/mcp-marketplace-page-BSk0qUOX.js +9 -0
  95. package/dist/assets/mcp-marketplace-page-BgZGc-S_.js +1 -0
  96. package/dist/assets/{mermaid-parser.core-D7lu2RbA.js → mermaid-parser.core-XUNZhr2W.js} +2 -2
  97. package/dist/assets/{mermaid.core-CbfW2Rk8.js → mermaid.core-ySrvolIe.js} +3 -3
  98. package/dist/assets/{mindmap-definition-LN4V7U3C-DUjGXlIC.js → mindmap-definition-LN4V7U3C-BypL9tei.js} +1 -1
  99. package/dist/assets/model-config-page-c8RnUGoH.js +1 -0
  100. package/dist/assets/{navigation-link-v3FaWcIr.js → navigation-link-D0agTj5t.js} +1 -1
  101. package/dist/assets/{ordinal-CjoUCHto.js → ordinal-CxxVWxYU.js} +1 -1
  102. package/dist/assets/packet-7NZHBO7P-CuFMADV0.js +1 -0
  103. package/dist/assets/{pegDiagram-2B236MQR-BQY2DgiP.js → pegDiagram-2B236MQR-D-U2KBGv.js} +1 -1
  104. package/dist/assets/pie-RZYD4A2V-XUeIXhM9.js +1 -0
  105. package/dist/assets/{pieDiagram-ENE6RG2P-D18owe4D.js → pieDiagram-ENE6RG2P-CBi3GusJ.js} +1 -1
  106. package/dist/assets/plus-BiMjkv3R.js +1 -0
  107. package/dist/assets/{privacy-settings-page-CYM1Dxwo.js → privacy-settings-page-CPkyTvEE.js} +1 -1
  108. package/dist/assets/providers-config-page-CGUEb5Dx.js +1 -0
  109. package/dist/assets/{quadrantDiagram-ABIIQ3AL-B8F7YoTA.js → quadrantDiagram-ABIIQ3AL-H0ZuvnZL.js} +1 -1
  110. package/dist/assets/radar-I7S5WNFK-D-NNGh1k.js +1 -0
  111. package/dist/assets/railroad-3IZDKUUU-C67_uDaM.js +1 -0
  112. package/dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +1 -0
  113. package/dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +1 -0
  114. package/dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +1 -0
  115. package/dist/assets/{railroadDiagram-RFXS5EU6-RU8GpxN5.js → railroadDiagram-RFXS5EU6-D7Y2EqSd.js} +1 -1
  116. package/dist/assets/react-BMYFkaGi.js +8 -0
  117. package/dist/assets/refresh-cw-DjgY2Eju.js +1 -0
  118. package/dist/assets/remote-1LxkpRED.js +1 -0
  119. package/dist/assets/{requirementDiagram-TGXJPOKE-ubPOmmNi.js → requirementDiagram-TGXJPOKE-BiXNX1NN.js} +1 -1
  120. package/dist/assets/rotate-cw-Dot4PVh0.js +1 -0
  121. package/dist/assets/{runtime-config-page-C7vksFVD.js → runtime-config-page-C6nzqTHg.js} +1 -1
  122. package/dist/assets/{sankeyDiagram-HTMAVEWB-8L_hXJWW.js → sankeyDiagram-HTMAVEWB-qzDeLztW.js} +1 -1
  123. package/dist/assets/save-B-jdTe_c.js +1 -0
  124. package/dist/assets/search-CEp2AIiV.js +1 -0
  125. package/dist/assets/{search-config-page-DKdEf7m9.js → search-config-page-Dp5guS5O.js} +1 -1
  126. package/dist/assets/{secrets-config-page-COlMqSfL.js → secrets-config-page-C7nRMjiv.js} +2 -2
  127. package/dist/assets/security-config-DvHUDxSg.js +1 -0
  128. package/dist/assets/{select-BACzapV3.js → select-BNA3cma8.js} +2 -2
  129. package/dist/assets/{sequenceDiagram-DBY2YBRQ-Dom6Qor5.js → sequenceDiagram-DBY2YBRQ-BtRbPQtL.js} +1 -1
  130. package/dist/assets/{sizeCapture-X5ZJPWSS-cZcFSpLJ.js → sizeCapture-X5ZJPWSS-CMYvM3SL.js} +1 -1
  131. package/dist/assets/skeleton-CbroEO8Q.js +1 -0
  132. package/dist/assets/{src-BE9E1xcR.js → src-Bw-mzbQb.js} +1 -1
  133. package/dist/assets/{stateDiagram-2N3HPSRC-CHrpxmGO.js → stateDiagram-2N3HPSRC-BJ-mFeOz.js} +1 -1
  134. package/dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +1 -0
  135. package/dist/assets/{swimlanes-5IMT3BWC-D6nJS2xQ.js → swimlanes-5IMT3BWC-BsucVOO2.js} +2 -2
  136. package/dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +8 -0
  137. package/dist/assets/{tag-chip-BnamTQVX.js → tag-chip-DmCNi4-9.js} +1 -1
  138. package/dist/assets/{timeline-definition-FHXFAJF6-DJNn-HQO.js → timeline-definition-FHXFAJF6-Bicewlzo.js} +1 -1
  139. package/dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +1 -0
  140. package/dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +1 -0
  141. package/dist/assets/{vennDiagram-L72KCM5P-CCEzHoXt.js → vennDiagram-L72KCM5P-BxOOnO9x.js} +1 -1
  142. package/dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +1 -0
  143. package/dist/assets/{wardleyDiagram-EHGQE667-BhyVxVXt.js → wardleyDiagram-EHGQE667-Cl7NltMv.js} +1 -1
  144. package/dist/assets/x-BTo5-A8h.js +1 -0
  145. package/dist/assets/{xychartDiagram-FW5EYKEG-CacW_246.js → xychartDiagram-FW5EYKEG-DiMIxQ7N.js} +1 -1
  146. package/dist/index.html +23 -22
  147. package/package.json +8 -8
  148. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +4 -0
  149. package/src/app/configs/app-navigation.config.ts +6 -0
  150. package/src/app/index.tsx +7 -0
  151. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +33 -1
  152. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +1 -0
  153. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +18 -1
  154. package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx +26 -0
  155. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +4 -1
  156. package/src/features/chat/features/conversation/hooks/use-session-run-queue.ts +8 -2
  157. package/src/features/chat/features/message/components/__tests__/chat-message-observation-event.test.tsx +46 -0
  158. package/src/features/chat/features/message/components/chat-message-list.container.tsx +11 -0
  159. package/src/features/chat/features/message/components/chat-message-observation-event.tsx +92 -0
  160. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline-compaction.utils.test.ts +38 -0
  161. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline.utils.test.ts +52 -0
  162. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +34 -0
  163. package/src/features/chat/features/message/utils/chat-message-observation-event.utils.ts +81 -0
  164. package/src/features/chat/features/message/utils/chat-message-part.utils.ts +15 -1
  165. package/src/features/chat/features/message/utils/chat-message-timeline.utils.ts +62 -1
  166. package/src/features/chat/features/ncp/hooks/use-ncp-session-queries.ts +36 -2
  167. package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +28 -0
  168. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +10 -2
  169. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +35 -0
  170. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +26 -47
  171. package/src/features/chat/features/session/components/session-header/chat-session-more-actions-menu.tsx +73 -0
  172. package/src/features/chat/features/session/utils/__tests__/ncp-session-adapter.utils.test.ts +28 -0
  173. package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +3 -1
  174. package/src/features/chat/features/session/utils/ncp-session-context-metadata.utils.ts +3 -4
  175. package/src/features/chat/features/workspace/components/__tests__/chat-session-child-sessions.test.tsx +27 -1
  176. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +13 -0
  177. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +29 -0
  178. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +19 -0
  179. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +36 -2
  180. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +4 -0
  181. package/src/features/chat/features/workspace/components/child-sessions/chat-session-child-sessions.tsx +28 -17
  182. package/src/features/chat/features/workspace/components/overview/__tests__/chat-session-continuous-attention.test.tsx +67 -0
  183. package/src/features/chat/features/workspace/components/overview/chat-session-continuous-attention.tsx +234 -0
  184. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +9 -7
  185. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +9 -4
  186. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +25 -0
  187. package/src/features/chat/managers/chat-thread.manager.ts +5 -7
  188. package/src/features/chat/stores/chat-thread.store.ts +7 -4
  189. package/src/features/extensions/hooks/use-extensions.ts +11 -0
  190. package/src/features/extensions/index.ts +1 -0
  191. package/src/features/extensions/pages/__tests__/extensions-config-page.test.tsx +34 -0
  192. package/src/features/extensions/pages/extensions-config-page.tsx +136 -0
  193. package/src/shared/lib/api/ncp-session.types.ts +38 -0
  194. package/src/shared/lib/api/runtime-control.types.ts +17 -0
  195. package/src/shared/lib/api/types.ts +6 -0
  196. package/src/shared/lib/api/utils/ncp-session.utils.ts +35 -1
  197. package/src/shared/lib/api/utils/runtime-control.utils.ts +8 -0
  198. package/src/shared/lib/i18n/locales/en-US/chat.json +40 -0
  199. package/src/shared/lib/i18n/locales/en-US/core.json +27 -0
  200. package/src/shared/lib/i18n/locales/zh-CN/chat.json +40 -0
  201. package/src/shared/lib/i18n/locales/zh-CN/core.json +27 -0
  202. package/dist/assets/api-CUSlBpt_.js +0 -13
  203. package/dist/assets/architecture-TIHT7OUA-Bq0i9WiE.js +0 -1
  204. package/dist/assets/book-open-BJ-xAIp9.js +0 -1
  205. package/dist/assets/channel-iCaZQ87u.js +0 -1
  206. package/dist/assets/channels-list-page-nRHOasWA.js +0 -8
  207. package/dist/assets/chunk-2Q5K7J3B-DFQtlnJS.js +0 -1
  208. package/dist/assets/chunk-VAUOI2AC-CF9A-TeE.js +0 -1
  209. package/dist/assets/chunk-XXDRQBXY-BRxdfVCU.js +0 -1
  210. package/dist/assets/classDiagram-OUVF2IWQ-Bo28fPi-.js +0 -1
  211. package/dist/assets/classDiagram-v2-EOCWNBFH-BOVN9wUz.js +0 -1
  212. package/dist/assets/confirm-dialog-CCae9Fr4.js +0 -5
  213. package/dist/assets/cynefin-VYW2F7L2-B7rF3JRp.js +0 -1
  214. package/dist/assets/dist-1N9UpL3c.js +0 -1
  215. package/dist/assets/doc-browser-BHFCZIoL.js +0 -1
  216. package/dist/assets/doc-browser-CRlpqMwH.js +0 -1
  217. package/dist/assets/eventmodeling-45OFAUF4-DzQLXa3s.js +0 -1
  218. package/dist/assets/flowDiagram-23GEKE2U-C81eexJZ.js +0 -1
  219. package/dist/assets/gitGraph-TEB2WS4Q-Dt3ZqpFD.js +0 -1
  220. package/dist/assets/index-DdYOaKm7.js +0 -109
  221. package/dist/assets/index-DxCGKhAw.css +0 -1
  222. package/dist/assets/info-DKCQHKI2-CCCE7dXC.js +0 -1
  223. package/dist/assets/loader-circle-B-UdXjl4.js +0 -1
  224. package/dist/assets/mcp-marketplace-page-BUIGtSda.js +0 -1
  225. package/dist/assets/mcp-marketplace-page-CStb8ml2.js +0 -9
  226. package/dist/assets/model-config-page-BkfUYm95.js +0 -1
  227. package/dist/assets/packet-7NZHBO7P-D19yoxFV.js +0 -1
  228. package/dist/assets/pie-RZYD4A2V-hMaJbLrn.js +0 -1
  229. package/dist/assets/plus-Dw9QFnKr.js +0 -1
  230. package/dist/assets/providers-config-page-fxL4I4bz.js +0 -1
  231. package/dist/assets/radar-I7S5WNFK-C8BkvScA.js +0 -1
  232. package/dist/assets/railroad-3IZDKUUU-CozZOitC.js +0 -1
  233. package/dist/assets/railroad-abnf-AHOZXSZD-BqIoFXFi.js +0 -1
  234. package/dist/assets/railroad-ebnf-EBAXGLYW-CD2e3dng.js +0 -1
  235. package/dist/assets/railroad-peg-LSFZ7HO6-DoKlRUOF.js +0 -1
  236. package/dist/assets/react-Dlz_IxoP.js +0 -8
  237. package/dist/assets/refresh-cw-CK4I5UFv.js +0 -1
  238. package/dist/assets/remote-B0pPgtC6.js +0 -1
  239. package/dist/assets/rotate-cw-Z48dmh13.js +0 -1
  240. package/dist/assets/save-Bo37cIFb.js +0 -1
  241. package/dist/assets/search-CZiEm7YD.js +0 -1
  242. package/dist/assets/security-config-CitLihXA.js +0 -1
  243. package/dist/assets/skeleton-B2PCAZJG.js +0 -1
  244. package/dist/assets/stateDiagram-v2-6OUMAXLB-b1pZQlDD.js +0 -1
  245. package/dist/assets/swimlanesDiagram-G3AALYLV-CowxgWVn.js +0 -8
  246. package/dist/assets/treeView-QDETBFTQ-BQlYkJbz.js +0 -1
  247. package/dist/assets/treemap-6X3UGDF4-DzTOd1bd.js +0 -1
  248. package/dist/assets/wardley-OPB4EBWU-D80jQc0y.js +0 -1
  249. package/dist/assets/x-BzYEzkLA.js +0 -1
  250. /package/dist/assets/{array-COEOjKUv.js → array-BQVzeGRt.js} +0 -0
  251. /package/dist/assets/{chunk-KEIR6QF5-D7oHAcry.js → chunk-KEIR6QF5-f9psyCXK.js} +0 -0
  252. /package/dist/assets/{chunk-Y2CYZVJY-08IUpgTP.js → chunk-Y2CYZVJY-D1mAU_Po.js} +0 -0
  253. /package/dist/assets/{config-hints-BoE41XDI.js → config-hints-nV5HPOvq.js} +0 -0
  254. /package/dist/assets/{cytoscape.esm-HifWufkp.js → cytoscape.esm-0uDtdD0l.js} +0 -0
  255. /package/dist/assets/{defaultLocale-CA-_SsC1.js → defaultLocale-DSWXGgt0.js} +0 -0
  256. /package/dist/assets/{dist-C60rvfy8.js → dist--ta5rX12.js} +0 -0
  257. /package/dist/assets/{graphlib-CGYCNsoJ.js → graphlib-CQ6QV4yP.js} +0 -0
  258. /package/dist/assets/{host-capabilities-DPNRAjIj.js → host-capabilities-Tk038i04.js} +0 -0
  259. /package/dist/assets/{init-C3plFVsG.js → init-Y6h9jGtZ.js} +0 -0
  260. /package/dist/assets/{jszip.min-CeYs17Gn.js → jszip.min-8hyJpgpx.js} +0 -0
  261. /package/dist/assets/{katex-DRThweSG.js → katex-ARhY9PS1.js} +0 -0
  262. /package/dist/assets/{middleware-D05fK5Sb.js → middleware-DXsbf9xI.js} +0 -0
  263. /package/dist/assets/{path-BKtKxQ6Y.js → path-10BjdyLh.js} +0 -0
  264. /package/dist/assets/{rough.esm-DurL7-u7.js → rough.esm-DxgC_14r.js} +0 -0
  265. /package/dist/assets/{xlsx-Sg8fZ6nH.js → xlsx-DrDuDNAa.js} +0 -0
@@ -48,14 +48,19 @@ export function useSessionRunQueue(sessionKey: string | null) {
48
48
  );
49
49
  }, [normalizedSessionKey]);
50
50
 
51
- const refreshQueuedInputs = useCallback(async (): Promise<readonly UiNcpSessionQueuedInputView[]> => {
51
+ const refreshPendingInputs = useCallback(async (): Promise<readonly UiNcpSessionPendingInputView[]> => {
52
52
  if (!normalizedSessionKey) {
53
53
  return [];
54
54
  }
55
55
  const result = await refetch();
56
- return result.data?.inputs.filter(({ placement }) => placement === 'queued') ?? [];
56
+ return result.data?.inputs ?? [];
57
57
  }, [normalizedSessionKey, refetch]);
58
58
 
59
+ const refreshQueuedInputs = useCallback(async (): Promise<readonly UiNcpSessionQueuedInputView[]> => {
60
+ const inputs = await refreshPendingInputs();
61
+ return inputs.filter(({ placement }) => placement === 'queued');
62
+ }, [refreshPendingInputs]);
63
+
59
64
  const steerQueuedInput = useCallback(async (
60
65
  queuedInputId: string,
61
66
  ): Promise<UiNcpSessionPendingInputView | null> => {
@@ -69,6 +74,7 @@ export function useSessionRunQueue(sessionKey: string | null) {
69
74
  inputs: inputs.filter(({ placement }) => placement === 'queued'),
70
75
  pendingInputs: inputs,
71
76
  isLoading,
77
+ refreshPendingInputs,
72
78
  refreshQueuedInputs,
73
79
  removeQueuedInput,
74
80
  steerQueuedInput,
@@ -0,0 +1,46 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { expect, it, vi } from "vitest";
3
+ import { ChatMessageObservationEvent } from "@/features/chat/features/message/components/chat-message-observation-event";
4
+
5
+ vi.mock("@/app/components/i18n-provider", () => ({
6
+ useI18n: () => ({ language: "en" }),
7
+ }));
8
+
9
+ vi.mock("@/shared/lib/i18n", () => ({
10
+ formatDateTime: (value: string) => `formatted:${value}`,
11
+ t: (key: string) => key,
12
+ }));
13
+
14
+ it("shows the event identity and keeps the payload behind an expandable detail", () => {
15
+ render(
16
+ <ChatMessageObservationEvent
17
+ event={{
18
+ deliveryId: "delivery-1",
19
+ extensionId: "calendar-extension",
20
+ eventId: "event-1",
21
+ eventType: "calendar.event.created",
22
+ occurredAt: "2026-08-23T10:00:00.000Z",
23
+ payload: { title: "Planning" },
24
+ }}
25
+ />,
26
+ );
27
+
28
+ expect(screen.getByTestId("chat-observation-event")).toBeTruthy();
29
+ expect(screen.getAllByText("calendar.event.created")).toHaveLength(2);
30
+ expect(screen.getByText(/calendar-extension/)).toBeTruthy();
31
+ const eventDetails = screen.getByTestId(
32
+ "chat-observation-event",
33
+ ) as HTMLDetailsElement;
34
+ expect(eventDetails.querySelector("summary")).toBeTruthy();
35
+ expect(eventDetails.open).toBe(false);
36
+ expect(screen.getByText(/event-1/)).toBeTruthy();
37
+ expect(screen.getByText(/Planning/)).toBeTruthy();
38
+ expect(screen.getByText("chatObservationEventDetailsTitle")).toBeTruthy();
39
+ expect(screen.getByText("chatObservationEventPayloadLabel")).toBeTruthy();
40
+
41
+ expect(eventDetails.className).toContain("my-3");
42
+ expect(eventDetails.querySelector("summary")?.textContent).toContain(
43
+ "calendar.event.created",
44
+ );
45
+ expect(eventDetails.className).not.toContain("amber");
46
+ });
@@ -64,6 +64,11 @@ import { buildServerPathContentUrl } from "@/shared/lib/api";
64
64
  import { formatDateTime, formatNumber, t } from "@/shared/lib/i18n";
65
65
  import { cn } from "@/shared/lib/utils";
66
66
  import type { SessionMessageToolPayloadState } from "@/features/chat/features/ncp/hooks/use-ncp-session-message-history";
67
+ import { ChatMessageObservationEvent } from "@/features/chat/features/message/components/chat-message-observation-event";
68
+ import {
69
+ isObservationEventPartExtensionType,
70
+ readObservationEventPartData,
71
+ } from "@/features/chat/features/message/utils/chat-message-observation-event.utils";
67
72
 
68
73
  type ChatMessageListContainerProps = {
69
74
  canContinue?: boolean;
@@ -371,6 +376,10 @@ export function ChatMessageListContainer({
371
376
  }, []);
372
377
  const renderCustomPart = useCallback(
373
378
  (part: Extract<ChatMessageViewModel["parts"][number], { type: "custom" }>) => {
379
+ if (isObservationEventPartExtensionType(part.customType)) {
380
+ const event = readObservationEventPartData(part.data);
381
+ return event ? <ChatMessageObservationEvent event={event} /> : undefined;
382
+ }
374
383
  if (part.customType !== CONTEXT_COMPACTION_PART_EXTENSION_TYPE) {
375
384
  return undefined;
376
385
  }
@@ -411,6 +420,8 @@ export function ChatMessageListContainer({
411
420
  <ChatContextCompactionDivider checkpoint={item.checkpoint} />
412
421
  ) : item.kind === "context-inheritance" ? (
413
422
  <ChatContextInheritanceDivider inheritance={item.inheritance} />
423
+ ) : item.kind === "observation-event" ? (
424
+ <ChatMessageObservationEvent event={item.event} />
414
425
  ) : (
415
426
  <div className={item.kind === "message" ? "pb-5" : undefined}>
416
427
  <ChatMessageList
@@ -0,0 +1,92 @@
1
+ import { ChevronDown } from "lucide-react";
2
+ import { formatDateTime, t } from "@/shared/lib/i18n";
3
+ import { useI18n } from "@/app/components/i18n-provider";
4
+ import {
5
+ stringifyObservationEventPayload,
6
+ type ObservationEventPartData,
7
+ } from "@/features/chat/features/message/utils/chat-message-observation-event.utils";
8
+
9
+ type ChatMessageObservationEventProps = {
10
+ event: ObservationEventPartData;
11
+ };
12
+
13
+ export function ChatMessageObservationEvent({
14
+ event,
15
+ }: ChatMessageObservationEventProps) {
16
+ const { language } = useI18n();
17
+ const payload = stringifyObservationEventPayload(event.payload);
18
+
19
+ return (
20
+ <details
21
+ aria-label={t("chatObservationEventLabel", language)}
22
+ data-testid="chat-observation-event"
23
+ className="group my-3 min-w-0 text-[11px] text-muted-foreground"
24
+ >
25
+ <summary
26
+ aria-label={`${t("chatObservationEventLabel", language)}: ${event.eventType}. ${t("chatObservationEventShowDetails", language)}`}
27
+ className="flex cursor-pointer list-none items-center gap-3 rounded-lg outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 [&::-webkit-details-marker]:hidden"
28
+ >
29
+ <span className="h-px min-w-4 flex-1 bg-border/70" />
30
+ <span className="inline-flex min-w-0 max-w-[min(80%,32rem)] items-center gap-1.5 px-1 text-xs text-muted-foreground transition-colors hover:text-foreground">
31
+ <span
32
+ aria-hidden="true"
33
+ className="h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50"
34
+ />
35
+ <span className="shrink-0">
36
+ {t("chatObservationEventLabel", language)}
37
+ </span>
38
+ <span aria-hidden="true" className="text-muted-foreground/60">·</span>
39
+ <span className="min-w-0 truncate">
40
+ {event.eventType}
41
+ </span>
42
+ <ChevronDown
43
+ className="h-3.5 w-3.5 shrink-0 transition-transform group-open:rotate-180"
44
+ aria-hidden="true"
45
+ />
46
+ </span>
47
+ <span className="h-px min-w-4 flex-1 bg-border/70" />
48
+ </summary>
49
+ <div className="mx-auto mt-3 max-w-2xl overflow-hidden rounded-xl border border-border/70 bg-card shadow-sm">
50
+ <div className="flex min-w-0 items-center gap-2 border-b border-border/60 bg-muted/35 px-3 py-2">
51
+ <span
52
+ aria-hidden="true"
53
+ className="h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/55"
54
+ />
55
+ <span className="shrink-0 text-xs font-medium text-foreground/85">
56
+ {t("chatObservationEventDetailsTitle", language)}
57
+ </span>
58
+ <span aria-hidden="true" className="text-muted-foreground/50">·</span>
59
+ <span className="min-w-0 truncate text-[11px] text-muted-foreground">
60
+ {event.eventType}
61
+ </span>
62
+ </div>
63
+ <dl className="grid grid-cols-[max-content_minmax(0,1fr)] gap-x-4 gap-y-2 px-3 py-3 text-xs">
64
+ <dt className="text-muted-foreground">
65
+ {t("chatObservationEventExtension", language)}
66
+ </dt>
67
+ <dd className="min-w-0 truncate text-foreground/80">{event.extensionId}</dd>
68
+ <dt className="text-muted-foreground">
69
+ {t("chatObservationEventId", language)}
70
+ </dt>
71
+ <dd className="min-w-0 break-all font-mono text-[11px] text-foreground/75">
72
+ {event.eventId}
73
+ </dd>
74
+ <dt className="text-muted-foreground">{t("chatObservationEventTime", language)}</dt>
75
+ <dd className="text-foreground/80">
76
+ <time dateTime={event.occurredAt}>
77
+ {formatDateTime(event.occurredAt, language)}
78
+ </time>
79
+ </dd>
80
+ </dl>
81
+ <div className="border-t border-border/60 px-3 py-3">
82
+ <div className="mb-1.5 text-[11px] font-medium text-muted-foreground">
83
+ {t("chatObservationEventPayloadLabel", language)}
84
+ </div>
85
+ <pre className="max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-lg bg-muted/55 px-3 py-2.5 text-[11px] leading-5 text-muted-foreground">
86
+ {payload || t("chatObservationEventPayloadEmpty", language)}
87
+ </pre>
88
+ </div>
89
+ </div>
90
+ </details>
91
+ );
92
+ }
@@ -90,6 +90,44 @@ describe("mid-run compaction timeline projection", () => {
90
90
  }).map((item) => item.kind)).toEqual(["message"]);
91
91
  });
92
92
 
93
+ it("keeps a deferred tool part in the coordinate space used by compaction", () => {
94
+ const activeAssistant = {
95
+ ...visibleMessage,
96
+ status: "streaming" as const,
97
+ parts: [
98
+ {
99
+ type: "tool-invocation" as const,
100
+ toolCallId: "tool-visible",
101
+ toolName: "exec",
102
+ state: "result" as const,
103
+ },
104
+ {
105
+ type: "tool-invocation" as const,
106
+ toolCallId: "tool-deferred",
107
+ toolName: "read_file",
108
+ state: "result" as const,
109
+ payloadDeferred: true,
110
+ },
111
+ { type: "text" as const, text: "after" },
112
+ ],
113
+ };
114
+ const compactionMessage = createCompactionMessage({
115
+ assistantId: activeAssistant.id,
116
+ coveredPartCount: activeAssistant.parts.length,
117
+ id: "context-compaction-deferred-tool",
118
+ });
119
+
120
+ expect(projectVisibleChatMessages([
121
+ activeAssistant,
122
+ compactionMessage,
123
+ ])[0]?.parts.map((part) => part.type)).toEqual([
124
+ "tool-invocation",
125
+ "tool-invocation",
126
+ "text",
127
+ "extension",
128
+ ]);
129
+ });
130
+
93
131
  it("keeps repeated compactions ordered inside one assistant message", () => {
94
132
  const activeAssistant = {
95
133
  ...visibleMessage,
@@ -62,6 +62,58 @@ describe("chat message timeline visibility", () => {
62
62
  ]);
63
63
  });
64
64
 
65
+ it("renders a standalone observation message at its timeline boundary", () => {
66
+ const observationMessage = {
67
+ ...visibleMessage,
68
+ id: "observation-event-1",
69
+ role: "service" as const,
70
+ timestamp: "2026-08-07T00:01:00.000Z",
71
+ parts: [{
72
+ type: "extension" as const,
73
+ extensionType: "observation.event",
74
+ data: {
75
+ deliveryId: "delivery-1",
76
+ extensionId: "calendar-extension",
77
+ eventId: "event-1",
78
+ eventType: "calendar.event.created",
79
+ occurredAt: "2026-08-07T00:00:59.000Z",
80
+ payload: { title: "Planning" },
81
+ },
82
+ }],
83
+ } satisfies NcpMessage;
84
+ const afterMessage = {
85
+ ...visibleMessage,
86
+ id: "assistant-after-observation",
87
+ timestamp: "2026-08-07T00:02:00.000Z",
88
+ };
89
+
90
+ expect(projectVisibleChatMessages([
91
+ visibleMessage,
92
+ observationMessage,
93
+ afterMessage,
94
+ ]).map((message) => message.id)).toEqual([
95
+ visibleMessage.id,
96
+ afterMessage.id,
97
+ ]);
98
+ const items = buildChatMessageTimelineItems({
99
+ rawMessages: [visibleMessage, observationMessage, afterMessage],
100
+ messages: [
101
+ { id: visibleMessage.id } as never,
102
+ { id: afterMessage.id } as never,
103
+ ],
104
+ });
105
+
106
+ expect(items.map((item) => item.kind)).toEqual([
107
+ "message",
108
+ "observation-event",
109
+ "message",
110
+ ]);
111
+ expect(items[1]).toMatchObject({
112
+ kind: "observation-event",
113
+ event: { eventId: "event-1" },
114
+ });
115
+ });
116
+
65
117
  it("hides internal and legacy silent messages", () => {
66
118
  expect(isVisibleChatMessage({
67
119
  ...visibleMessage,
@@ -116,6 +116,40 @@ it("maps context compaction extensions into stable process parts", () => {
116
116
  }]);
117
117
  });
118
118
 
119
+ it("maps observation event extensions into visible custom parts", () => {
120
+ const adapted = adapt([{
121
+ id: "observation-event-message-1",
122
+ role: "system",
123
+ parts: [{
124
+ type: "extension",
125
+ extensionType: "observation.event",
126
+ data: {
127
+ deliveryId: "delivery-1",
128
+ extensionId: "calendar-extension",
129
+ eventId: "event-1",
130
+ eventType: "calendar.event.created",
131
+ occurredAt: "2026-08-23T10:00:00.000Z",
132
+ payload: { title: "Planning" },
133
+ },
134
+ }],
135
+ }]);
136
+
137
+ expect(adapted[0]?.role).toBe("system");
138
+ expect(adapted[0]?.parts).toEqual([{
139
+ type: "custom",
140
+ id: "delivery-1",
141
+ customType: "observation.event",
142
+ data: {
143
+ deliveryId: "delivery-1",
144
+ extensionId: "calendar-extension",
145
+ eventId: "event-1",
146
+ eventType: "calendar.event.created",
147
+ occurredAt: "2026-08-23T10:00:00.000Z",
148
+ payload: { title: "Planning" },
149
+ },
150
+ }]);
151
+ });
152
+
119
153
  it("maps tool lifecycle statuses into visible card state feedback", () => {
120
154
  const adapted = adapt([
121
155
  {
@@ -0,0 +1,81 @@
1
+ import { OBSERVATION_EVENT_EXTENSION_TYPE } from "@nextclaw/ncp";
2
+
3
+ export const OBSERVATION_EVENT_PART_EXTENSION_TYPE =
4
+ OBSERVATION_EVENT_EXTENSION_TYPE;
5
+ const LEGACY_OBSERVATION_EVENT_PART_EXTENSION_TYPE =
6
+ "nextclaw.observation.event";
7
+ const PREVIOUS_OBSERVATION_EVENT_PART_EXTENSION_TYPE =
8
+ "ncp.observation.event";
9
+
10
+ export function isObservationEventPartExtensionType(value: string): boolean {
11
+ return value === OBSERVATION_EVENT_PART_EXTENSION_TYPE ||
12
+ value === PREVIOUS_OBSERVATION_EVENT_PART_EXTENSION_TYPE ||
13
+ value === LEGACY_OBSERVATION_EVENT_PART_EXTENSION_TYPE;
14
+ }
15
+
16
+ export type ObservationEventPartData = {
17
+ deliveryId: string;
18
+ extensionId: string;
19
+ eventId: string;
20
+ eventType: string;
21
+ occurredAt: string;
22
+ payload: unknown;
23
+ sourceRefs?: unknown;
24
+ causationId?: string;
25
+ };
26
+
27
+ function isRecord(value: unknown): value is Record<string, unknown> {
28
+ return typeof value === "object" && value !== null && !Array.isArray(value);
29
+ }
30
+
31
+ function readRequiredString(
32
+ record: Record<string, unknown>,
33
+ key: string,
34
+ ): string | null {
35
+ const value = record[key];
36
+ return typeof value === "string" && value.trim() ? value.trim() : null;
37
+ }
38
+
39
+ export function readObservationEventPartData(
40
+ value: unknown,
41
+ ): ObservationEventPartData | null {
42
+ if (!isRecord(value)) return null;
43
+ const deliveryId = readRequiredString(value, "deliveryId");
44
+ const extensionId = readRequiredString(value, "extensionId");
45
+ const eventId = readRequiredString(value, "eventId");
46
+ const eventType = readRequiredString(value, "eventType");
47
+ const occurredAt = readRequiredString(value, "occurredAt");
48
+ if (!deliveryId || !extensionId || !eventId || !eventType || !occurredAt) {
49
+ return null;
50
+ }
51
+ return {
52
+ deliveryId,
53
+ extensionId,
54
+ eventId,
55
+ eventType,
56
+ occurredAt,
57
+ payload: value.payload,
58
+ ...(value.sourceRefs !== undefined ? { sourceRefs: value.sourceRefs } : {}),
59
+ ...(typeof value.causationId === "string" && value.causationId.trim()
60
+ ? { causationId: value.causationId.trim() }
61
+ : {}),
62
+ };
63
+ }
64
+
65
+ export function stringifyObservationEventPayload(
66
+ value: unknown,
67
+ maxChars = 6000,
68
+ ): string {
69
+ let serialized: string;
70
+ if (typeof value === "string") {
71
+ serialized = value;
72
+ } else {
73
+ try {
74
+ serialized = JSON.stringify(value, null, 2) ?? "";
75
+ } catch {
76
+ serialized = String(value);
77
+ }
78
+ }
79
+ if (serialized.length <= maxChars) return serialized;
80
+ return `${serialized.slice(0, Math.max(0, maxChars - 16))}\n…`;
81
+ }
@@ -27,6 +27,10 @@ import {
27
27
  CONTEXT_COMPACTION_PART_EXTENSION_TYPE,
28
28
  type ContextCompactionPartData,
29
29
  } from "@/features/chat/features/message/utils/chat-message-timeline.utils";
30
+ import {
31
+ isObservationEventPartExtensionType,
32
+ readObservationEventPartData,
33
+ } from "@/features/chat/features/message/utils/chat-message-observation-event.utils";
30
34
 
31
35
  export type {
32
36
  ChatMessageAdapterTexts,
@@ -243,6 +247,16 @@ function isToolInvocationPart(
243
247
  function buildExtensionPart(
244
248
  part: Extract<ChatMessagePartSource, { type: "extension" }>,
245
249
  ): Extract<ChatMessagePartViewModel, { type: "custom" }> | null {
250
+ if (isObservationEventPartExtensionType(part.extensionType)) {
251
+ const data = readObservationEventPartData(part.data);
252
+ if (!data) return null;
253
+ return {
254
+ type: "custom",
255
+ id: data.deliveryId,
256
+ customType: part.extensionType,
257
+ data,
258
+ };
259
+ }
246
260
  if (part.extensionType !== CONTEXT_COMPACTION_PART_EXTENSION_TYPE) {
247
261
  return null;
248
262
  }
@@ -288,7 +302,7 @@ export function adaptChatMessagePart(
288
302
  return buildToolInvocationPart(part, texts);
289
303
  }
290
304
  if (isExtensionPart(part)) {
291
- return buildExtensionPart(part);
305
+ return buildExtensionPart(part) ?? buildUnknownPart(part, texts);
292
306
  }
293
307
  return buildUnknownPart(part, texts);
294
308
  }
@@ -8,6 +8,11 @@ import {
8
8
  readContextCompactionTimeline,
9
9
  type ContextCompactionTimelineView,
10
10
  } from "@/features/chat/features/session/utils/ncp-session-context-metadata.utils";
11
+ import {
12
+ isObservationEventPartExtensionType,
13
+ readObservationEventPartData,
14
+ type ObservationEventPartData,
15
+ } from "@/features/chat/features/message/utils/chat-message-observation-event.utils";
11
16
 
12
17
  const INHERITED_FROM_SESSION_METADATA_KEY = "inherited_from_session_id";
13
18
  export const CONTEXT_COMPACTION_PART_EXTENSION_TYPE =
@@ -43,6 +48,11 @@ export type ChatTimelineItem =
43
48
  key: string;
44
49
  inheritance: ContextInheritanceTimelineView;
45
50
  }
51
+ | {
52
+ kind: "observation-event";
53
+ key: string;
54
+ event: ObservationEventPartData;
55
+ }
46
56
  | {
47
57
  kind: "typing";
48
58
  key: "typing";
@@ -57,6 +67,21 @@ function readInheritedSourceSessionId(message: NcpMessage): string | null {
57
67
  return typeof value === "string" && value.trim() ? value.trim() : null;
58
68
  }
59
69
 
70
+ function readStandaloneObservationEvent(
71
+ message: NcpMessage,
72
+ ): ObservationEventPartData | null {
73
+ if (message.parts.length !== 1) return null;
74
+ const part = message.parts[0];
75
+ if (
76
+ !part ||
77
+ part.type !== "extension" ||
78
+ !isObservationEventPartExtensionType(part.extensionType)
79
+ ) {
80
+ return null;
81
+ }
82
+ return readObservationEventPartData(part.data);
83
+ }
84
+
60
85
  export function isVisibleChatMessage(message: NcpMessage): boolean {
61
86
  return (
62
87
  !isHiddenNcpMessage(message) &&
@@ -100,6 +125,13 @@ function mergeAssistantContinuation(
100
125
  type VisibleChatMessageProjection = {
101
126
  messages: NcpMessage[];
102
127
  inlineCompactionMessageIds: Set<string>;
128
+ observationEvents: ObservationEventTimelinePlacement[];
129
+ };
130
+
131
+ type ObservationEventTimelinePlacement = {
132
+ boundaryIndex: number;
133
+ event: ObservationEventPartData;
134
+ messageId: string;
103
135
  };
104
136
 
105
137
  type ProjectedMessagePartAnchor = {
@@ -127,6 +159,7 @@ function projectVisibleChatMessageState(
127
159
  );
128
160
  const inlineCompactions: InlineCompactionPlacement[] = [];
129
161
  const inlineCompactionMessageIds = new Set<string>();
162
+ const observationEvents: ObservationEventTimelinePlacement[] = [];
130
163
  let pendingContinuationTargetId: string | null = null;
131
164
 
132
165
  rawMessages.forEach((message, rawOrder) => {
@@ -166,6 +199,15 @@ function projectVisibleChatMessageState(
166
199
  if (!isVisibleChatMessage(message)) {
167
200
  return;
168
201
  }
202
+ const observationEvent = readStandaloneObservationEvent(message);
203
+ if (observationEvent) {
204
+ observationEvents.push({
205
+ boundaryIndex: messages.length,
206
+ event: observationEvent,
207
+ messageId: message.id,
208
+ });
209
+ return;
210
+ }
169
211
  const targetIndex = pendingContinuationTargetId && message.role === "assistant"
170
212
  ? projectedIndexByMessageId.get(pendingContinuationTargetId)
171
213
  : undefined;
@@ -238,7 +280,7 @@ function projectVisibleChatMessageState(
238
280
  status: "pending",
239
281
  };
240
282
  }
241
- return { messages, inlineCompactionMessageIds };
283
+ return { messages, inlineCompactionMessageIds, observationEvents };
242
284
  }
243
285
 
244
286
  export function projectVisibleChatMessages(
@@ -292,6 +334,7 @@ export function buildChatMessageTimelineItems(params: {
292
334
  }): ChatTimelineItem[] {
293
335
  const projection = projectVisibleChatMessageState(params.rawMessages);
294
336
  const visibleRawMessages = projection.messages;
337
+ const observationEvents = projection.observationEvents;
295
338
  const checkpoints = params.rawMessages
296
339
  .map((message) => ({
297
340
  rawMessageId: message.id,
@@ -324,6 +367,7 @@ export function buildChatMessageTimelineItems(params: {
324
367
  const items: ChatTimelineItem[] = [];
325
368
  let pendingMessages: ChatMessageViewModel[] = [];
326
369
  let checkpointCursor = 0;
370
+ let observationEventCursor = 0;
327
371
  const flushPendingMessages = () => {
328
372
  if (pendingMessages.length === 0) {
329
373
  return;
@@ -337,8 +381,24 @@ export function buildChatMessageTimelineItems(params: {
337
381
  );
338
382
  pendingMessages = [];
339
383
  };
384
+ const flushObservationEvents = (boundaryIndex: number) => {
385
+ while (
386
+ observationEventCursor < observationEvents.length &&
387
+ observationEvents[observationEventCursor]!.boundaryIndex <= boundaryIndex
388
+ ) {
389
+ const currentEvent = observationEvents[observationEventCursor]!;
390
+ flushPendingMessages();
391
+ items.push({
392
+ kind: "observation-event",
393
+ key: `observation-event:${currentEvent.messageId}`,
394
+ event: currentEvent.event,
395
+ });
396
+ observationEventCursor += 1;
397
+ }
398
+ };
340
399
 
341
400
  visibleRawMessages.forEach((rawMessage, index) => {
401
+ flushObservationEvents(index);
342
402
  if (contextInheritance?.boundaryIndex === index) {
343
403
  flushPendingMessages();
344
404
  items.push({
@@ -373,6 +433,7 @@ export function buildChatMessageTimelineItems(params: {
373
433
  inheritance: contextInheritance,
374
434
  });
375
435
  }
436
+ flushObservationEvents(visibleRawMessages.length);
376
437
  while (checkpointCursor < checkpoints.length) {
377
438
  const currentCheckpoint = checkpoints[checkpointCursor];
378
439
  flushPendingMessages();
@@ -1,8 +1,14 @@
1
- import { useQuery } from '@tanstack/react-query';
1
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
2
2
  import {
3
+ fetchNcpSessionObservations,
3
4
  fetchNcpSessionSkills,
4
5
  fetchNcpSessionTokenUsage,
5
- fetchNcpSessions
6
+ fetchNcpSessions,
7
+ updateNcpSessionObservation,
8
+ } from '@/shared/lib/api';
9
+ import type {
10
+ NcpSessionObservationAction,
11
+ NcpSessionObservationKind,
6
12
  } from '@/shared/lib/api';
7
13
 
8
14
  const ncpSessionQueryDefaults = { staleTime: 5_000, retry: false } as const;
@@ -40,3 +46,31 @@ export function useNcpSessionTokenUsage(sessionId: string | null) {
40
46
  ...ncpSessionQueryDefaults
41
47
  });
42
48
  }
49
+
50
+ export const ncpSessionObservationsQueryKey = (sessionId: string | null) =>
51
+ ['ncp-session-observations', sessionId] as const;
52
+
53
+ export function useNcpSessionObservations(sessionId: string | null) {
54
+ return useQuery({
55
+ queryKey: ncpSessionObservationsQueryKey(sessionId),
56
+ queryFn: () => fetchNcpSessionObservations(sessionId as string),
57
+ enabled: Boolean(sessionId),
58
+ ...ncpSessionQueryDefaults
59
+ });
60
+ }
61
+
62
+ export function useNcpObservationAction(sessionId: string | null) {
63
+ const queryClient = useQueryClient();
64
+ return useMutation({
65
+ mutationFn: (input: {
66
+ kind: NcpSessionObservationKind;
67
+ id: string;
68
+ action: NcpSessionObservationAction;
69
+ }) => updateNcpSessionObservation(sessionId as string, input),
70
+ onSuccess: () => {
71
+ void queryClient.invalidateQueries({
72
+ queryKey: ncpSessionObservationsQueryKey(sessionId),
73
+ });
74
+ },
75
+ });
76
+ }