@datalayer/agent-runtimes 1.3.114 → 1.5.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 (192) hide show
  1. package/dist-embed/chunks/ChatView-CaBuPTyG.js +32 -0
  2. package/dist-embed/chunks/{DeckComponent-CuRWiARr.js → DeckComponent-cRJJMGgt.js} +1 -1
  3. package/dist-embed/chunks/{DocumentView-BYU2HREd.js → DocumentView-CiqN9ze6.js} +1 -1
  4. package/dist-embed/chunks/{EphemeralDocument-BjFSuQKH.js → EphemeralDocument-BjJfn7J-.js} +1 -1
  5. package/dist-embed/chunks/{ExcalidrawComponent-CFLnMPnf.js → ExcalidrawComponent-BtNXWUN8.js} +1 -1
  6. package/dist-embed/chunks/{ExcalidrawModal-CB9d5Vpk.js → ExcalidrawModal-C6SEKFlD.js} +1 -1
  7. package/dist-embed/chunks/{JupyterLexicalExtension-CYnZrelh.js → JupyterLexicalExtension-BuRLImy5.js} +5 -5
  8. package/dist-embed/chunks/{NotebookToolSurfaces-D62q-lbb.js → NotebookToolSurfaces-ktcGRm7d.js} +1 -1
  9. package/dist-embed/chunks/{Output-2KxoKu5F.js → Output-BscOPLqE.js} +10 -10
  10. package/dist-embed/chunks/{YouTubePlugin-CjODyxZ2.js → YouTubePlugin-xBjNr2Iu.js} +1 -1
  11. package/dist-embed/chunks/{ar-SA-G6X2FPQ2-C-zAYgA-.js → ar-SA-G6X2FPQ2-BB82iKLz.js} +1 -1
  12. package/dist-embed/chunks/{az-AZ-76LH7QW2-BHq5js6U.js → az-AZ-76LH7QW2-DsMRKXlw.js} +1 -1
  13. package/dist-embed/chunks/{bg-BG-XCXSNQG7-BTcNNcTc.js → bg-BG-XCXSNQG7-43Y1kPxa.js} +1 -1
  14. package/dist-embed/chunks/{bn-BD-2XOGV67Q-DXRk27u1.js → bn-BD-2XOGV67Q-CLqPJBll.js} +1 -1
  15. package/dist-embed/chunks/{ca-ES-6MX7JW3Y-D-0J9rqp.js → ca-ES-6MX7JW3Y-CDFGSEh3.js} +1 -1
  16. package/dist-embed/chunks/{cs-CZ-2BRQDIVT-CgN3I-57.js → cs-CZ-2BRQDIVT-ByNB8eZd.js} +1 -1
  17. package/dist-embed/chunks/{da-DK-5WZEPLOC-CHQloSoX.js → da-DK-5WZEPLOC-B7MrVwy8.js} +1 -1
  18. package/dist-embed/chunks/{de-DE-XR44H4JA-C-Hq84pe.js → de-DE-XR44H4JA-CN1cdk94.js} +1 -1
  19. package/dist-embed/chunks/{el-GR-BZB4AONW-MTzGcSsP.js → el-GR-BZB4AONW-DnaGhWD1.js} +1 -1
  20. package/dist-embed/chunks/{es-ES-U4NZUMDT-Thj-4Rwn.js → es-ES-U4NZUMDT-DE1vZzDE.js} +1 -1
  21. package/dist-embed/chunks/{eu-ES-A7QVB2H4-BEEyNQo-.js → eu-ES-A7QVB2H4-DmHB0zpm.js} +1 -1
  22. package/dist-embed/chunks/{fa-IR-HGAKTJCU-CtUGmNBZ.js → fa-IR-HGAKTJCU-CNzE8tJj.js} +1 -1
  23. package/dist-embed/chunks/{fi-FI-Z5N7JZ37-6GMgpkSu.js → fi-FI-Z5N7JZ37-Ca2vTFQC.js} +1 -1
  24. package/dist-embed/chunks/{fr-FR-RHASNOE6-BakNCbxj.js → fr-FR-RHASNOE6-B0yWFX3_.js} +1 -1
  25. package/dist-embed/chunks/{gl-ES-HMX3MZ6V-Cwkb9OPk.js → gl-ES-HMX3MZ6V-2_3FMVJq.js} +1 -1
  26. package/dist-embed/chunks/{he-IL-6SHJWFNN-BaMmvCkr.js → he-IL-6SHJWFNN-BW1lby00.js} +1 -1
  27. package/dist-embed/chunks/{hi-IN-IWLTKZ5I-1aWewhep.js → hi-IN-IWLTKZ5I-DTixfSwB.js} +1 -1
  28. package/dist-embed/chunks/{hu-HU-A5ZG7DT2-BIHI23BQ.js → hu-HU-A5ZG7DT2-DOfYwLWP.js} +1 -1
  29. package/dist-embed/chunks/{id-ID-SAP4L64H-CYpgmx8X.js → id-ID-SAP4L64H-Cwtdtkvg.js} +1 -1
  30. package/dist-embed/chunks/{index-BhSMzuKq.js → index--qMT5k1q.js} +1 -1
  31. package/dist-embed/chunks/{index-b1yzCiTq.js → index-B-UP9DlM.js} +1 -1
  32. package/dist-embed/chunks/{index-DMKsCn-y.js → index-BAwsCLGT.js} +1 -1
  33. package/dist-embed/chunks/{index-BUhqZVtg.js → index-BITOMOWN.js} +1 -1
  34. package/dist-embed/chunks/{index-1wTrAXI1.js → index-B_9UD0bt.js} +2 -2
  35. package/dist-embed/chunks/{index-DtlUttQj.js → index-BgFbP5P0.js} +1 -1
  36. package/dist-embed/chunks/{index-CC-Ht79i.js → index-CMUTS_sA.js} +1 -1
  37. package/dist-embed/chunks/{index-B7nmHsEo.js → index-Cgf7tlW3.js} +1 -1
  38. package/dist-embed/chunks/{index-CsZ2HycN.js → index-CrNfUmIU.js} +1 -1
  39. package/dist-embed/chunks/{index-DIOcQUrz.js → index-CzuLxFBK.js} +1 -1
  40. package/dist-embed/chunks/{index-EmZm7_bH.js → index-DEn5R18M.js} +1 -1
  41. package/dist-embed/chunks/{index-DeVZ-nmF.js → index-DFEBhySA.js} +1 -1
  42. package/dist-embed/chunks/{index-CMYyiALV.js → index-DYkwi0aX.js} +1 -1
  43. package/dist-embed/chunks/{index-Fzz2KjFM.js → index-DvpdAlVH.js} +1 -1
  44. package/dist-embed/chunks/{index-W7TVoWP5.js → index-Dyh5xopp.js} +1 -1
  45. package/dist-embed/chunks/{index-en9Yf1Yz.js → index-Jt4bWLoz.js} +1 -1
  46. package/dist-embed/chunks/{index-BbucLMre.js → index-S-sjhoD3.js} +1 -1
  47. package/dist-embed/chunks/{index-D18sf241.js → index-TRLGqZaF.js} +1 -1
  48. package/dist-embed/chunks/{index-ZZnjmFwm.js → index-YcqCoWJl.js} +1 -1
  49. package/dist-embed/chunks/{index-BFLtEBuP.js → index-sQy5cmWo.js} +1 -1
  50. package/dist-embed/chunks/{it-IT-JPQ66NNP-CLcqplyX.js → it-IT-JPQ66NNP-C3xZ61-6.js} +1 -1
  51. package/dist-embed/chunks/{ja-JP-DBVTYXUO-u8Qe6tR7.js → ja-JP-DBVTYXUO-CeTmglEb.js} +1 -1
  52. package/dist-embed/chunks/{kaa-6HZHGXH3-BG2kx50I.js → kaa-6HZHGXH3-D6Jr6B6Y.js} +1 -1
  53. package/dist-embed/chunks/{kab-KAB-ZGHBKWFO-CSYUpRxd.js → kab-KAB-ZGHBKWFO-pEXBqeuG.js} +1 -1
  54. package/dist-embed/chunks/{kk-KZ-P5N5QNE5-CpBMgHAz.js → kk-KZ-P5N5QNE5-BRJunmHm.js} +1 -1
  55. package/dist-embed/chunks/{km-KH-HSX4SM5Z-CoMUUQMb.js → km-KH-HSX4SM5Z--GJgT9rN.js} +1 -1
  56. package/dist-embed/chunks/{ko-KR-MTYHY66A-DwxY8CGI.js → ko-KR-MTYHY66A-Bjnez4qR.js} +1 -1
  57. package/dist-embed/chunks/{ku-TR-6OUDTVRD-UoNYUfm0.js → ku-TR-6OUDTVRD-DgOdYJrS.js} +1 -1
  58. package/dist-embed/chunks/{lt-LT-XHIRWOB4-Dr4uXaEj.js → lt-LT-XHIRWOB4-BMwhrtjM.js} +1 -1
  59. package/dist-embed/chunks/{lv-LV-5QDEKY6T-CNC56J-_.js → lv-LV-5QDEKY6T-0pxW7YE0.js} +1 -1
  60. package/dist-embed/chunks/{mr-IN-CRQNXWMA-BKWa9nzZ.js → mr-IN-CRQNXWMA-tndp8BXC.js} +1 -1
  61. package/dist-embed/chunks/{my-MM-5M5IBNSE-bwAzOWhV.js → my-MM-5M5IBNSE-sispDhO4.js} +1 -1
  62. package/dist-embed/chunks/{nb-NO-T6EIAALU-CkpsChor.js → nb-NO-T6EIAALU-CjBurOuS.js} +1 -1
  63. package/dist-embed/chunks/{nl-NL-IS3SIHDZ-COVk4rlb.js → nl-NL-IS3SIHDZ-B58EVmr3.js} +1 -1
  64. package/dist-embed/chunks/{nn-NO-6E72VCQL-DlyFF-C1.js → nn-NO-6E72VCQL-D1p7LZSq.js} +1 -1
  65. package/dist-embed/chunks/{oc-FR-POXYY2M6-CFDosV2C.js → oc-FR-POXYY2M6-C1M8sddP.js} +1 -1
  66. package/dist-embed/chunks/{pa-IN-N4M65BXN-BKRB3O0U.js → pa-IN-N4M65BXN-D8ESzASl.js} +1 -1
  67. package/dist-embed/chunks/{percentages-BXMCSKIN-D7pnqUsZ.js → percentages-BXMCSKIN-BihMTsFR.js} +3 -3
  68. package/dist-embed/chunks/{pl-PL-T2D74RX3-C5r2Tds7.js → pl-PL-T2D74RX3-DQGe6LHC.js} +1 -1
  69. package/dist-embed/chunks/{pt-BR-5N22H2LF-CDnT98bW.js → pt-BR-5N22H2LF-CvXBgZQs.js} +1 -1
  70. package/dist-embed/chunks/{pt-PT-UZXXM6DQ-C6c4SPk1.js → pt-PT-UZXXM6DQ-BMnnlIUJ.js} +1 -1
  71. package/dist-embed/chunks/{ro-RO-JPDTUUEW-CW6pbzEZ.js → ro-RO-JPDTUUEW-DZ-9UUH7.js} +1 -1
  72. package/dist-embed/chunks/{ru-RU-B4JR7IUQ-CbaAJG0w.js → ru-RU-B4JR7IUQ-JlRBwjob.js} +1 -1
  73. package/dist-embed/chunks/{si-LK-N5RQ5JYF-BZkUjpXF.js → si-LK-N5RQ5JYF-Bx8kHnkd.js} +1 -1
  74. package/dist-embed/chunks/{sk-SK-C5VTKIMK-DsfWgpPU.js → sk-SK-C5VTKIMK-xsfEfbZb.js} +1 -1
  75. package/dist-embed/chunks/{sl-SI-NN7IZMDC-Kx0FqxKU.js → sl-SI-NN7IZMDC-SQYUECnr.js} +1 -1
  76. package/dist-embed/chunks/{subset-shared.chunk-DM3l9OuH.js → subset-shared.chunk-Ch6j8nKC.js} +1 -1
  77. package/dist-embed/chunks/{subset-worker.chunk-4w4yibm3.js → subset-worker.chunk-pJjck5pR.js} +1 -1
  78. package/dist-embed/chunks/{sv-SE-XGPEYMSR-DY0ryO-L.js → sv-SE-XGPEYMSR-BxcjSHE2.js} +1 -1
  79. package/dist-embed/chunks/{ta-IN-2NMHFXQM-CWpIs0i0.js → ta-IN-2NMHFXQM-rItSkDUS.js} +1 -1
  80. package/dist-embed/chunks/{th-TH-HPSO5L25-Cwkcfb3u.js → th-TH-HPSO5L25-B7UzESFj.js} +1 -1
  81. package/dist-embed/chunks/{tr-TR-DEFEU3FU-BqJZZl-Y.js → tr-TR-DEFEU3FU-Ci6oNfEX.js} +1 -1
  82. package/dist-embed/chunks/{uk-UA-QMV73CPH-Dg213mG4.js → uk-UA-QMV73CPH-C9csqvO6.js} +1 -1
  83. package/dist-embed/chunks/{vi-VN-M7AON7JQ-DY94NKxF.js → vi-VN-M7AON7JQ-DRAj2kZj.js} +1 -1
  84. package/dist-embed/chunks/{zh-CN-LNUGB5OW-B6I9A7sA.js → zh-CN-LNUGB5OW-DLOyW8hH.js} +1 -1
  85. package/dist-embed/chunks/{zh-HK-E62DVLB3-D3oqgDOt.js → zh-HK-E62DVLB3-DwC6_2Ws.js} +1 -1
  86. package/dist-embed/chunks/{zh-TW-RAJ6MFWO-CYwgY0Jo.js → zh-TW-RAJ6MFWO-DEMugIwa.js} +1 -1
  87. package/dist-embed/datalayer-app-main.js +156 -156
  88. package/lib/apps/apps/appspec.d.ts +13 -0
  89. package/lib/apps/apps/appspec.js +93 -0
  90. package/lib/apps/apps/checks.d.ts +1 -1
  91. package/lib/apps/apps/checks.js +2 -2
  92. package/lib/apps/apps/customComponents.js +1 -1
  93. package/lib/apps/core/canvasBlocks.d.ts +3 -3
  94. package/lib/apps/core/canvasParts.d.ts +6 -4
  95. package/lib/apps/core/index.d.ts +8 -0
  96. package/lib/apps/embed/AppEmbed.js +13 -20
  97. package/lib/apps/embed/embedSession.d.ts +8 -4
  98. package/lib/apps/embed/embedSession.js +16 -9
  99. package/lib/apps/embed/hostBridge.d.ts +47 -13
  100. package/lib/apps/embed/hostBridge.js +135 -18
  101. package/lib/apps/index.d.ts +1 -1
  102. package/lib/apps/index.js +1 -1
  103. package/lib/apps/plugins/a2ui-surface/AnswerShows.d.ts +21 -0
  104. package/lib/apps/plugins/a2ui-surface/AnswerShows.js +29 -0
  105. package/lib/apps/plugins/a2ui-surface/SurfaceToolResult.js +4 -7
  106. package/lib/apps/plugins/a2ui-surface/index.d.ts +2 -1
  107. package/lib/apps/plugins/a2ui-surface/index.js +10 -1
  108. package/lib/apps/plugins/a2ui-surface/toolResult.d.ts +20 -11
  109. package/lib/apps/plugins/a2ui-surface/toolResult.js +27 -11
  110. package/lib/apps/plugins/app-components/index.d.ts +1 -1
  111. package/lib/apps/plugins/app-components/index.js +2 -2
  112. package/lib/apps/plugins/app-elements/AppElements.d.ts +3 -3
  113. package/lib/apps/plugins/app-elements/AppElements.js +5 -20
  114. package/lib/apps/plugins/app-elements/QuestionView.d.ts +30 -0
  115. package/lib/apps/plugins/app-elements/QuestionView.js +70 -0
  116. package/lib/apps/plugins/app-elements/index.d.ts +7 -4
  117. package/lib/apps/plugins/app-elements/index.js +14 -5
  118. package/lib/apps/plugins/app-page/appPageModel.d.ts +6 -8
  119. package/lib/apps/plugins/app-page/appPageModel.js +0 -2
  120. package/lib/apps/plugins/app-page/pageRun.d.ts +2 -2
  121. package/lib/apps/plugins/app-page/pageRun.js +3 -3
  122. package/lib/apps/plugins/canvas-blocks/index.d.ts +13 -13
  123. package/lib/apps/plugins/canvas-blocks/index.js +24 -24
  124. package/lib/apps/plugins/canvas-parts/index.d.ts +7 -1
  125. package/lib/apps/plugins/canvas-parts/index.js +36 -0
  126. package/lib/apps/plugins/chat/ChatView.js +29 -3
  127. package/lib/chat/base/ChatBase.js +264 -43
  128. package/lib/chat/base/loopElement.d.ts +16 -17
  129. package/lib/chat/base/loopElement.js +11 -27
  130. package/lib/chat/base/loopStep.d.ts +15 -15
  131. package/lib/chat/base/loopStep.js +10 -13
  132. package/lib/chat/base/loopWindow.d.ts +15 -20
  133. package/lib/chat/base/loopWindow.js +26 -27
  134. package/lib/chat/base/uiFiles.d.ts +29 -0
  135. package/lib/chat/base/uiFiles.js +69 -0
  136. package/lib/chat/base/uiOps.d.ts +96 -0
  137. package/lib/chat/base/uiOps.js +251 -0
  138. package/lib/chat/messages/ChatMessageList.d.ts +13 -1
  139. package/lib/chat/messages/ChatMessageList.js +4 -4
  140. package/lib/components/a2ui/datalayer/Chart.d.ts +1 -1
  141. package/lib/components/a2ui/datalayer/schema.js +1 -1
  142. package/lib/components/teams/AnswerSurfaces.d.ts +3 -2
  143. package/lib/components/teams/AnswerSurfaces.js +7 -7
  144. package/lib/components/teams/useA2ATeam.d.ts +1 -1
  145. package/lib/config/AgentConfiguration.d.ts +1 -1
  146. package/lib/examples/ProtocolSignedRequestsExample.d.ts +10 -0
  147. package/lib/examples/ProtocolSignedRequestsExample.js +41 -0
  148. package/lib/examples/ProtocolUcpCheckoutExample.d.ts +10 -0
  149. package/lib/examples/ProtocolUcpCheckoutExample.js +59 -0
  150. package/lib/examples/example-selector.js +2 -0
  151. package/lib/examples/exampleGroups.d.ts +1 -1
  152. package/lib/examples/exampleGroups.js +4 -0
  153. package/lib/examples/index.d.ts +2 -0
  154. package/lib/examples/index.js +2 -0
  155. package/lib/examples/protocols/signedRequestsDemo.d.ts +27 -0
  156. package/lib/examples/protocols/signedRequestsDemo.js +59 -0
  157. package/lib/examples/protocols/ucpCheckoutDemo.d.ts +36 -0
  158. package/lib/examples/protocols/ucpCheckoutDemo.js +68 -0
  159. package/lib/protocols/AGUIAdapter.d.ts +7 -0
  160. package/lib/protocols/AGUIAdapter.js +43 -3
  161. package/lib/protocols/a2a/index.js +1 -0
  162. package/lib/protocols/agentic-commerce/index.js +1 -0
  163. package/lib/protocols/core.d.ts +6 -0
  164. package/lib/protocols/mcp/index.js +1 -0
  165. package/lib/protocols/pact/index.js +1 -0
  166. package/lib/protocols/ucp/index.js +1 -0
  167. package/lib/protocols/ucp/merchant.d.ts +15 -0
  168. package/lib/protocols/ucp/merchant.js +257 -0
  169. package/lib/protocols/web-bot-auth/index.js +1 -0
  170. package/lib/specs/agents/agents.js +338 -169
  171. package/lib/specs/apps.js +134 -6
  172. package/lib/specs/appspecSchema.js +59 -0
  173. package/lib/specs/cogs.js +6 -3
  174. package/lib/specs/index.d.ts +2 -1
  175. package/lib/specs/index.js +2 -1
  176. package/lib/specs/protocols.d.ts +24 -0
  177. package/lib/specs/protocols.js +197 -0
  178. package/lib/specs/ui.d.ts +21 -0
  179. package/lib/specs/{uiPlugins.js → ui.js} +14 -14
  180. package/lib/types/agentspecs.d.ts +69 -5
  181. package/lib/types/messages.d.ts +7 -0
  182. package/lib/types/protocol.d.ts +15 -0
  183. package/package.json +2 -2
  184. package/scripts/codegen/generate_agents.py +43 -8
  185. package/scripts/codegen/generate_protocols.py +207 -0
  186. package/scripts/codegen/generate_sandbox_agents.py +1 -1
  187. package/scripts/codegen/{generate_ui_plugins.py → generate_ui.py} +40 -40
  188. package/scripts/gen_workers.py +2 -2
  189. package/dist-embed/chunks/ChatView-D41Nx5rC.js +0 -32
  190. package/lib/chat/base/loopMessage.d.ts +0 -37
  191. package/lib/chat/base/loopMessage.js +0 -37
  192. package/lib/specs/uiPlugins.d.ts +0 -21
