@datalayer/agent-runtimes 1.3.75 → 1.3.79

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 (110) hide show
  1. package/lib/agents/AgentDetails.d.ts +16 -2
  2. package/lib/agents/AgentDetails.js +381 -272
  3. package/lib/chat/ChatFloating.d.ts +12 -2
  4. package/lib/chat/ChatFloating.js +48 -11
  5. package/lib/chat/assistant/AgentDetailsDialog.d.ts +21 -0
  6. package/lib/chat/assistant/AgentDetailsDialog.js +19 -0
  7. package/lib/chat/assistant/AssistantStage.d.ts +51 -5
  8. package/lib/chat/assistant/AssistantStage.js +60 -10
  9. package/lib/chat/assistant/BalloonParts.d.ts +18 -4
  10. package/lib/chat/assistant/BalloonParts.js +46 -41
  11. package/lib/chat/assistant/BalloonVisual.js +2 -1
  12. package/lib/chat/assistant/SandboxDetailsDialog.d.ts +44 -0
  13. package/lib/chat/assistant/SandboxDetailsDialog.js +214 -0
  14. package/lib/chat/assistant/SpeechBalloon.d.ts +8 -6
  15. package/lib/chat/assistant/SpeechBalloon.js +29 -30
  16. package/lib/chat/assistant/assistantDetails.d.ts +84 -0
  17. package/lib/chat/assistant/assistantDetails.js +140 -0
  18. package/lib/chat/assistant/formats/files.d.ts +23 -0
  19. package/lib/chat/assistant/formats/files.js +48 -0
  20. package/lib/chat/assistant/formats/index.d.ts +2 -0
  21. package/lib/chat/assistant/formats/index.js +1 -0
  22. package/lib/chat/assistant/state.d.ts +7 -14
  23. package/lib/chat/assistant/state.js +21 -20
  24. package/lib/chat/assistant/toolLine.d.ts +16 -0
  25. package/lib/chat/assistant/toolLine.js +46 -0
  26. package/lib/chat/base/ChatBase.js +20 -0
  27. package/lib/chat/base/loopMessage.d.ts +37 -0
  28. package/lib/chat/base/loopMessage.js +37 -0
  29. package/lib/chat/messages/ChatMarkdown.d.ts +16 -0
  30. package/lib/chat/messages/ChatMarkdown.js +18 -0
  31. package/lib/chat/messages/ChatMessageList.d.ts +8 -1
  32. package/lib/chat/messages/ChatMessageList.js +24 -18
  33. package/lib/chat/styles/streamdownStyles.js +3 -1
  34. package/lib/chat/tools/ToolCallDisplay.d.ts +8 -1
  35. package/lib/chat/tools/ToolCallDisplay.js +8 -7
  36. package/lib/components/code-sandboxes/CodeSandboxCellVariablesDialog.js +5 -11
  37. package/lib/components/code-sandboxes/CodeSandboxVariables.d.ts +8 -0
  38. package/lib/components/code-sandboxes/CodeSandboxVariables.js +17 -11
  39. package/lib/components/teams/A2ATeamGraph.d.ts +30 -3
  40. package/lib/components/teams/A2ATeamGraph.js +264 -41
  41. package/lib/components/teams/TeamNotebookView.js +15 -0
  42. package/lib/components/teams/teamNotebookKernel.d.ts +3 -0
  43. package/lib/components/teams/teamNotebookKernel.js +17 -0
  44. package/lib/components/teams/useA2ATeam.d.ts +10 -6
  45. package/lib/components/teams/useA2ATeam.js +29 -8
  46. package/lib/examples/AgentA2ATeamExample.js +6 -0
  47. package/lib/examples/AssistantExample.js +3 -24
  48. package/lib/examples/AssistantGalleryExample.js +2 -1
  49. package/lib/examples/exampleGroups.d.ts +1 -1
  50. package/lib/examples/exampleGroups.js +1 -1
  51. package/lib/examples/utils/assistantGallery.d.ts +7 -6
  52. package/lib/examples/utils/assistantGallery.js +23 -8
  53. package/lib/jupyter/exec/Python.d.ts +0 -1
  54. package/lib/jupyter/exec/Python.js +0 -32
  55. package/lib/jupyter/exec/Snippets.d.ts +4 -12
  56. package/lib/jupyter/exec/Snippets.js +0 -8
  57. package/lib/loop/apps/AppFeedback.js +3 -1
  58. package/lib/loop/apps/AppKept.d.ts +22 -0
  59. package/lib/loop/apps/AppKept.js +36 -0
  60. package/lib/loop/apps/AppRenderer.d.ts +11 -1
  61. package/lib/loop/apps/AppRenderer.js +21 -3
  62. package/lib/loop/apps/checks.d.ts +7 -0
  63. package/lib/loop/apps/checks.js +39 -0
  64. package/lib/loop/apps/index.d.ts +3 -0
  65. package/lib/loop/apps/index.js +3 -0
  66. package/lib/loop/apps/kept.d.ts +30 -0
  67. package/lib/loop/apps/kept.js +52 -0
  68. package/lib/loop/apps/records.d.ts +12 -4
  69. package/lib/loop/apps/records.js +13 -5
  70. package/lib/loop/apps/saved.d.ts +30 -0
  71. package/lib/loop/apps/saved.js +40 -0
  72. package/lib/loop/embed/AppEmbed.d.ts +8 -1
  73. package/lib/loop/embed/AppEmbed.js +4 -4
  74. package/lib/loop/embed/LoopEmbed.d.ts +6 -1
  75. package/lib/loop/embed/LoopEmbed.js +4 -2
  76. package/lib/loop/embed/element.js +1 -1
  77. package/lib/loop/plugins/agents/DatalayerAgentBridge.js +12 -6
  78. package/lib/loop/plugins/agents/browserService.d.ts +7 -1
  79. package/lib/loop/plugins/agents/browserService.js +4 -0
  80. package/lib/loop/plugins/agents/plugin.d.ts +16 -0
  81. package/lib/loop/plugins/agents/switchable.d.ts +3 -0
  82. package/lib/loop/plugins/agents/switchable.js +1 -0
  83. package/lib/loop/plugins/app-activity/index.js +3 -0
  84. package/lib/loop/plugins/app-computer/index.js +3 -0
  85. package/lib/loop/plugins/app-rules/AppRulesCard.d.ts +5 -0
  86. package/lib/loop/plugins/app-rules/AppRulesCard.js +25 -6
  87. package/lib/loop/plugins/app-rules/index.js +3 -0
  88. package/lib/loop/plugins/assistant/index.d.ts +7 -2
  89. package/lib/loop/plugins/assistant/index.js +53 -4
  90. package/lib/loop/plugins/assistant-characters/index.d.ts +7 -0
  91. package/lib/loop/plugins/assistant-characters/index.js +17 -0
  92. package/lib/loop/plugins/chat/ChatView.js +4 -1
  93. package/lib/loop/plugins/page-layout/SplitLayout.d.ts +2 -1
  94. package/lib/loop/plugins/page-layout/SplitLayout.js +4 -0
  95. package/lib/loop/presets.d.ts +4 -0
  96. package/lib/loop/presets.js +3 -1
  97. package/lib/loop/shell/LoopWorkspace.d.ts +7 -0
  98. package/lib/loop/shell/LoopWorkspace.js +5 -4
  99. package/lib/loop/shell/SidebarRail.d.ts +53 -0
  100. package/lib/loop/shell/SidebarRail.js +74 -0
  101. package/lib/loop/shell/index.d.ts +2 -0
  102. package/lib/loop/shell/index.js +2 -0
  103. package/lib/loop/shell/paneMotion.d.ts +21 -0
  104. package/lib/loop/shell/paneMotion.js +37 -0
  105. package/lib/specs/apps.js +8 -5
  106. package/lib/specs/uiPlugins.js +529 -0
  107. package/lib/types/agentspecs.d.ts +5 -3
  108. package/lib/types/chat.d.ts +5 -0
  109. package/package.json +2 -2
  110. package/scripts/codegen/generate_ui_plugins.py +112 -2
