@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
@@ -87,6 +87,19 @@ export interface ParsedAppspec {
87
87
  * is always whole, so an editor can open it and show what is wrong.
88
88
  */
89
89
  export declare function parseAppspec(document: unknown): ParsedAppspec;
90
+ /**
91
+ * What is wrong with the UI an application says its answers render in
92
+ * (AGENT_PROTOCOLS PS-04), as agentspecs says it: an id the catalogue does not
93
+ * know or said twice, one not enabled while it is offered.
94
+ */
95
+ export declare function uiProblems(app: Pick<AppSpec, 'ui' | 'enabled'>): string[];
96
+ /**
97
+ * What is wrong with the protocols an application says it speaks
98
+ * (AGENT_PROTOCOLS PS-02), as agentspecs says it: an id the catalogue does not
99
+ * know or said twice, a planned protocol while it is offered, and a `pap`,
100
+ * `pact` or `a2a` block configuring a protocol it does not list.
101
+ */
102
+ export declare function protocolsProblems(app: Pick<AppSpec, 'protocols' | 'enabled' | 'pap' | 'pact' | 'a2a'>): string[];
90
103
  /**
91
104
  * An application as the document its file holds.
92
105
  *
@@ -3,6 +3,8 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  import { BEHAVIOURS } from './rules';
6
+ import { PROTOCOL_CATALOGUE } from '../../specs/protocols';
7
+ import { UI_CATALOGUE } from '../../specs/ui';
6
8
  import { DEFAULT_MAX_FILES, DEFAULT_UPLOAD_MB } from './uploads';
7
9
  /** The version of the spec itself. */
8
10
  export const APP_SCHEMA = 'loop.app/v1';
@@ -130,6 +132,8 @@ export function emptyAppspec(kind = 'chat') {
130
132
  context: [],
131
133
  contents: [],
132
134
  connections: [],
135
+ protocols: [],
136
+ ui: [],
133
137
  rules: [],
134
138
  permissions: {
135
139
  spaces: [],
@@ -141,6 +145,7 @@ export function emptyAppspec(kind = 'chat') {
141
145
  starters: [],
142
146
  commands: [],
143
147
  modes: [],
148
+ actions: [],
144
149
  profiles: [],
145
150
  language: DEFAULT_LANGUAGE,
146
151
  translations: {},
@@ -195,6 +200,8 @@ const KNOWN_KEYS = [
195
200
  'context',
196
201
  'contents',
197
202
  'connections',
203
+ 'protocols',
204
+ 'ui',
198
205
  'pap',
199
206
  'pact',
200
207
  'a2a',
@@ -368,6 +375,17 @@ function parseRule(data) {
368
375
  };
369
376
  }
370
377
  /** A slash command (LOOP P-19); a wrong one is said by the checks. */
378
+ /** An action of its code, typed (REACTOR_UI RU-5): its payload's schema kept as written. */
379
+ function parseAction(data) {
380
+ const action = { name: text(data.name) };
381
+ if (text(data.description)) {
382
+ action.description = text(data.description);
383
+ }
384
+ if (isData(data.payload)) {
385
+ action.payload = JSON.parse(JSON.stringify(data.payload));
386
+ }
387
+ return action;
388
+ }
371
389
  function parseCommand(data) {
372
390
  return {
373
391
  name: text(data.name),
@@ -609,6 +627,7 @@ function parseInterface(data, kind) {
609
627
  starters: records(data.starters).map(parseStarter),
610
628
  commands: records(data.commands).map(parseCommand),
611
629
  modes: records(data.modes).map(parseMode),
630
+ actions: records(data.actions).map(parseAction),
612
631
  profiles: records(data.profiles).map(parseProfile),
613
632
  language: text(data.language, DEFAULT_LANGUAGE),
614
633
  translations: mapValues(recordsBy(data.translations), parseTranslation),
@@ -809,6 +828,8 @@ export function parseAppspec(document) {
809
828
  context: texts(data.context),
810
829
  contents: texts(data.contents),
811
830
  connections: records(data.connections).map(parseConnection),
831
+ protocols: texts(data.protocols),
832
+ ui: texts(data.ui),
812
833
  rules: records(data.rules).map(parseRule),
813
834
  permissions: {
814
835
  spaces: records(permissions.spaces).map(grant => ({
@@ -894,8 +915,69 @@ export function parseAppspec(document) {
894
915
  if (isData(data.a2a)) {
895
916
  app.a2a = parseA2A(data.a2a);
896
917
  }
918
+ problems.push(...protocolsProblems(app), ...uiProblems(app));
897
919
  return { app, problems };
898
920
  }
921
+ /**
922
+ * What is wrong with the UI an application says its answers render in
923
+ * (AGENT_PROTOCOLS PS-04), as agentspecs says it: an id the catalogue does not
924
+ * know or said twice, one not enabled while it is offered.
925
+ */
926
+ export function uiProblems(app) {
927
+ const problems = [];
928
+ const seen = [];
929
+ for (const id of app.ui) {
930
+ if (seen.includes(id)) {
931
+ problems.push(`It lists the UI '${id}' twice.`);
932
+ continue;
933
+ }
934
+ seen.push(id);
935
+ const spec = UI_CATALOGUE[id];
936
+ if (!spec) {
937
+ problems.push(`There is no UI named '${id}': one of ${Object.keys(UI_CATALOGUE).sort().join(', ')}.`);
938
+ }
939
+ else if (app.enabled && !spec.enabled) {
940
+ problems.push(`The UI ${spec.name} ('${id}') is not enabled: an application cannot render in it yet.`);
941
+ }
942
+ }
943
+ return problems;
944
+ }
945
+ /**
946
+ * What is wrong with the protocols an application says it speaks
947
+ * (AGENT_PROTOCOLS PS-02), as agentspecs says it: an id the catalogue does not
948
+ * know or said twice, a planned protocol while it is offered, and a `pap`,
949
+ * `pact` or `a2a` block configuring a protocol it does not list.
950
+ */
951
+ export function protocolsProblems(app) {
952
+ const problems = [];
953
+ const seen = [];
954
+ for (const id of app.protocols) {
955
+ if (seen.includes(id)) {
956
+ problems.push(`It lists the protocol '${id}' twice.`);
957
+ continue;
958
+ }
959
+ seen.push(id);
960
+ const spec = PROTOCOL_CATALOGUE[id];
961
+ if (!spec) {
962
+ problems.push(`There is no protocol named '${id}': one of ${Object.keys(PROTOCOL_CATALOGUE).sort().join(', ')}.`);
963
+ }
964
+ else if (app.enabled && spec.status === 'planned') {
965
+ problems.push(`${spec.name} ('${id}') is planned, not shipped: an application cannot speak it yet.`);
966
+ }
967
+ }
968
+ const configured = {
969
+ pap: Boolean(app.pap && (app.pap.connections.length > 0 || app.pap.company.enabled)),
970
+ pact: Boolean(app.pact && app.pact.connections.length > 0),
971
+ a2a: Boolean(app.a2a && app.a2a.extensions.length > 0),
972
+ };
973
+ for (const spec of Object.values(PROTOCOL_CATALOGUE)) {
974
+ const block = spec.appspecBlock;
975
+ if (block && configured[block] && !app.protocols.includes(spec.id)) {
976
+ problems.push(`Its \`${block}\` block configures ${spec.name}, which it does not list: add '${spec.id}' to \`protocols\`.`);
977
+ }
978
+ }
979
+ return problems;
980
+ }
899
981
  // --- writing --------------------------------------------------------------------------
900
982
  const sameList = (a, b) => a.length === b.length && a.every((item, index) => item === b[index]);
901
983
  /** A document with a key only when its value says something. */
@@ -1015,6 +1097,15 @@ function dumpInterface(spec, kind) {
1015
1097
  written.data.default = mode.default;
1016
1098
  }
1017
1099
  return written.data;
1100
+ }))
1101
+ .list('actions', (spec.actions ?? []).map(action => {
1102
+ const written = new Writer()
1103
+ .text('name', action.name, '\u0000')
1104
+ .text('description', action.description ?? '');
1105
+ if (action.payload) {
1106
+ written.data.payload = { ...action.payload };
1107
+ }
1108
+ return written.data;
1018
1109
  }))
1019
1110
  .list('profiles', (spec.profiles ?? []).map(profile => new Writer()
1020
1111
  .text('id', profile.id, '\u0000')
@@ -1148,6 +1239,8 @@ export function dumpAppspec(app) {
1148
1239
  .value('access', connection.access, 'read')
1149
1240
  .value('as', connection.as, 'owner')
1150
1241
  .list('only', connection.only).data))
1242
+ .list('protocols', app.protocols)
1243
+ .list('ui', app.ui)
1151
1244
  .part('pap', dumpPap(app.pap))
1152
1245
  .part('pact', dumpPact(app.pact))
1153
1246
  .part('a2a', dumpA2A(app.a2a))
@@ -11,7 +11,7 @@ export interface AppCheck {
11
11
  }
12
12
  /**
13
13
  * The component a layout names (LOOP C-13), from the catalogs of the enabled
14
- * UI plugins, by the name a surface gives it.
14
+ * UI specs, by the name a surface gives it.
15
15
  */
16
16
  export declare const componentNamed: (name: string) => ComponentSpec | undefined;
17
17
  /**
@@ -29,7 +29,7 @@ import { getCog } from '../../specs/cogs';
29
29
  import { getFrame } from '../../specs/frames';
30
30
  import { getGate } from '../../specs/gates';
31
31
  import { GUARD_CATALOGUE } from '../../specs/guards';
32
- import { getComponent } from '../../specs/uiPlugins';
32
+ import { getComponent } from '../../specs/ui';
33
33
  import { MCP_SERVER_LIBRARY } from '../../specs/mcpServers';
34
34
  import { getMemory } from '../../specs/memory';
35
35
  import { getModel } from '../../specs/models';
@@ -57,7 +57,7 @@ const idOf = (ref) => {
57
57
  };
58
58
  /**
59
59
  * The component a layout names (LOOP C-13), from the catalogs of the enabled
60
- * UI plugins, by the name a surface gives it.
60
+ * UI specs, by the name a surface gives it.
61
61
  */
62
62
  export const componentNamed = (name) => getComponent(name);
63
63
  const own = (record, key) => Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;
@@ -16,7 +16,7 @@
16
16
  *
17
17
  * @module apps/apps/customComponents
18
18
  */
19
- import { getComponent } from '../../specs/uiPlugins';
19
+ import { getComponent } from '../../specs/ui';
20
20
  /** Its name: a word starting with a capital letter, as the catalog's are named. */
21
21
  export const CUSTOM_COMPONENT_NAME = /^[A-Z][A-Za-z0-9]{0,63}$/;
22
22
  /** What one of its properties may be typed: what the renderer tells apart. */
@@ -1,7 +1,7 @@
1
1
  import type { ComponentSpec } from '../../types/agentspecs';
2
2
  /**
3
3
  * A block the Canvas may place (LOOP C-12): one component of the catalog of
4
- * visual components (C-13), contributed by the plugin of the UI plugin that
4
+ * visual components (C-13), contributed by the plugin of the UI that
5
5
  * renders it. The Canvas's palette is what the enabled plugins contribute
6
6
  * here, and nothing else: a plugin disabled takes its blocks off it, and an
7
7
  * application that uses one of them says so in its setup notes.
@@ -9,8 +9,8 @@ import type { ComponentSpec } from '../../types/agentspecs';
9
9
  export type CanvasBlockContribution = {
10
10
  /** The name a surface gives it, the component's id (e.g. 'Table'). */
11
11
  id: string;
12
- /** The UI plugin of the catalogue that renders it (e.g. 'a2ui'). */
13
- uiPlugin: string;
12
+ /** The UI of the catalogue that renders it (e.g. 'a2ui'). */
13
+ ui: string;
14
14
  component: ComponentSpec;
15
15
  };
16
16
  export declare const LoopCanvasBlock: import("@datalayer/reactor").ContributionPoint<CanvasBlockContribution>;
@@ -1,8 +1,10 @@
1
1
  /** The kinds of part an agent is built from on the Canvas. */
2
- export type CanvasPartKind = 'connection' | 'rule' | 'skill' | 'test' | 'event' | 'model';
2
+ export type CanvasPartKind = 'connection' | 'rule' | 'skill' | 'test' | 'event' | 'model' | 'protocol' | 'ui' | 'character';
3
3
  /**
4
4
  * A part of an agent the Canvas may place (LOOP C-20): a connection to a
5
- * server of the catalogue, a skill, a model, a rule, a test, an event —
5
+ * server of the catalogue, a skill, a model, a rule, a test, an event, a
6
+ * protocol it speaks, a UI its answers render in, the character it shows
7
+ * (AGENT_PROTOCOLS PS-04, PS-05) —
6
8
  * contributed by the plugin of what it comes from. The toolbox is what the
7
9
  * enabled plugins contribute here, and nothing else: a plugin disabled takes
8
10
  * its parts off it, as it takes its blocks off the palette.
@@ -18,8 +20,8 @@ export type CanvasPartContribution = {
18
20
  emoji?: string;
19
21
  /**
20
22
  * What it arrives with, spelled as the Appspec's text spells it: a
21
- * connection's, a rule's, a test's or an event's object, a skill's or a
22
- * model's id. Every example is one the Appspec's schema takes as it is.
23
+ * connection's, a rule's, a test's or an event's object, a skill's, a
24
+ * model's, a protocol's, a UI's or a character's id. Every example is one the Appspec's schema takes as it is.
23
25
  */
24
26
  example: unknown;
25
27
  /** Whether what it names is enabled today; a part that is not is offered, and its application's setup notes say so. */
@@ -634,6 +634,14 @@ export type LoopChatExtrasValue = {
634
634
  * client tool — A2UI Jupyter Output's `run_jupyter_output_demo`.
635
635
  */
636
636
  frontendTools?: FrontendToolDefinition[];
637
+ /**
638
+ * The ids of the `AgentTools` bundles (Reactor's) the chat hands its agent
639
+ * wherever it runs — on a runtime too, where the plugins' bundles are not
640
+ * otherwise given — each tool running its command on this workspace's
641
+ * reactor (REACTOR_UI RU-7): the host page's (`host`), which an embedded
642
+ * application calls as `host_<name>`.
643
+ */
644
+ agentToolBundles?: string[];
637
645
  /**
638
646
  * Take the composer off the screen, live.
639
647
  *
@@ -51,8 +51,7 @@ import { ChatFloating } from '../../chat/ChatFloating';
51
51
  import { AppRenderer, } from '../apps/AppRenderer';
52
52
  import { AssistantCharactersPlugin, assistantCharacterFor, assistantCharactersFrom, } from '../plugins/assistant-characters';
53
53
  import { floatingViewOf } from './embedConfig';
54
- import { createChatExtrasPlugin } from '../plugins/chat-extras';
55
- import { hostFrontendTools, hostUserRunProps, } from './hostBridge';
54
+ import { hostPlugin, hostUserRunProps } from './hostBridge';
56
55
  import { LoopRunProps } from '../core';
57
56
  import { embedThemeOverrides, embedThemeStyles } from './embedTheme';
58
57
  import { WINDOW_NOT_YET, embedSessionKey, postWindowMessage, reattachSession, sessionGoneSentence, sessionKeeper, visitOfToken, } from './embedSession';
@@ -157,18 +156,14 @@ export function useWindowPort({ serverUrl, embedToken, session, host, }) {
157
156
  if (!uid.current) {
158
157
  throw new Error(WINDOW_NOT_YET);
159
158
  }
160
- const said = await postWindowMessage({
159
+ // What its code answers comes on the ui socket, raised as any
160
+ // window message is (REACTOR_UI RU-W).
161
+ await postWindowMessage({
161
162
  serverUrl,
162
163
  uid: uid.current,
163
164
  ...(embedToken ? { token: embedToken } : {}),
164
165
  data,
165
166
  });
166
- for (const answer of said) {
167
- hostRef.current?.onEvent?.({
168
- type: 'window-message',
169
- detail: { data: answer },
170
- });
171
- }
172
167
  });
173
168
  return () => port(null);
174
169
  }, [serverUrl, embedToken, host]);
@@ -189,16 +184,14 @@ const NO_HOST_PLUGINS = [];
189
184
  export function useHostBridge(app, host) {
190
185
  const hostRef = useRef(host);
191
186
  hostRef.current = host;
192
- const handle = useMemo(() => createChatExtrasPlugin(), []);
193
187
  const bridge = app.deployment.embedded?.host;
194
188
  const key = JSON.stringify([bridge ?? null, app.rules, app.connections]);
195
- useEffect(() => {
196
- handle.setExtras({
197
- frontendTools: hostFrontendTools(app, () => hostRef.current ?? {}),
198
- });
199
- // The tools change with what the Appspec names, and the rules that decide them.
200
- // eslint-disable-next-line react-hooks/exhaustive-deps
201
- }, [handle, key]);
189
+ // The host's plugin (REACTOR_UI RU-7): the page's functions as its
190
+ // commands, named for the agent by its agent tools bundle — made again
191
+ // when what the Appspec names, or the rules that decide them, change.
192
+ const hosting = useMemo(() => hostPlugin(app, () => hostRef.current ?? {}),
193
+ // eslint-disable-next-line react-hooks/exhaustive-deps
194
+ [app.id, key]);
202
195
  // Who its user is (D-21): the token the host's server signed goes with
203
196
  // every run, for an application that takes only a signed user.
204
197
  const signed = bridge?.user === 'signed';
@@ -219,9 +212,9 @@ export function useHostBridge(app, host) {
219
212
  // Made again only when whether it is signed changes.
220
213
  // eslint-disable-next-line react-hooks/exhaustive-deps
221
214
  }, [app.id, signed]);
222
- const plugins = useMemo(() => bridge
223
- ? [handle.plugin, ...(userPlugin ? [userPlugin] : [])]
224
- : NO_HOST_PLUGINS, [bridge, handle, userPlugin]);
215
+ const plugins = useMemo(() => hosting
216
+ ? [hosting, ...(userPlugin ? [userPlugin] : [])]
217
+ : NO_HOST_PLUGINS, [hosting, userPlugin]);
225
218
  // What its code tells the page during a turn (LOOP P-25), raised on it.
226
219
  useEffect(() => onLoopWindowMessage(data => hostRef.current?.onEvent?.({
227
220
  type: 'window-message',
@@ -51,7 +51,9 @@ export declare function forgetSessionsInMemory(): void;
51
51
  /**
52
52
  * A session's conversation as the chat draws it, from the AG-UI messages
53
53
  * the runtime says (`GET …/sessions/{uid}/messages`): what was said and
54
- * answered, in words. A page an answer drew is not drawn again here.
54
+ * answered, in words. What its messages showed comes on the conversation's
55
+ * ui socket once the chat opens it (REACTOR_UI RU-W), never here: a
56
+ * `reactor.ui` activity in a thread is refused.
55
57
  */
56
58
  export declare function messagesOfThread(messages: unknown): ChatMessage[];
57
59
  /** What asking for a kept session found. */
@@ -79,8 +81,10 @@ export declare function reattachSession({ serverUrl, uid, token, fetcher, }: {
79
81
  export declare const WINDOW_NOT_YET = "The application takes a window message once its conversation has started, on its own server (the \"server\" attribute).";
80
82
  /**
81
83
  * Post a window message to a session (LOOP P-25): its code's `@app.window`
82
- * runs on it. Returns what the code told the page back; refused — the
83
- * runtime's sentence — when the session or its code takes none.
84
+ * runs on it. What the code tells the page back arrives on the
85
+ * conversation's ui socket (REACTOR_UI RU-W), raised as any window message
86
+ * is; refused — the runtime's sentence — when the session or its code takes
87
+ * none.
84
88
  */
85
89
  export declare function postWindowMessage({ serverUrl, uid, token, data, fetcher, }: {
86
90
  serverUrl: string;
@@ -88,6 +92,6 @@ export declare function postWindowMessage({ serverUrl, uid, token, data, fetcher
88
92
  token?: string;
89
93
  data: unknown;
90
94
  fetcher?: typeof fetch;
91
- }): Promise<unknown[]>;
95
+ }): Promise<void>;
92
96
  /** What the page says, once, when the conversation it kept is gone. */
93
97
  export declare const sessionGoneSentence: (name: string) => string;
@@ -2,7 +2,8 @@
2
2
  * Copyright (c) 2025-2026 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- import { windowTurnOf } from '../../chat/base/loopWindow';
5
+ import { windowTurnErrorOf } from '../../chat/base/loopWindow';
6
+ import { AGUI_NAME } from '@datalayer/reactor/ui';
6
7
  /** Where a visit's session is kept in the host's storage: `<prefix>:<app>:<visit>`. */
7
8
  export const EMBED_SESSION_KEY_PREFIX = 'datalayer-app:session';
8
9
  /**
@@ -93,7 +94,9 @@ export function forgetSessionsInMemory() {
93
94
  /**
94
95
  * A session's conversation as the chat draws it, from the AG-UI messages
95
96
  * the runtime says (`GET …/sessions/{uid}/messages`): what was said and
96
- * answered, in words. A page an answer drew is not drawn again here.
97
+ * answered, in words. What its messages showed comes on the conversation's
98
+ * ui socket once the chat opens it (REACTOR_UI RU-W), never here: a
99
+ * `reactor.ui` activity in a thread is refused.
97
100
  */
98
101
  export function messagesOfThread(messages) {
99
102
  if (!Array.isArray(messages)) {
@@ -104,7 +107,10 @@ export function messagesOfThread(messages) {
104
107
  if (!message || typeof message !== 'object') {
105
108
  continue;
106
109
  }
107
- const { id, role, content } = message;
110
+ const { id, role, content, activityType } = message;
111
+ if (role === 'activity' && activityType === AGUI_NAME) {
112
+ throw new Error(`Activity ${String(id)}: what a message showed comes on the ui socket (REACTOR_UI RU-W)`);
113
+ }
108
114
  if ((role === 'user' || role === 'assistant') &&
109
115
  typeof id === 'string' &&
110
116
  typeof content === 'string' &&
@@ -137,8 +143,10 @@ export async function reattachSession({ serverUrl, uid, token, fetcher = fetch,
137
143
  export const WINDOW_NOT_YET = 'The application takes a window message once its conversation has started, on its own server (the "server" attribute).';
138
144
  /**
139
145
  * Post a window message to a session (LOOP P-25): its code's `@app.window`
140
- * runs on it. Returns what the code told the page back; refused — the
141
- * runtime's sentence — when the session or its code takes none.
146
+ * runs on it. What the code tells the page back arrives on the
147
+ * conversation's ui socket (REACTOR_UI RU-W), raised as any window message
148
+ * is; refused — the runtime's sentence — when the session or its code takes
149
+ * none.
142
150
  */
143
151
  export async function postWindowMessage({ serverUrl, uid, token, data, fetcher = fetch, }) {
144
152
  const response = await fetcher(`${serverUrl.replace(/\/+$/, '')}/api/v1/apps/sessions/${encodeURIComponent(uid)}/window`, {
@@ -160,11 +168,10 @@ export async function postWindowMessage({ serverUrl, uid, token, data, fetcher =
160
168
  }
161
169
  throw new Error(detail || `The window message was refused (${response.status}).`);
162
170
  }
163
- const turn = windowTurnOf(await response.text());
164
- if (turn.error) {
165
- throw new Error(turn.error);
171
+ const error = windowTurnErrorOf(await response.text());
172
+ if (error) {
173
+ throw new Error(error);
166
174
  }
167
- return turn.said;
168
175
  }
169
176
  /** What the page says, once, when the conversation it kept is gone. */
170
177
  export const sessionGoneSentence = (name) => `Your earlier conversation with ${name} has ended, so this is a new one.`;
@@ -27,20 +27,26 @@
27
27
  * reaches the page.
28
28
  *
29
29
  * Offered: the functions of the page its Appspec names
30
- * (`deployment.embedded.host.functions`), each called by its agent as the
31
- * tool `host_<name>`. Every one of these tools is decided in the page by
32
- * the rule that names it (`behaviourFor`), before the page is called: one no
33
- * rule names, or *leave it to me*, is refused; *ask me first* and *do it if
34
- * I asked* ask the person on the page (`ask`, else the browser's `confirm`),
35
- * and a call they do not allow is refused; *do it* is done.
30
+ * (`deployment.embedded.host.functions`), as Reactor has a plugin offer
31
+ * what it does (REACTOR_UI RU-7): each a **command** of the host's plugin,
32
+ * `host.<name>` (`host.context` for the values it passes), and the plugin's
33
+ * **agent tools** bundle (`AgentTools`, id `host`) naming them for its agent
34
+ * as the tools `host_<name>` and `host_context` — which the chat turns into
35
+ * tools that run `reactor.executeCommand`, as for any plugin's bundle, and
36
+ * hands its agent wherever it runs (`agentToolBundles`). Every one of these
37
+ * commands is decided in the page by the rule that names its tool
38
+ * (`behaviourFor`), before the page is called: one no rule names, or
39
+ * *leave it to me*, is refused; *ask me first* and *do it if I asked* ask
40
+ * the person on the page (`ask`, else the browser's `confirm`), and a call
41
+ * they do not allow is refused; *do it* is done.
36
42
  *
37
- * Pure: the tools call the page, and ask, through what they are given.
43
+ * Pure: the commands call the page, and ask, through what they are given.
38
44
  *
39
45
  * @module apps/embed/hostBridge
40
46
  */
47
+ import { type AgentToolBundle, type ReactorCommand, type ReactorPlugin } from '@datalayer/reactor';
41
48
  import type { AppSpec } from '../../types/agentspecs';
42
- import type { FrontendToolDefinition } from '../../types/tools';
43
- import type { RunPropsContribution } from '../core';
49
+ import { type RunPropsContribution } from '../core';
44
50
  import { HOST_CONTEXT_TOOL, HOST_NAME, hostTool, hostToolsOf, signedUser } from '../apps/hostTools';
45
51
  export { HOST_CONTEXT_TOOL, HOST_NAME, hostTool, hostToolsOf, signedUser };
46
52
  /** What the application tells the page it sits in. */
@@ -109,12 +115,40 @@ export type HostQuestion = {
109
115
  export declare const hostRefused: (tool: string) => string;
110
116
  /** The sentence a call is refused with when the person did not allow it. */
111
117
  export declare const hostNotAllowed: (tool: string) => string;
118
+ /** The command that reads what the page passes (`host_context`). */
119
+ export declare const HOST_CONTEXT_COMMAND = "host.context";
120
+ /** The command a function of the page runs as. */
121
+ export declare const hostCommand: (name: string) => string;
122
+ /** The id of the host plugin's agent tools bundle. */
123
+ export declare const HOST_TOOLS_BUNDLE = "host";
124
+ /** What a command of the host answers its tool: what came back, or why not. */
125
+ export type HostAnswer = {
126
+ values: Record<string, unknown>;
127
+ unsaid?: string[];
128
+ } | {
129
+ result?: unknown;
130
+ error?: string;
131
+ };
132
+ type HostCommand = ReactorCommand<Record<string, unknown> | undefined, HostAnswer>;
133
+ /**
134
+ * The host plugin's commands (REACTOR_UI RU-7): `host.context` when the
135
+ * Appspec names values, and `host.<name>` for each function it names, each
136
+ * decided by the rule naming its tool before the page is called. `host` is
137
+ * read at each call, so that what the page passes is the newest.
138
+ */
139
+ export declare function hostCommands(app: Pick<AppSpec, 'name' | 'connections' | 'rules' | 'deployment'>, host: () => AppEmbedHost): HostCommand[];
140
+ /**
141
+ * The host plugin's agent tools (REACTOR_UI RU-7): `host_context` and
142
+ * `host_<name>`, each running its command; `null` for an application the
143
+ * Appspec embeds with no host bridge.
144
+ */
145
+ export declare function hostAgentTools(app: Pick<AppSpec, 'name' | 'deployment'>): AgentToolBundle | null;
112
146
  /**
113
- * The frontend tools its agent is given for the page: `host_context` when
114
- * the Appspec names values, and `host_<name>` for each function it names.
115
- * `host` is read at each call, so that what the page passes is the newest.
147
+ * The host's plugin (REACTOR_UI RU-7): its commands, its agent tools bundle,
148
+ * and the chat extras that hand the bundle to the chat's agent wherever it
149
+ * runs. `null` for an application with no host bridge.
116
150
  */
117
- export declare function hostFrontendTools(app: Pick<AppSpec, 'connections' | 'rules' | 'deployment'>, host: () => AppEmbedHost): FrontendToolDefinition[];
151
+ export declare function hostPlugin(app: Pick<AppSpec, 'id' | 'name' | 'connections' | 'rules' | 'deployment'>, host: () => AppEmbedHost): ReactorPlugin<Record<string, never>, unknown, unknown> | null;
118
152
  /**
119
153
  * What goes with every run for the host's user (LOOP D-21): the token the
120
154
  * host's server signed, as `forwardedProps.loop.user_token`, for an