@datalayer/agent-runtimes 1.0.29 → 1.3.10

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 (768) hide show
  1. package/lib/AgentDocument.js +5 -22
  2. package/lib/AgentNode.d.ts +1 -1
  3. package/lib/AgentNode.js +193 -23
  4. package/lib/AgentNotebook.js +1 -1
  5. package/lib/App.d.ts +1 -1
  6. package/lib/AppExamples2.d.ts +1 -1
  7. package/lib/agent-node/AgentNodeGallery.d.ts +14 -1
  8. package/lib/agent-node/AgentNodeGallery.js +19 -15
  9. package/lib/agent-node/themeStore.js +7 -6
  10. package/lib/agents/AgentDetails.d.ts +8 -2
  11. package/lib/agents/AgentDetails.js +41 -11
  12. package/lib/agents/AgentRuntimeChat.d.ts +3 -3
  13. package/lib/agents/AgentRuntimeChat.js +15 -15
  14. package/lib/api/agents.d.ts +10 -10
  15. package/lib/api/agents.js +15 -15
  16. package/lib/api/checkpoints.d.ts +40 -0
  17. package/lib/api/checkpoints.js +75 -0
  18. package/lib/api/index.d.ts +1 -0
  19. package/lib/api/index.js +2 -1
  20. package/lib/api/notifications.d.ts +21 -6
  21. package/lib/api/notifications.js +32 -14
  22. package/lib/api/runtimes/environments.d.ts +385 -4
  23. package/lib/api/runtimes/environments.js +610 -9
  24. package/lib/api/runtimes/runtimes.d.ts +19 -19
  25. package/lib/api/runtimes/runtimes.js +47 -46
  26. package/lib/api/spacer/notebooks.js +1 -1
  27. package/lib/chat/Chat.d.ts +16 -4
  28. package/lib/chat/Chat.js +18 -5
  29. package/lib/chat/ChatFloating.d.ts +13 -2
  30. package/lib/chat/ChatFloating.js +192 -117
  31. package/lib/chat/ChatInline.d.ts +15 -0
  32. package/lib/chat/ChatInline.js +0 -18
  33. package/lib/chat/ChatPopupStandalone.d.ts +1 -1
  34. package/lib/chat/ChatSidebar.d.ts +14 -2
  35. package/lib/chat/ChatSidebar.js +1 -1
  36. package/lib/chat/ChatStandalone.d.ts +1 -1
  37. package/lib/chat/EphemeralSurfaceControl.d.ts +30 -0
  38. package/lib/chat/EphemeralSurfaceControl.js +55 -0
  39. package/lib/chat/base/ChatAvailability.d.ts +34 -0
  40. package/lib/chat/base/ChatAvailability.js +18 -0
  41. package/lib/chat/base/ChatBase.d.ts +2 -1
  42. package/lib/chat/base/ChatBase.js +657 -28
  43. package/lib/chat/display/EmptyState.d.ts +15 -1
  44. package/lib/chat/display/EmptyState.js +78 -12
  45. package/lib/chat/display/FloatingBrandButton.d.ts +1 -1
  46. package/lib/chat/display/PoweredByTag.d.ts +1 -1
  47. package/lib/chat/display/groupSuggestions.d.ts +21 -0
  48. package/lib/chat/display/groupSuggestions.js +18 -0
  49. package/lib/chat/document/EphemeralDocument.d.ts +70 -6
  50. package/lib/chat/document/EphemeralDocument.js +154 -52
  51. package/lib/chat/header/ChatHeader.d.ts +1 -1
  52. package/lib/chat/header/ChatHeaderBase.d.ts +10 -1
  53. package/lib/chat/header/ChatHeaderBase.js +67 -96
  54. package/lib/chat/index.d.ts +4 -1
  55. package/lib/chat/index.js +8 -1
  56. package/lib/chat/indicators/McpStatusIndicator.d.ts +1 -1
  57. package/lib/chat/indicators/SandboxStatusIndicator.d.ts +1 -1
  58. package/lib/chat/indicators/SandboxStatusIndicator.js +1 -1
  59. package/lib/chat/indicators/SkillsStatusIndicator.d.ts +1 -1
  60. package/lib/chat/messages/ChatMessageList.d.ts +22 -1
  61. package/lib/chat/messages/ChatMessageList.js +370 -166
  62. package/lib/chat/messages/ChatMessages.d.ts +1 -1
  63. package/lib/chat/messages/NotebookToolSurfaces.d.ts +68 -0
  64. package/lib/chat/messages/NotebookToolSurfaces.js +302 -0
  65. package/lib/chat/messages/TurnFooter.d.ts +42 -0
  66. package/lib/chat/messages/TurnFooter.js +75 -0
  67. package/lib/chat/messages/assistantMarkdown.d.ts +22 -0
  68. package/lib/chat/messages/assistantMarkdown.js +56 -0
  69. package/lib/chat/notebook/EphemeralNotebook.d.ts +67 -6
  70. package/lib/chat/notebook/EphemeralNotebook.js +194 -61
  71. package/lib/chat/parts/DynamicToolPart.d.ts +1 -1
  72. package/lib/chat/parts/MessagePart.d.ts +1 -1
  73. package/lib/chat/parts/ReasoningPart.d.ts +8 -1
  74. package/lib/chat/parts/TextPart.d.ts +1 -1
  75. package/lib/chat/parts/ToolPart.d.ts +8 -1
  76. package/lib/chat/prompt/FloatingCard.d.ts +26 -0
  77. package/lib/chat/prompt/FloatingCard.js +80 -0
  78. package/lib/chat/prompt/InputPrompt.d.ts +206 -53
  79. package/lib/chat/prompt/InputPrompt.js +161 -80
  80. package/lib/chat/prompt/InputPromptBase.d.ts +112 -0
  81. package/lib/chat/prompt/InputPromptBase.js +225 -0
  82. package/lib/chat/prompt/InputPromptLexical.d.ts +18 -1
  83. package/lib/chat/prompt/InputPromptLexical.js +227 -30
  84. package/lib/chat/prompt/InputPromptText.d.ts +10 -2
  85. package/lib/chat/prompt/InputPromptText.js +35 -3
  86. package/lib/chat/prompt/footer/BelowPromptFooter.d.ts +25 -0
  87. package/lib/chat/prompt/footer/BelowPromptFooter.js +12 -0
  88. package/lib/chat/prompt/footer/InPromptFooter.d.ts +35 -0
  89. package/lib/chat/prompt/footer/InPromptFooter.js +16 -0
  90. package/lib/chat/prompt/footer/index.d.ts +7 -0
  91. package/lib/chat/prompt/footer/index.js +11 -0
  92. package/lib/chat/prompt/header/BelowPromptHeader.d.ts +23 -0
  93. package/lib/chat/prompt/header/BelowPromptHeader.js +12 -0
  94. package/lib/chat/prompt/header/InPromptHeader.d.ts +31 -0
  95. package/lib/chat/prompt/header/InPromptHeader.js +14 -0
  96. package/lib/chat/prompt/header/index.d.ts +7 -0
  97. package/lib/chat/prompt/header/index.js +11 -0
  98. package/lib/chat/prompt/index.d.ts +8 -4
  99. package/lib/chat/prompt/index.js +15 -3
  100. package/lib/chat/prompt/menus/AgentsMenu.d.ts +14 -0
  101. package/lib/chat/prompt/menus/AgentsMenu.js +42 -0
  102. package/lib/chat/prompt/menus/InlineAgentsMenu.d.ts +22 -0
  103. package/lib/chat/prompt/menus/InlineAgentsMenu.js +24 -0
  104. package/lib/chat/prompt/menus/ModelSelector.d.ts +7 -0
  105. package/lib/chat/prompt/menus/ModelSelector.js +27 -0
  106. package/lib/chat/prompt/menus/SkillsMenu.d.ts +10 -0
  107. package/lib/chat/prompt/menus/SkillsMenu.js +75 -0
  108. package/lib/chat/prompt/menus/SuggestionsMenu.d.ts +13 -0
  109. package/lib/chat/prompt/menus/SuggestionsMenu.js +31 -0
  110. package/lib/chat/prompt/menus/ToolsMenu.d.ts +13 -0
  111. package/lib/chat/prompt/menus/ToolsMenu.js +103 -0
  112. package/lib/chat/prompt/menus/index.d.ts +15 -0
  113. package/lib/chat/prompt/menus/index.js +19 -0
  114. package/lib/chat/prompt/plugins/AgentMentionPlugin.d.ts +54 -0
  115. package/lib/chat/prompt/plugins/AgentMentionPlugin.js +370 -0
  116. package/lib/chat/prompt/plugins/CommandPlugin.d.ts +52 -0
  117. package/lib/chat/prompt/plugins/CommandPlugin.js +359 -0
  118. package/lib/chat/prompt/plugins/MentionChip.d.ts +15 -0
  119. package/lib/chat/prompt/plugins/MentionChip.js +24 -0
  120. package/lib/chat/prompt/plugins/MentionNode.d.ts +66 -0
  121. package/lib/chat/prompt/plugins/MentionNode.js +77 -0
  122. package/lib/chat/prompt/promptHistory.d.ts +52 -0
  123. package/lib/chat/prompt/promptHistory.js +123 -0
  124. package/lib/chat/prompt/stack.d.ts +81 -0
  125. package/lib/chat/prompt/stack.js +41 -0
  126. package/lib/chat/prompt/useTypingPlaceholder.d.ts +52 -0
  127. package/lib/chat/prompt/useTypingPlaceholder.js +180 -0
  128. package/lib/chat/tools/A2AAgentDialog.d.ts +60 -0
  129. package/lib/chat/tools/A2AAgentDialog.js +265 -0
  130. package/lib/chat/tools/ToolApprovalBanner.d.ts +1 -1
  131. package/lib/chat/tools/ToolApprovalDialog.d.ts +1 -1
  132. package/lib/chat/tools/ToolCallDisplay.d.ts +8 -1
  133. package/lib/chat/tools/index.d.ts +1 -0
  134. package/lib/chat/tools/index.js +1 -0
  135. package/lib/chat/usage/ContextPie.d.ts +17 -0
  136. package/lib/chat/usage/{TokenUsageBar.js → ContextPie.js} +20 -14
  137. package/lib/chat/useViewportDrag.d.ts +11 -0
  138. package/lib/chat/useViewportDrag.js +61 -0
  139. package/lib/chat/viewModes.d.ts +51 -0
  140. package/lib/chat/viewModes.js +57 -0
  141. package/lib/client/AgentRuntimesClient.d.ts +10 -9
  142. package/lib/client/AgentRuntimesClient.js +1 -1
  143. package/lib/client/AgentRuntimesClientContext.d.ts +1 -0
  144. package/lib/client/AgentsMixin.d.ts +12 -12
  145. package/lib/client/AgentsMixin.js +31 -31
  146. package/lib/client/IAgentRuntimesClient.d.ts +10 -10
  147. package/lib/client/SdkAgentRuntimesClient.d.ts +10 -10
  148. package/lib/client/SdkAgentRuntimesClient.js +10 -10
  149. package/lib/client/mixins/RuntimesMixin.d.ts +37 -10
  150. package/lib/client/mixins/RuntimesMixin.js +54 -21
  151. package/lib/components/a2ui/A2uiSurfaceComposed.d.ts +1 -1
  152. package/lib/components/agents/AgentSummary.d.ts +13 -0
  153. package/lib/components/agents/AgentSummary.js +21 -4
  154. package/lib/components/cards/NotificationEventCard.d.ts +1 -1
  155. package/lib/components/cards/OutputCard.d.ts +1 -1
  156. package/lib/components/cards/ToolApprovalCard.d.ts +2 -2
  157. package/lib/components/cards/ToolApprovalCard.js +1 -0
  158. package/lib/components/code-sandboxes/CodeSandboxCellVariables.d.ts +1 -0
  159. package/lib/components/code-sandboxes/CodeSandboxCellVariables.js +0 -4
  160. package/lib/components/code-sandboxes/CodeSandboxCellVariablesDialog.d.ts +1 -0
  161. package/lib/components/code-sandboxes/CodeSandboxCellVariablesDialog.js +0 -4
  162. package/lib/components/code-sandboxes/CodeSandboxEnvironmentSelect.d.ts +35 -0
  163. package/lib/components/code-sandboxes/CodeSandboxEnvironmentSelect.js +27 -29
  164. package/lib/components/code-sandboxes/CodeSandboxLauncher.d.ts +1 -0
  165. package/lib/components/code-sandboxes/CodeSandboxLauncher.js +42 -19
  166. package/lib/components/code-sandboxes/CodeSandboxNames.js +7 -6
  167. package/lib/components/code-sandboxes/CodeSandboxPicker.js +89 -42
  168. package/lib/components/code-sandboxes/CodeSandboxPickerCell.d.ts +1 -0
  169. package/lib/components/code-sandboxes/CodeSandboxPickerCell.js +0 -4
  170. package/lib/components/code-sandboxes/CodeSandboxReservationControl.d.ts +1 -0
  171. package/lib/components/code-sandboxes/CodeSandboxReservationControl.js +5 -7
  172. package/lib/components/code-sandboxes/CodeSandboxTransfer.d.ts +5 -0
  173. package/lib/components/code-sandboxes/CodeSandboxUtils.d.ts +13 -1
  174. package/lib/components/code-sandboxes/CodeSandboxUtils.js +10 -4
  175. package/lib/components/code-sandboxes/NewCodeSandboxControls.d.ts +21 -15
  176. package/lib/components/code-sandboxes/NewCodeSandboxControls.js +28 -51
  177. package/lib/components/code-sandboxes/codeSandboxAllowance.d.ts +33 -0
  178. package/lib/components/code-sandboxes/codeSandboxAllowance.js +37 -0
  179. package/lib/components/code-sandboxes/codeSandboxEnvironments.d.ts +86 -0
  180. package/lib/components/code-sandboxes/codeSandboxEnvironments.js +147 -0
  181. package/lib/components/code-sandboxes/codeSandboxProviders.js +14 -5
  182. package/lib/components/code-sandboxes/index.d.ts +1 -0
  183. package/lib/components/code-sandboxes/index.js +1 -0
  184. package/lib/components/context/SpaceSelect.d.ts +1 -1
  185. package/lib/components/flashes/FlashDisclaimer.d.ts +1 -1
  186. package/lib/components/icons/ArtifactIcon.d.ts +1 -0
  187. package/lib/components/nbgrader/NbGradesDetails.d.ts +1 -1
  188. package/lib/components/progress/CreditsIndicator.d.ts +1 -0
  189. package/lib/components/progress/CreditsIndicator.js +0 -4
  190. package/lib/components/scheduler/ScheduleMenu.d.ts +1 -1
  191. package/lib/components/snapshots/SandboxSnapshotMenu.d.ts +3 -2
  192. package/lib/components/snapshots/SandboxSnapshotMenu.js +11 -15
  193. package/lib/components/snippets/SnippetDialog.d.ts +1 -0
  194. package/lib/components/snippets/SnippetDialog.js +0 -4
  195. package/lib/components/specs/SpecPayloadPreview.d.ts +34 -0
  196. package/lib/components/specs/SpecPayloadPreview.js +102 -0
  197. package/lib/components/tokens/SpaceVariantToken.d.ts +1 -1
  198. package/lib/context/ContextDistribution.d.ts +1 -1
  199. package/lib/context/ContextInspector.d.ts +2 -1
  200. package/lib/context/ContextPanel.d.ts +1 -1
  201. package/lib/context/ContextUsage.d.ts +1 -1
  202. package/lib/context/CostTracker.d.ts +1 -1
  203. package/lib/context/CostUsageChart.d.ts +1 -1
  204. package/lib/context/CostUsageChart.js +4 -4
  205. package/lib/context/MessageHistory.d.ts +3 -2
  206. package/lib/context/TokenUsageChart.d.ts +1 -1
  207. package/lib/context/TokenUsageChart.js +4 -4
  208. package/lib/examples/A2UiAgentExample.js +15 -6
  209. package/lib/examples/A2UiComponentsGalleryExample.d.ts +10 -0
  210. package/lib/examples/A2UiComponentsGalleryExample.js +24 -855
  211. package/lib/examples/A2UiContactCardExample.d.ts +10 -0
  212. package/lib/examples/A2UiContactCardExample.js +23 -170
  213. package/lib/examples/A2UiJupyterOutputExample.d.ts +3 -0
  214. package/lib/examples/A2UiJupyterOutputExample.js +792 -0
  215. package/lib/examples/A2UiRestaurantExample.d.ts +10 -0
  216. package/lib/examples/A2UiRestaurantExample.js +24 -179
  217. package/lib/examples/A2UiViewerExample.d.ts +10 -0
  218. package/lib/examples/A2UiViewerExample.js +24 -378
  219. package/lib/examples/AgUiAgenticExample.js +2 -4
  220. package/lib/examples/AgUiBackendToolRenderingExample.js +3 -5
  221. package/lib/examples/AgUiHaikuGenUiExample.js +2 -4
  222. package/lib/examples/AgUiHumanInTheLoopExample.js +2 -4
  223. package/lib/examples/AgUiSharedStateExample.js +2 -4
  224. package/lib/examples/AgUiToolsBasedGenUiExample.js +2 -4
  225. package/lib/examples/AgentA2AExample.d.ts +17 -0
  226. package/lib/examples/AgentA2AExample.js +56 -0
  227. package/lib/examples/AgentCheckpointsExample.d.ts +9 -10
  228. package/lib/examples/AgentCheckpointsExample.js +72 -54
  229. package/lib/examples/AgentCodeSandboxExample.d.ts +7 -7
  230. package/lib/examples/AgentCodeSandboxExample.js +93 -303
  231. package/lib/examples/AgentCodeSandboxesExample.d.ts +10 -0
  232. package/lib/examples/AgentCodeSandboxesExample.js +56 -162
  233. package/lib/examples/AgentCodemodeExample.d.ts +7 -2
  234. package/lib/examples/AgentCodemodeExample.js +60 -125
  235. package/lib/examples/AgentCompactionExample.js +19 -135
  236. package/lib/examples/AgentEvalsExample.js +34 -66
  237. package/lib/examples/AgentGuardrailsExample.js +64 -112
  238. package/lib/examples/AgentHooksExample.d.ts +11 -0
  239. package/lib/examples/AgentHooksExample.js +30 -67
  240. package/lib/examples/AgentInferenceProviderExample.js +8 -32
  241. package/lib/examples/AgentLoopExample.d.ts +4 -2
  242. package/lib/examples/AgentLoopExample.js +45 -93
  243. package/lib/examples/AgentMCPExample.js +30 -79
  244. package/lib/examples/AgentMemoryExample.js +21 -64
  245. package/lib/examples/AgentMonitoringExample.js +33 -94
  246. package/lib/examples/AgentNotificationsExample.js +56 -95
  247. package/lib/examples/AgentOtelExample.js +35 -88
  248. package/lib/examples/AgentOutputsExample.d.ts +2 -1
  249. package/lib/examples/AgentOutputsExample.js +16 -137
  250. package/lib/examples/AgentParametersExample.js +7 -17
  251. package/lib/examples/AgentSkillsExample.js +40 -154
  252. package/lib/examples/AgentSubagentsExample.d.ts +7 -6
  253. package/lib/examples/AgentSubagentsExample.js +80 -191
  254. package/lib/examples/AgentToolApprovalsExample.js +35 -91
  255. package/lib/examples/AgentTriggersExample.js +43 -59
  256. package/lib/examples/AgentspecsExample.js +4 -4
  257. package/lib/examples/CellExample.d.ts +1 -1
  258. package/lib/examples/ChatExample.d.ts +12 -5
  259. package/lib/examples/ChatExample.js +38 -13
  260. package/lib/examples/CopilotKitLexicalExample.d.ts +1 -0
  261. package/lib/examples/CopilotKitLexicalExample.js +4 -41
  262. package/lib/examples/CopilotKitNotebookExample.d.ts +10 -0
  263. package/lib/examples/CopilotKitNotebookExample.js +2 -14
  264. package/lib/examples/DecksAgent.d.ts +21 -0
  265. package/lib/examples/DecksAgent.js +23 -0
  266. package/lib/examples/DocumentPageAgent.d.ts +19 -0
  267. package/lib/examples/DocumentPageAgent.js +15 -0
  268. package/lib/examples/Lexical2Example.d.ts +2 -2
  269. package/lib/examples/Lexical2Example.js +17 -38
  270. package/lib/examples/LexicalAgentExample.d.ts +2 -1
  271. package/lib/examples/LexicalAgentExample.js +29 -102
  272. package/lib/examples/LexicalAgentSidebarExample.d.ts +16 -5
  273. package/lib/examples/LexicalAgentSidebarExample.js +99 -131
  274. package/lib/examples/LoopShellExample.d.ts +38 -0
  275. package/lib/examples/LoopShellExample.js +68 -0
  276. package/lib/examples/LoopWorkspaceEmbed.d.ts +50 -0
  277. package/lib/examples/LoopWorkspaceEmbed.js +73 -0
  278. package/lib/examples/LoopWorkspaceExample.d.ts +150 -0
  279. package/lib/examples/LoopWorkspaceExample.js +151 -0
  280. package/lib/examples/NotebookAgentExample.d.ts +13 -0
  281. package/lib/examples/NotebookAgentExample.js +36 -86
  282. package/lib/examples/NotebookAgentSidebarExample.d.ts +10 -4
  283. package/lib/examples/NotebookAgentSidebarExample.js +39 -83
  284. package/lib/examples/NotebookCollaborationExample.d.ts +1 -1
  285. package/lib/examples/NotebookCollaborationExample.js +108 -20
  286. package/lib/examples/NotebookExample.d.ts +1 -1
  287. package/lib/examples/NotebookExample.js +20 -10
  288. package/lib/examples/NotebookPageAgent.d.ts +23 -0
  289. package/lib/examples/NotebookPageAgent.js +17 -0
  290. package/lib/examples/components/ExampleWrapper.d.ts +5 -0
  291. package/lib/examples/components/ExampleWrapper.js +36 -28
  292. package/lib/examples/components/LexicalEditor.d.ts +1 -1
  293. package/lib/examples/components/LexicalEditor.js +4 -24
  294. package/lib/examples/components/haiku/HaikuDisplay.d.ts +1 -1
  295. package/lib/examples/components/haiku/InlineHaikuCard.d.ts +1 -1
  296. package/lib/examples/components/weather/InlineWeatherCard.d.ts +1 -1
  297. package/lib/examples/example-selector.js +26 -6
  298. package/lib/examples/hooks/useCreateAgentOnce.d.ts +41 -0
  299. package/lib/examples/hooks/useCreateAgentOnce.js +51 -0
  300. package/lib/examples/hooks/useExampleAgentProtocol.d.ts +35 -0
  301. package/lib/examples/hooks/useExampleAgentProtocol.js +63 -0
  302. package/lib/examples/hooks/useExampleAgentRuntime.d.ts +16 -16
  303. package/lib/examples/hooks/useExampleAgentRuntime.js +26 -25
  304. package/lib/examples/hooks/useExampleAgentRuntimes.js +45 -61
  305. package/lib/examples/hooks/useExampleJupyterAgent.d.ts +91 -0
  306. package/lib/examples/hooks/useExampleJupyterAgent.js +151 -0
  307. package/lib/examples/index.d.ts +4 -0
  308. package/lib/examples/index.js +6 -0
  309. package/lib/examples/lexical/editorConfig.d.ts +2 -75
  310. package/lib/examples/lexical/editorConfig.js +26 -48
  311. package/lib/examples/lexical/lexical-theme.css +65 -47
  312. package/lib/examples/main.js +450 -322
  313. package/lib/examples/scenes/A2UiComponentsGalleryScene.d.ts +3 -0
  314. package/lib/examples/scenes/A2UiComponentsGalleryScene.js +872 -0
  315. package/lib/examples/scenes/A2UiContactCardScene.d.ts +3 -0
  316. package/lib/examples/scenes/A2UiContactCardScene.js +188 -0
  317. package/lib/examples/scenes/A2UiRestaurantScene.d.ts +3 -0
  318. package/lib/examples/scenes/A2UiRestaurantScene.js +196 -0
  319. package/lib/examples/scenes/A2UiViewerScene.d.ts +3 -0
  320. package/lib/examples/scenes/A2UiViewerScene.js +395 -0
  321. package/lib/examples/utils/agentSummaryStore.d.ts +7 -1
  322. package/lib/examples/utils/agents/earthquake-detector.ipynb.json +1 -1
  323. package/lib/examples/utils/agents/earthquake-detector.lexical.json +1 -1
  324. package/lib/examples/utils/agents/sales-forecaster.ipynb.json +1 -1
  325. package/lib/examples/utils/agents/sales-forecaster.lexical.json +1 -1
  326. package/lib/examples/utils/agents/social-post-generator.ipynb.json +1 -1
  327. package/lib/examples/utils/agents/social-post-generator.lexical.json +1 -1
  328. package/lib/examples/utils/exampleSurfaces.d.ts +31 -0
  329. package/lib/examples/utils/exampleSurfaces.js +38 -0
  330. package/lib/examples/utils/jupyterSandboxUrl.d.ts +27 -0
  331. package/lib/examples/utils/jupyterSandboxUrl.js +55 -0
  332. package/lib/examples/utils/localUrl.d.ts +2 -0
  333. package/lib/examples/utils/localUrl.js +49 -0
  334. package/lib/examples/utils/notebookToolbarItems.d.ts +46 -0
  335. package/lib/examples/utils/notebookToolbarItems.js +129 -0
  336. package/lib/examples/utils/runtimeTargetStore.d.ts +40 -1
  337. package/lib/examples/utils/runtimeTargetStore.js +82 -1
  338. package/lib/examples/utils/themedProvider.d.ts +7 -0
  339. package/lib/examples/utils/themedProvider.js +57 -4
  340. package/lib/examples/utils/useExampleAgentRuntimesUrl.js +30 -5
  341. package/lib/examples/utils/waitForAgent.d.ts +23 -0
  342. package/lib/examples/utils/waitForAgent.js +24 -0
  343. package/lib/examples2/CellExample.d.ts +1 -1
  344. package/lib/examples2/DatalayerNotebookExample.d.ts +1 -1
  345. package/lib/examples2/NotebookExample.d.ts +1 -1
  346. package/lib/examples2/NotebookMutationsKernel.d.ts +1 -1
  347. package/lib/examples2/NotebookMutationsServiceManager.d.ts +1 -1
  348. package/lib/examples2/main.js +24 -4
  349. package/lib/extensions/A2UIExtension.d.ts +1 -1
  350. package/lib/hooks/index.d.ts +8 -5
  351. package/lib/hooks/index.js +20 -5
  352. package/lib/hooks/useAgentRuntimes.d.ts +49 -22
  353. package/lib/hooks/useAgentRuntimes.js +214 -90
  354. package/lib/hooks/useAgentsCatalog.js +32 -4
  355. package/lib/hooks/useBrowserAgent.d.ts +26 -0
  356. package/lib/hooks/useBrowserAgent.js +75 -0
  357. package/lib/hooks/useBrowserInference.d.ts +27 -0
  358. package/lib/hooks/useBrowserInference.js +67 -0
  359. package/lib/hooks/useCheckpoints.d.ts +8 -17
  360. package/lib/hooks/useCheckpoints.js +25 -59
  361. package/lib/hooks/useConfig.d.ts +1 -1
  362. package/lib/hooks/useConfig.js +5 -1
  363. package/lib/hooks/useContextSnapshot.d.ts +18 -7
  364. package/lib/hooks/useContextSnapshot.js +14 -10
  365. package/lib/hooks/useNotifications.d.ts +11 -11
  366. package/lib/hooks/useNotifications.js +1 -1
  367. package/lib/hooks/useProjects.d.ts +7 -19
  368. package/lib/hooks/useProjects.js +5 -5
  369. package/lib/hooks/useSkills.d.ts +0 -1
  370. package/lib/hooks/useSkills.js +6 -2
  371. package/lib/hooks/useToolApprovals.d.ts +8 -8
  372. package/lib/hooks/useToolApprovals.js +3 -3
  373. package/lib/identity/AgentIdentity.d.ts +9 -2
  374. package/lib/index.d.ts +1 -0
  375. package/lib/index.js +4 -0
  376. package/lib/jupyter/index.d.ts +2 -1
  377. package/lib/jupyter/index.js +2 -1
  378. package/lib/jupyter/serverExecution.d.ts +78 -0
  379. package/lib/jupyter/serverExecution.js +258 -0
  380. package/lib/jupyter/useResumeServerExecutions.d.ts +11 -0
  381. package/lib/jupyter/useResumeServerExecutions.js +64 -0
  382. package/lib/lexical/ChatInlinePlugin.d.ts +33 -0
  383. package/lib/lexical/ChatInlinePlugin.js +0 -36
  384. package/lib/loop/core/focusRequests.d.ts +10 -0
  385. package/lib/loop/core/focusRequests.js +46 -0
  386. package/lib/loop/core/index.d.ts +894 -0
  387. package/lib/loop/core/index.js +264 -0
  388. package/lib/loop/core/promptStore.d.ts +44 -0
  389. package/lib/loop/core/promptStore.js +63 -0
  390. package/lib/loop/core/surfaceRequests.d.ts +33 -0
  391. package/lib/loop/core/surfaceRequests.js +29 -0
  392. package/lib/loop/core/toolbar.d.ts +28 -0
  393. package/lib/loop/core/toolbar.js +59 -0
  394. package/lib/loop/embed/LoopEmbed.d.ts +57 -0
  395. package/lib/loop/embed/LoopEmbed.js +118 -0
  396. package/lib/loop/extensions.d.ts +10 -0
  397. package/lib/loop/extensions.js +49 -0
  398. package/lib/loop/index.d.ts +68 -0
  399. package/lib/loop/index.js +87 -0
  400. package/lib/loop/plugins/a2a-sidebar/A2ASidebar.d.ts +48 -0
  401. package/lib/loop/plugins/a2a-sidebar/A2ASidebar.js +190 -0
  402. package/lib/loop/plugins/a2a-sidebar/index.d.ts +5 -0
  403. package/lib/loop/plugins/a2a-sidebar/index.js +39 -0
  404. package/lib/loop/plugins/a2ui/A2uiView.d.ts +12 -0
  405. package/lib/loop/plugins/a2ui/A2uiView.js +97 -0
  406. package/lib/loop/plugins/a2ui/index.d.ts +3 -0
  407. package/lib/loop/plugins/a2ui/index.js +50 -0
  408. package/lib/loop/plugins/a2ui-scene/index.d.ts +36 -0
  409. package/lib/loop/plugins/a2ui-scene/index.js +28 -0
  410. package/lib/loop/plugins/agent-a2a/index.d.ts +3 -0
  411. package/lib/loop/plugins/agent-a2a/index.js +26 -0
  412. package/lib/loop/plugins/agent-a2ui/index.d.ts +3 -0
  413. package/lib/loop/plugins/agent-a2ui/index.js +42 -0
  414. package/lib/loop/plugins/agent-a2ui-jupyter-output/index.d.ts +3 -0
  415. package/lib/loop/plugins/agent-a2ui-jupyter-output/index.js +53 -0
  416. package/lib/loop/plugins/agent-capacity/index.d.ts +39 -0
  417. package/lib/loop/plugins/agent-capacity/index.js +52 -0
  418. package/lib/loop/plugins/agent-checkpoints/index.d.ts +3 -0
  419. package/lib/loop/plugins/agent-checkpoints/index.js +26 -0
  420. package/lib/loop/plugins/agent-code-sandbox/index.d.ts +3 -0
  421. package/lib/loop/plugins/agent-code-sandbox/index.js +24 -0
  422. package/lib/loop/plugins/agent-code-sandboxes/index.d.ts +13 -0
  423. package/lib/loop/plugins/agent-code-sandboxes/index.js +85 -0
  424. package/lib/loop/plugins/agent-codemode/index.d.ts +5 -0
  425. package/lib/loop/plugins/agent-codemode/index.js +41 -0
  426. package/lib/loop/plugins/agent-compaction/index.d.ts +10 -0
  427. package/lib/loop/plugins/agent-compaction/index.js +34 -0
  428. package/lib/loop/plugins/agent-evals/index.d.ts +3 -0
  429. package/lib/loop/plugins/agent-evals/index.js +25 -0
  430. package/lib/loop/plugins/agent-guardrails/index.d.ts +3 -0
  431. package/lib/loop/plugins/agent-guardrails/index.js +25 -0
  432. package/lib/loop/plugins/agent-hooks/index.d.ts +3 -0
  433. package/lib/loop/plugins/agent-hooks/index.js +28 -0
  434. package/lib/loop/plugins/agent-inference/index.d.ts +7 -0
  435. package/lib/loop/plugins/agent-inference/index.js +29 -0
  436. package/lib/loop/plugins/agent-mcp/index.d.ts +3 -0
  437. package/lib/loop/plugins/agent-mcp/index.js +25 -0
  438. package/lib/loop/plugins/agent-memory/index.d.ts +3 -0
  439. package/lib/loop/plugins/agent-memory/index.js +25 -0
  440. package/lib/loop/plugins/agent-monitoring/index.d.ts +3 -0
  441. package/lib/loop/plugins/agent-monitoring/index.js +25 -0
  442. package/lib/loop/plugins/agent-notifications/index.d.ts +3 -0
  443. package/lib/loop/plugins/agent-notifications/index.js +25 -0
  444. package/lib/loop/plugins/agent-otel/index.d.ts +3 -0
  445. package/lib/loop/plugins/agent-otel/index.js +25 -0
  446. package/lib/loop/plugins/agent-outputs/index.d.ts +3 -0
  447. package/lib/loop/plugins/agent-outputs/index.js +25 -0
  448. package/lib/loop/plugins/agent-parameters/index.d.ts +3 -0
  449. package/lib/loop/plugins/agent-parameters/index.js +25 -0
  450. package/lib/loop/plugins/agent-skills/index.d.ts +3 -0
  451. package/lib/loop/plugins/agent-skills/index.js +25 -0
  452. package/lib/loop/plugins/agent-subagents/index.d.ts +3 -0
  453. package/lib/loop/plugins/agent-subagents/index.js +25 -0
  454. package/lib/loop/plugins/agent-tool-approvals/index.d.ts +11 -0
  455. package/lib/loop/plugins/agent-tool-approvals/index.js +38 -0
  456. package/lib/loop/plugins/agent-triggers/index.d.ts +3 -0
  457. package/lib/loop/plugins/agent-triggers/index.js +26 -0
  458. package/lib/loop/plugins/agents/AgentSummaryPanel.d.ts +20 -0
  459. package/lib/loop/plugins/agents/AgentSummaryPanel.js +50 -0
  460. package/lib/loop/plugins/agents/AnonymousKeyBadge.d.ts +35 -0
  461. package/lib/loop/plugins/agents/AnonymousKeyBadge.js +53 -0
  462. package/lib/loop/plugins/agents/DatalayerAgentBridge.d.ts +24 -0
  463. package/lib/loop/plugins/agents/DatalayerAgentBridge.js +102 -0
  464. package/lib/loop/plugins/agents/DatalayerAgentMount.d.ts +18 -0
  465. package/lib/loop/plugins/agents/DatalayerAgentMount.js +12 -0
  466. package/lib/loop/plugins/agents/SandboxSelector.d.ts +18 -0
  467. package/lib/loop/plugins/agents/SandboxSelector.js +99 -0
  468. package/lib/loop/plugins/agents/SandboxStatusBridge.d.ts +19 -0
  469. package/lib/loop/plugins/agents/SandboxStatusBridge.js +23 -0
  470. package/lib/loop/plugins/agents/SandboxView.d.ts +11 -0
  471. package/lib/loop/plugins/agents/SandboxView.js +43 -0
  472. package/lib/loop/plugins/agents/TeamMemberPicker.d.ts +17 -0
  473. package/lib/loop/plugins/agents/TeamMemberPicker.js +60 -0
  474. package/lib/loop/plugins/agents/agentIcons.d.ts +23 -0
  475. package/lib/loop/plugins/agents/agentIcons.js +88 -0
  476. package/lib/loop/plugins/agents/browserService.d.ts +50 -0
  477. package/lib/loop/plugins/agents/browserService.js +233 -0
  478. package/lib/loop/plugins/agents/index.d.ts +13 -0
  479. package/lib/loop/plugins/agents/index.js +17 -0
  480. package/lib/loop/plugins/agents/plugin.d.ts +91 -0
  481. package/lib/loop/plugins/agents/plugin.js +201 -0
  482. package/lib/loop/plugins/agents/service.d.ts +99 -0
  483. package/lib/loop/plugins/agents/service.js +167 -0
  484. package/lib/loop/plugins/agents/specSubagents.d.ts +18 -0
  485. package/lib/loop/plugins/agents/specSubagents.js +33 -0
  486. package/lib/loop/plugins/agents/switchable.d.ts +107 -0
  487. package/lib/loop/plugins/agents/switchable.js +405 -0
  488. package/lib/loop/plugins/agents/team.d.ts +87 -0
  489. package/lib/loop/plugins/agents/team.js +143 -0
  490. package/lib/loop/plugins/agents/useSandboxService.d.ts +11 -0
  491. package/lib/loop/plugins/agents/useSandboxService.js +36 -0
  492. package/lib/loop/plugins/agents/useTeamSelection.d.ts +10 -0
  493. package/lib/loop/plugins/agents/useTeamSelection.js +27 -0
  494. package/lib/loop/plugins/agentspecs/AgentspecPicker.d.ts +15 -0
  495. package/lib/loop/plugins/agentspecs/AgentspecPicker.js +90 -0
  496. package/lib/loop/plugins/agentspecs/index.d.ts +6 -0
  497. package/lib/loop/plugins/agentspecs/index.js +63 -0
  498. package/lib/loop/plugins/chat/ChatView.d.ts +20 -0
  499. package/lib/loop/plugins/chat/ChatView.js +1670 -0
  500. package/lib/loop/plugins/chat/chatViewTools.d.ts +41 -0
  501. package/lib/loop/plugins/chat/chatViewTools.js +92 -0
  502. package/lib/loop/plugins/chat/index.d.ts +111 -0
  503. package/lib/loop/plugins/chat/index.js +143 -0
  504. package/lib/loop/plugins/chat/turnState.d.ts +41 -0
  505. package/lib/loop/plugins/chat/turnState.js +90 -0
  506. package/lib/loop/plugins/chat-extras/index.d.ts +14 -0
  507. package/lib/loop/plugins/chat-extras/index.js +51 -0
  508. package/lib/loop/plugins/chat-header/HeaderView.d.ts +13 -0
  509. package/lib/loop/plugins/chat-header/HeaderView.js +6 -0
  510. package/lib/loop/plugins/chat-header/index.d.ts +3 -0
  511. package/lib/loop/plugins/chat-header/index.js +21 -0
  512. package/lib/loop/plugins/chat-view/index.d.ts +10 -0
  513. package/lib/loop/plugins/chat-view/index.js +29 -0
  514. package/lib/loop/plugins/checkpoints-sidebar/CheckpointsSidebar.d.ts +27 -0
  515. package/lib/loop/plugins/checkpoints-sidebar/CheckpointsSidebar.js +174 -0
  516. package/lib/loop/plugins/checkpoints-sidebar/index.d.ts +5 -0
  517. package/lib/loop/plugins/checkpoints-sidebar/index.js +39 -0
  518. package/lib/loop/plugins/commands/index.d.ts +20 -0
  519. package/lib/loop/plugins/commands/index.js +148 -0
  520. package/lib/loop/plugins/decks/DeckSurface.d.ts +10 -0
  521. package/lib/loop/plugins/decks/DeckSurface.js +6 -0
  522. package/lib/loop/plugins/decks/DecksMenu.d.ts +11 -0
  523. package/lib/loop/plugins/decks/DecksMenu.js +42 -0
  524. package/lib/loop/plugins/decks/index.d.ts +19 -0
  525. package/lib/loop/plugins/decks/index.js +133 -0
  526. package/lib/loop/plugins/decks/surface.d.ts +7 -0
  527. package/lib/loop/plugins/decks/surface.js +11 -0
  528. package/lib/loop/plugins/document/DocumentView.d.ts +12 -0
  529. package/lib/loop/plugins/document/DocumentView.js +68 -0
  530. package/lib/loop/plugins/document/index.d.ts +3 -0
  531. package/lib/loop/plugins/document/index.js +86 -0
  532. package/lib/loop/plugins/document/openingDocument.d.ts +28 -0
  533. package/lib/loop/plugins/document/openingDocument.js +122 -0
  534. package/lib/loop/plugins/document-toolbar/SandboxStatusItem.d.ts +16 -0
  535. package/lib/loop/plugins/document-toolbar/SandboxStatusItem.js +31 -0
  536. package/lib/loop/plugins/document-toolbar/index.d.ts +4 -0
  537. package/lib/loop/plugins/document-toolbar/index.js +35 -0
  538. package/lib/loop/plugins/document-toolbar/names.d.ts +6 -0
  539. package/lib/loop/plugins/document-toolbar/names.js +10 -0
  540. package/lib/loop/plugins/document-toolbar/plugin.d.ts +2 -0
  541. package/lib/loop/plugins/document-toolbar/plugin.js +38 -0
  542. package/lib/loop/plugins/document-view/index.d.ts +10 -0
  543. package/lib/loop/plugins/document-view/index.js +28 -0
  544. package/lib/loop/plugins/graph/GraphToggle.d.ts +17 -0
  545. package/lib/loop/plugins/graph/GraphToggle.js +22 -0
  546. package/lib/loop/plugins/graph/GraphView.d.ts +16 -0
  547. package/lib/loop/plugins/graph/GraphView.js +6 -0
  548. package/lib/loop/plugins/graph/index.d.ts +5 -0
  549. package/lib/loop/plugins/graph/index.js +80 -0
  550. package/lib/loop/plugins/graph/viewType.d.ts +10 -0
  551. package/lib/loop/plugins/graph/viewType.js +14 -0
  552. package/lib/loop/plugins/input-prompt/ComposerView.d.ts +15 -0
  553. package/lib/loop/plugins/input-prompt/ComposerView.js +25 -0
  554. package/lib/loop/plugins/input-prompt/index.d.ts +25 -0
  555. package/lib/loop/plugins/input-prompt/index.js +26 -0
  556. package/lib/loop/plugins/models/index.d.ts +3 -0
  557. package/lib/loop/plugins/models/index.js +49 -0
  558. package/lib/loop/plugins/notebook/NotebookView.d.ts +9 -0
  559. package/lib/loop/plugins/notebook/NotebookView.js +189 -0
  560. package/lib/loop/plugins/notebook/index.d.ts +3 -0
  561. package/lib/loop/plugins/notebook/index.js +91 -0
  562. package/lib/loop/plugins/notebook/openingNotebook.d.ts +72 -0
  563. package/lib/loop/plugins/notebook/openingNotebook.js +90 -0
  564. package/lib/loop/plugins/notebook-toolbar/index.d.ts +4 -0
  565. package/lib/loop/plugins/notebook-toolbar/index.js +45 -0
  566. package/lib/loop/plugins/notebook-toolbar/items.d.ts +10 -0
  567. package/lib/loop/plugins/notebook-toolbar/items.js +45 -0
  568. package/lib/loop/plugins/notebook-toolbar/names.d.ts +9 -0
  569. package/lib/loop/plugins/notebook-toolbar/names.js +13 -0
  570. package/lib/loop/plugins/notebook-toolbar/plugin.d.ts +2 -0
  571. package/lib/loop/plugins/notebook-toolbar/plugin.js +24 -0
  572. package/lib/loop/plugins/notebook-view/index.d.ts +10 -0
  573. package/lib/loop/plugins/notebook-view/index.js +30 -0
  574. package/lib/loop/plugins/page-layout/TurnPanel.d.ts +25 -0
  575. package/lib/loop/plugins/page-layout/TurnPanel.js +126 -0
  576. package/lib/loop/plugins/page-layout/index.d.ts +35 -0
  577. package/lib/loop/plugins/page-layout/index.js +80 -0
  578. package/lib/loop/plugins/plugins-panel/index.d.ts +14 -0
  579. package/lib/loop/plugins/plugins-panel/index.js +74 -0
  580. package/lib/loop/plugins/prompt/NewChatAction.d.ts +19 -0
  581. package/lib/loop/plugins/prompt/NewChatAction.js +10 -0
  582. package/lib/loop/plugins/prompt/index.d.ts +11 -0
  583. package/lib/loop/plugins/prompt/index.js +73 -0
  584. package/lib/loop/plugins/shell/editorChoice.d.ts +31 -0
  585. package/lib/loop/plugins/shell/editorChoice.js +58 -0
  586. package/lib/loop/plugins/shell/index.d.ts +47 -0
  587. package/lib/loop/plugins/shell/index.js +142 -0
  588. package/lib/loop/plugins/shell/useEditorPreviews.d.ts +32 -0
  589. package/lib/loop/plugins/shell/useEditorPreviews.js +217 -0
  590. package/lib/loop/plugins/subagent-activity/SubagentPulse.d.ts +16 -0
  591. package/lib/loop/plugins/subagent-activity/SubagentPulse.js +45 -0
  592. package/lib/loop/plugins/subagent-activity/index.d.ts +12 -0
  593. package/lib/loop/plugins/subagent-activity/index.js +42 -0
  594. package/lib/loop/plugins/view-switch/index.d.ts +46 -0
  595. package/lib/loop/plugins/view-switch/index.js +68 -0
  596. package/lib/loop/plugins/window-frame/WindowFrame.d.ts +48 -0
  597. package/lib/loop/plugins/window-frame/WindowFrame.js +63 -0
  598. package/lib/loop/plugins/window-frame/index.d.ts +6 -0
  599. package/lib/loop/plugins/window-frame/index.js +79 -0
  600. package/lib/loop/plugins/window-frame/slots.d.ts +26 -0
  601. package/lib/loop/plugins/window-frame/slots.js +30 -0
  602. package/lib/loop/presets.d.ts +167 -0
  603. package/lib/loop/presets.js +139 -0
  604. package/lib/loop/shell/LoopWorkspace.d.ts +109 -0
  605. package/lib/loop/shell/LoopWorkspace.js +231 -0
  606. package/lib/loop/shell/PluginToggles.d.ts +21 -0
  607. package/lib/loop/shell/PluginToggles.js +41 -0
  608. package/lib/loop/shell/ViewSwitcher.d.ts +24 -0
  609. package/lib/loop/shell/ViewSwitcher.js +43 -0
  610. package/lib/loop/shell/WorkspaceFullScreenAction.d.ts +25 -0
  611. package/lib/loop/shell/WorkspaceFullScreenAction.js +24 -0
  612. package/lib/loop/shell/index.d.ts +10 -0
  613. package/lib/loop/shell/index.js +14 -0
  614. package/lib/loop/shell/useWorkspaceFullScreen.d.ts +93 -0
  615. package/lib/loop/shell/useWorkspaceFullScreen.js +167 -0
  616. package/lib/loop-example-main.d.ts +1 -0
  617. package/lib/loop-example-main.js +42 -0
  618. package/lib/loop-main.d.ts +1 -0
  619. package/lib/loop-main.js +138 -0
  620. package/lib/mcp/McpServerManager.d.ts +1 -1
  621. package/lib/models/CodeSandboxSnapshotDTO.d.ts +1 -1
  622. package/lib/models/CodeSandboxVariant.d.ts +13 -5
  623. package/lib/models/CodeSandboxVariant.js +17 -5
  624. package/lib/models/Content.d.ts +26 -0
  625. package/lib/models/Environment.d.ts +561 -5
  626. package/lib/models/Environment.js +12 -1
  627. package/lib/models/EnvironmentDTO.d.ts +24 -6
  628. package/lib/models/EnvironmentDTO.js +13 -2
  629. package/lib/models/Exercise.d.ts +0 -2
  630. package/lib/models/Library.d.ts +0 -2
  631. package/lib/models/Notebook.d.ts +0 -2
  632. package/lib/models/ProjectDTO.d.ts +2 -2
  633. package/lib/models/ProjectDTO.js +4 -4
  634. package/lib/models/Runtime.d.ts +11 -11
  635. package/lib/models/RuntimeDTO.d.ts +16 -7
  636. package/lib/models/RuntimeDTO.js +9 -9
  637. package/lib/models/Space.d.ts +10 -0
  638. package/lib/models/Space.js +1 -1
  639. package/lib/models/SpaceDTO.d.ts +1 -1
  640. package/lib/models/SpaceItem.d.ts +1 -2
  641. package/lib/models/environments.generated.d.ts +113 -0
  642. package/lib/models/environments.generated.js +13 -0
  643. package/lib/models/index.d.ts +0 -1
  644. package/lib/models/index.js +0 -1
  645. package/lib/protocols/A2AAdapter.d.ts +39 -6
  646. package/lib/protocols/A2AAdapter.js +180 -11
  647. package/lib/protocols/ACPAdapter.js +40 -37
  648. package/lib/protocols/AGUIAdapter.d.ts +14 -0
  649. package/lib/protocols/AGUIAdapter.js +34 -9
  650. package/lib/protocols/BrowserAgentAdapter.d.ts +117 -0
  651. package/lib/protocols/BrowserAgentAdapter.js +310 -0
  652. package/lib/protocols/VercelAIAdapter.d.ts +10 -0
  653. package/lib/protocols/VercelAIAdapter.js +27 -7
  654. package/lib/protocols/index.d.ts +1 -0
  655. package/lib/protocols/index.js +1 -0
  656. package/lib/runtimes/actions.d.ts +3 -3
  657. package/lib/runtimes/actions.js +27 -14
  658. package/lib/runtimes/apis.d.ts +13 -4
  659. package/lib/runtimes/browser/agent.d.ts +54 -0
  660. package/lib/runtimes/browser/agent.js +63 -0
  661. package/lib/runtimes/browser/anonymousToken.d.ts +121 -0
  662. package/lib/runtimes/browser/anonymousToken.js +300 -0
  663. package/lib/runtimes/browser/frontendTools.d.ts +61 -0
  664. package/lib/runtimes/browser/frontendTools.js +152 -0
  665. package/lib/runtimes/browser/index.d.ts +11 -0
  666. package/lib/runtimes/browser/index.js +20 -0
  667. package/lib/runtimes/browser/model.d.ts +52 -0
  668. package/lib/runtimes/browser/model.js +110 -0
  669. package/lib/runtimes/browser/protocol.d.ts +54 -0
  670. package/lib/runtimes/browser/protocol.js +35 -0
  671. package/lib/runtimes/browser/subagents.d.ts +131 -0
  672. package/lib/runtimes/browser/subagents.js +241 -0
  673. package/lib/runtimes/index.d.ts +3 -0
  674. package/lib/runtimes/index.js +3 -0
  675. package/lib/runtimes/lifecycle.d.ts +76 -0
  676. package/lib/runtimes/lifecycle.js +99 -0
  677. package/lib/runtimes/variants.d.ts +172 -0
  678. package/lib/runtimes/variants.js +187 -0
  679. package/lib/services/reconnectToRuntime.d.ts +2 -2
  680. package/lib/services/reconnectToRuntime.js +3 -3
  681. package/lib/services/sandboxServiceManagers.d.ts +2 -2
  682. package/lib/services/sandboxServiceManagers.js +11 -11
  683. package/lib/specs/agents/agents.d.ts +128 -112
  684. package/lib/specs/agents/agents.js +8024 -5052
  685. package/lib/specs/evals.js +9 -0
  686. package/lib/specs/frontendTools.d.ts +3 -0
  687. package/lib/specs/frontendTools.js +46 -3
  688. package/lib/specs/mcpServers.d.ts +1 -0
  689. package/lib/specs/mcpServers.js +25 -2
  690. package/lib/specs/models.d.ts +18 -0
  691. package/lib/specs/models.js +154 -0
  692. package/lib/specs/outputs.d.ts +2 -0
  693. package/lib/specs/outputs.js +22 -0
  694. package/lib/specs/personas.js +1 -1
  695. package/lib/specs/teams/teams.d.ts +2 -0
  696. package/lib/specs/teams/teams.js +628 -111
  697. package/lib/state/index.d.ts +1 -1
  698. package/lib/state/index.js +1 -1
  699. package/lib/state/substates/RuntimesState.d.ts +5 -5
  700. package/lib/state/substates/RuntimesState.js +14 -14
  701. package/lib/state/substates/index.d.ts +1 -1
  702. package/lib/state/substates/index.js +1 -1
  703. package/lib/stores/agentRuntimeStore.d.ts +43 -1
  704. package/lib/stores/agentRuntimeStore.js +100 -11
  705. package/lib/stores/index.d.ts +1 -1
  706. package/lib/stores/index.js +1 -1
  707. package/lib/stories/Button.d.ts +1 -1
  708. package/lib/stories/Button.stories.d.ts +1 -1
  709. package/lib/stories/Header.d.ts +1 -1
  710. package/lib/stories/Header.stories.d.ts +1 -1
  711. package/lib/test-setup.js +66 -0
  712. package/lib/tools/adapters/agent-runtimes/lexicalHooks.d.ts +15 -0
  713. package/lib/tools/adapters/agent-runtimes/lexicalHooks.js +43 -2
  714. package/lib/tools/adapters/agent-runtimes/notebookHooks.d.ts +9 -0
  715. package/lib/tools/adapters/agent-runtimes/notebookHooks.js +12 -0
  716. package/lib/tools/adapters/commands/frontendCommandTools.d.ts +11 -0
  717. package/lib/tools/adapters/commands/frontendCommandTools.js +60 -0
  718. package/lib/tools/adapters/commands/index.d.ts +1 -0
  719. package/lib/{models/Dataset.js → tools/adapters/commands/index.js} +1 -1
  720. package/lib/tools/adapters/copilotkit/lexicalHooks.js +7 -3
  721. package/lib/tools/index.d.ts +1 -0
  722. package/lib/tools/index.js +1 -0
  723. package/lib/types/a2a.d.ts +15 -1
  724. package/lib/types/agents-lifecycle.d.ts +11 -6
  725. package/lib/types/agents.d.ts +31 -6
  726. package/lib/types/agentspecs.d.ts +120 -4
  727. package/lib/types/chat.d.ts +251 -3
  728. package/lib/types/checkpoints.d.ts +20 -0
  729. package/lib/types/config.d.ts +13 -1
  730. package/lib/types/connection.d.ts +1 -1
  731. package/lib/types/evals.d.ts +2 -0
  732. package/lib/types/messages.d.ts +60 -0
  733. package/lib/types/models.d.ts +26 -0
  734. package/lib/types/notifications.d.ts +15 -6
  735. package/lib/types/protocol.d.ts +7 -2
  736. package/lib/types/stream.d.ts +48 -3
  737. package/lib/types/stream.js +5 -0
  738. package/lib/types/teams.d.ts +102 -4
  739. package/lib/types/tool-approvals.d.ts +1 -1
  740. package/lib/types/tools.d.ts +8 -2
  741. package/lib/utils/utils.js +7 -1
  742. package/package.json +376 -361
  743. package/scripts/codegen/__pycache__/compose.cpython-313.pyc +0 -0
  744. package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
  745. package/scripts/codegen/compose.py +208 -0
  746. package/scripts/codegen/generate_agents.py +202 -31
  747. package/scripts/codegen/generate_evals.py +2 -0
  748. package/scripts/codegen/generate_frontend_tools.py +35 -6
  749. package/scripts/codegen/generate_models.py +40 -15
  750. package/scripts/codegen/generate_sandbox_agents.py +76 -62
  751. package/scripts/codegen/generate_teams.py +178 -4
  752. package/scripts/codegen/generate_tools.py +6 -4
  753. package/scripts/gen_workers.py +278 -110
  754. package/scripts/generate-environments-types.py +404 -0
  755. package/lib/chat/prompt/InputFooter.d.ts +0 -58
  756. package/lib/chat/prompt/InputFooter.js +0 -194
  757. package/lib/chat/prompt/InputPromptFooter.d.ts +0 -27
  758. package/lib/chat/prompt/InputPromptFooter.js +0 -15
  759. package/lib/chat/prompt/InputPromptHeader.d.ts +0 -15
  760. package/lib/chat/prompt/InputPromptHeader.js +0 -15
  761. package/lib/chat/usage/TokenUsageBar.d.ts +0 -8
  762. package/lib/hooks/useRuntimes.d.ts +0 -5
  763. package/lib/hooks/useRuntimes.js +0 -34
  764. package/lib/jupyter/kernelsHandler.d.ts +0 -8
  765. package/lib/jupyter/kernelsHandler.js +0 -39
  766. package/lib/models/Dataset.d.ts +0 -16
  767. package/lib/utils/Cells.d.ts +0 -2
  768. package/lib/utils/Cells.js +0 -28