@@ -14,13 +14,12 @@ import { Fragment, useState, useCallback, useEffect, useMemo, useRef, } from 're
14
14
  import { Text, Spinner, Link, Label, RelativeTime } from '@primer/react';
15
15
  import { ArrowRightIcon, BroadcastIcon, ClockIcon, DependabotIcon, PersonIcon, SkipIcon, ToolsIcon, XCircleFillIcon, } from '@primer/octicons-react';
16
16
  import { Box } from '@datalayer/primer-addons';
17
- import { Streamdown } from 'streamdown';
18
- import { streamdownMarkdownStyles, streamdownCodeBlockStyles, } from '../styles/streamdownStyles';
17
+ import { streamdownCodeBlockStyles } from '../styles/streamdownStyles';
18
+ import { ChatMarkdown } from './ChatMarkdown';
19
19
  import { ToolCallDisplay } from '../tools/ToolCallDisplay';
20
20
  import { marksOfToolCall, skillIdOfCall } from '../marks';
21
21
  import { TypingDots } from '../indicators/TypingDots';
22
22
  import { TurnFooter } from './TurnFooter';
23
- import { normalizeAssistantMarkdown } from './assistantMarkdown';
24
23
  import { parseFormSubmission } from './formSubmission';
25
24
  import { FormSubmissionMessage } from './FormSubmissionMessage';