@@ -19,6 +19,8 @@ import { useContext } from 'react';
19
19
  import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
20
20
  import { Text, Spinner, IconButton } from '@primer/react';
21
21
  import { ReactorLazy } from '@datalayer/reactor/react';
22
+ import { ANSWER_ACTION, emptyUiModel, isFileRef, uploadFile, } from '@datalayer/reactor/ui';
23
+ import { UiSocket } from '@datalayer/reactor/ui/ws';
22
24
  import { SkeletonText } from '@primer/react/experimental';
23
25
  import { SidebarExpandIcon } from '@primer/octicons-react';
24
26
  import { notebookStore, JupyterReactTheme } from '@datalayer/jupyter-react';
@@ -70,10 +72,11 @@ const ephemeralNotebookRefused = lazyViewRefused('notebook');
70
72
  import { useNotebookTools } from '../../tools/adapters/agent-runtimes/notebookHooks';
71
73
  import { useAgentInspectorTracer } from '../../components/inspector/agentSpans';
72
74
  import { chatSpanRecorder, } from '../../components/inspector/chatSpans';
73
- import { loopMessageChange, speakerOf, withLoopMessage } from './loopMessage';
74
- import { loopStepOf, withLoopStep } from './loopStep';
75
- import { applyLoopElement, loopElementChange } from './loopElement';
76
- import { loopWindowMessage, tellLoopWindow } from './loopWindow';
75
+ import { isStepDisplay, withLoopStep } from './loopStep';
76
+ import { applyLoopElement } from './loopElement';
77
+ import { tellLoopWindow } from './loopWindow';
78
+ import { displayPressOf, placeable, routeUiOp, withPress, withUiOp, } from './uiOps';
79
+ import { namesFiles, withUploadedFiles, } from './uiFiles';
77
80
  import { useChatWords } from '../ChatLanguage';
