@datalayer/agent-runtimes 0.0.11 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +2 -2
  2. package/lib/Agent.d.ts +29 -0
  3. package/lib/Agent.js +131 -0
  4. package/lib/AgentLexical.d.ts +33 -0
  5. package/lib/AgentLexical.js +295 -0
  6. package/lib/AgentNotebook.d.ts +19 -0
  7. package/lib/AgentNotebook.js +192 -0
  8. package/lib/agent-lexical-main.d.ts +1 -0
  9. package/lib/agent-lexical-main.js +11 -0
  10. package/lib/agent-main.d.ts +1 -0
  11. package/lib/agent-main.js +11 -0
  12. package/lib/agent-notebook-main.d.ts +1 -0
  13. package/lib/agent-notebook-main.js +12 -0
  14. package/lib/components/AgentConfiguration.d.ts +4 -22
  15. package/lib/components/AgentConfiguration.js +8 -8
  16. package/lib/components/chat/components/AgentDetails.d.ts +3 -1
  17. package/lib/components/chat/components/AgentDetails.js +6 -6
  18. package/lib/components/chat/components/Chat.d.ts +29 -3
  19. package/lib/components/chat/components/Chat.js +64 -59
  20. package/lib/components/chat/components/ChatFloating.d.ts +34 -12
  21. package/lib/components/chat/components/ChatFloating.js +54 -21
  22. package/lib/components/chat/components/ChatInline.d.ts +5 -1
  23. package/lib/components/chat/components/ChatInline.js +8 -1
  24. package/lib/components/chat/components/ChatSidebar.d.ts +6 -1
  25. package/lib/components/chat/components/ChatSidebar.js +2 -2
  26. package/lib/components/chat/components/ChatStandalone.d.ts +6 -1
  27. package/lib/components/chat/components/ChatStandalone.js +2 -2
  28. package/lib/components/chat/components/base/ChatBase.d.ts +49 -8
  29. package/lib/components/chat/components/base/ChatBase.js +544 -149
  30. package/lib/components/chat/components/base/InputPrompt.d.ts +42 -0
  31. package/lib/components/chat/components/base/InputPrompt.js +131 -0
  32. package/lib/components/chat/components/index.d.ts +3 -3
  33. package/lib/components/chat/components/index.js +1 -1
  34. package/lib/components/chat/components/parts/ReasoningPart.js +2 -4
  35. package/lib/components/chat/components/parts/TextPart.js +2 -70
  36. package/lib/components/chat/components/styles/streamdownStyles.d.ts +23 -0
  37. package/lib/components/chat/components/styles/streamdownStyles.js +319 -0
  38. package/lib/components/chat/index.d.ts +1 -1
  39. package/lib/components/chat/index.js +1 -1
  40. package/lib/components/chat/inference/DatalayerInferenceProvider.js +16 -12
  41. package/lib/components/chat/inference/SelfHostedInferenceProvider.js +16 -12
  42. package/lib/components/chat/protocols/AGUIAdapter.d.ts +10 -3
  43. package/lib/components/chat/protocols/AGUIAdapter.js +123 -44
  44. package/lib/components/chat/types/tool.d.ts +5 -2
  45. package/lib/components/index.d.ts +1 -18
  46. package/lib/components/index.js +0 -9
  47. package/lib/config/index.d.ts +0 -4
  48. package/lib/config/index.js +0 -4
  49. package/lib/examples/A2UiRestaurantExample.js +1 -1
  50. package/lib/examples/AgentRuntimeChatExample.d.ts +15 -0
  51. package/lib/examples/AgentRuntimeChatExample.js +126 -0
  52. package/lib/examples/{AgentSpaceFormExample.d.ts → AgentRuntimeFormExample.d.ts} +3 -3
  53. package/lib/examples/{AgentSpaceFormExample.js → AgentRuntimeFormExample.js} +10 -8
  54. package/lib/examples/AgentRuntimeLexical2Example.d.ts +0 -1
  55. package/lib/examples/AgentRuntimeLexical2Example.js +0 -1
  56. package/lib/examples/AgentRuntimeLexicalExample.d.ts +0 -1
  57. package/lib/examples/AgentRuntimeLexicalExample.js +6 -4
  58. package/lib/examples/AgentRuntimeLexicalSidebarExample.d.ts +0 -1
  59. package/lib/examples/AgentRuntimeLexicalSidebarExample.js +8 -2
  60. package/lib/examples/AgentRuntimeNotebookExample.js +6 -5
  61. package/lib/examples/CopilotKitLexicalExample.d.ts +0 -1
  62. package/lib/examples/CopilotKitLexicalExample.js +0 -1
  63. package/lib/examples/CopilotKitNotebookExample.js +2 -2
  64. package/lib/examples/JupyterNotebookExample.js +2 -2
  65. package/lib/{components → examples/components}/Header.d.ts +2 -1
  66. package/lib/{components → examples/components}/HeaderControls.js +1 -1
  67. package/lib/{components → examples/components}/LexicalEditor.d.ts +6 -1
  68. package/lib/{components → examples/components}/LexicalEditor.js +4 -4
  69. package/lib/{components → examples/components}/MainContent.d.ts +1 -1
  70. package/lib/{components → examples/components}/MainContent.js +7 -5
  71. package/lib/examples/components/index.d.ts +16 -0
  72. package/lib/examples/components/index.js +13 -0
  73. package/lib/examples/example-selector.js +2 -1
  74. package/lib/examples/index.d.ts +1 -1
  75. package/lib/examples/index.js +1 -1
  76. package/lib/examples/main.js +2 -2
  77. package/lib/examples/stores/examplesStore.d.ts +2 -23
  78. package/lib/index.d.ts +2 -1
  79. package/lib/index.js +1 -0
  80. package/lib/lexical/ChatInlinePlugin.d.ts +13 -2
  81. package/lib/lexical/ChatInlinePlugin.js +66 -183
  82. package/lib/lexical/index.d.ts +1 -0
  83. package/lib/lexical/index.js +1 -0
  84. package/lib/lexical/useChatInlineToolbarItems.d.ts +35 -0
  85. package/lib/lexical/useChatInlineToolbarItems.js +91 -0
  86. package/lib/runtime/useAgentRuntime.d.ts +1 -1
  87. package/lib/runtime/useAgentRuntime.js +1 -1
  88. package/lib/{config/agents/code-ai → specs/agents/codeai}/agents.d.ts +5 -2
  89. package/lib/specs/agents/codeai/agents.js +151 -0
  90. package/lib/{config → specs}/agents/codemode-paper/agents.d.ts +4 -2
  91. package/lib/{config → specs}/agents/codemode-paper/agents.js +39 -19
  92. package/lib/{config → specs}/agents/datalayer-ai/agents.d.ts +4 -2
  93. package/lib/{config → specs}/agents/datalayer-ai/agents.js +17 -2
  94. package/lib/{config → specs}/agents/index.d.ts +3 -1
  95. package/lib/{config → specs}/agents/index.js +12 -3
  96. package/lib/{config → specs}/envvars.d.ts +1 -0
  97. package/lib/{config → specs}/envvars.js +10 -0
  98. package/lib/specs/index.d.ts +5 -0
  99. package/lib/specs/index.js +9 -0
  100. package/lib/{config → specs}/mcpServers.d.ts +2 -1
  101. package/lib/{config → specs}/mcpServers.js +23 -1
  102. package/lib/specs/models.d.ts +68 -0
  103. package/lib/specs/models.js +239 -0
  104. package/lib/state/substates/AIAgentState.d.ts +0 -1
  105. package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.d.ts +11 -22
  106. package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.js +5 -5
  107. package/lib/tools/adapters/agent-runtimes/lexicalHooks.d.ts +6 -6
  108. package/lib/tools/adapters/agent-runtimes/lexicalHooks.js +4 -4
  109. package/lib/tools/adapters/agent-runtimes/notebookHooks.d.ts +6 -6
  110. package/lib/tools/adapters/agent-runtimes/notebookHooks.js +4 -4
  111. package/lib/{types.d.ts → types/Types.d.ts} +32 -6
  112. package/lib/types/index.d.ts +1 -0
  113. package/lib/types/index.js +1 -0
  114. package/package.json +11 -5
  115. package/scripts/codegen/generate_agents.py +53 -13
  116. package/scripts/codegen/generate_envvars.py +1 -1
  117. package/scripts/codegen/generate_mcp_servers.py +5 -5
  118. package/scripts/codegen/generate_models.py +486 -0
  119. package/scripts/codegen/generate_skills.py +2 -2
  120. package/style/primer-primitives.css +22 -0
  121. package/lib/components/chat/components/elements/ChatInputPrompt.d.ts +0 -37
  122. package/lib/components/chat/components/elements/ChatInputPrompt.js +0 -150
  123. package/lib/config/agents/code-ai/agents.js +0 -70
  124. /package/lib/{components → examples/components}/FooterMetrics.d.ts +0 -0
  125. /package/lib/{components → examples/components}/FooterMetrics.js +0 -0
  126. /package/lib/{components → examples/components}/Header.js +0 -0
  127. /package/lib/{components → examples/components}/HeaderControls.d.ts +0 -0
  128. /package/lib/{components → examples/components}/MockFileBrowser.d.ts +0 -0
  129. /package/lib/{components → examples/components}/MockFileBrowser.js +0 -0
  130. /package/lib/{components → examples/components}/SessionTabs.d.ts +0 -0
  131. /package/lib/{components → examples/components}/SessionTabs.js +0 -0
  132. /package/lib/{components → examples/components}/TimeTravel.d.ts +0 -0
  133. /package/lib/{components → examples/components}/TimeTravel.js +0 -0
  134. /package/lib/{config/agents/code-ai → specs/agents/codeai}/index.d.ts +0 -0
  135. /package/lib/{config/agents/code-ai → specs/agents/codeai}/index.js +0 -0
  136. /package/lib/{config → specs}/agents/codemode-paper/index.d.ts +0 -0
  137. /package/lib/{config → specs}/agents/codemode-paper/index.js +0 -0
  138. /package/lib/{config → specs}/agents/datalayer-ai/index.d.ts +0 -0
  139. /package/lib/{config → specs}/agents/datalayer-ai/index.js +0 -0
  140. /package/lib/{config → specs}/skills.d.ts +0 -0
  141. /package/lib/{config → specs}/skills.js +0 -0
  142. /package/lib/{types.js → types/Types.js} +0 -0
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  /*
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
@@ -6,27 +6,41 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  /**
7
7
  * ChatInlinePlugin - Lexical plugin for inline AI chat.
8
8
  *
9
- * This plugin displays a floating AI chat interface when text is selected
10
- * in the Lexical editor. It provides AI-powered text manipulation features
11
- * like improve, summarize, translate, etc.
9
+ * This plugin displays a floating AI chat interface when the user triggers
10
+ * an AI action (via the toolbar's AI dropdown or sparkle button). It provides
11
+ * AI-powered text manipulation features like improve, summarize, translate, etc.
12
12
  *
13
- * Features:
14
- * - Detects text selection in the editor
15
- * - Shows floating ChatInline component near the selection
16
- * - Supports custom prompts and pre-defined AI actions
17
- * - Can replace selection, insert inline, or insert below
18
- * - Uses floating-ui for positioning
13
+ * IMPORTANT: This plugin no longer renders its own formatting toolbar.
14
+ * Instead, AI actions are registered as `extraItems` in the
15
+ * `FloatingTextFormatToolbarPlugin` via the `useChatInlineToolbarItems` hook.
16
+ *
17
+ * Usage:
18
+ * ```tsx
19
+ * const { toolbarItems, isAiOpen, pendingPrompt, clearPendingPrompt, closeAi } =
20
+ * useChatInlineToolbarItems();
21
+ *
22
+ * <FloatingTextFormatToolbarPlugin
23
+ * anchorElem={floatingAnchorElem}
24
+ * setIsLinkEditMode={setIsLinkEditMode}
25
+ * extraItems={toolbarItems}
26
+ * />
27
+ * <ChatInlinePlugin
28
+ * protocol={protocol}
29
+ * isOpen={isAiOpen}
30
+ * onClose={closeAi}
31
+ * pendingPrompt={pendingPrompt}
32
+ * onPendingPromptConsumed={clearPendingPrompt}
33
+ * />
34
+ * ```
19
35
  *
20
36
  * @module lexical/ChatInlinePlugin
21
37
  */