26
25
  import { isToolCallMessage, getMessageText } from '../../utils';
@@ -263,7 +262,7 @@ export function SubagentChatPanel({ toolCallId, subagentName: subagentNameHint,
263
262
  // DefaultToolCallRenderer — reads approvals from the Zustand store,
264
263
  // sends decisions over the shared WebSocket (no REST polling).
265
264
  // ---------------------------------------------------------------------------
266
- function DefaultToolCallRenderer({ item, onRespond, mcpServers, }) {
265
+ function DefaultToolCallRenderer({ item, onRespond, mcpServers, density, }) {
267
266
  const resultObject = item.result && typeof item.result === 'object'
268
267
  ? item.result
269
268
  : undefined;
@@ -379,12 +378,18 @@ function DefaultToolCallRenderer({ item, onRespond, mcpServers, }) {
379
378
  ? () => makeDecision('approve')
380
379
  : undefined, onDeny: effectiveApprovalId && !decision && !externalDecision
381
380
  ? () => makeDecision('reject')
382
- : undefined, approvalLoading: false, marks: marks }), isSubagentDelegation && (_jsx(SubagentChatPanel, { toolCallId: item.toolCallId, subagentName: delegatedSubagentName }))] }));
381
+ : undefined, approvalLoading: false, marks: marks, summary: item.summary, density: density }), isSubagentDelegation && (_jsx(SubagentChatPanel, { toolCallId: item.toolCallId, subagentName: delegatedSubagentName }))] }));
383
382
  }
384
383
  // ---------------------------------------------------------------------------
385
384
  // Component
386
385
  // ---------------------------------------------------------------------------