78
81
  // Tracks pending prompts already auto-sent for a given conversation scope.
79
82
  // This prevents layout-driven unmount/remount cycles from re-sending prompts.
@@ -1196,6 +1199,10 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
1196
1199
  const [historyLoaded, setHistoryLoaded] = useState(!historyScopeId);
1197
1200
  const [historyRefreshTick, setHistoryRefreshTick] = useState(0);
1198
1201
  const historyRetryAttemptsRef = useRef(new Map());
1202
+ // The steps of an application's code shown so far, as displays (patched
1203
+ // as they stream), and the elements it showed (REACTOR_UI RU-3).
1204
+ const uiStepsRef = useRef(emptyUiModel());
1205
+ const uiElementsRef = useRef(new Set());
1199
1206
  // Adapter-ready flag — flipped to true once the protocol adapter is initialised
1200
1207
  const [adapterReady, setAdapterReady] = useState(false);
1201
1208
  // Guard so each distinct pending prompt is sent at most once. Stores the
@@ -1578,6 +1585,187 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
1578
1585
  threadGivenRef.current?.onStarted?.(id);
1579
1586
  }
1580
1587
  }, []);
1588
+ /*
1589
+ * The conversation's ui channel (REACTOR_UI RU-W): one WebSocket per
1590
+ * conversation, its thread the scope, opened once its session is there
1591
+ * (the first event of its first run, or a thread reopened). What its
1592
+ * messages show, its steps, its elements, its authors and its window
1593
+ * messages arrive here as `reactor.ui` ops; the presses of what they
1594
+ * offered go up it. An op about a message the run stream has not brought
1595
+ * yet — they are two connections — waits for it (`placeable`).
1596
+ */
1597
+ const uiSocketRef = useRef(null);
1598
+ const parkedUiOpsRef = useRef([]);
1599
+ const historyStepsRef = useRef(new Set());
1600
+ const displayItemsRef = useRef([]);
1601
+ const uiSocketUrl = protocol?.uiSocket;
1602
+ const uiSocketTokenRef = useRef(protocol?.authToken);
1603
+ uiSocketTokenRef.current = protocol?.authToken;
1604
+ /*
1605
+ * Its files (REACTOR_UI RU-6): uploaded to its runtime before the run or
1606
+ * the press that names them, the conversation's thread their scope; the
1607
+ * run carries the ref, never the bytes.
1608
+ */
1609
+ const uiFilesUrl = protocol?.uiFiles;
1610
+ const uploadToConversation = useCallback(file => {
1611
+ if (!uiFilesUrl) {
1612
+ return Promise.reject(new Error('This conversation takes no file.'));
1613
+ }
1614
+ return uploadFile(file, {
1615
+ url: uiFilesUrl,
1616
+ scope: threadIdRef.current,
1617
+ token: uiSocketTokenRef.current,
1618
+ });
1619
+ }, [uiFilesUrl]);
1620
+ const applyToMessages = useCallback((op) => {
1621
+ const apply = (items) => {
1622
+ try {
1623
+ return withUiOp(items, op);
1624
+ }
1625
+ catch (error) {
1626
+ console.error('[ChatBase] reactor.ui op not applied:', error);
1627
+ return items;
1628
+ }
1629
+ };
1630
+ setDisplayItems(prev => apply(prev));
1631
+ if (useStoreMode) {
1632
+ const store = useChatStore.getState();
1633
+ store.setMessages(apply(store.messages));
1634
+ }
1635
+ }, [useStoreMode]);
1636
+ const applySocketOp = useCallback((op, history) => {
1637
+ // The past is drawn again, never acted on: a window message is not
1638
+ // raised again, and the steps of turns long over are not drawn again.
1639
+ if (history) {
1640
+ if (op.op === 'window')
1641
+ return;
1642
+ if ((op.op === 'show' || op.op === 'ask') && isStepDisplay(op.body)) {
1643
+ historyStepsRef.current.add(op.body.id);
1644
+ return;
1645
+ }
1646
+ if ((op.op === 'patch' || op.op === 'append') &&
1647
+ historyStepsRef.current.has(op.id)) {
1648
+ return;
1649
+ }
1650
+ }
1651
+ let next;
1652
+ try {
1653
+ next = routeUiOp(op, uiStepsRef.current, uiElementsRef.current);
1654
+ }
1655
+ catch (error) {
1656
+ console.error('[ChatBase] reactor.ui op not applied:', error);
1657
+ return;
1658
+ }
1659
+ uiStepsRef.current = next.steps;
1660
+ const routed = next.routed;
1661
+ if (routed.to === 'window') {
1662
+ // For the page it sits in, outside the conversation (LOOP P-25).
1663
+ tellLoopWindow(routed.data);
1664
+ }
1665
+ else if (routed.to === 'step') {
1666
+ // A step of its code, drawn as it runs (LOOP P-16).
1667
+ const step = routed.step;
1668
+ setDisplayItems(prev => withLoopStep(prev, step));
1669
+ }
1670
+ else if (routed.to === 'element') {
1671
+ // In a side panel or on a page of its own (LOOP P-18).
1672
+ uiElementsRef.current.add(routed.change.id);
1673
+ applyLoopElement(routed.change);
1674
+ }
1675
+ else if (!placeable(displayItemsRef.current, routed.op)) {
1676
+ const under = routed.op.op === 'show' || routed.op.op === 'ask'
1677
+ ? routed.op.body.data?.message_id
1678
+ : undefined;
1679
+ if (history && typeof under === 'string') {
1680
+ // Shown in the past under a message that said nothing: the
1681
+ // thread did not draw it, the chat draws it for what it showed.
1682
+ const placeholder = {
1683
+ id: under,
1684
+ role: 'assistant',
1685
+ content: '',
1686
+ createdAt: new Date(),
1687
+ };
1688
+ displayItemsRef.current = [...displayItemsRef.current, placeholder];
1689
+ setDisplayItems(prev => prev.some(item => item.id === under)
1690
+ ? prev
1691
+ : [...prev, placeholder]);
1692
+ if (useStoreMode)
1693
+ useChatStore.getState().addMessage(placeholder);
1694
+ applyToMessages(routed.op);
1695
+ }
1696
+ else {
1697
+ parkedUiOpsRef.current.push(routed.op);
1698
+ }
1699
+ }
1700
+ else {
1701
+ applyToMessages(routed.op);
1702
+ }
1703
+ }, [applyToMessages, useStoreMode]);
1704
+ const applySocketOpRef = useRef(applySocketOp);
1705
+ applySocketOpRef.current = applySocketOp;
1706
+ // What waited for its message, applied once the message is here.
1707
+ useEffect(() => {
1708
+ displayItemsRef.current = displayItems;
1709
+ if (parkedUiOpsRef.current.length === 0)
1710
+ return;
1711
+ const parked = parkedUiOpsRef.current.splice(0);
1712
+ let items = displayItems;
1713
+ for (const op of parked) {
1714
+ if (!placeable(items, op)) {
1715
+ parkedUiOpsRef.current.push(op);
1716
+ continue;
1717
+ }
1718
+ try {
1719
+ items = withUiOp(items, op);
1720
+ }
1721
+ catch {
1722
+ // Said by `applyToMessages`, which refuses it the same way.
1723
+ }
1724
+ applyToMessages(op);
1725
+ }
1726
+ }, [displayItems, applyToMessages]);
1727
+ /** The conversation's ui socket, opened for its thread when it is not yet. */
1728
+ const ensureUiSocket = useCallback(() => {
1729
+ if (!uiSocketUrl)
1730
+ return null;
1731
+ const scope = threadIdRef.current;
1732
+ const open = uiSocketRef.current;
1733
+ if (open && open.scope === scope)
1734
+ return open.socket;
1735
+ // Another conversation: what the last one showed goes with it.
1736
+ open?.socket.close();
1737
+ uiStepsRef.current = emptyUiModel();
1738
+ uiElementsRef.current = new Set();
1739
+ parkedUiOpsRef.current = [];
1740
+ historyStepsRef.current = new Set();
1741
+ const socket = new UiSocket({
1742
+ url: uiSocketUrl,
1743
+ scope,
1744
+ token: () => uiSocketTokenRef.current ?? '',
1745
+ onOp: (op, _seq, history) => applySocketOpRef.current(op, history),
1746
+ onStatus: (status, reason) => {
1747
+ if (status === 'refused' || status === 'gone') {
1748
+ console.error(`[ChatBase] ui socket ${status}: ${reason ?? ''}`);
1749
+ }
1750
+ },
1751
+ });
1752
+ uiSocketRef.current = { socket, scope };
1753
+ socket.connect();
1754
+ return socket;
1755
+ }, [uiSocketUrl]);
1756
+ const ensureUiSocketRef = useRef(ensureUiSocket);
1757
+ ensureUiSocketRef.current = ensureUiSocket;
1758
+ // A thread reopened has its session already: its socket opens now.
1759
+ useEffect(() => {
1760
+ if (thread?.messages.length)
1761
+ ensureUiSocketRef.current();
1762
+ return () => {
1763
+ uiSocketRef.current?.socket.close();
1764
+ uiSocketRef.current = null;
1765
+ };
1766
+ // At mount: the thread it was given.
1767
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1768
+ }, []);
1581
1769
  const messagesContainerRef = useRef(null);