22
- import { useCallback, useEffect, useLayoutEffect, useRef, useState, } from 'react';
38
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
23
39
  import { createPortal } from 'react-dom';
24
- import { $getSelection, $isRangeSelection, $createParagraphNode, $createTextNode, TextNode, COMMAND_PRIORITY_LOW, createCommand, FORMAT_TEXT_COMMAND, } from 'lexical';
25
- import { $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
40
+ import { $getSelection, $isRangeSelection, $createParagraphNode, $createTextNode, TextNode, COMMAND_PRIORITY_LOW, createCommand, } from 'lexical';
26
41
  import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
27
42
  import { autoUpdate, hide, limitShift, offset, shift, size, useFloating, } from '@floating-ui/react-dom';
28
- import { Box, IconButton } from '@primer/react';
29
- import { BoldIcon, ItalicIcon, StrikethroughIcon, CodeIcon, LinkIcon, SparkleFillIcon, } from '@primer/octicons-react';
43
+ import { Box } from '@primer/react';
30
44
  import { ChatInline, } from '../components/chat/components/ChatInline';
31
45
  // Margin from editor edges
32
46
  const MARGIN_X = 32;
@@ -53,7 +67,6 @@ function usePreserveSelection(editor) {
53
67
  editor.update(() => {
54
68
  const selection = savedSelectionRef.current;
55
69
  if (selection) {
56
- // Note: We create a new reference to avoid stale selection issues
57
70
  try {
58
71
  const anchor = selection.anchor;
59
72
  const focus = selection.focus;
@@ -83,16 +96,13 @@ function usePreserveSelection(editor) {
83
96
  }
84
97
  /**
85
98
  * Hook to get current text selection range
86
- * Uses native DOM selection for immediate response during drag operations
87
99
  */
88
100
  function useRange() {
89
101
  const [editor] = useLexicalComposerContext();
90
102
  const [range, setRange] = useState(null);
91
103
  useEffect(() => {
92
- // Function to update range from DOM selection
93
104
  const updateRange = () => {
94
105
  const domSelection = window.getSelection();
95
- // Check if selection exists and is within the editor
96
106
  if (!domSelection ||
97
107
  domSelection.rangeCount === 0 ||
98
108
  !editor._rootElement) {
@@ -100,26 +110,21 @@ function useRange() {
100
110
  return;
101
111
  }
102
112
  const domRange = domSelection.getRangeAt(0);
103
- // Check if selection is within the editor
104
113
  if (!editor._rootElement.contains(domRange.commonAncestorContainer)) {
105
114
  setRange(null);
106
115
  return;
107
116
  }
108
- // Check if selection is collapsed (just a cursor, no text selected)
109
117
  if (domRange.collapsed) {
110
118
  setRange(null);
111
119
  return;
112
120
  }
113
121
  setRange(domRange.cloneRange());
114
122
  };
115
- // Listen for Lexical editor updates
116
123
  const unregister = editor.registerUpdateListener(({ tags }) => {
117
- // Ignore collaboration updates
118
124
  if (tags.has('collaboration'))
119
125
  return;
120
126
  updateRange();
121
127
  });
122
- // Listen for DOM selection changes to catch drag selections
123
128
  document.addEventListener('selectionchange', updateRange);
124
129
  return () => {
125
130
  unregister();
@@ -145,91 +150,18 @@ function useSelectionText() {
145
150
  return textContent;
146
151
  }
147
152
  /**
148
- * Hook to detect if mouse is pressed outside a specific element (for drag selection detection)
149
- * Returns true only when mouse is down AND the click started outside the provided element
150
- */
151
- function useIsMouseDownOutside(getElement) {
152
- const [isMouseDownOutside, setIsMouseDownOutside] = useState(false);
153
- // Force update counter to trigger re-render on mouseup
154
- const [, forceUpdate] = useState(0);
155
- useEffect(() => {
156
- const handleMouseDown = (e) => {
157
- const element = getElement();
158
- // Check if the click is outside the toolbar element
159
- if (element && element.contains(e.target)) {
160
- // Click is inside toolbar, don't set mouse down state
161
- setIsMouseDownOutside(false);
162
- }
163
- else {
164
- // Click is outside toolbar (in editor), set mouse down state
165
- setIsMouseDownOutside(true);
166
- }
167
- };
168
- const handleMouseUp = () => {
169
- setIsMouseDownOutside(false);
170
- // Force a re-render to show toolbar after selection completes
171
- forceUpdate(n => n + 1);
172
- };
173
- document.addEventListener('mousedown', handleMouseDown);
174
- document.addEventListener('mouseup', handleMouseUp);
175
- return () => {
176
- document.removeEventListener('mousedown', handleMouseDown);
177
- document.removeEventListener('mouseup', handleMouseUp);
178
- };
179
- }, [getElement]);
180
- return isMouseDownOutside;
181
- }
182
- /**
183
- * ChatInlinePlugin - Floating AI toolbar for Lexical text selection.
153
+ * ChatInlinePlugin - Floating AI chat panel for Lexical text selection.
154
+ *
155
+ * This plugin is controlled externally via `isOpen` prop. It positions a
156
+ * ChatInline component near the text selection when open.
184
157
  */
185
- export function ChatInlinePlugin({ protocol, portalContainer, }) {
158
+ export function ChatInlinePlugin({ protocol, isOpen, onClose, pendingPrompt, onPendingPromptConsumed, portalContainer, }) {
186
159
  const [editor] = useLexicalComposerContext();
187
- const [toolbarState, setToolbarState] = useState('closed');
188
- const [fullWidth, setFullWidth] = useState(false);
189
160
  const padding = 20;
190
- // Text format state
191
- const [isBold, setIsBold] = useState(false);
192
- const [isItalic, setIsItalic] = useState(false);
193
- const [isStrikethrough, setIsStrikethrough] = useState(false);
194
- const [isCode, setIsCode] = useState(false);
195
- const [isLink, setIsLink] = useState(false);
196
- // Update text format state based on selection
197
- const updateFormatState = useCallback(() => {
198
- editor.getEditorState().read(() => {
199
- const selection = $getSelection();
200
- if ($isRangeSelection(selection)) {
201
- setIsBold(selection.hasFormat('bold'));
202
- setIsItalic(selection.hasFormat('italic'));
203
- setIsStrikethrough(selection.hasFormat('strikethrough'));
204
- setIsCode(selection.hasFormat('code'));
205
- // Check if selection contains a link
206
- const nodes = selection.getNodes();
207
- const isLinkNode = nodes.some(node => {
208
- const parent = node.getParent();
209
- return $isLinkNode(parent) || $isLinkNode(node);
210
- });
211
- setIsLink(isLinkNode);
212
- }
213
- });
214
- }, [editor]);
215
- // Listen for selection changes to update format state
216
- useEffect(() => {
217
- return editor.registerUpdateListener(({ editorState }) => {
218
- editorState.read(() => {
219
- updateFormatState();
220
- });
221
- });
222
- }, [editor, updateFormatState]);
223
161
  // Selection preservation
224
162
  const { saveSelection, restoreSelection } = usePreserveSelection(editor);
225
- // Ref for the toolbar container to detect clicks inside vs outside
226
- const toolbarRef = useRef(null);
227
- // Stable getter function for the toolbar element
228
- const getToolbarElement = useCallback(() => toolbarRef.current, []);
229
- // Track mouse state for detecting ongoing drag selections (only outside toolbar)
230
- const isMouseDownOutside = useIsMouseDownOutside(getToolbarElement);
231
163
  // Floating UI setup
232
- const { refs: { setReference, setFloating }, strategy, x, y, } = useFloating({
164
+ const { refs: { setReference, setFloating }, strategy, y, } = useFloating({
233
165
  strategy: 'fixed',
234
166
  placement: 'bottom',
235
167
  middleware: [
@@ -247,23 +179,33 @@ export function ChatInlinePlugin({ protocol, portalContainer, }) {
247
179
  // Selection tracking
248
180
  const { range } = useRange();
249
181
  const selectedText = useSelectionText();
250
- // Update floating reference position based on selection
251
- useLayoutEffect(() => {
252
- setReference({
253
- getBoundingClientRect: () => range?.getBoundingClientRect() || new DOMRect(),
254
- });
255
- }, [setReference, range]);
256
- // Reset width when selection is removed, show button when selection appears
182
+ // ---------------------------------------------------------------
183
+ // Latch: save position & text when AI panel opens so that a
184
+ // transient selection loss (e.g. portal render triggering
185
+ // selectionchange) does not unmount the panel.
186
+ // ---------------------------------------------------------------
187
+ const savedRectRef = useRef(null);
188
+ const savedTextRef = useRef('');
257
189
  useEffect(() => {
258
- if (range === null) {
259
- setFullWidth(false);
260
- setToolbarState('closed');
190
+ if (isOpen && range) {
191
+ // Keep saving the latest rect/text while open and range is valid
192
+ savedRectRef.current = range.getBoundingClientRect();
193
+ savedTextRef.current = selectedText || '';
261
194
  }
262
- else {
263
- // Only transition from closed to button, not from ai to button
264
- setToolbarState(prev => (prev === 'closed' ? 'button' : prev));
195
+ if (!isOpen) {
196
+ savedRectRef.current = null;
197
+ savedTextRef.current = '';
265
198
  }
266
- }, [range]);
199
+ }, [isOpen, range, selectedText]);
200
+ // Effective values: prefer live selection, fall back to saved snapshot
201
+ const effectiveRect = useMemo(() => range?.getBoundingClientRect() ?? savedRectRef.current ?? null, [range]);
202
+ const effectiveText = range ? selectedText : savedTextRef.current;
203
+ // Update floating reference position based on selection (or saved rect)
204
+ useLayoutEffect(() => {
205
+ setReference({
206
+ getBoundingClientRect: () => effectiveRect || new DOMRect(),
207
+ });
208
+ }, [setReference, effectiveRect]);
267
209
  // Handle replace selection
268
210
  const handleReplaceSelection = useCallback((text) => {
269
211
  editor.update(() => {
@@ -298,82 +240,23 @@ export function ChatInlinePlugin({ protocol, portalContainer, }) {
298
240
  }
299
241
  });
300
242
  }, [editor]);
301
- // Handle close
302
- const handleClose = useCallback(() => {
303
- setToolbarState('button');
304
- setFullWidth(false);
305
- }, []);
306
- // Handle open AI
307
- const handleOpenAI = useCallback(() => {
308
- setToolbarState('ai');
309
- setFullWidth(true);
310
- }, []);
311
- // Text formatting handlers
312
- const handleFormat = useCallback((format) => {
313
- editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
314
- }, [editor]);
315
- const handleToggleLink = useCallback(() => {
316
- if (isLink) {
317
- editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
318
- }
319
- else {
320
- editor.dispatchCommand(TOGGLE_LINK_COMMAND, 'https://');
321
- }
322
- }, [editor, isLink]);
323
- // Don't render if no selection, mouse is still down outside toolbar (dragging), or toolbar closed
324
- if (range === null || isMouseDownOutside || toolbarState === 'closed') {
243
+ // Don't render if not open, or if we have neither a live range nor a saved rect
244
+ if (!isOpen || (range === null && savedRectRef.current === null)) {
325
245
  return null;
326
246
  }
327
247
  const portalTarget = portalContainer || document.body;
328
- return createPortal(_jsxs(Box, { ref: (el) => {
329
- setFloating(el);
330
- toolbarRef.current =
331
- el;
332
- }, sx: {
248
+ return createPortal(_jsx(Box, { ref: setFloating, sx: {
333
249
  pointerEvents: 'auto',
334
250
  zIndex: 50,
335
251
  position: strategy,
336
252
  top: 0,
337
- left: fullWidth && editor._rootElement
253
+ left: editor._rootElement
338
254
  ? editor._rootElement.getBoundingClientRect().left + MARGIN_X
339
255
  : 0,
340
- transform: fullWidth
341
- ? `translate3d(0, ${Math.round(y)}px, 0)`
342
- : `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
343
- width: fullWidth && editor._rootElement
256
+ transform: `translate3d(0, ${Math.round(y)}px, 0)`,
257
+ width: editor._rootElement
344
258
  ? editor._rootElement.getBoundingClientRect().width - MARGIN_X * 2
345
259
  : 'auto',
346
- minWidth: fullWidth ? undefined : 'max-content',
347
- }, children: [toolbarState === 'button' && (_jsxs(Box, { sx: {
348
- display: 'flex',
349
- alignItems: 'center',
350
- gap: 0,
351
- p: 1,
352
- borderRadius: '12px',
353
- border: '1px solid',
354
- borderColor: 'border.default',
355
- boxShadow: 'shadow.large',
356
- bg: 'canvas.default',
357
- }, children: [_jsx(IconButton, { icon: BoldIcon, "aria-label": "Bold", variant: "invisible", onClick: () => handleFormat('bold'), sx: {
358
- color: isBold ? 'accent.fg' : 'fg.muted',
359
- bg: isBold ? 'accent.subtle' : 'transparent',
360
- } }), _jsx(IconButton, { icon: ItalicIcon, "aria-label": "Italic", variant: "invisible", onClick: () => handleFormat('italic'), sx: {
361
- color: isItalic ? 'accent.fg' : 'fg.muted',
362
- bg: isItalic ? 'accent.subtle' : 'transparent',
363
- } }), _jsx(IconButton, { icon: StrikethroughIcon, "aria-label": "Strikethrough", variant: "invisible", onClick: () => handleFormat('strikethrough'), sx: {
364
- color: isStrikethrough ? 'accent.fg' : 'fg.muted',
365
- bg: isStrikethrough ? 'accent.subtle' : 'transparent',
366
- } }), _jsx(IconButton, { icon: CodeIcon, "aria-label": "Code", variant: "invisible", onClick: () => handleFormat('code'), sx: {
367
- color: isCode ? 'accent.fg' : 'fg.muted',
368
- bg: isCode ? 'accent.subtle' : 'transparent',
369
- } }), _jsx(IconButton, { icon: LinkIcon, "aria-label": "Link", variant: "invisible", onClick: handleToggleLink, sx: {
370
- color: isLink ? 'accent.fg' : 'fg.muted',
371
- bg: isLink ? 'accent.subtle' : 'transparent',
372
- } }), _jsx(Box, { sx: {
373
- width: '1px',
374
- height: '16px',
375
- bg: 'border.default',
376
- mx: 1,
377
- } }), _jsx(IconButton, { icon: SparkleFillIcon, "aria-label": "AI Assistant", variant: "invisible", onClick: handleOpenAI, sx: { color: 'fg.muted' } })] })), toolbarState === 'ai' && (_jsx(ChatInline, { selectedText: selectedText, protocol: protocol, onReplaceSelection: handleReplaceSelection, onInsertInline: handleInsertInline, onInsertBelow: handleInsertBelow, onClose: handleClose, onSaveSelection: saveSelection, onRestoreSelection: restoreSelection }))] }), portalTarget);
260
+ }, children: _jsx(ChatInline, { selectedText: effectiveText, protocol: protocol, onReplaceSelection: handleReplaceSelection, onInsertInline: handleInsertInline, onInsertBelow: handleInsertBelow, onClose: onClose, onSaveSelection: saveSelection, onRestoreSelection: restoreSelection, pendingPrompt: pendingPrompt, onPendingPromptConsumed: onPendingPromptConsumed }) }), portalTarget);
378
261
  }
379
262
  export default ChatInlinePlugin;
@@ -4,3 +4,4 @@
4
4
  * @module lexical
5
5
  */
6
6
  export { ChatInlinePlugin, type ChatInlinePluginProps, SAVE_SELECTION_COMMAND, RESTORE_SELECTION_COMMAND, } from './ChatInlinePlugin';
7
+ export { useChatInlineToolbarItems, type ChatInlineToolbarOptions, type ChatInlineToolbarState, } from './useChatInlineToolbarItems';
@@ -8,3 +8,4 @@
8
8
  * @module lexical
9
9
  */
10
10
  export { ChatInlinePlugin, SAVE_SELECTION_COMMAND, RESTORE_SELECTION_COMMAND, } from './ChatInlinePlugin';
11
+ export { useChatInlineToolbarItems, } from './useChatInlineToolbarItems';
@@ -0,0 +1,35 @@
1
+ import type { ToolbarItem } from '@datalayer/primer-addons';
2
+ /**
3
+ * Return type for useChatInlineToolbarItems.
4
+ */
5
+ export interface ChatInlineToolbarState {
6
+ /** ToolbarItem[] to pass as extraItems to FloatingTextFormatToolbarPlugin */
7
+ toolbarItems: ToolbarItem[];
8
+ /** Whether the AI inline chat panel is open */
9
+ isAiOpen: boolean;
10
+ /** Submit a prompt directly (used by the dropdown actions) */
11
+ submitPrompt: (prompt: string) => void;
12
+ /** The pending prompt (set by dropdown, consumed by ChatInlinePlugin) */
13
+ pendingPrompt: string | null;
14
+ /** Clear the pending prompt after it has been consumed */
15
+ clearPendingPrompt: () => void;
16
+ /** Open the AI panel (with custom prompt input) */
17
+ openAi: () => void;
18
+ /** Close the AI panel */
19
+ closeAi: () => void;
20
+ }
21
+ /**
22
+ * Options for useChatInlineToolbarItems.
23
+ */
24
+ export interface ChatInlineToolbarOptions {
25
+ /** When true the AI sparkle button is rendered in a disabled state. */
26
+ disabled?: boolean;
27
+ }
28
+ /**
29
+ * Hook that creates ToolbarItem[] for AI actions in the floating toolbar.
30
+ *
31
+ * Returns toolbar items (divider + AI sparkle button) and
32
+ * state for controlling the ChatInline panel.
33
+ */
34
+ export declare function useChatInlineToolbarItems(options?: ChatInlineToolbarOptions): ChatInlineToolbarState;
35
+ export default useChatInlineToolbarItems;
@@ -0,0 +1,91 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * useChatInlineToolbarItems - Hook that creates ToolbarItem[] for the
7
+ * FloatingTextFormatToolbarPlugin's extraItems prop.
8
+ *
9
+ * Registers an AI sparkle button in the floating inline toolbar.
10
+ * Clicking the sparkle button directly opens the ChatInlinePlugin
11
+ * floating panel, where users can type free-form AI prompts.
12
+ *
13
+ * Usage:
14
+ * ```tsx
15
+ * const { toolbarItems, isAiOpen, pendingPrompt, clearPendingPrompt, closeAi } =
16
+ * useChatInlineToolbarItems();
17
+ *
18
+ * <FloatingTextFormatToolbarPlugin
19
+ * anchorElem={floatingAnchorElem}
20
+ * setIsLinkEditMode={setIsLinkEditMode}
21
+ * extraItems={toolbarItems}
22
+ * />
23
+ *
24
+ * <ChatInlinePlugin
25
+ * isOpen={isAiOpen}
26
+ * onClose={closeAi}
27
+ * pendingPrompt={pendingPrompt}
28
+ * onPendingPromptConsumed={clearPendingPrompt}
29
+ * />
30
+ * ```
31
+ *
32
+ * @module lexical/useChatInlineToolbarItems
33
+ */
34
+ import { useState, useMemo, useCallback } from 'react';
35
+ import { SparkleFillIcon } from '@primer/octicons-react';
36
+ /**
37
+ * Hook that creates ToolbarItem[] for AI actions in the floating toolbar.
38
+ *
39
+ * Returns toolbar items (divider + AI sparkle button) and
40
+ * state for controlling the ChatInline panel.
41
+ */
42
+ export function useChatInlineToolbarItems(options) {
43
+ const [isAiOpen, setIsAiOpen] = useState(false);
44
+ const [pendingPrompt, setPendingPrompt] = useState(null);
45
+ const openAi = useCallback(() => {
46
+ setIsAiOpen(true);
47
+ }, []);
48
+ const closeAi = useCallback(() => {
49
+ setIsAiOpen(false);
50
+ setPendingPrompt(null);
51
+ }, []);
52
+ const submitPrompt = useCallback((prompt) => {
53
+ setPendingPrompt(prompt);
54
+ setIsAiOpen(true);
55
+ }, []);
56
+ const clearPendingPrompt = useCallback(() => {
57
+ setPendingPrompt(null);
58
+ }, []);
59
+ const isDisabled = options?.disabled ?? false;
60
+ const toolbarItems = useMemo(() => {
61
+ return [
62
+ {
63
+ key: 'ai-divider',
64
+ type: 'divider',
65
+ order: 900,
66
+ },
67
+ {
68
+ key: 'ai-actions',
69
+ type: 'button',
70
+ order: 901,
71
+ ariaLabel: 'AI Actions',
72
+ title: isDisabled
73
+ ? 'Assign an agent to enable AI actions'
74
+ : 'AI Actions',
75
+ icon: SparkleFillIcon,
76
+ onClick: openAi,
77
+ disabled: isDisabled,
78
+ },
79
+ ];
80
+ }, [openAi, isDisabled]);
81
+ return {
82
+ toolbarItems,
83
+ isAiOpen,
84
+ submitPrompt,
85
+ pendingPrompt,
86
+ clearPendingPrompt,
87
+ openAi,
88
+ closeAi,
89
+ };
90
+ }
91
+ export default useChatInlineToolbarItems;
@@ -82,7 +82,7 @@ export interface UseAgentRuntimeReturn {
82
82
  * <>
83
83
  * <Notebook />
84
84
  * {isReady && (
85
- * <ChatFloating endpoint={endpoint} tools={tools} />
85
+ * <ChatFloating endpoint={endpoint} frontendTools={frontendTools} />
86
86
  * )}
87
87
  * {error && <ErrorBanner>{error}</ErrorBanner>}
88
88
  * </>
@@ -57,7 +57,7 @@ import { useRuntimeStore, useRuntime, useAgent, useRuntimeStatus, useRuntimeErro
57
57
  * <>
58
58
  * <Notebook />
59
59
  * {isReady && (
60
- * <ChatFloating endpoint={endpoint} tools={tools} />
60
+ * <ChatFloating endpoint={endpoint} frontendTools={frontendTools} />
61
61
  * )}
62
62
  * {error && <ErrorBanner>{error}</ErrorBanner>}
63
63
  * </>
@@ -5,7 +5,8 @@
5
5
  * THIS FILE IS AUTO-GENERATED. DO NOT EDIT MANUALLY.
6
6
  * Generated from YAML specifications in specs/agents/
7
7
  */
8
- import type { AgentSpec } from '../../../types';
8
+ import type { AgentSpec } from '../../../types/Types';
9
+ export declare const DATA_ACQUISITION_AGENT_SPEC: AgentSpec;
9
10
  export declare const SIMPLE_AGENT_SPEC: AgentSpec;
10
11
  export declare const AGENT_SPECS: Record<string, AgentSpec>;
11
12
  /**
@@ -14,8 +15,10 @@ export declare const AGENT_SPECS: Record<string, AgentSpec>;
14
15
  export declare function getAgentSpecs(agentId: string): AgentSpec | undefined;
15
16
  /**
16
17
  * List all available agent specifications.
18
+ *
19
+ * @param prefix - If provided, only return specs whose ID starts with this prefix.
17
20
  */
18
- export declare function listAgentSpecs(): AgentSpec[];
21
+ export declare function listAgentSpecs(prefix?: string): AgentSpec[];
19
22
  /**
20
23
  * Collect all required environment variables for an agent spec.
21
24
  *