387
- export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoadingIndicator, hideMessagesAfterToolUI, avatarConfig, padding, renderToolResult, emptyContent, messagesEndRef, onRespond, approvalConfig, showTurnFooters = false, agentUsage, onRemoveItems, renderMessageFooter, mcpServers, }) {
386
+ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoadingIndicator, hideMessagesAfterToolUI, avatarConfig, padding, renderToolResult, emptyContent, messagesEndRef, onRespond, approvalConfig, showTurnFooters = false, agentUsage, onRemoveItems, renderMessageFooter, mcpServers, density = 'comfortable', }) {
387
+ const compact = density === 'compact';
388
+ if (compact) {
389
+ // The balloon's: no avatars, no turn footers.
390
+ avatarConfig = { ...avatarConfig, showAvatars: false };
391
+ showTurnFooters = false;
392
+ }
388
393
  if (displayItems.length === 0) {
389
394
  return _jsx(_Fragment, { children: emptyContent });
390
395
  }
@@ -486,7 +491,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
486
491
  not care about hid those tools entirely. Offering the default as a
487
492
  node lets it compose instead of choosing.
488
493
  */
489
- const defaultUI = (_jsx(DefaultToolCallRenderer, { item: item, approvalConfig: approvalConfig, onRespond: createRespondCallback(item.toolCallId), mcpServers: mcpServers }));
494
+ const defaultUI = (_jsx(DefaultToolCallRenderer, { item: item, approvalConfig: approvalConfig, onRespond: createRespondCallback(item.toolCallId), mcpServers: mcpServers, density: density }));
490
495
  const toolUI = renderToolResult
491
496
  ? renderToolResult({
492
497
  toolCallId: item.toolCallId,
@@ -502,7 +507,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
502
507
  : defaultUI;
503
508
  if (toolUI === null || toolUI === undefined)
504
509
  return null;
505
- return (_jsx(Box, { sx: {
510
+ return (_jsx(Box, { "data-chat-tool-row": item.toolName, sx: {
506
511
  display: 'flex',
507
512
  flexDirection: 'column',
508
513
  alignItems: 'flex-start',
@@ -517,7 +522,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
517
522
  */
518
523
  width: '100%',
519
524
  px: padding,
520
- py: 1,
525
+ py: compact ? '2px' : 1,
521
526
  }, children: toolUI }, item.id));
522
527
  }
523
528
  // ---- Chat message item ----
@@ -586,12 +591,12 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
586
591
  }
587
592
  }
588
593
  }
589
- return (_jsx(Box, { sx: {
594
+ return (_jsx(Box, { "data-chat-message": message.role, sx: {
590
595
  display: 'flex',
591
596
  flexDirection: 'column',
592
597
  alignItems: isUser ? 'flex-end' : 'flex-start',
593
598
  px: padding,
594
- py: 1,
599
+ py: compact ? '2px' : 1,
595
600
  }, children: _jsxs(Box, { sx: {
596
601
  display: 'flex',
597
602
  gap: 2,
@@ -635,7 +640,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
635
640
  ? speaker.initials || '?'
636
641
  : isUser
637
642
  ? avatarConfig.userAvatar
638
- : avatarConfig.assistantAvatar })), _jsxs(Box, { sx: { maxWidth: '85%', minWidth: 0 }, children: [speaker ? (_jsxs(Box, { sx: {
643
+ : avatarConfig.assistantAvatar })), _jsxs(Box, { sx: { maxWidth: compact ? '92%' : '85%', minWidth: 0 }, children: [speaker ? (_jsxs(Box, { sx: {
639
644
  display: 'flex',
640
645
  gap: 2,
641
646
  alignItems: 'baseline',
@@ -657,7 +662,8 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
657
662
  fontSize: 1,
658
663
  color: toneColorsOf(message.directedTo.tone).fg,
659
664
  }, children: message.directedTo.name })] })) : speaker.role ? (_jsx(Label, { size: "small", children: speaker.role })) : null, message.createdAt ? (_jsx(RelativeTime, { datetime: message.createdAt.toISOString(), sx: { fontSize: 0, color: 'fg.muted' } })) : null] })) : null, _jsxs(Box, { sx: {
660
- p: 2,
665
+ p: compact ? 1 : 2,
666
+ px: compact ? 2 : 2,
661
667
  overflowX: 'auto',
662
668
  // The theme's bubble (LOOP T-03, T-06): today's 6px elsewhere.
663
669
  borderRadius: 'var(--theme-radius-bubble, 6px)',
@@ -696,7 +702,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
696
702
  const text = getMessageText(message);
697
703
  const submission = parseFormSubmission(text);
698
704
  return submission ? (_jsx(FormSubmissionMessage, { submission: submission })) : (_jsxs(Text, { sx: {
699
- fontSize: 1,
705
+ fontSize: compact ? 0 : 1,
700
706
  whiteSpace: 'pre-wrap',
701
707
  wordBreak: 'break-word',
702
708
  }, children: [message.metadata?.input === 'voice' ? (_jsx(Box, { as: "span", "data-spoken": "", title: "Said aloud", "aria-label": "Said aloud:", sx: {
@@ -705,7 +711,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
705
711
  mr: 1,
706
712
  opacity: 0.85,
707
713
  }, children: _jsx(MicrophoneIcon, { size: 14, "aria-hidden": "true" }) })) : null, text] }));
708
- })()) : message.live && !getMessageText(message) ? (_jsx(TypingDots, { size: 6 })) : (_jsx(Box, { sx: streamdownMarkdownStyles, children: _jsx(Streamdown, { children: normalizeAssistantMarkdown(getMessageText(message) || (isStreaming ? '...' : '')) }) }))] }), renderMessageFooter ? (_jsx(Box, { sx: {
714
+ })()) : message.live && !getMessageText(message) ? (_jsx(TypingDots, { size: 6 })) : (_jsx(ChatMarkdown, { density: density, text: getMessageText(message) || (isStreaming ? '...' : '') }))] }), renderMessageFooter ? (_jsx(Box, { sx: {
709
715
  display: 'flex',
710
716
  gap: 2,
711
717
  alignItems: 'center',
@@ -721,7 +727,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
721
727
  return null;
722
728
  }
723
729
  return (_jsxs(Fragment, { children: [itemUI, footer] }, item.id));
724
- }), showLoadingIndicator && (isLoading || isStreaming) && (_jsx(Box, { sx: {
730
+ }), showLoadingIndicator && (isLoading || isStreaming) && (_jsx(Box, { "data-chat-typing": "", sx: {
725
731
  display: 'flex',
726
732
  alignItems: 'flex-start',
727
733
  px: padding,
@@ -743,9 +749,9 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
743
749
  }, children: avatarConfig.assistantAvatar })), _jsx(Box, { sx: {
744
750
  display: 'flex',
745
751
  alignItems: 'center',
746
- p: 2,
752
+ p: compact ? 1 : 2,
747
753
  borderRadius: 'var(--theme-radius-bubble, 6px)',
748
754
  bg: 'canvas.subtle',
749
- minHeight: '32px',
755
+ minHeight: compact ? '20px' : '32px',
750
756
  }, children: _jsx(TypingDots, {}) })] }) })), _jsx("div", { ref: messagesEndRef })] }));