1582
1770
  const messagesEndRef = useRef(null);
1583
1771
  const inputRef = useRef(null);
@@ -2378,6 +2566,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2378
2566
  adapterRef.current = adapter;
2379
2567
  setAdapterReady(true);
2380
2568
  unsubscribeRef.current = adapter.subscribe((event) => {
2569
+ // The run's session is there once it answers: its ui socket opens.
2570
+ ensureUiSocketRef.current();
2381
2571
  /*
2382
2572
  * Nothing more from a turn the reader has stopped.
2383
2573
  *
@@ -2707,45 +2897,11 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2707
2897
  }
2708
2898
  }
2709
2899
  break;
2710
- case 'activity': {
2711
- // A step of an application's code, drawn as it runs (LOOP P-16).
2712
- const step = loopStepOf(event.activity);
2713
- if (step) {
2714
- setDisplayItems(prev => withLoopStep(prev, step));
2715
- break;
2716
- }
2717
- // What its code tells the page it sits in, outside the
2718
- // conversation (LOOP P-25): handed to whoever listens.
2719
- const windowMessage = loopWindowMessage(event.activity);
2720
- if (windowMessage) {
2721
- tellLoopWindow(windowMessage.data);
2722
- break;
2723
- }
2724
- // An element its code opened in a side panel or on a page of its
2725
- // own, changed or closed (LOOP P-18): kept for whoever draws them.
2726
- const element = loopElementChange(event.activity);
2727
- if (element) {
2728
- applyLoopElement(element);
2729
- break;
2730
- }
2731
- // An application's code changed a message it sent: its author
2732
- // said, or the message taken away (LOOP P-15).
2733
- const change = loopMessageChange(event.activity);
2734
- if (!change)
2735
- break;
2736
- setDisplayItems(prev => withLoopMessage(prev, change));
2737
- if (useStoreMode) {
2738
- if ('removed' in change) {
2739
- useChatStore.getState().deleteMessage(change.id);
2740
- }
2741
- else {
2742
- useChatStore.getState().updateMessage(change.id, {
2743
- speaker: speakerOf(change.author),
2744
- });
2745
- }
2746
- }
2900
+ case 'activity':
2901
+ // What the server says besides the conversation's text comes on
2902
+ // the ui socket (REACTOR_UI RU-W); the run's other activities —
2903
+ // `loop.session`, `loop.page` — are their readers'.
2747
2904
  break;
2748
- }
2749
2905
  case 'done':
2750
2906
  /*
2751
2907
  * What the turn cost, when nobody else is counting.
@@ -2949,6 +3105,38 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2949
3105
  return;
2950
3106
  if (!adapterRef.current && !onSendMessage)
2951
3107
  return;
3108
+ // Its files are uploaded first: the run names their refs (RU-6).
3109
+ if (forwardedPropsGiven && namesFiles(forwardedPropsGiven)) {
3110
+ try {
3111
+ forwardedPropsGiven = await withUploadedFiles(forwardedPropsGiven, uploadToConversation);
3112
+ }
3113
+ catch (failure) {
3114
+ setError(failure instanceof Error ? failure : new Error(String(failure)));
3115
+ return;
3116
+ }
3117
+ }
3118
+ // A press of what a display offered goes up the ui socket, checked
3119
+ // there; the run that answers it names it only (REACTOR_UI RU-W).
3120
+ const pressed = displayPressOf(forwardedPropsGiven);
3121
+ if (pressed && forwardedPropsGiven) {
3122
+ const socket = uiSocketRef.current?.socket;
3123
+ if (!socket) {
3124
+ setError(new Error('This conversation’s ui channel is not open.'));
3125
+ return;
3126
+ }
3127
+ try {
3128
+ const result = await socket.act(pressed);
3129
+ if (!result.ok) {
3130
+ setError(new Error(result.detail || `The press was refused (${result.status}).`));
3131
+ return;
3132
+ }
3133
+ forwardedPropsGiven = withPress(forwardedPropsGiven, result.value);
3134
+ }
3135
+ catch (failure) {
3136
+ setError(failure instanceof Error ? failure : new Error(String(failure)));
3137
+ return;
3138
+ }
3139
+ }
2952
3140
  stoppedRef.current = false;
2953
3141
  inspectAnswerRef.current = '';
2954
3142
  recorderRef.current?.recorder.turnStarted(messageContent, selectedModel || undefined);
@@ -3099,6 +3287,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
3099
3287
  getEnabledSkillIds,
3100
3288
  noteThreadStarted,
3101
3289
  chatText,
3290
+ uploadToConversation,
3102
3291
  ]);
3103
3292
  // Send pending prompt once history loaded and adapter/handler available
3104
3293
  useEffect(() => {
@@ -3221,6 +3410,38 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
3221
3410
  protocol?.authToken,
3222
3411
  protocol?.agentId,
3223
3412
  ]);
3413
+ /*
3414
+ * How a message's display presses what it offered (REACTOR_UI RU-4,
3415
+ * RU-W): with the token of the offer, as the run's press — which
3416
+ * `handleSend` sends up the ui socket before the run, the run naming it
3417
+ * only. An answer is the person's words in the conversation; any other
3418
+ * press, the action's name.
3419
+ */
3420
+ const actOnDisplay = useCallback((display) => async (action) => {
3421
+ const offer = display.actions?.find(one => one.name === action.action);
3422
+ if (!offer) {
3423
+ throw new Error(`“${action.action}” was not offered here.`);
3424
+ }
3425
+ const value = action.payload
3426
+ ?.value;
3427
+ const words = action.action === ANSWER_ACTION
3428
+ ? typeof value === 'string'
3429
+ ? value
3430
+ : isFileRef(value)
3431
+ ? value.name
3432
+ : 'Answered.'
3433
+ : action.action;
3434
+ await handleSend(words, {
3435
+ loop: {
3436
+ action: {
3437
+ name: action.action,
3438
+ display_id: display.id,
3439
+ token: offer.token,
3440
+ payload: action.payload ?? {},
3441
+ },
3442
+ },
3443
+ });
3444
+ }, [handleSend]);
3224
3445
  // ---- handleNewChat ----
3225
3446
  const handleNewChat = useCallback(() => {
3226
3447
  setDisplayItems([]);
@@ -3618,7 +3839,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
3618
3839
  rows inside carry their own horizontal padding, which becomes the
3619
3840
  margin once the cap does bind.
3620
3841
  */
3621
- width: "100%", maxWidth: 920, mx: "auto", bg: "canvas.default", children: [_jsx(ChatMessageList, { displayItems: welcomedItems, isLoading: isLoading, isStreaming: isStreaming, showLoadingIndicator: showLoadingIndicator, hideMessagesAfterToolUI: hideMessagesAfterToolUI, avatarConfig: defaultAvatarConfig, padding: padding,
3842
+ width: "100%", maxWidth: 920, mx: "auto", bg: "canvas.default", children: [_jsx(ChatMessageList, { displayItems: welcomedItems, actOn: protocol?.uiSocket ? actOnDisplay : undefined, upload: protocol?.uiFiles ? uploadToConversation : undefined, isLoading: isLoading, isStreaming: isStreaming, showLoadingIndicator: showLoadingIndicator, hideMessagesAfterToolUI: hideMessagesAfterToolUI, avatarConfig: defaultAvatarConfig, padding: padding,
3622
3843
  // Tool calls are drawn by the page's Reactor plugins; a named
3623
3844
  // notebook's cell surfaces stand in for the default row of its tools,
3624
3845
  // so every chat with a headless notebook gets the same transcript.
@@ -3,16 +3,14 @@
3
3
  * panel beside the conversation, or on a page of its own over it. Inline,
4
4
  * an element is a message, and the chat draws it as one (P-04).
5
5
  *
6
- * The session API says it with a `CUSTOM` event named `loop.element` —
7
- * `{id, where, title, shows}`, `shows` the A2UI surface an answer's
8
- * components are drawn from, or `{id, closed: true}` — which the AG-UI
9
- * adapter hands on as an `activity`. The chat does not draw it: it keeps
10
- * what is open here, and whoever draws panels and pages (the `app-elements`
11
- * plugin) listens. One store per page, as there is one chat per
12
- * application on it.
6
+ * The session API shows it as a `reactor.ui` display that says where it
7
+ * shows in its data (`where: "panel" | "page"`, with its `title`) — an
8
+ * answer's display (REACTOR_UI RU-2) — and closes it with a `remove` of its
9
+ * id (RU-3). The chat does not draw it: it keeps what is open here, and
10
+ * whoever draws panels and pages (the `app-elements` plugin) listens. One
11
+ * store per page, as there is one chat per application on it.
13
12
  */
14
- /** The `CUSTOM` event's name. */
15
- export declare const LOOP_ELEMENT = "loop.element";
13
+ import type { Display } from '@datalayer/reactor/ui';
16
14
  /** Where an element opens, besides inline. */
17
15
  export type LoopElementWhere = 'panel' | 'page';
18
16
  /** An element open in a side panel or on a page. */
@@ -20,19 +18,20 @@ export type LoopElement = {
20
18
  id: string;
21
19
  where: LoopElementWhere;
22
20
  title: string;
23
- /** The surface it draws: what `render_a2ui_surface` returns. */
24
- shows: unknown;
21
+ /** The display it draws: what an answer shows (`AnswerShows`). */
22
+ shows: Display;
25
23
  };
26
- /** What an event says: an element opened or changed, or one closed. */
24
+ /** What changed: an element opened or changed, or one closed. */
27
25
  export type LoopElementChange = LoopElement | {
28
26
  id: string;
29
27
  closed: true;
30
28
  };
31
- /** The change an activity says, or `null` when it says none. */
32
- export declare function loopElementChange(activity: {
33
- type: string;
34
- data: unknown;
35
- } | undefined): LoopElementChange | null;
29
+ /**
30
+ * The element a display is, or `null` for one shown inline, under its
31
+ * message: a display is an element when it says it shows in a panel or on
32
+ * a page.
33
+ */
34
+ export declare function elementOfDisplay(display: Display): LoopElement | null;
36
35
  /**
37
36
  * The elements open with a change applied: one opened is added last, one
38
37
  * changed is replaced where it is, one closed is taken away.
@@ -3,36 +3,20 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  /**
6
- * Where an element of an application's code shows (LOOP P-18): in a side
7
- * panel beside the conversation, or on a page of its own over it. Inline,
8
- * an element is a message, and the chat draws it as one (P-04).
9
- *
10
- * The session API says it with a `CUSTOM` event named `loop.element` —
11
- * `{id, where, title, shows}`, `shows` the A2UI surface an answer's
12
- * components are drawn from, or `{id, closed: true}` — which the AG-UI
13
- * adapter hands on as an `activity`. The chat does not draw it: it keeps
14
- * what is open here, and whoever draws panels and pages (the `app-elements`
15
- * plugin) listens. One store per page, as there is one chat per
16
- * application on it.
6
+ * The element a display is, or `null` for one shown inline, under its
7
+ * message: a display is an element when it says it shows in a panel or on
8
+ * a page.
17
9
  */
18
- /** The `CUSTOM` event's name. */
19
- export const LOOP_ELEMENT = 'loop.element';
20
- /** The change an activity says, or `null` when it says none. */
21
- export function loopElementChange(activity) {
22
- if (!activity || activity.type !== LOOP_ELEMENT)
23
- return null;
24
- const data = activity.data;
25
- if (!data || typeof data.id !== 'string' || !data.id)
26
- return null;
27
- if (data.closed === true)
28
- return { id: data.id, closed: true };
29
- if (data.where !== 'panel' && data.where !== 'page')
10
+ export function elementOfDisplay(display) {
11
+ const where = display.data?.where;
12
+ if (where !== 'panel' && where !== 'page')
30
13
  return null;
14
+ const title = display.data?.title;
31
15
  return {
32
- id: data.id,
33
- where: data.where,
34
- title: typeof data.title === 'string' ? data.title : '',
35
- shows: data.shows ?? null,
16
+ id: display.id,
17
+ where,
18
+ title: typeof title === 'string' ? title : '',
19
+ shows: display,
36
20
  };
37
21
  }
38
22
  /**
@@ -3,18 +3,19 @@
3
3
  * (LOOP P-16): the chain of thought.
4
4
  *
5
5
  * AG-UI's `STEP_STARTED` and `STEP_FINISHED` carry a step's name only; the
6
- * session API says the step whole beside them, with a `CUSTOM` event named
7
- * `loop.step` — `{id, name, kind, parent_id, input, output, error,
8
- * started_at, ended_at}` — which the AG-UI adapter hands on as an
9
- * `activity`. A step is drawn as the chat draws a tool call: one row,
10
- * collapsed, its input and output inside, running until it ends; a nested
11
- * step says the step it is in. A step that streams its output (LOOP P-31)
12
- * is said again as it writes, its output so far, and drawn in place.
6
+ * session API shows the step whole beside them as a `reactor.ui` display of
7
+ * type `application/vnd.datalayer.loop.step+json` (REACTOR_UI RU-3) — its
8
+ * data `{name, kind, parent_id, input, output, error, started_at,
9
+ * ended_at}`, its id the step's — shown as it starts and again as it ends,
10
+ * its output patched in as it streams (LOOP P-31). A step is drawn as the
11
+ * chat draws a tool call: one row, collapsed, its input and output inside,
12
+ * running until it ends; a nested step says the step it is in.
13
13
  */
14
+ import type { Display } from '@datalayer/reactor/ui';
14
15
  import type { DisplayItem, ToolCallMessage } from '../../types/chat';
15
- /** The `CUSTOM` event's name. */
16
- export declare const LOOP_STEP = "loop.step";
17
- /** A step, as the event says it. */
16
+ /** The display type of a step. */
17
+ export declare const STEP_DISPLAY_TYPE = "application/vnd.datalayer.loop.step+json";
18
+ /** A step, as its display says it. */
18
19
  export type LoopStep = {
19
20
  id: string;
20
21
  name: string;
@@ -25,11 +26,10 @@ export type LoopStep = {
25
26
  error: string;
26
27
  ended: boolean;
27
28
  };
28
- /** The step an activity says, or `null` when it says none. */
29
- export declare function loopStepOf(activity: {
30
- type: string;
31
- data: unknown;
32
- } | undefined): LoopStep | null;
29
+ /** Whether a display is a step's. */
30
+ export declare const isStepDisplay: (display: Display) => boolean;
31
+ /** The step a step's display says. Throws for one that is not a step's. */
32
+ export declare function stepOfDisplay(display: Display): LoopStep;
33
33
  /** The id of the row a step is drawn as. */
34
34
  export declare const stepCallId: (id: string) => string;
35
35
  /** A step as the row the chat draws a tool call as. */
@@ -2,21 +2,18 @@
2
2
  * Copyright (c) 2025-2026 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- /** The `CUSTOM` event's name. */
6
- export const LOOP_STEP = 'loop.step';
7
- /** The step an activity says, or `null` when it says none. */
8
- export function loopStepOf(activity) {
9
- if (!activity || activity.type !== LOOP_STEP)
10
- return null;
11
- const data = activity.data;
12
- if (!data ||
13
- typeof data.id !== 'string' ||
14
- !data.id ||
15
- typeof data.name !== 'string') {
16
- return null;
5
+ /** The display type of a step. */
6
+ export const STEP_DISPLAY_TYPE = 'application/vnd.datalayer.loop.step+json';
7
+ /** Whether a display is a step's. */
8
+ export const isStepDisplay = (display) => display.type === STEP_DISPLAY_TYPE;
9
+ /** The step a step's display says. Throws for one that is not a step's. */
10
+ export function stepOfDisplay(display) {
11
+ const data = display.data ?? {};
12
+ if (!isStepDisplay(display) || typeof data.name !== 'string') {
13
+ throw new Error(`Display ${display.id} is not a step`);
17
14
  }
18
15
  return {
19
- id: data.id,
16
+ id: display.id,
20
17
  name: data.name,
21
18
  kind: typeof data.kind === 'string' ? data.kind : 'run',
22
19
  parentId: typeof data.parent_id === 'string' && data.parent_id
@@ -2,30 +2,25 @@
2
2
  * Window messages (LOOP P-25): what an application's code tells the page it
3
3
  * sits in, outside the conversation — ``session.send_window_message(data)``.
4
4
  *
5
- * The session API says it with a `CUSTOM` event named `loop.window` —
6
- * `{data}` — which the AG-UI adapter hands on as an `activity`. The chat
7
- * does not draw it: it hands it to whoever listens here — the embed's host
8
- * bridge, which raises it on the element as its `window-message` event.
5
+ * The session says it with a `reactor.ui` `window` op named `message`, its
6
+ * `args` `{data}` (REACTOR_UI RU-3), on the conversation's ui socket (RU-W). The chat does not draw it: it hands
7
+ * it to whoever listens here — the embed's host bridge, which raises it on
8
+ * the element as its `window-message` event. A window op of another name is
9
+ * not one this page acts on: refused, it throws.
9
10
  */
10
- /** The `CUSTOM` event's name. */
11
- export declare const LOOP_WINDOW = "loop.window";
12
- /** What an activity says to the page, or `null` when it is not a window message. */
13
- export declare function loopWindowMessage(activity: {
14
- type: string;
15
- data: unknown;
16
- } | undefined): {
17
- data: unknown;
18
- } | null;
11
+ import { type WindowOp } from '@datalayer/reactor/ui';
12
+ /** The name of the window op that hands the page a message. */
13
+ export declare const WINDOW_MESSAGE = "message";
14
+ /** What a window op hands the page. Throws for a window op of another name. */
15
+ export declare function windowMessageOf(op: WindowOp): unknown;
19
16
  /** Hand a window message to whoever listens. */
20
17
  export declare function tellLoopWindow(data: unknown): void;
21
18
  /** Listen for window messages. Returns the unsubscribe. */
22
19
  export declare function onLoopWindowMessage(listener: (data: unknown) => void): () => void;
23
20
  /**
24
- * What a turn's stream says to the page — the `loop.window` events of the
25
- * turn a window message posted by the page ran — and the sentence its
26
- * `RUN_ERROR` said, if it failed.
21
+ * Why the turn a window message posted by the page ran failed — its
22
+ * `RUN_ERROR`'s sentence — or `null`. What its code tells the page back comes
23
+ * on the conversation's ui socket (REACTOR_UI RU-W), never on this stream: a
24
+ * `reactor.ui` event here is refused.
27
25
  */
28
- export declare function windowTurnOf(stream: string): {
29
- said: unknown[];
30
- error: string | null;
31
- };
26
+ export declare function windowTurnErrorOf(stream: string): string | null;