@@ -0,0 +1,1670 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { Box, IconButton, SegmentedControl, Text, Truncate, } from '@primer/react';
4
+ import { useColorPalette } from '@datalayer/primer-addons';
5
+ import { ScreenFullIcon, ScreenNormalIcon } from '@primer/octicons-react';
6
+ import { signal } from '@datalayer/reactor';
7
+ import { useContributions, useSignalValue, useGate, useReactorPlatform, ReactorLazy, ReactorSlot, useSlotComponents, } from '@datalayer/reactor/react';
8
+ import { ChatBase } from '../../../chat/base/ChatBase';
9
+ import { SUGGESTION_CHIP_WIDTH } from '../../../chat/display/EmptyState';
10
+ import { AnonymousKeyExpired } from '@datalayer/core/lib/components/anonymous/AnonymousKeyExpired';
11
+ import { useAnonymousSessionStore } from '../../../runtimes/browser/anonymousToken';
12
+ import { browserProtocolConfig } from '../../../runtimes/browser';
13
+ import { useBrowserInference } from '../../../hooks/useBrowserInference';
14
+ import { getAgentspecs } from '../../../specs/agents';
15
+ import { targetRunsAgentInPage, } from '../agents/switchable';
16
+ import { agentIcon } from '../agents/agentIcons';
17
+ import { specSubagents } from '../agents/specSubagents';
18
+ import { subagentsFor } from '../agents/team';
19
+ import { useOptionalTeamSelection } from '../agents/useTeamSelection';
20
+ /**
21
+ * Stands in for a workspace with no team.
22
+ *
23
+ * `useSignalValue` needs a signal on every render, and a hook cannot be
24
+ * skipped for the ordinary single-agent case.
25
+ */
26
+ const EMPTY_SELECTION = signal('');
27
+ /* A signal to read when no example contributed chat extras, so the hook
28
+ below always has one — a hook cannot be called conditionally. */
29
+ const EMPTY_CHAT_EXTRAS = signal({});
30
+ import { useWorkspaceFullScreen } from '../../shell/useWorkspaceFullScreen';
31
+ import { CHAT_PLUGIN_NAME } from './index';
32
+ import { INPUT_PROMPT_PLUGIN_NAME, } from '../input-prompt';
33
+ import { agentRuntimeStore, useAgentRuntimeContextSnapshot, } from '../../../stores';
34
+ import { useIAMStore } from '../../../state';
35
+ import { useConfig } from '../../../hooks/useConfig';
36
+ import { useSkills, useSkillActions } from '../../../hooks/useSkills';
37
+ import { AI_MODEL_CATALOGUE } from '../../../specs/models';
38
+ import { LoopAgentBlueprint, LoopAgentGate, LoopChatComposer, LoopChatExtras, LoopChatHeader, LoopChatLayout, LoopChatSuggestion, LoopChatSurface, LoopChatTurn, LoopFrontendTool, LoopSlots, canOpenView, onPromptFocusRequest, onSurfaceRequest, useLoopPromptStore, } from '../../core';
39
+ import { turnWritersOf } from './turnState';
40
+ import { isInactiveSurfaceContribution, orderToolContributions, toolsForChatView, } from './chatViewTools';
41
+ import { useAgentCommandTools } from '../../../tools/adapters/commands';
42
+ import { NONE_EDITOR, seedEditorChoice, setEditorOptions, } from '../shell/editorChoice';
43
+ /** No editor: the conversation on its own. */
44
+ const NO_SURFACE = '';
45
+ /**
46
+ * How fast the full-screen control breathes once it starts asking.
47
+ *
48
+ * Slow enough to read as breathing rather than blinking — a fast pulse on a
49
+ * small control reads as an error state, and this one is an invitation.
50
+ */
51
+ const FULLSCREEN_HINT_PERIOD_MS = 1400;
52
+ export default function ChatView({ workspace }) {
53
+ /* The active theme's own colours. Read from the store rather than a
54
+ provider, so a workspace mounted without the addons theme still gets the
55
+ default palette instead of throwing. */
56
+ const palette = useColorPalette();
57
+ const controlsRef = useRef(null);
58
+ const { setViewControls } = workspace;
59
+ const [transient, setTransient] = useState(null);
60
+ // Read from the reactor rather than taken as a prop: the placeholder and the
61
+ // default editor are the chat plugin's own configuration, so a host sets them
62
+ // where it sets anything else about this plugin.
63
+ const reactor = useReactorPlatform();
64
+ const config = reactor.getConfig(CHAT_PLUGIN_NAME);
65
+ const placeholder = config?.placeholder ?? 'Ask anything, type / for commands or @ for mention';
66
+ const defaultSurface = config?.defaultSurface ?? 'notebook';
67
+ /*
68
+ * The input-prompt plugin's own configuration, read from here rather than
69
+ * from that plugin's component.
70
+ *
71
+ * `firstPromptHook` has to fire for *every* way a message reaches
72
+ * `handleSend` below — typed and sent through the composer, a suggestion
73
+ * chip clicked, or a host's own `suggestLoopPrompt(text, {submit: true})`
74
+ * arriving through the prompt store — and this view is the only thing all
75
+ * three of those already go through. The composer that renders is
76
+ * swappable (a host may contribute a different one to `LoopChatComposer`
77
+ * entirely) and does not see the other two paths at all, so watching for
78
+ * the first send from inside it would miss most of what "first prompt"
79
+ * needs to mean.
80
+ */
81
+ const inputPromptConfig = reactor.getConfig(INPUT_PROMPT_PLUGIN_NAME);
82
+ /*
83
+ * The default editor is the opening selection, not something switched on
84
+ * later.
85
+ *
86
+ * It used to be applied by an effect that waited for the surface to become
87
+ * openable, which meant the picker read `None` until a sandbox existed —
88
+ * a workspace configured for the notebook opened saying it was configured
89
+ * for nothing. What the host configured is true from the first render; what
90
+ * the surface can do about it yet is the surface's business.
91
+ */
92
+ /*
93
+ * Nothing open yet, whatever the host asked for.
94
+ *
95
+ * Opening the default on the first render puts an editor on screen before
96
+ * its surface exists — plugins arrive as they activate — and before the
97
+ * sandbox it needs is running. What the reader saw then was not the notebook
98
+ * but the notebook's "needs a running sandbox" placeholder, which is a worse
99
+ * answer than an empty chat that fills in a moment later.
100
+ *
101
+ * The effect below opens it the moment it can actually be opened.
102
+ */
103
+ const [surfaceId, setSurfaceId] = useState(NO_SURFACE);
104
+ /**
105
+ * Whether the reader has chosen a surface themselves.
106
+ *
107
+ * Once they have, the default is spent. Without this it re-applies every
108
+ * time a new surface lands — so closing the notebook would reopen it as soon
109
+ * as any other plugin activated, which reads as the close button not working.
110
+ */
111
+ const surfaceChosen = useRef(false);
112
+ const surfaces = useContributions(LoopChatSurface);
113
+ /* The composer and the title bar arrive as plugins: this view assembles
114
+ their props, whoever contributed renders them. First contribution wins —
115
+ these are single-occupant surfaces, not lists. */
116
+ const composerEntries = useContributions(LoopChatComposer);
117
+ const headerEntries = useContributions(LoopChatHeader);
118
+ /* Live per-example chat extras — an error banner, the codemode toggle, the
119
+ footer's MCP/codemode status. Carried as a signal so the example can
120
+ update it without the plugin being rebuilt; first contribution wins. */
121
+ /* How the parts are arranged. No contribution: the split below. A layout
122
+ plugin — the page layout — takes the same wired parts and arranges them
123
+ its own way; first contribution wins. */
124
+ const layoutEntries = useContributions(LoopChatLayout);
125
+ const layout = layoutEntries[0]?.value;
126
+ /* The current turn, kept for whoever shows the conversation without the
127
+ transcript. The chat plugin contributed the feed at build; this view is
128
+ its writer — begin on send, the reply as it arrives, end when it stops. */
129
+ const turnEntries = useContributions(LoopChatTurn);
130
+ const turnFeed = turnWritersOf(turnEntries[0]?.value);
131
+ /* Reached through a ref from the send and loading handlers, which are
132
+ memoised with empty deps and must not go stale on it. */
133
+ const turnFeedRef = useRef(turnFeed);
134
+ turnFeedRef.current = turnFeed;
135
+ /* Who is working, for the activity line — read through a ref by a
136
+ handler memoised with empty deps. Set once the spec is resolved below. */
137
+ const agentNameRef = useRef('');
138
+ const extrasEntries = useContributions(LoopChatExtras);
139
+ const chatExtras = useSignalValue(extrasEntries[0]?.value.extras ?? EMPTY_CHAT_EXTRAS);
140
+ /* Which editors have ever been mounted; they are never unmounted after —
141
+ see the render below. A ref, not state: adding to it during render is
142
+ idempotent and must not schedule another one. */
143
+ const everMounted = useRef(new Set());
144
+ // Asked, not assumed: the chat cannot know whether anything is listening,
145
+ // and whichever plugin does answers the gate. Re-asked on every render with
146
+ // the live workspace, so switching the sandbox switches the prompt.
147
+ const usable = useGate(LoopAgentGate, workspace);
148
+ /* The sandbox's answer. It is not the only thing that can close the chat —
149
+ an anonymous visitor's trial key runs out too — so the two are combined
150
+ further down, once the key is known. */
151
+ const gateBlocked = !usable.allowed;
152
+ const gateReason = gateBlocked
153
+ ? (usable.reason ?? 'Chat is unavailable for this sandbox')
154
+ : undefined;
155
+ // Stable: ChatBase calls these in effects, and a new identity every render
156
+ // would make it re-publish on every render.
157
+ /*
158
+ * Whether the agent is working, held here rather than read back from the
159
+ * shell.
160
+ *
161
+ * It used to live only in `workspace.viewControls`, written by two
162
+ * callbacks that each replaced the whole object — and `onSendReady` fires
163
+ * again during a send, because ChatBase rebuilds its `handleSend` when the
164
+ * send starts. So the sequence was: loading true, then a fresh
165
+ * `{ stop }` with no `busy` at all. The prompt went live again one tick
166
+ * after the agent started, which is exactly when it must not be.
167
+ *
168
+ * Local state, and the shell is told from one place below.
169
+ */
170
+ const [busy, setBusy] = useState(false);
171
+ const [sendReady, setSendReady] = useState(false);
172
+ const handleSendReady = useCallback((controls) => {
173
+ controlsRef.current = controls;
174
+ setSendReady(!!controls);
175
+ }, []);
176
+ /*
177
+ * What the agent is doing, for the turn feed.
178
+ *
179
+ * The newest tool call that has not returned is the activity: "Analyst is
180
+ * adding a cell…". Named by what the tool does in the page rather than by
181
+ * the tool — a reader watching the notebook is told what to look for.
182
+ * Cleared when nothing is running.
183
+ */
184
+ const handleDisplayItemsChange = useCallback((items) => {
185
+ const feed = turnFeedRef.current;
186
+ if (!feed) {
187
+ return;
188
+ }
189
+ const SETTLED = new Set([
190
+ 'complete',
191
+ 'completed',
192
+ 'done',
193
+ 'error',
194
+ 'failed',
195
+ 'cancelled',
196
+ 'canceled',
197
+ 'rejected',
198
+ 'denied',
199
+ 'stopped',
200
+ ]);
201
+ const VERBS = {
202
+ insertcell: 'adding a cell',
203
+ updatecell: 'editing a cell',
204
+ runcell: 'running a cell',
205
+ deletecells: 'removing cells',
206
+ readallcells: 'reading the notebook',
207
+ readcell: 'reading a cell',
208
+ executecode: 'running code',
209
+ insertblock: 'adding a block',
210
+ updateblock: 'editing a block',
211
+ runblock: 'running a block',
212
+ readdocument: 'reading the document',
213
+ };
214
+ let running;
215
+ for (let index = items.length - 1; index >= 0; index -= 1) {
216
+ const item = items[index];
217
+ if (typeof item.toolName === 'string' && item.toolCallId) {
218
+ if (!SETTLED.has(String(item.status).toLowerCase())) {
219
+ running = item;
220
+ }
221
+ break;
222
+ }
223
+ }
224
+ if (!running) {
225
+ feed.activity(undefined);
226
+ return;
227
+ }
228
+ const key = running.toolName
229
+ .toLowerCase()
230
+ .replace(/^datalayer_/, '')
231
+ .replace(/_lexical$/, '')
232
+ .replace(/[^a-z]/g, '');
233
+ const verb = VERBS[key] ?? `using ${running.toolName}`;
234
+ feed.activity(`${agentNameRef.current || 'The agent'} is ${verb}…`);
235
+ }, []);
236
+ /* Read through a ref by the snapshot handler, memoised with empty deps. */
237
+ const chatExtrasRef = useRef(chatExtras);
238
+ chatExtrasRef.current = chatExtras;
239
+ // The window, for the prompt band, the turn feed, and a host counting it.
240
+ const handleContextSnapshot = useCallback((snapshot) => {
241
+ setChatUsage(snapshot);
242
+ turnFeedRef.current?.usage(snapshot);
243
+ chatExtrasRef.current.onUsage?.(snapshot);
244
+ }, []);
245
+ const handleLoadingChange = useCallback((next) => {
246
+ setBusy(next);
247
+ if (!next) {
248
+ turnFeedRef.current?.end('done');
249
+ }
250
+ }, []);
251
+ /*
252
+ * The reply as it arrives, for the turn feed.
253
+ *
254
+ * `onMessagesChange` reports the conversation on every change of it,
255
+ * streaming included; the last assistant message is the one the current
256
+ * turn is about. Text only — a tool call is shown where it acted, in the
257
+ * editor, and the panel is for what the agent *said*.
258
+ */
259
+ const handleMessagesChange = useCallback((messages) => {
260
+ const feed = turnFeedRef.current;
261
+ if (!feed) {
262
+ return;
263
+ }
264
+ /*
265
+ * The whole reply since the person last spoke, not the latest segment.
266
+ *
267
+ * An agent that calls a tool speaks in more than one message per turn —
268
+ * "I'll start…", the tool, "Good, the frame shows…" — and a reader
269
+ * watching the panel wants all of it, in order. Text only: the tool's
270
+ * work shows where it acted, in the editor.
271
+ */
272
+ let lastUser = -1;
273
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
274
+ if (messages[index].role === 'user') {
275
+ lastUser = index;
276
+ break;
277
+ }
278
+ }
279
+ const textOf = (message) => {
280
+ const content = message.content;
281
+ return typeof content === 'string'
282
+ ? content
283
+ : content
284
+ .map(part => typeof part === 'string'
285
+ ? part
286
+ : (part.text ?? ''))
287
+ .join('');
288
+ };
289
+ const reply = messages
290
+ .slice(lastUser + 1)
291
+ .filter(message => message.role === 'assistant')
292
+ .map(textOf)
293
+ .filter(text => text.trim().length > 0)
294
+ .join('\n\n');
295
+ feed.assistant(reply);
296
+ }, []);
297
+ // One writer, so neither fact can erase the other.
298
+ useEffect(() => {
299
+ setViewControls(sendReady
300
+ ? {
301
+ busy,
302
+ stop: controlsRef.current?.stop,
303
+ newChat: controlsRef.current?.newChat,
304
+ }
305
+ : null);
306
+ }, [busy, sendReady, setViewControls]);
307
+ // Stop reporting when the view goes away, or the shell would keep a stop
308
+ // button for something that is no longer there.
309
+ useEffect(() => () => setViewControls(null), [setViewControls]);
310
+ useEffect(() => workspace.prompts.subscribe(message => {
311
+ // A prompt typed before the adapter is ready is dropped rather than
312
+ // queued: silently sending it minutes later, out of context, is worse
313
+ // than saying nothing happened.
314
+ controlsRef.current?.send(message);
315
+ }), [workspace.prompts]);
316
+ /*
317
+ * Fired once, on the first real send, for the life of this mounted chat —
318
+ * a ref rather than a signal, because nothing here needs to re-render when
319
+ * it flips; the host's hook is the only thing that reacts.
320
+ */
321
+ const firstPromptFired = useRef(false);
322
+ const handleSend = useCallback(async (message) => {
323
+ /*
324
+ * Every way a message reaches this view runs through here — typed and
325
+ * sent through the composer, a suggestion chip clicked, or a host's own
326
+ * `suggestLoopPrompt(text, {submit: true})` arriving through the prompt
327
+ * store (see the `suggestion.submit` effect below) — so this is the one
328
+ * place "the first prompt" means the same thing regardless of which one
329
+ * a person or a host used.
330
+ */
331
+ if (!firstPromptFired.current) {
332
+ firstPromptFired.current = true;
333
+ inputPromptConfig?.firstPromptHook?.();
334
+ }
335
+ setTransient(null);
336
+ // A new turn: whatever the panel showed is gone, this message is it.
337
+ turnFeedRef.current?.begin(message);
338
+ const outcome = await workspace.submit(message);
339
+ if (!outcome.handled) {
340
+ /*
341
+ * Nothing took it, so the words stay where they were typed.
342
+ *
343
+ * The reason appears under the prompt; emptying the box as well would
344
+ * make a failed send look like a successful one and cost the person
345
+ * the sentence they wrote.
346
+ */
347
+ setTransient(outcome.reason ?? null);
348
+ return;
349
+ }
350
+ /*
351
+ * Sent, so the composer is empty again.
352
+ *
353
+ * `InputPromptBase` clears itself only when it owns its own text. This
354
+ * view hands it a controlled value — a page embedding the workspace can
355
+ * offer a prompt, which needs somewhere outside the editor to put it —
356
+ * and a controlled value is the owner's to clear. It was not being
357
+ * cleared at all: the sentence stayed in the box after the agent had
358
+ * answered it, so the next thing typed was appended to the last thing
359
+ * asked, and the placeholder that suggests what to ask never came back.
360
+ */
361
+ setDraft('');
362
+ if (outcome.result?.content) {
363
+ setTransient(outcome.result.content);
364
+ }
365
+ }, [workspace, inputPromptConfig?.firstPromptHook]);
366
+ const active = useMemo(() => surfaces.find(entry => entry.value.surfaceId === surfaceId)?.value, [surfaces, surfaceId]);
367
+ /**
368
+ * The reader picking a surface, including picking none.
369
+ *
370
+ * It records the choice as well as making it: from here on the host's
371
+ * default is spent, so a surface closed stays closed.
372
+ */
373
+ const chooseSurface = useCallback((next) => {
374
+ surfaceChosen.current = true;
375
+ setSurfaceId(next);
376
+ }, []);
377
+ /*
378
+ * A command asking for a surface — `/notebook`, `/document`, or their
379
+ * shortcuts. Treated exactly like a reader picking one from the strip, so
380
+ * the choice sticks the same way and the host's default is spent.
381
+ */
382
+ useEffect(() => onSurfaceRequest(chooseSurface), [chooseSurface]);
383
+ /*
384
+ * The editor choice store — what the shell's selector, the `/editor`
385
+ * command and the reactor shell's cycle read — learns two things only the
386
+ * chat knows: which editors exist, and which one is on screen. Nobody fed
387
+ * it the options before, so "cycle the editors" cycled an empty list and
388
+ * always landed on none; and a surface opened by a tool or a plugin, past
389
+ * the store, left it pointing at the wrong one. Seeded, not chosen: the
390
+ * chat already shows it, there is nothing to announce.
391
+ */
392
+ useEffect(() => {
393
+ setEditorOptions(surfaces.map(entry => entry.value.surfaceId));
394
+ }, [surfaces]);
395
+ useEffect(() => {
396
+ seedEditorChoice(surfaceId && surfaceId !== NO_SURFACE ? surfaceId : NONE_EDITOR);
397
+ }, [surfaceId]);
398
+ /** The surface the host asked to open, once its plugin has contributed it. */
399
+ const wanted = useMemo(() => defaultSurface === NO_SURFACE || defaultSurface === 'none'
400
+ ? undefined
401
+ : surfaces.find(entry => entry.value.surfaceId === defaultSurface), [surfaces, defaultSurface]);
402
+ /*
403
+ * Open the default the moment it can be opened.
404
+ *
405
+ * Both conditions are the point. A surface arrives when its plugin
406
+ * activates, so it may not exist on the first render; and these two need a
407
+ * running sandbox, which takes as long as a Pyodide kernel takes to start.
408
+ * Waiting for both is what turns "configured for the notebook" into a
409
+ * notebook rather than a placeholder.
410
+ */
411
+ useEffect(() => {
412
+ if (surfaceChosen.current || !wanted) {
413
+ return;
414
+ }
415
+ if (canOpenView(wanted.value, workspace)) {
416
+ setSurfaceId(defaultSurface);
417
+ }
418
+ }, [wanted, workspace, defaultSurface]);
419
+ /*
420
+ * An editor that stops being openable — its sandbox went away — should not
421
+ * stay on screen claiming otherwise.
422
+ *
423
+ * Closed, but remembered. This used to set the surface to none and stop
424
+ * there, which spent the reader's choice on an interruption: a sandbox
425
+ * blinking during a target switch closed the notebook, `surfaceChosen`
426
+ * meant the default could not reopen it, and the control settled on None
427
+ * for a workspace nobody had asked to empty. What was on screen and what
428
+ * the control said agreed with each other and with neither the reader nor
429
+ * the configuration.
430
+ */
431
+ /* State, not a ref: the layout below keeps this surface's column while it
432
+ is away, and a ref changing re-renders nothing. */
433
+ const [suspendedId, setSuspendedId] = useState(null);
434
+ /*
435
+ * Full screen: the whole view, on the whole screen.
436
+ *
437
+ * Everything the workspace is showing goes — the editor as well as the
438
+ * conversation. An earlier version hid the editor, on the theory that a long
439
+ * transcript wants the room; but somebody working on a notebook who asks for
440
+ * more room is asking for more room *for the work*, and taking the notebook
441
+ * away to give it is answering a question they did not ask.
442
+ *
443
+ * Done with the Fullscreen API rather than by drawing a big box, because a
444
+ * component cannot know what it is inside of. `position: fixed` escapes only
445
+ * as far as the nearest ancestor with a transform, and a page that animates
446
+ * its sections in — the landing does — leaves one behind permanently: the
447
+ * "full screen" chat then filled the card it was already in. The API
448
+ * promotes the element to the browser's top layer, where no ancestor can
449
+ * hold it, and unlike a portal it does not move in the DOM — so every
450
+ * inherited theme variable the editors read still resolves.
451
+ *
452
+ * The CSS overlay is kept as the fallback for where the API is refused: an
453
+ * iframe without `allow="fullscreen"`, mostly. Confined to a card is a worse
454
+ * answer than full screen and a better one than nothing.
455
+ */
456
+ const viewRef = useRef(null);
457
+ // A host's own fixed header, drawn outside this workspace entirely —
458
+ // reserved at the top of the overlay below, and forcing full screen onto
459
+ // the overlay door for good; see `ChatPluginConfig.fullScreenTopOffset`.
460
+ const fullScreenTopOffset = config?.fullScreenTopOffset ?? 0;
461
+ /* Shared with the workspace header's icon — same machinery, two doors in.
462
+ See `useWorkspaceFullScreen` for why it is the browser's API rather than
463
+ a big box, and for the CSS fallback the styling below paints. */
464
+ const { fullScreen, usingApi: usingFullscreenApi, toggle: toggleFullScreen, topOffsetPx: fullScreenTopOffsetPx, } = useWorkspaceFullScreen(viewRef, {
465
+ forceOverlay: Boolean(fullScreenTopOffset),
466
+ topOffset: fullScreenTopOffset,
467
+ });
468
+ /*
469
+ * The full-screen control, pointed at from the first run onwards.
470
+ *
471
+ * This view is usually a panel inside somebody else's page — a few hundred
472
+ * pixels of a landing page or an example. The moment it becomes worth more
473
+ * room is the moment it starts answering, and that is also the moment a
474
+ * reader's attention is on the transcript rather than on a small grey icon
475
+ * in a corner. So from the first answer the icon takes the theme's own
476
+ * colour and breathes.
477
+ *
478
+ * It does not stop on a timer. A reader who is deep in the first answer has
479
+ * not yet had the thought "this is too small", and a hint that has already
480
+ * expired by the time they have it is a hint that was never given. What ends
481
+ * it is the reader: taking the offer, or reaching the thing it was offering.
482
+ *
483
+ * `hinted` is a ref because it must not itself cause a render, and because
484
+ * it has to survive `busy` going true again for the second message — this
485
+ * starts once, on the first run, not on every turn.
486
+ */
487
+ const [hintFullScreen, setHintFullScreen] = useState(false);
488
+ const hinted = useRef(false);
489
+ useEffect(() => {
490
+ if (!busy || hinted.current || fullScreen) {
491
+ return;
492
+ }
493
+ hinted.current = true;
494
+ setHintFullScreen(true);
495
+ }, [busy, fullScreen]);
496
+ // Arriving is the end of it, however they got there — the button, a
497
+ // keyboard shortcut, the host promoting the workspace. There is nothing
498
+ // left to point at, and it never comes back.
499
+ useEffect(() => {
500
+ if (fullScreen) {
501
+ setHintFullScreen(false);
502
+ }
503
+ }, [fullScreen]);
504
+ useEffect(() => {
505
+ if (active && !canOpenView(active, workspace)) {
506
+ setSuspendedId(active.surfaceId);
507
+ setSurfaceId(NO_SURFACE);
508
+ }
509
+ }, [active, workspace]);
510
+ /**
511
+ * The surface that is closed but coming back.
512
+ *
513
+ * Held so the layout can keep its column: what is missing is the editor,
514
+ * not the half of the workspace it lives in.
515
+ */
516
+ const waiting = useMemo(() => {
517
+ if (suspendedId) {
518
+ return surfaces.find(item => item.value.surfaceId === suspendedId)?.value;
519
+ }
520
+ /*
521
+ * The host's default, before it has managed to open.
522
+ *
523
+ * It needs a sandbox, and a sandbox takes as long as a kernel takes to
524
+ * start — so for the first seconds of every workspace there is a
525
+ * configured notebook that is not open yet. Counting it as "waiting" is
526
+ * what lets the control say Notebook from the outset and the column hold
527
+ * its half of the split, instead of both saying None and then changing
528
+ * their minds.
529
+ *
530
+ * Only until somebody chooses for themselves. After that the default is
531
+ * spent, and a reader who picked None must not be shown Notebook.
532
+ */
533
+ if (!surfaceChosen.current && surfaceId === NO_SURFACE) {
534
+ return wanted?.value;
535
+ }
536
+ return undefined;
537
+ }, [surfaces, suspendedId, surfaceId, wanted]);
538
+ // And opened again when it can be. The reader asked for it once; an
539
+ // interruption is not them changing their mind.
540
+ useEffect(() => {
541
+ if (!suspendedId || surfaceId !== NO_SURFACE) {
542
+ return;
543
+ }
544
+ const entry = surfaces.find(item => item.value.surfaceId === suspendedId);
545
+ if (entry && canOpenView(entry.value, workspace)) {
546
+ setSuspendedId(null);
547
+ setSurfaceId(suspendedId);
548
+ }
549
+ }, [surfaces, surfaceId, suspendedId, workspace]);
550
+ // The AG-UI mount is per agent, and `default` is the agent a server runs when
551
+ // it was not told otherwise, so a workspace opened without one still talks to
552
+ // something.
553
+ const agentId = workspace.agentId?.trim() || 'default';
554
+ /*
555
+ * Which protocol, decided by where the sandbox is.
556
+ *
557
+ * On the browser target there is no server to mount an agent on, so the loop
558
+ * turns in this page with the Vercel AI SDK and the chat calls it rather
559
+ * than addressing it. Everywhere else the agent lives on the runtime and the
560
+ * chat speaks AG-UI to it, exactly as before.
561
+ *
562
+ * The spec's own `harness` does not decide this. It says where the agent
563
+ * normally runs, and a page cannot turn a pydantic-ai loop whatever it asks
564
+ * for — so the location wins, which is the same rule the examples follow.
565
+ */
566
+ const inPage = targetRunsAgentInPage(workspace.sandbox.target ?? 'local');
567
+ /*
568
+ * Who is being addressed, when this workspace runs a team.
569
+ *
570
+ * The team's own answer, not the workspace's: `workspace.agentId` is the
571
+ * session's agent, and a team has several behind one front door. Picking a
572
+ * member changes which spec the next prompt is answered by, and nothing
573
+ * else — the sandbox, the notebook and the transcript stay where they are.
574
+ */
575
+ const team = useOptionalTeamSelection();
576
+ const selectedMemberId = useSignalValue(team?.selected ?? EMPTY_SELECTION);
577
+ const member = team?.members.find(entry => entry.id === selectedMemberId);
578
+ /*
579
+ * Looked up through `getAgentspecs`, not by subscripting the record.
580
+ *
581
+ * Agent ids reach this component versioned as often as not —
582
+ * `jupyter-data-analyst:0.0.1` — and the record is keyed on the bare id, so
583
+ * a raw subscript on a versioned id silently misses. What follows from a
584
+ * miss is not an error but a quiet wrong answer: no model, no openers, no
585
+ * name. `getAgentspecs` strips the version and retries, which is the whole
586
+ * reason the specs package exports it.
587
+ */
588
+ /*
589
+ * The spec, found two ways.
590
+ *
591
+ * By the agent's id first — a team member's spec id, or a host that names
592
+ * the spec as the agent, as the Loop Shell does. Failing that, by the
593
+ * blueprint a capacity plugin contributed: an agent it created on a server
594
+ * carries an instance name (`subagents-example-agent-…`), not a spec id, and
595
+ * the same agent turned in this page had no prompt, no subagents and no
596
+ * icon for want of this lookup — it used the document tools and called
597
+ * nobody.
598
+ */
599
+ const blueprintSpecId = useContributions(LoopAgentBlueprint)[0]?.value.specId;
600
+ const spec = getAgentspecs(member?.specId ?? agentId) ??
601
+ (blueprintSpecId ? getAgentspecs(blueprintSpecId) : undefined);
602
+ /*
603
+ * The team's name for a member first, then the spec's own.
604
+ *
605
+ * A spec is named for the catalogue — "Jupyter Data Analyst" — and a team
606
+ * names the same agent for the person working with it — "Analyst", which is
607
+ * what the picker in the header says. The header, the empty state and the
608
+ * openers' heading say the same word as the picker, or a person reads two
609
+ * names for one agent on one screen.
610
+ */
611
+ agentNameRef.current = member?.name ?? spec?.name ?? agentId;
612
+ /*
613
+ * The openers: a capacity plugin's first, then the team's with the
614
+ * addressed member's own beneath, then — with no team — the agent's own.
615
+ *
616
+ * A contribution to `LoopChatSuggestion` is a deliberate statement about
617
+ * what this workspace is worth asking, so it replaces the spec's generic
618
+ * list rather than joining it.
619
+ *
620
+ * With a team, its openers are always shown: they are what the *team* can
621
+ * be asked, whoever is addressed, and a person who has just opened the
622
+ * workspace should see the whole before the part. Under them, in a block
623
+ * with its name on it, come the addressed member's own openers — picking
624
+ * the Reviewer used to change nothing on screen, and the reverse (the
625
+ * member's only) hid the team. An opener the team already lists is not
626
+ * repeated.
627
+ */
628
+ const suggestionEntries = useContributions(LoopChatSuggestion);
629
+ const hiddenOpeners = chatExtras.hiddenOpeners;
630
+ const suggestions = useMemo(() => {
631
+ // What the host took off this page, by the chip's words — the same key
632
+ // the two-group merge below uses to tell openers apart.
633
+ const hidden = new Set(hiddenOpeners ?? []);
634
+ const offered = (items) => hidden.size === 0 ? items : items.filter(item => !hidden.has(item.text));
635
+ const contributed = suggestionEntries.flatMap(entry => entry.value.suggestions);
636
+ if (contributed.length > 0) {
637
+ return offered(contributed);
638
+ }
639
+ const own = offered(spec?.suggestions ?? []);
640
+ const teams = offered(team?.team.suggestions ?? []);
641
+ if (teams.length === 0) {
642
+ return own;
643
+ }
644
+ // Two groups, named for the two levels the empty state draws: the
645
+ // team's openers under the team's name, the member's own under its.
646
+ const listed = new Set(teams.map(item => item.text));
647
+ const teamName = team?.team.name ?? 'Team';
648
+ const memberName = member?.name ?? spec?.name ?? agentId;
649
+ return [
650
+ ...teams.map(item => ({ ...item, group: teamName })),
651
+ ...own
652
+ .filter(item => !listed.has(item.text))
653
+ .map(item => ({ ...item, group: memberName })),
654
+ ];
655
+ }, [suggestionEntries, team, spec, member, agentId, hiddenOpeners]);
656
+ /*
657
+ * The same openers in the shape the chat's empty state asks for.
658
+ *
659
+ * `Suggestion` is a title and a message — what a chip shows and what it
660
+ * sends. A spec's opener with a `summary` shows that and sends its text;
661
+ * one without shows the whole request; a contributed opener may split the
662
+ * two its own way.
663
+ */
664
+ const chatSuggestions = useMemo(() => suggestions.map(item => ({
665
+ title: item.summary ?? item.text,
666
+ message: item.message ?? item.text,
667
+ group: item.group,
668
+ })), [suggestions]);
669
+ /* The icon its spec asked for, at the size the empty state draws. */
670
+ const BrandIcon = agentIcon(spec?.icon);
671
+ /* And the team's, for the level above it. */
672
+ const TeamIcon = agentIcon(team?.team.icon);
673
+ /*
674
+ * How an in-page agent reaches the notebook.
675
+ *
676
+ * On every other target the agent runs on a server with a sandbox of its
677
+ * own, and "run this cell" happens there — in the same kernel the notebook
678
+ * is bound to, which is why it appears to work by magic. In the browser
679
+ * there is no server and no second kernel: the only way to touch the
680
+ * notebook is a frontend tool, executed here.
681
+ *
682
+ * Without these the browser agent could hold a conversation and do nothing,
683
+ * which is exactly how it behaved — it answered, and the cell never ran.
684
+ *
685
+ * From the chat's own extension point rather than a hard-wired notebook
686
+ * import: the notebook plugin contributes its cell tools, the document its
687
+ * lexical ones, and a chat mounted without either simply has fewer tools.
688
+ * Each factory runs against the live workspace, so tools addressed by
689
+ * `surfaceId` can never point at a different notebook than the one on
690
+ * screen.
691
+ */
692
+ const toolContributions = useContributions(LoopFrontendTool);
693
+ const notebookTools = useMemo(() => {
694
+ /*
695
+ * One tool per name, first contribution wins — so the order is decided
696
+ * here rather than by which lazy import landed first. The notebook and
697
+ * the document each ship a kernel tool — `executeCodeInNotebook` runs in the
698
+ * sandbox and streams onto the conversation, the document's runs on the
699
+ * document's own kernel and returns silently. The editor on screen owns
700
+ * the shared names; with none on screen the notebook does, since its
701
+ * outputs are what the conversation shows. The document's block tools
702
+ * (runBlock, insertBlock…) keep their own names and are untouched.
703
+ */
704
+ const merged = [];
705
+ const owners = new Map();
706
+ // Tools a contribution vouched for in the chat view; see `chatView`.
707
+ const keep = new Set();
708
+ // See `isInactiveSurfaceContribution`: with an editor on screen, only
709
+ // its own `${surfaceId}-tools` contribution survives this filter.
710
+ const surfaceIds = new Set(surfaces.map(entry => entry.value.surfaceId));
711
+ for (const entry of orderToolContributions(toolContributions, active?.surfaceId)) {
712
+ if (isInactiveSurfaceContribution(entry.value.id, surfaceIds, active?.surfaceId)) {
713
+ continue;
714
+ }
715
+ let tools;
716
+ try {
717
+ tools = entry.value.tools(workspace);
718
+ }
719
+ catch (error) {
720
+ // One broken contributor must not cost the agent every tool.
721
+ console.warn(`[loop] frontend tools from '${entry.plugin}' failed:`, error);
722
+ continue;
723
+ }
724
+ for (const tool of tools) {
725
+ const owner = owners.get(tool.name);
726
+ if (owner) {
727
+ console.warn(`[loop] frontend tool '${tool.name}' from '${entry.plugin}' is shadowed by the one from '${owner}'.`);
728
+ continue;
729
+ }
730
+ owners.set(tool.name, entry.plugin);
731
+ merged.push(tool);
732
+ if (entry.value.chatView) {
733
+ keep.add(tool.name);
734
+ }
735
+ }
736
+ }
737
+ // A host example's own frontend tools, folded in last (first name wins),
738
+ // so a bespoke client tool like A2UI's run_jupyter_output_demo joins the
739
+ // agent's toolset without a plugin of its own.
740
+ for (const tool of chatExtras.frontendTools ?? []) {
741
+ if (owners.has(tool.name)) {
742
+ continue;
743
+ }
744
+ owners.set(tool.name, 'chat-extras');
745
+ merged.push(tool);
746
+ }
747
+ /*
748
+ * The view decides the toolset. With an editor on screen the agent has
749
+ * that editor's own tools (`belongsToInactiveSurface` above, plus
750
+ * whatever isn't tied to a surface at all); with none — the chat view —
751
+ * it keeps only what leaves the editors alone: the `executeCodeIn…`
752
+ * tools, whose outputs stream onto the conversation as surfaces, and
753
+ * the read tools. The editors stay mounted out of sight either way, so
754
+ * what it can still call, works.
755
+ */
756
+ return active ? merged : toolsForChatView(merged, keep);
757
+ // The workspace object is rebuilt when its facts change; surfaceId is
758
+ // the one the factories address by.
759
+ // eslint-disable-next-line react-hooks/exhaustive-deps
760
+ }, [
761
+ toolContributions,
762
+ workspace.surfaceId,
763
+ workspace.agentId,
764
+ chatExtras.frontendTools,
765
+ active?.surfaceId,
766
+ surfaces,
767
+ ]);
768
+ /*
769
+ * The commands the mounted plugins declared for an agent — the reactor's
770
+ * `AgentTools` point — executed on this workspace's own reactor. Folded in
771
+ * after the contributions, which keep their names, so a plugin with a
772
+ * richer in-page implementation of the same tool (the decks plugin's) is
773
+ * what the agent gets, and the bundle's command is the fallback. The agent
774
+ * spec names none of these: they follow the plugin.
775
+ */
776
+ const commandTools = useAgentCommandTools();
777
+ const agentTools = useMemo(() => {
778
+ if (commandTools.length === 0) {
779
+ return notebookTools;
780
+ }
781
+ const taken = new Set(notebookTools.map(tool => tool.name));
782
+ return [
783
+ ...notebookTools,
784
+ ...commandTools.filter(tool => !taken.has(tool.name)),
785
+ ];
786
+ }, [notebookTools, commandTools]);
787
+ /*
788
+ * Where this workspace's agent actually lives.
789
+ *
790
+ * A Datalayer runtime brings its own agent-runtimes server: the agent is
791
+ * created on the pod from an agentspec, not on the server the workspace was
792
+ * opened against. Addressing the latter would be talking to a machine that
793
+ * has never heard of it. The same value for every other target, where the
794
+ * two are the same server.
795
+ */
796
+ const agentServerUrl = workspace.sandbox.agentBaseUrl || workspace.serverUrl;
797
+ /*
798
+ * Who a single request may be addressed to.
799
+ *
800
+ * The same set the harness gets as tools, and deliberately so: a menu that
801
+ * offered a name the model could not reach would be a menu that produces
802
+ * silent no-ops. Derived here rather than in the plugin because it changes
803
+ * with the selected member.
804
+ */
805
+ const mentionable = useMemo(() => {
806
+ if (!team || !member) {
807
+ // No team: the spec's own subagents, which the in-page loop can reach
808
+ // and a server-side one already could.
809
+ return specSubagents(spec).map(subagent => ({
810
+ name: subagent.name,
811
+ description: subagent.description,
812
+ icon: agentIcon(subagent.icon),
813
+ }));
814
+ }
815
+ /*
816
+ * The team, plus whatever specialists the selected member brings.
817
+ *
818
+ * It used to be `subagentsFor(member)` alone, which made the list read as
819
+ * arbitrary: a team of two offered one name, and the name was whichever
820
+ * member you were *not* talking to. Everyone the team contains is listed,
821
+ * because "who is on this team" is the question a person types `@` to
822
+ * ask; the one already being addressed is shown greyed rather than
823
+ * dropped, so the list is stable as the selection moves.
824
+ */
825
+ const roster = team.members.map(entry => ({
826
+ name: entry.name,
827
+ description: entry.description,
828
+ emoji: entry.emoji,
829
+ icon: agentIcon(entry.icon),
830
+ disabled: entry.id === member.id,
831
+ disabledReason: entry.id === member.id
832
+ ? `You are already talking to ${entry.name}`
833
+ : undefined,
834
+ }));
835
+ const specialists = subagentsFor(team.team, member.id)
836
+ .filter(subagent => !team.members.some(m => m.name === subagent.name))
837
+ .map(subagent => ({
838
+ name: subagent.name,
839
+ description: subagent.description,
840
+ icon: agentIcon(subagent.icon),
841
+ }));
842
+ return [...roster, ...specialists];
843
+ }, [team, member, spec]);
844
+ /*
845
+ * Where the model is reached, and on whose key.
846
+ *
847
+ * Told whether an in-page agent is going to ask at all: a workspace on a
848
+ * server-backed agent authenticates itself, and minting a visitor's one
849
+ * trial key for it would start a clock against a conversation that never
850
+ * spends it.
851
+ */
852
+ const { inference, anonymous } = useBrowserInference(inPage);
853
+ /* Read from the store rather than passed in: the sign-in form inside the
854
+ expiry panel writes here, so the same render that gains a member gains
855
+ the wording that goes with one. */
856
+ const signedInUser = useIAMStore(state => state.user);
857
+ /* The trial is over, and this chat is the thing that stops working. Only
858
+ for an in-page agent: everywhere else the runtime holds its own
859
+ credentials and never saw the visitor's key. */
860
+ const keyExpired = inPage && anonymous.status === 'expired';
861
+ /*
862
+ * Whose key ran out, which decides what the chat is allowed to call it.
863
+ *
864
+ * The anonymous store only ever holds the trial key, so reaching this
865
+ * through `anonymous.status` means the reader never signed in. A member
866
+ * whose own session expires arrives by a different route and must not be
867
+ * told a temporary key ran out — they never had one, and would go looking
868
+ * for something that was never theirs.
869
+ */
870
+ const expiredKeyIsTemporary = !signedInUser;
871
+ const chatDisabled = gateBlocked || keyExpired;
872
+ const disabledReason = keyExpired
873
+ ? expiredKeyIsTemporary
874
+ ? 'This demo runs on a shared key, and its time is up. Sign in to keep going.'
875
+ : 'Your key has expired. Sign in to keep going.'
876
+ : gateReason;
877
+ /*
878
+ * The prompt's text, held here rather than inside `InputPrompt`.
879
+ *
880
+ * A page embedding the workspace can offer a request — "try asking it
881
+ * this" — and the only honest place to put such an offer is the box the
882
+ * visitor would have typed it into, where they can read it, change their
883
+ * mind, or send it. That needs a controlled prompt, which needs the text to
884
+ * live somewhere both the suggestion and the composer can reach.
885
+ */
886
+ const [draft, setDraft] = useState('');
887
+ /*
888
+ * The model this conversation is on.
889
+ *
890
+ * Three answers, and the order matters more than it looks. The reader's own
891
+ * pick wins, then the *agent's spec*, then whatever the host mounted the
892
+ * workspace with.
893
+ *
894
+ * The spec used to come last, behind `workspace.model` — which is a
895
+ * workspace-wide default, set once for whichever agent happens to be
896
+ * addressed. So launching an agent whose spec names one model showed a
897
+ * different one ticked in the menu, and the footer disagreed with the thing
898
+ * actually answering. An agent's spec is the definition of that agent; a
899
+ * host default is a fallback for when there is no definition, and a fallback
900
+ * that overrides the definition is not a fallback.
901
+ *
902
+ * Held here rather than in the workspace because the choice belongs to the
903
+ * conversation: it is what the next message is sent with, and it resets when
904
+ * the member being addressed changes.
905
+ */
906
+ const [pickedModel, setPickedModel] = useState();
907
+ const activeModel = pickedModel ?? spec?.model ?? workspace.model ?? '';
908
+ /*
909
+ * The team, in the shape the footer asks for.
910
+ *
911
+ * The footer knows nothing about teamspecs, and should not: it renders a
912
+ * list of names and reports which one was chosen. Everything that makes a
913
+ * member a member stays on this side of the boundary.
914
+ */
915
+ /* What is left of the context window, as the runtime last reported it. The
916
+ footer shows nothing at all until there is a real number, so a workspace
917
+ whose agent has not answered yet simply has no bar. */
918
+ /*
919
+ * The window, and only for the agent being addressed now.
920
+ *
921
+ * The store keeps one snapshot rather than one per agent, so switching
922
+ * member left the previous one's numbers on screen under the new one's
923
+ * name. Ignored until the store hands back a different object, which is the
924
+ * only evidence available that the new agent has reported.
925
+ */
926
+ const storedUsage = useAgentRuntimeContextSnapshot();
927
+ const usageAtSwitch = useRef(storedUsage);
928
+ const addressedAgent = useRef(selectedMemberId);
929
+ const storedUsageRef = useRef(storedUsage);
930
+ storedUsageRef.current = storedUsage;
931
+ useEffect(() => {
932
+ if (addressedAgent.current === selectedMemberId) {
933
+ return;
934
+ }
935
+ addressedAgent.current = selectedMemberId;
936
+ usageAtSwitch.current = storedUsageRef.current;
937
+ // And the model goes back to whatever the new agent's spec asks for. A
938
+ // pick made for one member is not a statement about the next.
939
+ setPickedModel(undefined);
940
+ }, [selectedMemberId]);
941
+ const fromStore = storedUsage && storedUsage !== usageAtSwitch.current ? storedUsage : null;
942
+ /*
943
+ * What the chat itself accounts for, when nothing else does.
944
+ *
945
+ * A server-side runtime pushes a snapshot over the socket and that is what
946
+ * `fromStore` holds. An in-page agent has no server to push one, and its
947
+ * only account of the window is the totals its harness reports — which
948
+ * `ChatBase` assembles and hands out. Without this the browser agent's
949
+ * footer had no numbers at all, and the space kept for them showed as a
950
+ * white stripe under the prompt.
951
+ */
952
+ const [chatUsage, setChatUsage] = useState();
953
+ const contextUsage = fromStore ?? chatUsage ?? null;
954
+ // Read to decide whether the strip exists at all, not to render it.
955
+ const inpromptMenu = useSlotComponents(LoopSlots.inpromptMenu);
956
+ // Buttons for the prompt's footer bar, beside the session menus. Asked
957
+ // whether anyone contributed before anything is drawn, for the same reason
958
+ // as the in-prompt menu: an empty slot is still an element.
959
+ const promptActions = useSlotComponents(LoopSlots.promptAction);
960
+ // Same question for the chat's own title bar, which plugins may add to.
961
+ const chatHeaderItems = useSlotComponents(LoopSlots.chatHeader);
962
+ const footerAgents = useMemo(() => team?.members.map(entry => ({
963
+ id: entry.id,
964
+ name: entry.name,
965
+ description: entry.description,
966
+ icon: agentIcon(entry.icon),
967
+ })) ?? [], [team]);
968
+ const suggestion = useLoopPromptStore(state => state.pending);
969
+ /*
970
+ * `/prompt`, or its keystroke, asking for the caret.
971
+ *
972
+ * A command runs outside the component tree, so the ask arrives on the
973
+ * focus channel; each one bumps a nonce that joins the suggestion's in
974
+ * `focusTrigger` below. The chat answers wherever its composer is —
975
+ * docked, in-column, or floating.
976
+ */
977
+ const [focusAsked, setFocusAsked] = useState(0);
978
+ useEffect(() => onPromptFocusRequest(() => setFocusAsked(nonce => nonce + 1)), []);
979
+ useEffect(() => {
980
+ if (!suggestion) {
981
+ return;
982
+ }
983
+ setDraft(suggestion.text);
984
+ // Taken, so a second click on the same button offers it again rather than
985
+ // finding the store already holding it.
986
+ useLoopPromptStore.getState().consume();
987
+ if (suggestion.submit) {
988
+ void handleSend(suggestion.text);
989
+ }
990
+ // `handleSend` is stable for the life of a connection; re-running this on
991
+ // a new identity would resend the last suggestion.
992
+ // eslint-disable-next-line react-hooks/exhaustive-deps
993
+ }, [suggestion]);
994
+ const protocol = useMemo(() => inPage
995
+ ? browserProtocolConfig({
996
+ agentId: member?.specId ?? agentId,
997
+ instructions: spec?.systemPrompt,
998
+ model: activeModel || undefined,
999
+ inference,
1000
+ // Who this member may hand work to, and what they are told. Both
1001
+ // come from the teamspec: the supervisor routes to the others, a
1002
+ // member reaches only its own specialists, and `context.sharing`
1003
+ // decides whether the child sees this conversation.
1004
+ // The agent runs them itself, so they go to the harness rather
1005
+ // than to the chat — handing them to both would run each tool
1006
+ // twice.
1007
+ frontendTools: agentTools,
1008
+ // A team's members and specialists when there is a team; the
1009
+ // spec's own subagents otherwise — a researcher and a writer are
1010
+ // as much the agent's as its prompt is.
1011
+ subagents: team && member
1012
+ ? subagentsFor(team.team, member.id)
1013
+ : specSubagents(spec),
1014
+ sharing: team?.sharing,
1015
+ // What a delegated run does lands in the same store the
1016
+ // server's monitoring stream fills, so the side panel and the
1017
+ // composer's pulse draw an in-page delegation like any other.
1018
+ onSubagentEvent: event => agentRuntimeStore.getState().appendSubagentEvent(event),
1019
+ })
1020
+ : {
1021
+ type: 'ag-ui',
1022
+ endpoint: `${agentServerUrl}/api/v1/ag-ui/${agentId}/`,
1023
+ agentId,
1024
+ // `/api/v1/configure`, not `/api/v1/configure/config`: the hooks
1025
+ // strip one trailing `config`/`configure` segment to find the API
1026
+ // base, so the longer form doubles it.
1027
+ configEndpoint: `${agentServerUrl}/api/v1/configure`,
1028
+ enableConfigQuery: true,
1029
+ }, [
1030
+ agentId,
1031
+ inPage,
1032
+ inference,
1033
+ member,
1034
+ agentTools,
1035
+ team,
1036
+ spec,
1037
+ activeModel,
1038
+ agentServerUrl,
1039
+ ]);
1040
+ /*
1041
+ * The model catalogue, and the builtin tools and skills the agent reports.
1042
+ *
1043
+ * Read here rather than left to `ChatBase`, because this view draws its own
1044
+ * prompt: the toolbar under it can only offer what this component hands it.
1045
+ *
1046
+ * `useSkills` reads the runtime's codemode status out of the store, so it
1047
+ * needs no endpoint and works for an in-page agent too. `useConfig` does
1048
+ * need one, and a browser agent has none — hence the menus below being
1049
+ * gated on the data rather than switched on unconditionally.
1050
+ */
1051
+ const configQuery = useConfig(!inPage, protocol.type === 'ag-ui' ? protocol.configEndpoint : undefined, undefined, agentId);
1052
+ const skillsQuery = useSkills(true);
1053
+ const skillActions = useSkillActions(agentId);
1054
+ const [catalogModels, setCatalogModels] = useState([]);
1055
+ useEffect(() => {
1056
+ /*
1057
+ * Only where there is a server to ask.
1058
+ *
1059
+ * An in-page agent has none, and `agentServerUrl` then holds whatever the
1060
+ * host defaulted to — on a public page that was a developer's localhost,
1061
+ * so every visitor's console carried a connection-refused error for a
1062
+ * catalogue that was never going to arrive. The agentspecs catalogue below
1063
+ * is the answer for this case and needs no request at all.
1064
+ */
1065
+ if (inPage) {
1066
+ return undefined;
1067
+ }
1068
+ let cancelled = false;
1069
+ void fetch(`${agentServerUrl}/api/v1/configure/models`)
1070
+ .then(response => (response.ok ? response.json() : { models: [] }))
1071
+ .then(payload => {
1072
+ if (!cancelled) {
1073
+ setCatalogModels(payload.models ?? []);
1074
+ }
1075
+ })
1076
+ // No catalogue is not an error worth a banner: the menu simply has
1077
+ // nothing to offer, and the agent answers on whatever it was given.
1078
+ .catch(() => undefined);
1079
+ return () => {
1080
+ cancelled = true;
1081
+ };
1082
+ }, [agentServerUrl, inPage]);
1083
+ /*
1084
+ * What to offer when the server has no catalogue of its own.
1085
+ *
1086
+ * `/configure/models` answers for a server-backed agent and is
1087
+ * authoritative. An in-page agent has no server to ask, and a model menu
1088
+ * with nothing in it is a control that opens onto an empty list — so the
1089
+ * agentspecs catalogue stands in, filtered to the models marked available.
1090
+ */
1091
+ const offeredModels = useMemo(() => catalogModels.length > 0
1092
+ ? catalogModels
1093
+ : Object.values(AI_MODEL_CATALOGUE)
1094
+ .filter(model => model.available)
1095
+ .map(model => ({
1096
+ id: model.id,
1097
+ name: model.name,
1098
+ provider: model.provider,
1099
+ })), [catalogModels]);
1100
+ /*
1101
+ * The tools the agent can call, from both sides.
1102
+ *
1103
+ * The server's builtins, and the notebook tools this workspace hands the
1104
+ * harness — which are the only ones an in-page agent has, and the reason
1105
+ * "run this cell" works at all. Listing a tool and running it are different
1106
+ * jobs, so a tool the chat does not execute still belongs in the menu.
1107
+ */
1108
+ const offeredTools = useMemo(() => {
1109
+ const fromServer = configQuery.data?.builtinTools ?? [];
1110
+ const seen = new Set(fromServer.map(tool => tool.name));
1111
+ return [
1112
+ ...fromServer,
1113
+ ...agentTools
1114
+ .filter(tool => !seen.has(tool.name))
1115
+ .map(tool => ({ id: tool.name, name: tool.name })),
1116
+ ];
1117
+ }, [configQuery.data?.builtinTools, agentTools]);
1118
+ /* Which skills are on, as the runtime last reported them. Derived rather
1119
+ than held: the source of truth is the agent, and a local copy would drift
1120
+ the moment a skill was enabled from anywhere else. */
1121
+ const enabledSkills = useMemo(() => new Set((skillsQuery.data?.skills ?? [])
1122
+ // `enabled` and `loaded` both mean the agent has it; `available`
1123
+ // means it could. There is no `disabled` — a skill that is off is
1124
+ // simply one that is merely available.
1125
+ .filter(skill => skill.status === 'enabled' || skill.status === 'loaded')
1126
+ .map(skill => skill.id)), [skillsQuery.data]);
1127
+ /*
1128
+ * Taken here first, then told to the server.
1129
+ *
1130
+ * Locally, because an in-page agent has no server to tell and its model is
1131
+ * whatever this view hands the harness — without recording the choice, the
1132
+ * menu ticked a row for a moment and the next message went to the old model.
1133
+ * And on the server for the agents that live there, where the chip in its
1134
+ * header makes the same call: whichever control a person used, the other has
1135
+ * to agree.
1136
+ */
1137
+ const selectModel = useCallback(async (model) => {
1138
+ setPickedModel(model);
1139
+ if (inPage) {
1140
+ return;
1141
+ }
1142
+ await fetch(`${agentServerUrl}/api/v1/configure/inference/provider`, {
1143
+ method: 'PUT',
1144
+ headers: { 'content-type': 'application/json' },
1145
+ body: JSON.stringify({ model }),
1146
+ }).catch(() => undefined);
1147
+ }, [agentServerUrl, inPage]);
1148
+ /* `bottom-chat` keeps the prompt in the chat column; `bottom`, the default,
1149
+ spans the workspace. */
1150
+ const besideChat = config?.promptPlacement === 'bottom-chat';
1151
+ /* `floating` renders the same composer in a draggable card over the
1152
+ workspace — the prompt below simply gains `draggable`, and the card takes
1153
+ itself out of the layout. */
1154
+ const floatingPrompt = config?.promptPlacement === 'floating';
1155
+ /* `top` puts the composer above the editors as a horizontal bar, with the
1156
+ openers as chips under it — for a host whose editor is the point. */
1157
+ const topPrompt = config?.promptPlacement === 'top';
1158
+ /* No prompt at all, for a workspace where something else owns the typing —
1159
+ by configuration, or live through the extras channel when the host
1160
+ changes its mind while the workspace is running. */
1161
+ const promptHidden = config?.hidePrompt === true || chatExtras.hidePrompt === true;
1162
+ /*
1163
+ * The composer, assembled here and rendered by whoever contributed to the
1164
+ * `LoopChatComposer` point — the input-prompt plugin, normally.
1165
+ *
1166
+ * The wiring is this view's knowledge: the controlled draft (so an outside
1167
+ * suggestion has somewhere to land, with `focusTrigger` putting the caret
1168
+ * back), the lexical variant (the `@` menu needs it), the menus' data with
1169
+ * every control drawn even when its list is empty (a menu that opens onto
1170
+ * "0" is a statement; a missing control is not), the `promptAction` and
1171
+ * `inpromptMenu` slots (asked whether anyone contributed first — an empty
1172
+ * `ReactorSlot` is still an element and would pad out a band of nothing).
1173
+ * The surface is the plugin's: no contribution, no composer, which is the
1174
+ * honest outcome for a workspace mounted without one.
1175
+ */
1176
+ const composerProps = {
1177
+ onSend: () => void handleSend(draft),
1178
+ input: draft,
1179
+ setInput: setDraft,
1180
+ focusTrigger: suggestion || focusAsked
1181
+ ? (suggestion?.nonce ?? 0) + focusAsked
1182
+ : undefined,
1183
+ // In a draggable card over the workspace when the host asked for the
1184
+ // floating placement; the dragging is the prompt's own feature.
1185
+ placement: floatingPrompt ||
1186
+ layout?.prompt === 'floating' ||
1187
+ layout?.prompt === 'floating-top'
1188
+ ? 'floating'
1189
+ : 'docked',
1190
+ // Where a floating card starts: the page layout wants it over the top
1191
+ // of the sheet, like a document's title bar; everyone else, bottom.
1192
+ floatingAnchor: layout?.prompt === 'floating-top' ? 'top' : 'bottom',
1193
+ // The agent is working: `isLoading` disables the editor and turns the
1194
+ // send button into a stop — the person keeps a way out.
1195
+ isLoading: busy,
1196
+ onStop: () => workspace.viewControls.stop?.(),
1197
+ // The reason where the typing would go, read before the person types.
1198
+ placeholder: disabledReason ?? placeholder,
1199
+ typingSuggestions: suggestions.map(item => item.text),
1200
+ // The same openers behind the composer's suggestions control.
1201
+ suggestions: chatSuggestions,
1202
+ disableInputPrompt: chatDisabled,
1203
+ connectionConfirmed: !chatDisabled,
1204
+ // Tighter on top: every pixel of the composer is a pixel of the editor
1205
+ // under it pushed down, and the bar reads as a command line at this size.
1206
+ // Both of the page layout's placements are that bar — one floating over
1207
+ // the page, one docked above it — so both take the tighter padding.
1208
+ padding: topPrompt ||
1209
+ layout?.prompt === 'floating-top' ||
1210
+ layout?.prompt === 'docked-top'
1211
+ ? 2
1212
+ : 3,
1213
+ promptVariant: 'lexical',
1214
+ // True unless the host asked otherwise: the workspace is there to be typed
1215
+ // into. A page that embeds the loop as one section among many turns it off,
1216
+ // because focusing an input on mount scrolls the browser to it.
1217
+ autoFocus: config?.autoFocusPrompt ?? true,
1218
+ mentionableAgents: mentionable,
1219
+ headerContent: inpromptMenu.length > 0 ? (_jsx(ReactorSlot, { slot: LoopSlots.inpromptMenu, props: { workspace } })) : undefined,
1220
+ footerExtras: promptActions.length > 0 ? (_jsx(ReactorSlot, { slot: LoopSlots.promptAction, props: { workspace } })) : undefined,
1221
+ showAgentsMenu: true,
1222
+ showInlineAgentsMenu: false,
1223
+ agents: footerAgents,
1224
+ selectedAgentId: selectedMemberId,
1225
+ onSelectAgent: id => team?.select(id),
1226
+ // On unless the host said otherwise: a public page turns the counters
1227
+ // off, because they answer questions a visitor is not asking.
1228
+ showTokenUsage: chatExtras.showTokenUsage ?? true,
1229
+ showContextRing: true,
1230
+ agentUsage: contextUsage ?? undefined,
1231
+ showModelSelector: true,
1232
+ models: offeredModels,
1233
+ selectedModel: activeModel,
1234
+ onModelSelect: model => void selectModel(model),
1235
+ showToolsMenu: true,
1236
+ availableTools: offeredTools,
1237
+ mcpServers: configQuery.data?.mcpServers ?? [],
1238
+ // Live from the host example, when one feeds it: the footer's MCP status
1239
+ // indicator. (Codemode surfaces through the toggle below, not a blob.)
1240
+ mcpStatusData: chatExtras.mcpStatusData ?? undefined,
1241
+ showSkillsMenu: true,
1242
+ skills: skillsQuery.data?.skills ?? [],
1243
+ skillsLoading: skillsQuery.isLoading,
1244
+ enabledSkills,
1245
+ onToggleSkill: skillId => enabledSkills.has(skillId)
1246
+ ? skillActions.disableSkill(skillId)
1247
+ : skillActions.enableSkill(skillId),
1248
+ onToggleAllSkills: (skillIds, enable) => skillIds.forEach(skillId => enable
1249
+ ? skillActions.enableSkill(skillId)
1250
+ : skillActions.disableSkill(skillId)),
1251
+ codemodeEnabled: chatExtras.codemodeEnabled ?? false,
1252
+ onToggleCodemode: chatExtras.onToggleCodemode,
1253
+ isA2AProtocol: false,
1254
+ hasConfigData: !!configQuery.data,
1255
+ hasSkillsData: !!skillsQuery.data,
1256
+ };
1257
+ const ComposerComponent = composerEntries[0]?.value.Component;
1258
+ const HeaderComponent = headerEntries[0]?.value.Component;
1259
+ const prompt = ComposerComponent ? (_jsx(ComposerComponent, { workspace: workspace, composer: composerProps })) : null;
1260
+ /*
1261
+ * The parts, named, so a layout can arrange them.
1262
+ *
1263
+ * Each is wired here — the surfaces' hidden mounts, the transcript's
1264
+ * stream, the composer's draft — and only *placed* below: by the split
1265
+ * this view has always drawn, or by whatever `LoopChatLayout` contributed.
1266
+ */
1267
+ const pickerEl = surfaces.length > 0 && config?.showSurfaceSelector !== false ? (_jsx(SurfacePicker, { surfaces: surfaces.map(entry => entry.value),
1268
+ /*
1269
+ What is on screen, not what was asked for.
1270
+
1271
+ It read `surfaceId` — the request — while the column beside it
1272
+ renders `active`, the surface that request actually resolved to.
1273
+ The two are the same once everything has settled and differ
1274
+ exactly while it has not: a surface still arriving, or one closed
1275
+ because its sandbox went away. So the control could say None over
1276
+ a notebook, which is the one thing a control must never do.
1277
+
1278
+ Reporting the rendered surface makes them agree by construction.
1279
+ */
1280
+ active: active?.surfaceId ?? waiting?.surfaceId ?? NO_SURFACE, onChange: chooseSurface, workspace: workspace })) : null;
1281
+ const editorsEl = (_jsxs(_Fragment, { children: [surfaces.map(entry => {
1282
+ const surface = entry.value;
1283
+ const shown = active?.surfaceId === surface.surfaceId;
1284
+ const mount = shown ||
1285
+ everMounted.current.has(surface.surfaceId) ||
1286
+ canOpenView(surface, workspace);
1287
+ if (!mount) {
1288
+ return null;
1289
+ }
1290
+ everMounted.current.add(surface.surfaceId);
1291
+ return (_jsx(Box, { sx: shown
1292
+ ? { flex: '1 1 0', minWidth: 0, minHeight: 0 }
1293
+ : {
1294
+ position: 'absolute',
1295
+ inset: 0,
1296
+ visibility: 'hidden',
1297
+ pointerEvents: 'none',
1298
+ zIndex: -1,
1299
+ }, children: _jsx(ReactorLazy, { load: surface.load, props: { surfaceId: surface.surfaceId, workspace }, fallback: _jsxs(Centered, { children: ["Loading ", surface.title, "\u2026"] }), errorFallback: error => (_jsxs(Centered, { children: [surface.title, " failed to load: ", error.message] })) }) }, surface.surfaceId));
1300
+ }), !active && waiting ? (_jsx(Box, { sx: { flex: '1 1 0', minWidth: 0, minHeight: 0 }, children: _jsxs(Centered, { children: ["Starting ", waiting.title, "\u2026"] }) })) : null] }));
1301
+ const transcriptEl = (_jsx(_Fragment, { children: _jsxs(Box, { sx: {
1302
+ /*
1303
+ Beside an editor, with the prompt on top, the conversation is
1304
+ the narrower column: the editor is what a `top` host put the
1305
+ prompt over, and the transcript reads fine at a third of the
1306
+ width. Every other placement splits the row evenly.
1307
+ */
1308
+ flex: topPrompt && active ? '0 0 34%' : '1 1 0',
1309
+ maxWidth: topPrompt && active ? 460 : undefined,
1310
+ minWidth: 0,
1311
+ minHeight: 0,
1312
+ display: 'flex',
1313
+ flexDirection: 'column',
1314
+ borderLeft: active ? '1px solid' : undefined,
1315
+ borderColor: 'border.default',
1316
+ // So the expired-key panel below can cover exactly this column and
1317
+ // nothing else: the notebook beside it still works.
1318
+ position: 'relative',
1319
+ }, children: [chatExtras.errorBanner ? (_jsx(Box, { sx: {
1320
+ flexShrink: 0,
1321
+ px: 3,
1322
+ py: 2,
1323
+ fontSize: 1,
1324
+ borderBottom: '1px solid',
1325
+ bg: chatExtras.errorBanner.variant === 'warning'
1326
+ ? 'attention.subtle'
1327
+ : 'danger.subtle',
1328
+ color: chatExtras.errorBanner.variant === 'warning'
1329
+ ? 'attention.fg'
1330
+ : 'danger.fg',
1331
+ borderColor: chatExtras.errorBanner.variant === 'warning'
1332
+ ? 'attention.muted'
1333
+ : 'danger.muted',
1334
+ }, children: chatExtras.errorBanner.message })) : null, _jsx(Box, { sx: { flex: '1 1 auto', minHeight: 0, display: 'flex' }, children: _jsx(ChatBase
1335
+ // The header says why, beside the title, for the same reason the
1336
+ // placeholder does: a dead control with no explanation is worse
1337
+ // than an absent one.
1338
+ , {
1339
+ // The header says why, beside the title, for the same reason the
1340
+ // placeholder does: a dead control with no explanation is worse
1341
+ // than an absent one.
1342
+ disabled: chatDisabled, disableReason: disabledReason, protocol: protocol,
1343
+ /*
1344
+ Who is answering, in the words its spec uses.
1345
+
1346
+ `ChatBase` falls back to "Start a conversation with the AI
1347
+ agent", which is true of every chat ever built and says
1348
+ nothing about this one. The empty state is the first thing a
1349
+ person sees and the only place the agent introduces itself.
1350
+ */
1351
+ title: member?.name ?? spec?.name ?? agentId, description: spec?.description,
1352
+ /*
1353
+ Two sizes, because it is drawn in two places.
1354
+
1355
+ The header wants a mark beside a line of text; the empty state
1356
+ wants the thing a person's eye lands on first. One `brandIcon`
1357
+ served both, so a 48px icon meant for the empty state sat in
1358
+ the header at three times the height of the words next to it.
1359
+ */
1360
+ // Big enough to read as the agent's mark rather than as
1361
+ // punctuation before its name, and still short enough not to
1362
+ // set the header's height.
1363
+ brandIcon: _jsx(BrandIcon, { size: 20 }), emptyState: {
1364
+ icon: _jsx(BrandIcon, { size: 48 }),
1365
+ // `ChatEmptyState` reads its heading from here and nowhere
1366
+ // else — the `title` above reaches the header only — so
1367
+ // without this the agent introduced itself as "Start a
1368
+ // conversation".
1369
+ title: member?.name ?? spec?.name ?? agentId,
1370
+ /*
1371
+ Two levels when there is a team: the team first — its name,
1372
+ what it is for, what it can be asked — and under it the
1373
+ member being addressed, with its own description and its
1374
+ own openers. The groups match the ones the openers carry.
1375
+ */
1376
+ ...(team && member
1377
+ ? {
1378
+ sections: [
1379
+ {
1380
+ group: team.team.name,
1381
+ icon: _jsx(TeamIcon, { size: 48 }),
1382
+ title: team.team.name,
1383
+ subtitle: team.team.description,
1384
+ },
1385
+ {
1386
+ group: member.name,
1387
+ icon: _jsx(BrandIcon, { size: 32 }),
1388
+ title: member.name,
1389
+ subtitle: spec?.description,
1390
+ },
1391
+ ],
1392
+ }
1393
+ : null),
1394
+ },
1395
+ /*
1396
+ And what it can be asked. From the team rather than the
1397
+ member: the supervisor answers first, and somebody who has
1398
+ just opened the workspace does not yet know there are two
1399
+ agents behind it.
1400
+ */
1401
+ // With the prompt on top the openers are already chips under
1402
+ // it; the empty state repeating them was the same three buttons
1403
+ // twice on one screen.
1404
+ suggestions: topPrompt || layout ? [] : chatSuggestions,
1405
+ /*
1406
+ The title bar arrives as a plugin: the chat-header plugin
1407
+ contributes the component, this view hands it the assembled
1408
+ props through `renderHeader`. No contribution — or a host
1409
+ that set `hideHeader` — means no bar.
1410
+ */
1411
+ showHeader: !config?.hideHeader && !!HeaderComponent, renderHeader: HeaderComponent
1412
+ ? headerProps => (_jsx(HeaderComponent, { workspace: workspace, header: headerProps }))
1413
+ : undefined,
1414
+ /*
1415
+ The (i), which opens the agent's details over the transcript.
1416
+
1417
+ Worth having here in particular: this workspace can be moved
1418
+ between four runtimes and several agents, and the details pane
1419
+ is the only place that says which one is actually answering
1420
+ and where it is running.
1421
+ */
1422
+ showInformation: true,
1423
+ /*
1424
+ Full screen: this view, on the whole screen, editor and all.
1425
+ See `toggleFullScreen` for why it is the browser's API rather
1426
+ than a big box.
1427
+ */
1428
+ headerActions: _jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 2 }, children: [workspace.chatHeaderActions, chatHeaderItems.length > 0 ? (_jsx(ReactorSlot, { slot: LoopSlots.chatHeader, props: { workspace } })) : null, _jsx(IconButton, { icon: fullScreen ? ScreenNormalIcon : ScreenFullIcon, "aria-label": fullScreen ? 'Exit full screen' : 'Enter full screen', variant: "invisible", size: "small", onClick: () => {
1429
+ // Whether or not it takes, the hint has been answered:
1430
+ // they found the control, which is all it was for.
1431
+ setHintFullScreen(false);
1432
+ toggleFullScreen();
1433
+ }, sx: hintFullScreen
1434
+ ? {
1435
+ /*
1436
+ Colour and opacity, never geometry.
1437
+
1438
+ The colour is the theme's own `primary` — the
1439
+ same brand the page around this workspace is
1440
+ already using — because a grey icon in a row of
1441
+ grey icons cannot be picked out however hard it
1442
+ fades. Colour is what makes it findable; the
1443
+ fade is what makes it look like it is asking.
1444
+
1445
+ It never fades to nothing: a control that
1446
+ vanishes and returns reads as a rendering fault,
1447
+ not an invitation. And nothing here moves or
1448
+ resizes, so the header does not reflow and the
1449
+ controls beside it stay where a reader last saw
1450
+ them.
1451
+ */
1452
+ '@keyframes dla-fullscreen-hint': {
1453
+ '0%, 100%': { opacity: 1 },
1454
+ '50%': { opacity: 0.4 },
1455
+ },
1456
+ /* `&&` doubles the specificity, because Primer
1457
+ ships Button as a CSS module and
1458
+ `prc-Button-*` outranks a single generated
1459
+ class — without it the keyframes register and
1460
+ the button sits there at `animation: none`.
1461
+ The colour needs the same treatment: an
1462
+ invisible IconButton sets `color` itself.
1463
+
1464
+ And no `:focus` or `:hover` clause to stop it:
1465
+ anything that matches the button while it is
1466
+ being pointed at would cancel the pointing —
1467
+ which is exactly how the first version of this
1468
+ silently did nothing. It ends when the reader
1469
+ takes the offer, or arrives without it. */
1470
+ '&&': {
1471
+ /*
1472
+ The brand on the box, not on the glyph.
1473
+
1474
+ Painting the icon `palette.primary` was the
1475
+ obvious reading and it is measurably
1476
+ backwards: in the theme this workspace ships
1477
+ on, `primary` is #FFC107, which sits at 1.55
1478
+ contrast against the header — where the
1479
+ icon's ordinary olive sits at 5.07. Recolouring
1480
+ the stroke made the control roughly three
1481
+ times harder to see, and at the bottom of the
1482
+ fade it was 1.2 and simply gone.
1483
+
1484
+ A ring and a wash carry the same colour on a
1485
+ far larger area, and they do it without asking
1486
+ the glyph to be legible in a brand colour that
1487
+ changes with every theme — this palette has
1488
+ six, from a dark teal to this amber, and a
1489
+ rule that works for one fails for another. The
1490
+ glyph keeps the colour it can be read in.
1491
+ */
1492
+ bg: `color-mix(in srgb, ${palette.primary} 16%, transparent)`,
1493
+ boxShadow: `inset 0 0 0 1.5px ${palette.primary}`,
1494
+ animation: `dla-fullscreen-hint ${FULLSCREEN_HINT_PERIOD_MS}ms ease-in-out infinite`,
1495
+ },
1496
+ // A reader who asked the machine to hold still
1497
+ // keeps the colour and loses the knocking: the
1498
+ // control is still the findable one, it just
1499
+ // holds still.
1500
+ '@media (prefers-reduced-motion: reduce)': {
1501
+ '&&': { animation: 'none' },
1502
+ },
1503
+ }
1504
+ : undefined })] }),
1505
+ // This view owns the prompt, below, so the chat does not draw a
1506
+ // second one: two input boxes on one screen is one too many.
1507
+ showInput: false, onSendReady: handleSendReady,
1508
+ /*
1509
+ The notebook tools' results, drawn into the transcript — the
1510
+ chat's own machinery, switched on only while no editor is on
1511
+ screen: the hidden notebook is where the agent works, and the
1512
+ transcript is then the one place the reader can see what a
1513
+ tool did. With an editor open the change is visible where it
1514
+ happened, and the default tool row is enough.
1515
+ */
1516
+ notebookToolSurfacesId: active ? undefined : workspace.surfaceId,
1517
+ // A host example's own tool-result renderer, when it feeds one
1518
+ // through the extras channel — the A2UI examples draw their
1519
+ // surface here. Wins over the notebook surfaces in ChatBase.
1520
+ renderToolResult: chatExtras.renderToolResult, showTurnFooter: chatExtras.showTokenUsage ?? true, onContextSnapshot: handleContextSnapshot, onLoadingChange: handleLoadingChange, onItemsChange: handleMessagesChange, onDisplayItemsChange: handleDisplayItemsChange, enableStreaming: true }) }), besideChat && !promptHidden ? prompt : null] }) }));
1521
+ const chipsEl = chatSuggestions.length > 0 ? (_jsx(Box, { "aria-label": "Suggested prompts", sx: { display: 'flex', flexWrap: 'wrap', gap: 2, px: 2, pb: '6px' }, children: chatSuggestions.map(item => (_jsx(Box, { as: "button", type: "button",
1522
+ // The whole request, where the chip shows only its summary.
1523
+ title: item.message, disabled: busy || chatDisabled, onClick: () => void handleSend(item.message), sx: {
1524
+ appearance: 'none',
1525
+ font: 'inherit',
1526
+ fontSize: 0,
1527
+ fontWeight: 'semibold',
1528
+ // Room for descenders: the truncated span clips what falls
1529
+ // below its line, and at a line-height of one that is the
1530
+ // tail of every "y".
1531
+ lineHeight: 1.25,
1532
+ px: '10px',
1533
+ py: '5px',
1534
+ width: SUGGESTION_CHIP_WIDTH,
1535
+ flex: `0 0 ${SUGGESTION_CHIP_WIDTH}px`,
1536
+ borderRadius: '999px',
1537
+ border: '1px solid',
1538
+ borderColor: 'border.default',
1539
+ bg: 'canvas.subtle',
1540
+ color: 'fg.default',
1541
+ cursor: 'pointer',
1542
+ whiteSpace: 'nowrap',
1543
+ '&:hover:not(:disabled)': {
1544
+ borderColor: 'accent.fg',
1545
+ color: 'accent.fg',
1546
+ },
1547
+ '&:disabled': { opacity: 0.5, cursor: 'default' },
1548
+ }, children: _jsx(Truncate, { title: item.title, maxWidth: "100%", sx: { minWidth: 0 }, children: item.title }) }, item.title))) })) : null;
1549
+ const transientEl = transient ? (_jsx(Box, { sx: {
1550
+ flex: '0 0 auto',
1551
+ px: 3,
1552
+ py: 2,
1553
+ borderTop: '1px solid',
1554
+ borderColor: 'border.default',
1555
+ bg: 'canvas.subtle',
1556
+ fontSize: 1,
1557
+ maxHeight: '40%',
1558
+ overflowY: 'auto',
1559
+ }, children: transient })) : null;
1560
+ return (_jsxs(Box, { ref: viewRef, sx: {
1561
+ height: '100%',
1562
+ minHeight: 0,
1563
+ display: 'flex',
1564
+ flexDirection: 'column',
1565
+ // The positioned root the expiry panel below covers.
1566
+ position: 'relative',
1567
+ /*
1568
+ A background of its own once it is full screen, in both modes.
1569
+
1570
+ The element is promoted out of whatever was painting behind it — the
1571
+ browser's top layer, or the page — and a workspace that inherited its
1572
+ canvas from an ancestor would arrive transparent over black.
1573
+ */
1574
+ ...(fullScreen ? { bg: 'canvas.default' } : null),
1575
+ // The fallback, for a host where the API was refused, or where
1576
+ // `fullScreenTopOffset` asked for the overlay outright. Covers as
1577
+ // much as the nearest transformed ancestor allows; see the note
1578
+ // above. `top` leaves room for a host's own fixed header rather than
1579
+ // `inset: 0`'s full viewport — 0 (no offset given) is the same rect
1580
+ // either way.
1581
+ ...(fullScreen && !usingFullscreenApi.current
1582
+ ? {
1583
+ position: 'fixed',
1584
+ top: fullScreenTopOffsetPx,
1585
+ right: 0,
1586
+ bottom: 0,
1587
+ left: 0,
1588
+ // Over the `height: '100%'` above, which would otherwise win
1589
+ // over `top`/`bottom` and push the bottom off the window.
1590
+ height: 'auto',
1591
+ zIndex: 1000,
1592
+ }
1593
+ : null),
1594
+ }, children: [layout ? (_jsx(layout.Component, { workspace: workspace, editors: editorsEl, hasEditor: !!active, transcript: transcriptEl, prompt: promptHidden ? null : prompt, chips: promptHidden ? null : chipsEl, picker: pickerEl, transient: transientEl })) : (_jsxs(_Fragment, { children: [topPrompt && !promptHidden ? (_jsxs(Box, { sx: {
1595
+ flex: '0 0 auto',
1596
+ borderBottom: '1px solid',
1597
+ borderColor: 'border.default',
1598
+ }, children: [prompt, chipsEl] })) : null, pickerEl, _jsxs(Box, { sx: {
1599
+ flex: '1 1 auto',
1600
+ minHeight: 0,
1601
+ display: 'flex',
1602
+ // The hidden editors position themselves against this row.
1603
+ position: 'relative',
1604
+ }, children: [editorsEl, transcriptEl] }), transientEl, besideChat || promptHidden || topPrompt ? null : prompt] })), keyExpired ? (_jsx(Box, { sx: {
1605
+ position: 'absolute',
1606
+ inset: 0,
1607
+ zIndex: 5,
1608
+ bg: 'canvas.default',
1609
+ display: 'flex',
1610
+ flexDirection: 'column',
1611
+ minHeight: 0,
1612
+ }, children: _jsx(AnonymousKeyExpired, { agentName: member?.name ?? spec?.name,
1613
+ // On the browser target the kernel is in this page and owes the
1614
+ // inference service nothing, so the notebook is genuinely
1615
+ // unaffected and the panel may say so.
1616
+ sandboxStillRuns: inPage, temporary: expiredKeyIsTemporary,
1617
+ // The trial key is spent once somebody signs in, and a session
1618
+ // left `expired` would keep this panel over a working chat.
1619
+ onSignedIn: () => useAnonymousSessionStore.getState().clear() }) })) : null] }));
1620
+ }
1621
+ /**
1622
+ * Which editor sits beside the conversation.
1623
+ *
1624
+ * Rendered only when a plugin contributed one — a chat on its own has nothing
1625
+ * to pick between, and a control with a single option is noise.
1626
+ */
1627
+ function SurfacePicker({ surfaces, active, onChange, workspace, }) {
1628
+ const ordered = [...surfaces].sort((left, right) => (left.order ?? 100) - (right.order ?? 100));
1629
+ return (_jsxs(Box, { sx: {
1630
+ flex: '0 0 auto',
1631
+ display: 'flex',
1632
+ alignItems: 'center',
1633
+ gap: 2,
1634
+ px: 3,
1635
+ py: 2,
1636
+ borderBottom: '1px solid',
1637
+ borderColor: 'border.default',
1638
+ }, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Beside the chat" }), _jsxs(SegmentedControl, { "aria-label": "Editor beside the chat", size: "small", children: [_jsx(SegmentedControl.Button, { selected: active === NO_SURFACE, onClick: () => onChange(NO_SURFACE), children: "Chat" }), ordered.map(surface => {
1639
+ const openable = canOpenView(surface, workspace);
1640
+ const reason = openable
1641
+ ? undefined
1642
+ : (surface.unavailableReason?.(workspace) ??
1643
+ 'Not available right now');
1644
+ return (_jsx(SegmentedControl.Button, { selected: active === surface.surfaceId, "aria-disabled": !openable,
1645
+ // The native attribute rather than Primer's `Tooltip`: that
1646
+ // component requires its child to *be* the interactive element,
1647
+ // and `SegmentedControl.Button` renders a list item around its
1648
+ // button — wrapping it throws before the workspace can paint.
1649
+ title: reason ?? surface.title,
1650
+ // Primer types this as its own icon shape; a contribution may
1651
+ // bring any component, which is the point of the extension point.
1652
+ leadingIcon: surface.icon, onClick: () => {
1653
+ if (openable) {
1654
+ onChange(surface.surfaceId);
1655
+ }
1656
+ }, children: surface.title }, surface.surfaceId));
1657
+ })] })] }));
1658
+ }
1659
+ function Centered({ children }) {
1660
+ return (_jsx(Box, { sx: {
1661
+ height: '100%',
1662
+ display: 'flex',
1663
+ alignItems: 'center',
1664
+ justifyContent: 'center',
1665
+ color: 'fg.muted',
1666
+ fontSize: 1,
1667
+ px: 3,
1668
+ textAlign: 'center',
1669
+ }, children: children }));
1670
+ }