751
757
  }
@@ -215,8 +215,10 @@ export const streamdownMarkdownStyles = {
215
215
  marginRight: 0,
216
216
  color: 'fg.muted',
217
217
  },
218
+ // A link reads as its theme says (LOOP T-06): in the accent, or plain —
219
+ // the colour of the words around it — and underlined in every theme.
218
220
  '& a': {
219
- color: 'accent.fg',
221
+ color: 'var(--theme-message-link, var(--fgColor-accent, #0969da))',
220
222
  textDecoration: 'underline',
221
223
  },
222
224
  '& table': {
@@ -50,6 +50,13 @@ export interface ToolCallDisplayProps {
50
50
  * icon, else the emoji, else nothing.
51
51
  */
52
52
  marks?: Marks | null;
53
+ /** What it does in its runtime's words: shown in place of the arguments. */
54
+ summary?: string;
55
+ /**
56
+ * How dense: the chat's (`comfortable`), or the floating assistant's
57
+ * balloon (`compact`: a smaller header, the same card).
58
+ */
59
+ density?: 'comfortable' | 'compact';
53
60
  }
54
61
  /**
55
62
  * ToolCallDisplay component - Default display for tool calls in chat
@@ -61,5 +68,5 @@ export interface ToolCallDisplayProps {
61
68
  * - Color-coded status indicators
62
69
  * - Rich error display distinguishing execution errors from code errors
63
70
  */
64
- export declare function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, approvalRequired, approvalState, approvalDecisionSource, onApprove, onDeny, approvalLoading, marks, }: ToolCallDisplayProps): React.JSX.Element;
71
+ export declare function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, approvalRequired, approvalState, approvalDecisionSource, onApprove, onDeny, approvalLoading, marks, summary, density, }: ToolCallDisplayProps): React.JSX.Element;
65
72
  export default ToolCallDisplay;
@@ -125,7 +125,8 @@ function getArgsSummary(args) {
125
125
  * - Color-coded status indicators
126
126
  * - Rich error display distinguishing execution errors from code errors
127
127
  */
128
- export function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, approvalRequired = false, approvalState, approvalDecisionSource, onApprove, onDeny, approvalLoading = false, marks, }) {
128
+ export function ToolCallDisplay({ toolCallId, toolName, args, result, status, error, executionResult, codeError, exitCode, executionError, approvalRequired = false, approvalState, approvalDecisionSource, onApprove, onDeny, approvalLoading = false, marks, summary, density = 'comfortable', }) {
129
+ const compact = density === 'compact';
129
130
  const [isExpanded, setIsExpanded] = useState(false);
130
131
  // Determine effective exit code from props or execution result
131
132
  const effectiveExitCode = exitCode ?? executionResult?.exit_code;
@@ -143,7 +144,7 @@ export function ToolCallDisplay({ toolCallId, toolName, args, result, status, er
143
144
  : undefined;
144
145
  const statusDisplay = getStatusDisplay(status, errorType);
145
146
  const displayName = formatToolName(toolName);
146
- const argsSummary = getArgsSummary(args);
147
+ const argsSummary = summary || getArgsSummary(args);
147
148
  const resultObject = result && typeof result === 'object'
148
149
  ? result
149
150
  : undefined;
@@ -168,19 +169,19 @@ export function ToolCallDisplay({ toolCallId, toolName, args, result, status, er
168
169
  result.stderr ??
169
170
  undefined)
170
171
  : undefined);
171
- return (_jsxs(Box, { sx: {
172
+ return (_jsxs(Box, { "data-tool-call": toolName, "data-tool-call-status": status, sx: {
172
173
  width: '100%',
173
174
  border: '1px solid',
174
175
  borderColor: 'border.default',
175
- borderRadius: '12px',
176
+ borderRadius: compact ? '8px' : '12px',
176
177
  overflow: 'hidden',
177
178
  backgroundColor: 'canvas.default',
178
179
  }, children: [_jsxs(Box, { as: "button", onClick: () => setIsExpanded(!isExpanded), sx: {
179
180
  width: '100%',
180
181
  display: 'flex',
181
182
  alignItems: 'center',
182
- gap: 2,
183
- padding: 2,
183
+ gap: compact ? 1 : 2,
184
+ padding: compact ? 1 : 2,
184
185
  backgroundColor: 'canvas.subtle',
185
186
  border: 'none',
186
187
  borderBottom: isExpanded ? '1px solid' : 'none',
@@ -192,7 +193,7 @@ export function ToolCallDisplay({ toolCallId, toolName, args, result, status, er
192
193
  },
193
194
  }, children: [_jsx(Box, { sx: { color: 'fg.muted', flexShrink: 0 }, children: isExpanded ? (_jsx(ChevronDownIcon, { size: 16 })) : (_jsx(ChevronRightIcon, { size: 16 })) }), hasMark(marks) && (_jsx(Box, { sx: { color: 'fg.muted', flexShrink: 0, display: 'flex' }, children: _jsx(SpecMark, { icon: marks?.icon, emoji: marks?.emoji, size: 16 }) })), _jsx(Text, { sx: {
194
195
  fontWeight: 'semibold',
195
- fontSize: 1,
196
+ fontSize: compact ? 0 : 1,
196
197
  color: 'fg.default',
197
198
  flexShrink: 0,
198
199
  }, children: displayName }), _jsxs(Box, { sx: {
@@ -3,8 +3,9 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
3
3
  import { Dialog } from '@primer/react/experimental';
4
4
  import { nullTranslator } from '@jupyterlab/translation';
5
5
  import { JSONExt } from '@lumino/coreutils';
6
- import { KernelExecutor } from '@datalayer/jupyter-react';
6
+ import { kernelConnectionExecutor, listKernelVariables, } from '@datalayer/jupyter-react';
7
7
  import { RuntimeSnippetsFacade } from '../../jupyter';
8
+ import { transferableVariables } from './CodeSandboxVariables';
8
9
  import { CodeSandboxCellVariables } from './CodeSandboxCellVariables';
9
10
  /**
10
11
  * Dialog to define the runtime cell variables to transfer
@@ -53,16 +54,9 @@ export function CodeSandboxCellVariablesDialog(props) {
53
54
  }
54
55
  const connection = sessionContext.session.kernel;
55
56
  const spec = sessionContext.specsManager.specs.kernelspecs[connection.model.name];
56
- const snippets = new RuntimeSnippetsFacade(spec.language);
57
- const outputs = await new KernelExecutor({ connection }).execute(snippets.listVariables());
58
- const content = outputs.get(0).data['text/plain'];
59
- if (content) {
60
- const runtimeVariables = JSON.parse(
61
- // We need to remove the quotes prior to parsing
62
- content.slice(1, content.length - 1));
63
- return Object.keys(runtimeVariables ?? {});
64
- }
65
- return [];
57
+ return Object.keys(transferableVariables(await listKernelVariables(kernelConnectionExecutor(connection), {
58
+ language: spec.language,
59
+ })));
66
60
  }, [preference, sessionContext]);
67
61
  const getOutputCandidates = useCallback(async () => {
68
62
  // TODO this is only valid for python - using cell mimetype?
@@ -1,7 +1,15 @@
1
1
  import { ReactElement } from 'react';
2
2
  import { ISessionContext } from '@jupyterlab/apputils';
3
3
  import { ITranslator } from '@jupyterlab/translation';
4
+ import { type KernelVariable } from '@datalayer/jupyter-react';
4
5
  import type { IRuntimeDesc } from '../../models';
6
+ /**
7
+ * The variables that can be carried to another sandbox, by name and type:
8
+ * values, not the modules, functions and classes code defines again.
9
+ */
10
+ export declare function transferableVariables(variables: readonly KernelVariable[]): {
11
+ [name: string]: string;
12
+ };
5
13
  /** What {@link useCodeSandboxVariablesTransfer} answers. */
6
14
  export interface ICodeSandboxVariablesTransfer {
7
15
  /**
@@ -10,8 +10,19 @@ import { Blankslate, DataTable, Table } from '@primer/react/experimental';
10
10
  import { nullTranslator } from '@jupyterlab/translation';
11
11
  import { checkIcon } from '@jupyterlab/ui-components';
12
12
  import { JSONExt } from '@lumino/coreutils';
13
- import { KernelExecutor } from '@datalayer/jupyter-react';
13
+ import { kernelConnectionExecutor, listKernelVariables, } from '@datalayer/jupyter-react';
14
14
  import { RuntimeSnippetsFacade } from '../../jupyter';
15
+ /**
16
+ * The variables that can be carried to another sandbox, by name and type:
17
+ * values, not the modules, functions and classes code defines again.
18
+ */
19
+ export function transferableVariables(variables) {
20
+ return Object.fromEntries(variables
21
+ .filter(variable => variable.kind !== 'module' &&
22
+ variable.kind !== 'function' &&
23
+ variable.kind !== 'class')
24
+ .map(variable => [variable.name, variable.type]));
25
+ }
15
26
  /**
16
27
  * The variables of the current sandbox, and which of them to carry over.
17
28
  *
@@ -45,18 +56,13 @@ export function useCodeSandboxVariablesTransfer(sessionContext, target, enabled
45
56
  setVariables({});
46
57
  return;
47
58
  }
48
- const snippets = new RuntimeSnippetsFacade(spec.language);
49
- const outputs = await new KernelExecutor({ connection }).execute(snippets.listVariables());
50
- const content = outputs.get(0).data['text/plain'];
51
- if (!content) {
52
- setVariables({});
53
- return;
54
- }
55
- // The payload comes quoted, as the representation of a string.
56
- const listedVariables = JSON.parse(content.slice(1, content.length - 1));
59
+ // jupyter-react's snippet, run silently: the variables, typed.
60
+ const listedVariables = transferableVariables(await listKernelVariables(kernelConnectionExecutor(connection), {
61
+ language: spec.language,
62
+ }));
57
63
  setVariables(listedVariables);
58
64
  // Everything is carried over unless the user says otherwise.
59
- setSelectedState(Object.keys(listedVariables ?? {}));
65
+ setSelectedState(Object.keys(listedVariables));
60
66
  }, [listed, sessionContext]);
61
67
  const setSelected = useCallback((names) => {
62
68
  setSelectedState(current => JSONExt.deepEqual(current, names) ? current : names);
@@ -27,8 +27,9 @@ import { type Edge, type EdgeProps, type Viewport } from '@xyflow/react';
27
27
  import '@xyflow/react/dist/base.css';
28
28
  import { type AssistantAbout } from '../../chat/assistant/AssistantStage';
29
29
  import type { BalloonSuggestion } from '../../chat/assistant/SpeechBalloon';
30
- import type { BalloonHistoryMessage } from '../../chat/assistant/state';
30
+ import type { DisplayItem } from '../../types/chat';
31
31
  import type { AssistantMenuItem } from '../../chat/assistant/AssistantContextMenu';
32
+ import type { AssistantSandbox } from '../../chat/assistant/assistantDetails';
32
33
  import type { AgentInspectorSink } from '../inspector/agentInspector';
33
34
  import { type A2ATeamCall, type A2ATeamConnection, type A2ATeamFlow } from './a2aTeamFlow';
34
35
  import type { A2ATeamPersona } from './useA2ATeam';
@@ -83,8 +84,14 @@ export type A2ATeamGraphMember = {
83
84
  inspector?: AgentInspectorSink | null;
84
85
  /** Stops its turn, from its menu, while it works. */
85
86
  onStop?: () => void;
86
- /** What its menu's *About* says. */
87
+ /** What its menu's *About* and *Agent Details…* say. */
87
88
  about?: AssistantAbout;
89
+ /**
90
+ * Its code sandbox, for *Code Sandbox Details…*. The entry — the agent in
91
+ * the page — has the kernel of the notebook open under the graph, while
92
+ * one is.
93
+ */
94
+ sandbox?: AssistantSandbox;
88
95
  /** The host's own entries of its menu. */
89
96
  contextMenu?: readonly AssistantMenuItem[];
90
97
  /**
@@ -97,7 +104,7 @@ export type A2ATeamGraphMember = {
97
104
  * What it said and did, as its `history` balloon lists it (`useA2ATeam`'s
98
105
  * `entryHistory`, `peerHistory`): shown when its menu chooses *History*.
99
106
  */
100
- history?: readonly BalloonHistoryMessage[];
107
+ history?: readonly DisplayItem[];
101
108
  /** Its balloon's display was chosen in its menu: the page may keep it. */
102
109
  onBalloonDisplayChange?: (display: BalloonDisplay) => void;
103
110
  };
@@ -123,6 +130,26 @@ export type A2ATeamGraphProps = {
123
130
  */
124
131
  balloonRoom?: number;
125
132
  };
133
+ /** How far a member was moved from its place, in the graph's coordinates. */
134
+ export type MemberOffset = {
135
+ dx: number;
136
+ dy: number;
137
+ };
138
+ /** How far a member may move: its node stays inside the graph's box. */
139
+ export type MemberBounds = {
140
+ minDx: number;
141
+ maxDx: number;
142
+ minDy: number;
143
+ maxDy: number;
144
+ };
145
+ /** An offset kept inside its bounds. */
146
+ export declare function clampOffset(offset: MemberOffset, bounds: MemberBounds): MemberOffset;
147
+ /** A member's accessible name: its name, and where it runs. */
148
+ export declare function memberLabel(member: Pick<A2ATeamGraphMember, 'name' | 'where'>): string;
149
+ /** A connection's accessible name: `Odoo, Accounting's MCP connection`. */
150
+ export declare function connectionLabel(connection: Pick<A2ATeamConnection, 'label'>, member: string | undefined): string;
151
+ /** What a connection's details say: the server, who reaches it, and the call running now. */
152
+ export declare function connectionDetails(connection: Pick<A2ATeamConnection, 'name' | 'tools'>, member: string | undefined, calling?: string): string;
126
153
  /** The words on the edge for a flow. */
127
154
  export declare function flowWords(flow: A2ATeamFlow, entry: string, peer: string): string;
128
155
  type CallData = {