@datalayer/agent-runtimes 1.0.19 → 1.0.20

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 (141) hide show
  1. package/README.md +11 -3
  2. package/lib/AgentNode.js +141 -40
  3. package/lib/App.js +2 -2
  4. package/lib/agent-node/AgentNodeGallery.js +188 -25
  5. package/lib/api/runtimes/runtimes.d.ts +57 -0
  6. package/lib/api/runtimes/runtimes.js +55 -1
  7. package/lib/chat/Chat.d.ts +1 -1
  8. package/lib/chat/Chat.js +2 -2
  9. package/lib/chat/base/ChatBase.js +50 -13
  10. package/lib/chat/document/EphemeralDocument.d.ts +5 -1
  11. package/lib/chat/document/EphemeralDocument.js +7 -5
  12. package/lib/chat/header/ChatHeaderBase.d.ts +3 -1
  13. package/lib/chat/header/ChatHeaderBase.js +5 -3
  14. package/lib/chat/messages/ChatMessageList.d.ts +19 -0
  15. package/lib/chat/messages/ChatMessageList.js +180 -9
  16. package/lib/chat/notebook/EphemeralNotebook.d.ts +5 -1
  17. package/lib/chat/notebook/EphemeralNotebook.js +9 -6
  18. package/lib/chat/prompt/InputPrompt.js +1 -1
  19. package/lib/chat/tools/SubagentActivity.d.ts +20 -0
  20. package/lib/chat/tools/SubagentActivity.js +154 -0
  21. package/lib/chat/tools/index.d.ts +1 -0
  22. package/lib/chat/tools/index.js +1 -0
  23. package/lib/chat/usage/TokenUsageBar.js +3 -3
  24. package/lib/client/AgentRuntimesClient.d.ts +5 -0
  25. package/lib/client/AgentsMixin.js +3 -1
  26. package/lib/client/mixins/RuntimesMixin.d.ts +12 -0
  27. package/lib/client/mixins/RuntimesMixin.js +24 -1
  28. package/lib/components/AgentSummary.d.ts +1 -0
  29. package/lib/components/AgentSummary.js +66 -10
  30. package/lib/components/runtimes/RuntimePickerBase.js +64 -29
  31. package/lib/components/runtimes/RuntimePickerCell.js +1 -1
  32. package/lib/components/runtimes/RuntimePickerNotebook.js +1 -1
  33. package/lib/components/runtimes/RuntimeSimplePicker.js +3 -2
  34. package/lib/components/runtimes/RuntimeUtils.js +2 -2
  35. package/lib/context/GraphFlowChart.js +1 -1
  36. package/lib/context/TokenUsageChart.js +1 -1
  37. package/lib/context/TurnGraphChart.js +2 -2
  38. package/lib/examples/A2UiAgentExample.js +4 -4
  39. package/lib/examples/A2UiComponentsGalleryExample.js +3 -3
  40. package/lib/examples/A2UiContactCardExample.js +3 -3
  41. package/lib/examples/A2UiRestaurantExample.js +2 -2
  42. package/lib/examples/A2UiViewerExample.js +3 -3
  43. package/lib/examples/AgUiAgenticExample.js +3 -3
  44. package/lib/examples/AgUiBackendToolRenderingExample.js +2 -2
  45. package/lib/examples/AgUiHaikuGenUiExample.js +3 -3
  46. package/lib/examples/AgUiHumanInTheLoopExample.js +5 -5
  47. package/lib/examples/AgUiSharedStateExample.js +3 -3
  48. package/lib/examples/AgUiToolsBasedGenUiExample.js +7 -5
  49. package/lib/examples/AgentCheckpointsExample.js +6 -5
  50. package/lib/examples/{AgentSandboxExample.d.ts → AgentCodeSandboxExample.d.ts} +4 -4
  51. package/lib/examples/{AgentSandboxExample.js → AgentCodeSandboxExample.js} +10 -9
  52. package/lib/examples/AgentCodeSandboxesExample.js +2 -2
  53. package/lib/examples/AgentCodemodeExample.js +3 -3
  54. package/lib/examples/AgentCompactionExample.d.ts +12 -0
  55. package/lib/examples/AgentCompactionExample.js +244 -0
  56. package/lib/examples/AgentEvalsExample.js +10 -20
  57. package/lib/examples/AgentGuardrailsExample.js +2 -2
  58. package/lib/examples/AgentHooksExample.js +1 -1
  59. package/lib/examples/AgentInferenceProviderExample.js +6 -8
  60. package/lib/examples/AgentLoopExample.js +3 -3
  61. package/lib/examples/AgentMCPExample.js +3 -3
  62. package/lib/examples/AgentMemoryExample.d.ts +4 -2
  63. package/lib/examples/AgentMemoryExample.js +93 -10
  64. package/lib/examples/AgentMonitoringExample.js +2 -2
  65. package/lib/examples/AgentNotificationsExample.js +1 -1
  66. package/lib/examples/AgentOtelExample.d.ts +2 -3
  67. package/lib/examples/AgentOtelExample.js +7 -12
  68. package/lib/examples/AgentOutputsExample.js +5 -5
  69. package/lib/examples/AgentParametersExample.js +3 -3
  70. package/lib/examples/AgentSkillsExample.js +4 -4
  71. package/lib/examples/AgentSubagentsExample.d.ts +2 -2
  72. package/lib/examples/AgentSubagentsExample.js +43 -34
  73. package/lib/examples/AgentToolApprovalsExample.js +1 -1
  74. package/lib/examples/AgentTriggersExample.js +9 -11
  75. package/lib/examples/AgentspecsExample.js +13 -5
  76. package/lib/examples/CellExample.d.ts +6 -0
  77. package/lib/examples/CellExample.js +84 -0
  78. package/lib/examples/ChatCustomExample.js +1 -1
  79. package/lib/examples/ChatExample.js +1 -1
  80. package/lib/examples/ChatStandaloneExample.js +2 -2
  81. package/lib/examples/HomeExample.js +29 -28
  82. package/lib/examples/Lexical2Example.js +2 -2
  83. package/lib/examples/LexicalAgentExample.js +1 -1
  84. package/lib/examples/LexicalAgentSidebarExample.js +2 -2
  85. package/lib/examples/NotebookAgentSidebarExample.d.ts +1 -1
  86. package/lib/examples/NotebookAgentSidebarExample.js +5 -4
  87. package/lib/examples/NotebookCollaborationExample.js +3 -3
  88. package/lib/examples/NotebookExample.js +2 -2
  89. package/lib/examples/components/ExampleWrapper.js +5 -0
  90. package/lib/examples/components/Header.js +2 -2
  91. package/lib/examples/components/HeaderControls.js +1 -1
  92. package/lib/examples/components/LexicalEditor.js +1 -1
  93. package/lib/examples/components/MainContent.js +1 -1
  94. package/lib/examples/components/MockFileBrowser.js +8 -8
  95. package/lib/examples/components/TimeTravel.js +1 -1
  96. package/lib/examples/components/haiku/HaikuDisplay.js +2 -2
  97. package/lib/examples/example-selector.js +4 -3
  98. package/lib/examples/hooks/useExampleAgentRuntime.js +11 -1
  99. package/lib/examples/hooks/useExampleAgentRuntimes.d.ts +7 -0
  100. package/lib/examples/hooks/useExampleAgentRuntimes.js +82 -0
  101. package/lib/examples/index.d.ts +2 -1
  102. package/lib/examples/index.js +2 -1
  103. package/lib/examples/main.js +359 -46
  104. package/lib/examples/utils/agentSummaryStore.d.ts +17 -0
  105. package/lib/examples/utils/themedProvider.js +32 -2
  106. package/lib/examples/utils/useExampleAgentRuntimesUrl.js +2 -1
  107. package/lib/examples2/NotebookMutationsKernel.js +6 -3
  108. package/lib/examples2/NotebookMutationsServiceManager.js +6 -3
  109. package/lib/examples2/ReactRouterExample.js +5 -5
  110. package/lib/examples2/main.js +38 -0
  111. package/lib/hooks/useAIAgentsWebSocket.js +35 -0
  112. package/lib/hooks/useAgentRuntimes.d.ts +22 -0
  113. package/lib/hooks/useAgentRuntimes.js +192 -5
  114. package/lib/hooks/useCheckpoints.js +2 -2
  115. package/lib/hooks/useToolApprovals.d.ts +10 -4
  116. package/lib/hooks/useToolApprovals.js +11 -5
  117. package/lib/models/Runtime.d.ts +10 -8
  118. package/lib/models/RuntimeDTO.d.ts +5 -3
  119. package/lib/models/RuntimeDTO.js +3 -3
  120. package/lib/runtimes/actions.js +3 -1
  121. package/lib/runtimes/apis.d.ts +7 -0
  122. package/lib/specs/agents/agents.d.ts +51 -0
  123. package/lib/specs/agents/agents.js +3389 -94
  124. package/lib/specs/models.d.ts +2 -0
  125. package/lib/specs/models.js +37 -0
  126. package/lib/stores/agentRuntimeStore.d.ts +32 -1
  127. package/lib/stores/agentRuntimeStore.js +65 -1
  128. package/lib/stores/index.d.ts +1 -1
  129. package/lib/stores/index.js +1 -1
  130. package/lib/types/agents.d.ts +9 -3
  131. package/lib/types/agentspecs.d.ts +2 -0
  132. package/lib/types/chat.d.ts +12 -0
  133. package/lib/types/models.d.ts +5 -0
  134. package/lib/types/stream.d.ts +58 -1
  135. package/package.json +4 -4
  136. package/scripts/codegen/__pycache__/versioning.cpython-313.pyc +0 -0
  137. package/scripts/codegen/generate_agents.py +7 -0
  138. package/scripts/codegen/generate_models.py +22 -9
  139. package/scripts/gen_workers.py +340 -0
  140. package/lib/examples/CellSimpleExample.d.ts +0 -6
  141. package/lib/examples/CellSimpleExample.js +0 -20
@@ -40,6 +40,10 @@ export interface EphemeralDocumentProps {
40
40
  runtimePodName?: string;
41
41
  /** Optional explicit runtime endpoint (agent-node tunnel proxy path). */
42
42
  runtimeOverride?: EphemeralRuntimeOverride;
43
+ /** Optional theme variant override from host chat context. */
44
+ themeVariant?: string;
45
+ /** Optional color mode override from host chat context. */
46
+ colorMode?: 'light' | 'dark' | 'auto';
43
47
  /** Optional persisted Lexical editor state (JSON string) to restore. */
44
48
  content?: string;
45
49
  /** Callback fired when the document's editor state changes. */
@@ -63,5 +67,5 @@ export interface EphemeralDocumentProps {
63
67
  /**
64
68
  * Renders an in-memory Lexical document backed by a sandbox kernel.
65
69
  */
66
- export declare function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, content, onContentChange, onToolsReady, onKernelChange, collaboration, }: EphemeralDocumentProps): import("react/jsx-runtime").JSX.Element;
70
+ export declare function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, }: EphemeralDocumentProps): import("react/jsx-runtime").JSX.Element;
67
71
  export default EphemeralDocument;
@@ -108,7 +108,7 @@ function DocumentToolbar({ setIsLinkEditMode, }) {
108
108
  /**
109
109
  * Renders an in-memory Lexical document backed by a sandbox kernel.
110
110
  */
111
- export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, content, onContentChange, onToolsReady, onKernelChange, collaboration, }) {
111
+ export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride, themeVariant, colorMode, content, onContentChange, onToolsReady, onKernelChange, collaboration, }) {
112
112
  // Real-time collaboration is active only when both a WebSocket endpoint and a
113
113
  // room id are supplied. In that mode the shared Loro CRDT is the single source
114
114
  // of truth: local content-seeding and undo history are disabled so the local
@@ -296,10 +296,12 @@ export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride,
296
296
  // Resolve the active theme/color-mode exactly like the notebook editor so
297
297
  // the document honours dark / branded themes instead of always rendering
298
298
  // light.
299
- const { colorMode, theme: themeVariant } = useThemeStore();
299
+ const { colorMode: storeColorMode, theme: storeThemeVariant } = useThemeStore();
300
+ const effectiveColorMode = colorMode ?? storeColorMode;
301
+ const effectiveThemeVariant = themeVariant ?? storeThemeVariant;
300
302
  const systemMode = useSystemColorMode();
301
- const themeConfig = getThemeConfig(themeVariant);
302
- const resolvedMode = colorMode === 'auto' ? systemMode : colorMode;
303
+ const themeConfig = getThemeConfig(effectiveThemeVariant);
304
+ const resolvedMode = effectiveColorMode === 'auto' ? systemMode : effectiveColorMode;
303
305
  const modeStyles = resolvedMode === 'dark'
304
306
  ? themeConfig.themeStyles.dark
305
307
  : themeConfig.themeStyles.light;
@@ -311,7 +313,7 @@ export function EphemeralDocument({ documentId, runtimePodName, runtimeOverride,
311
313
  position: 'relative',
312
314
  overflow: 'hidden',
313
315
  bg: 'canvas.default',
314
- }, children: activeServiceManager ? (_jsx(DatalayerThemeProvider, { colorMode: colorMode, theme: themeConfig.primerTheme, themeStyles: themeConfig.themeStyles, children: _jsx(JupyterReactTheme, { colormode: resolvedMode, backgroundColor: themeBackground, children: _jsx(Box, { sx: {
316
+ }, children: activeServiceManager ? (_jsx(DatalayerThemeProvider, { colorMode: effectiveColorMode, theme: themeConfig.primerTheme, themeStyles: themeConfig.themeStyles, children: _jsx(JupyterReactTheme, { colormode: resolvedMode, backgroundColor: themeBackground, children: _jsx(Box, { sx: {
315
317
  position: 'absolute',
316
318
  inset: 0,
317
319
  display: 'flex',
@@ -26,6 +26,8 @@ export interface ChatBaseHeaderProps {
26
26
  padding: number;
27
27
  /** Optional kernel indicator state override from notebook runtime. */
28
28
  kernelIndicatorState?: ExecutionState;
29
+ /** Horizontal placement for the kernel indicator in the title row. */
30
+ kernelIndicatorPlacement?: 'left' | 'center' | 'right';
29
31
  /**
30
32
  * Runtime status from agent-runtimes sandbox status stream.
31
33
  * Uses the same execution-state model as KernelIndicator.
@@ -69,5 +71,5 @@ export interface ChatBaseHeaderProps {
69
71
  /** Callback fired when the user changes the companion-surface mode. */
70
72
  onEphemeralSurfaceModeChange?: (mode: EphemeralSurfaceMode) => void;
71
73
  }
72
- export declare function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, showEphemeralSurfaceControl, enableEphemeralNotebookOption, enableEphemeralDocumentOption, ephemeralSurfaceMode, onEphemeralSurfaceModeChange, }: ChatBaseHeaderProps): import("react/jsx-runtime").JSX.Element;
74
+ export declare function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, kernelIndicatorPlacement, runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, showEphemeralSurfaceControl, enableEphemeralNotebookOption, enableEphemeralDocumentOption, ephemeralSurfaceMode, onEphemeralSurfaceModeChange, }: ChatBaseHeaderProps): import("react/jsx-runtime").JSX.Element;
73
75
  export {};
@@ -29,11 +29,13 @@ export function toRuntimeExecutionState(runtimeStatus) {
29
29
  // ---------------------------------------------------------------------------
30
30
  // Component
31
31
  // ---------------------------------------------------------------------------
32
- export function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, showEphemeralSurfaceControl = false, enableEphemeralNotebookOption = false, enableEphemeralDocumentOption = false, ephemeralSurfaceMode = 'none', onEphemeralSurfaceModeChange, }) {
32
+ export function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, kernelIndicatorPlacement = 'left', runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, showEphemeralSurfaceControl = false, enableEphemeralNotebookOption = false, enableEphemeralDocumentOption = false, ephemeralSurfaceMode = 'none', onEphemeralSurfaceModeChange, }) {
33
33
  const effectiveIndicatorState = kernelIndicatorState ?? toRuntimeExecutionState(runtimeStatus);
34
+ const kernelIndicatorElement = kernel ? (_jsx(KernelIndicator, { kernel: kernel, environmentName: kernelEnvironmentName, cpu: kernelCpu, memory: kernelMemory, gpu: kernelGpu, position: "s", bordered: false })) : (_jsx(KernelIndicator, { state: effectiveIndicatorState ?? 'undefined', environmentName: kernelEnvironmentName, cpu: kernelCpu, memory: kernelMemory, gpu: kernelGpu, position: "s", bordered: false }));
34
35
  return (_jsx(Box, { sx: {
35
36
  display: 'flex',
36
37
  flexDirection: 'column',
38
+ bg: 'canvas.default',
37
39
  borderBottom: '1px solid',
38
40
  borderColor: 'border.default',
39
41
  }, children: _jsxs(Box, { sx: {
@@ -47,7 +49,7 @@ export function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, head
47
49
  gap: 2,
48
50
  minWidth: 0,
49
51
  flex: '1 1 auto',
50
- }, children: [brandIcon || _jsx(AiAgentIcon, { colored: true, size: 20 }), kernel ? (_jsx(KernelIndicator, { kernel: kernel, environmentName: kernelEnvironmentName, cpu: kernelCpu, memory: kernelMemory, gpu: kernelGpu, position: "s", bordered: false })) : (_jsx(KernelIndicator, { state: effectiveIndicatorState ?? 'undefined', environmentName: kernelEnvironmentName, cpu: kernelCpu, memory: kernelMemory, gpu: kernelGpu, position: "s", bordered: false })), (title || subtitle) && (_jsxs(Box, { sx: {
52
+ }, children: [kernelIndicatorPlacement === 'left' && kernelIndicatorElement, brandIcon || _jsx(AiAgentIcon, { colored: true, size: 20 }), (title || subtitle) && (_jsxs(Box, { sx: {
51
53
  display: 'flex',
52
54
  flexDirection: 'column',
53
55
  minWidth: 0,
@@ -62,7 +64,7 @@ export function ChatBaseHeader({ title, subtitle, brandIcon, headerContent, head
62
64
  color: 'fg.muted',
63
65
  minWidth: 0,
64
66
  maxWidth: '100%',
65
- }, children: _jsx(Truncate, { title: subtitle, maxWidth: "40ch", children: subtitle }) }))] })), headerContent, showInformation && (_jsx(IconButton, { icon: InfoIcon, "aria-label": "Information", variant: "invisible", size: "small", onClick: onInformationClick }))] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [headerButtons?.showNewChat && (_jsx(IconButton, { icon: PlusIcon, "aria-label": "New chat", variant: "invisible", size: "small", onClick: onNewChat })), headerButtons?.showClear && messageCount > 0 && (_jsx(IconButton, { icon: TrashIcon, "aria-label": "Clear messages", variant: "invisible", size: "small", onClick: onClear })), headerButtons?.showSettings && (_jsx(IconButton, { icon: GearIcon, "aria-label": "Settings", variant: "invisible", size: "small", onClick: headerButtons.onSettings })), showEphemeralSurfaceControl && (_jsx(Box, { sx: {
67
+ }, children: _jsx(Truncate, { title: subtitle, maxWidth: "40ch", children: subtitle }) }))] })), headerContent, showInformation && (_jsx(IconButton, { icon: InfoIcon, "aria-label": "Information", variant: "invisible", size: "small", onClick: onInformationClick })), kernelIndicatorPlacement === 'center' && kernelIndicatorElement] }), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }, children: [kernelIndicatorPlacement === 'right' && kernelIndicatorElement, headerButtons?.showNewChat && (_jsx(IconButton, { icon: PlusIcon, "aria-label": "New chat", variant: "invisible", size: "small", onClick: onNewChat })), headerButtons?.showClear && messageCount > 0 && (_jsx(IconButton, { icon: TrashIcon, "aria-label": "Clear messages", variant: "invisible", size: "small", onClick: onClear })), headerButtons?.showSettings && (_jsx(IconButton, { icon: GearIcon, "aria-label": "Settings", variant: "invisible", size: "small", onClick: headerButtons.onSettings })), showEphemeralSurfaceControl && (_jsx(Box, { sx: {
66
68
  display: 'inline-flex',
67
69
  alignItems: 'center',
68
70
  bg: 'neutral.muted',
@@ -46,4 +46,23 @@ export interface ChatMessageListProps {
46
46
  */
47
47
  approvalConfig?: ToolApprovalConfig;
48
48
  }
49
+ type SubagentAvatarConfig = Required<Pick<AvatarConfig, 'userAvatar' | 'assistantAvatar' | 'showAvatars' | 'avatarSize' | 'userAvatarBg' | 'assistantAvatarBg'>>;
50
+ export interface SubagentChatPanelProps {
51
+ /** Parent `delegate_task` tool call id used to look up streamed events. */
52
+ toolCallId: string;
53
+ /** Subagent name used as a fallback when the tool-call id does not match. */
54
+ subagentName?: string;
55
+ /** Fixed viewport height in pixels. */
56
+ height?: number;
57
+ /** Avatar configuration for the embedded message list. */
58
+ avatarConfig?: SubagentAvatarConfig;
59
+ }
60
+ /**
61
+ * Fixed-height, chat-style viewport for a single delegated subagent run.
62
+ * Reuses {@link ChatMessageList} so subagent output is formatted exactly like
63
+ * the primary agent, including tool-call cards and inline approvals. Tool
64
+ * approval decisions are sent over the shared monitoring socket.
65
+ */
66
+ export declare function SubagentChatPanel({ toolCallId, subagentName: subagentNameHint, height, avatarConfig, }: SubagentChatPanelProps): React.ReactElement | null;
49
67
  export declare function ChatMessageList({ displayItems, isLoading, isStreaming, showLoadingIndicator, hideMessagesAfterToolUI, avatarConfig, padding, renderToolResult, emptyContent, messagesEndRef, onRespond, approvalConfig, }: ChatMessageListProps): import("react/jsx-runtime").JSX.Element;
68
+ export {};
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } 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.
@@ -9,14 +9,15 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
9
9
  *
10
10
  * @module chat/messages/MessageList
11
11
  */
12
- import { useState, useCallback, useMemo, } from 'react';
13
- import { Text } from '@primer/react';
12
+ import { useState, useCallback, useEffect, useMemo, useRef, } from 'react';
13
+ import { Text, Spinner } from '@primer/react';
14
+ import { DependabotIcon, PersonIcon } from '@primer/octicons-react';
14
15
  import { Box } from '@datalayer/primer-addons';
15
16
  import { Streamdown } from 'streamdown';
16
17
  import { streamdownMarkdownStyles, streamdownCodeBlockStyles, } from '../styles/streamdownStyles';
17
18
  import { ToolCallDisplay } from '../tools/ToolCallDisplay';
18
19
  import { isToolCallMessage, getMessageText } from '../../utils';
19
- import { useAgentRuntimeStore } from '../../stores/agentRuntimeStore';
20
+ import { useAgentRuntimeStore, useAgentRuntimeSubagentActivityByToolCall, agentRuntimeStore, } from '../../stores/agentRuntimeStore';
20
21
  // ---------------------------------------------------------------------------
21
22
  // Normalize helper
22
23
  // ---------------------------------------------------------------------------
@@ -70,6 +71,171 @@ function normalizeAssistantMarkdown(text) {
70
71
  });
71
72
  return out;
72
73
  }
74
+ const SUBAGENT_AVATAR_CONFIG = {
75
+ userAvatar: _jsx(PersonIcon, { size: 14 }),
76
+ assistantAvatar: _jsx(DependabotIcon, { size: 14 }),
77
+ showAvatars: true,
78
+ avatarSize: 24,
79
+ userAvatarBg: 'neutral.muted',
80
+ assistantAvatarBg: 'accent.emphasis',
81
+ };
82
+ /**
83
+ * Convert streamed subagent activity into the `DisplayItem[]` shape the main
84
+ * chat renders: text deltas merge into markdown messages, and tool events pair
85
+ * into tool-call cards (with approval controls when the runtime requests one).
86
+ * Reasoning (`thinking`) is omitted to mirror the primary agent view.
87
+ */
88
+ function buildSubagentDisplayItems(events, keyPrefix) {
89
+ const items = [];
90
+ const openByName = new Map();
91
+ let textBuffer = '';
92
+ let seq = 0;
93
+ const flushText = () => {
94
+ if (textBuffer.trim()) {
95
+ items.push({
96
+ id: `${keyPrefix}:msg:${seq++}`,
97
+ role: 'assistant',
98
+ content: textBuffer,
99
+ createdAt: new Date(0),
100
+ });
101
+ }
102
+ textBuffer = '';
103
+ };
104
+ for (const event of events) {
105
+ switch (event.phase) {
106
+ case 'text':
107
+ textBuffer += event.text ?? '';
108
+ break;
109
+ case 'tool_call': {
110
+ flushText();
111
+ const id = `${keyPrefix}:tool:${seq++}`;
112
+ const toolCall = {
113
+ id,
114
+ type: 'tool-call',
115
+ toolCallId: id,
116
+ toolName: event.toolName ?? 'tool',
117
+ args: event.toolArgs ?? {},
118
+ status: 'inProgress',
119
+ };
120
+ items.push(toolCall);
121
+ if (event.toolName) {
122
+ openByName.set(event.toolName, toolCall);
123
+ }
124
+ break;
125
+ }
126
+ case 'tool_result': {
127
+ flushText();
128
+ const open = event.toolName
129
+ ? openByName.get(event.toolName)
130
+ : undefined;
131
+ if (open) {
132
+ open.result = event.result;
133
+ open.status = 'complete';
134
+ if (event.toolName) {
135
+ openByName.delete(event.toolName);
136
+ }
137
+ }
138
+ else {
139
+ const id = `${keyPrefix}:tool:${seq++}`;
140
+ items.push({
141
+ id,
142
+ type: 'tool-call',
143
+ toolCallId: id,
144
+ toolName: event.toolName ?? 'tool',
145
+ args: {},
146
+ result: event.result,
147
+ status: 'complete',
148
+ });
149
+ }
150
+ break;
151
+ }
152
+ case 'error':
153
+ flushText();
154
+ items.push({
155
+ id: `${keyPrefix}:msg:${seq++}`,
156
+ role: 'assistant',
157
+ content: `**\u26a0\ufe0f ${event.error ?? 'Subagent failed'}**`,
158
+ createdAt: new Date(0),
159
+ });
160
+ break;
161
+ // `start`, `thinking`, and `end` do not produce display items.
162
+ default:
163
+ break;
164
+ }
165
+ }
166
+ flushText();
167
+ return items;
168
+ }
169
+ /**
170
+ * Fixed-height, chat-style viewport for a single delegated subagent run.
171
+ * Reuses {@link ChatMessageList} so subagent output is formatted exactly like
172
+ * the primary agent, including tool-call cards and inline approvals. Tool
173
+ * approval decisions are sent over the shared monitoring socket.
174
+ */
175
+ export function SubagentChatPanel({ toolCallId, subagentName: subagentNameHint, height = 280, avatarConfig = SUBAGENT_AVATAR_CONFIG, }) {
176
+ const events = useAgentRuntimeSubagentActivityByToolCall(toolCallId, subagentNameHint);
177
+ const displayItems = useMemo(() => buildSubagentDisplayItems(events, toolCallId), [events, toolCallId]);
178
+ const messagesEndRef = useRef(null);
179
+ const subagentName = useMemo(() => {
180
+ for (const event of events) {
181
+ if (event.subagentName)
182
+ return event.subagentName;
183
+ }
184
+ return subagentNameHint ?? 'subagent';
185
+ }, [events, subagentNameHint]);
186
+ const isDone = useMemo(() => events.some(e => e.phase === 'end' || e.phase === 'error'), [events]);
187
+ const hasError = useMemo(() => events.some(e => e.phase === 'error'), [events]);
188
+ // Forward inline tool-approval decisions to the shared monitoring socket.
189
+ const handleRespond = useCallback(async (_toolCallId, result) => {
190
+ if (result && typeof result === 'object') {
191
+ const record = result;
192
+ if (record.type === 'tool-approval-decision' &&
193
+ typeof record.approved === 'boolean' &&
194
+ typeof record.approvalId === 'string') {
195
+ agentRuntimeStore
196
+ .getState()
197
+ .sendDecision(record.approvalId, record.approved);
198
+ }
199
+ }
200
+ }, []);
201
+ useEffect(() => {
202
+ messagesEndRef.current?.scrollIntoView({ block: 'end' });
203
+ }, [displayItems]);
204
+ if (events.length === 0) {
205
+ return null;
206
+ }
207
+ return (_jsxs(Box, { sx: {
208
+ mt: 2,
209
+ display: 'flex',
210
+ flexDirection: 'column',
211
+ height,
212
+ width: '100%',
213
+ border: '1px solid',
214
+ borderColor: 'border.default',
215
+ borderRadius: 2,
216
+ overflow: 'hidden',
217
+ bg: 'canvas.default',
218
+ }, children: [_jsxs(Box, { sx: {
219
+ display: 'flex',
220
+ alignItems: 'center',
221
+ gap: 1,
222
+ px: 2,
223
+ py: 1,
224
+ borderBottom: '1px solid',
225
+ borderColor: 'border.muted',
226
+ bg: 'canvas.subtle',
227
+ flexShrink: 0,
228
+ }, children: [_jsx(Box, { sx: {
229
+ display: 'flex',
230
+ color: hasError ? 'danger.fg' : isDone ? 'success.fg' : 'accent.fg',
231
+ }, children: _jsx(DependabotIcon, { size: 14 }) }), _jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.default' }, children: subagentName }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', ml: 'auto' }, children: hasError ? 'failed' : isDone ? 'done' : 'working\u2026' })] }), _jsx(Box, { sx: { flex: 1, minHeight: 0, overflowY: 'auto' }, children: _jsx(ChatMessageList, { displayItems: displayItems, isLoading: !isDone, isStreaming: !isDone, showLoadingIndicator: !isDone, hideMessagesAfterToolUI: false, avatarConfig: avatarConfig, padding: 2, onRespond: handleRespond, messagesEndRef: messagesEndRef, emptyContent: _jsxs(Box, { sx: {
232
+ display: 'flex',
233
+ alignItems: 'center',
234
+ gap: 1,
235
+ color: 'fg.muted',
236
+ p: 2,
237
+ }, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 0 }, children: "Starting\u2026" })] }) }) })] }));
238
+ }
73
239
  // ---------------------------------------------------------------------------
74
240
  // DefaultToolCallRenderer — reads approvals from the Zustand store,
75
241
  // sends decisions over the shared WebSocket (no REST polling).
@@ -175,11 +341,16 @@ function DefaultToolCallRenderer({ item, onRespond, }) {
175
341
  : externalDecision
176
342
  ? 'external'
177
343
  : undefined;
178
- return (_jsx(ToolCallDisplay, { toolCallId: item.toolCallId, toolName: item.toolName, args: item.args, result: item.result, status: item.status, error: item.error, executionError: item.executionError, codeError: item.codeError, exitCode: item.exitCode, approvalRequired: hasApproval, approvalState: approvalState, approvalDecisionSource: approvalDecisionSource, onApprove: effectiveApprovalId && !decision && !externalDecision
179
- ? () => makeDecision('approve')
180
- : undefined, onDeny: effectiveApprovalId && !decision && !externalDecision
181
- ? () => makeDecision('reject')
182
- : undefined, approvalLoading: false }));
344
+ // `normalizeName` strips underscores, so compare against the normalized form.
345
+ const isSubagentDelegation = normalizedToolName === 'delegatetask';
346
+ const delegatedSubagentName = typeof item.args?.subagent_name === 'string'
347
+ ? item.args.subagent_name
348
+ : undefined;
349
+ return (_jsxs(_Fragment, { children: [_jsx(ToolCallDisplay, { toolCallId: item.toolCallId, toolName: item.toolName, args: item.args, result: item.result, status: item.status, error: item.error, executionError: item.executionError, codeError: item.codeError, exitCode: item.exitCode, approvalRequired: hasApproval, approvalState: approvalState, approvalDecisionSource: approvalDecisionSource, onApprove: effectiveApprovalId && !decision && !externalDecision
350
+ ? () => makeDecision('approve')
351
+ : undefined, onDeny: effectiveApprovalId && !decision && !externalDecision
352
+ ? () => makeDecision('reject')
353
+ : undefined, approvalLoading: false }), isSubagentDelegation && (_jsx(SubagentChatPanel, { toolCallId: item.toolCallId, subagentName: delegatedSubagentName }))] }));
183
354
  }
184
355
  // ---------------------------------------------------------------------------
185
356
  // Component
@@ -43,6 +43,10 @@ export interface EphemeralNotebookProps {
43
43
  onNbformatChange?: (content: INotebookContent) => void;
44
44
  /** Optional toolbar component override. */
45
45
  toolbarComponent?: EphemeralNotebookToolbarComponent;
46
+ /** Optional theme variant override from host chat context. */
47
+ themeVariant?: string;
48
+ /** Optional color mode override from host chat context. */
49
+ colorMode?: 'light' | 'dark' | 'auto';
46
50
  /**
47
51
  * Optional real-time collaboration provider. When supplied, the notebook
48
52
  * joins a shared collaborative room (the ydoc becomes the source of truth)
@@ -55,5 +59,5 @@ export interface EphemeralNotebookProps {
55
59
  /**
56
60
  * Renders an in-memory notebook backed by a sandbox kernel.
57
61
  */
58
- export declare function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin, nbformat, onNbformatChange, toolbarComponent, collaborationProvider, }: EphemeralNotebookProps): import("react/jsx-runtime").JSX.Element;
62
+ export declare function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin, nbformat, onNbformatChange, toolbarComponent, themeVariant, colorMode, collaborationProvider, }: EphemeralNotebookProps): import("react/jsx-runtime").JSX.Element;
59
63
  export default EphemeralNotebook;
@@ -55,7 +55,7 @@ const EPHEMERAL_NOTEBOOK_CONTENT = {
55
55
  /**
56
56
  * Renders an in-memory notebook backed by a sandbox kernel.
57
57
  */
58
- export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin = 120, nbformat, onNbformatChange, toolbarComponent, collaborationProvider, }) {
58
+ export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride, cellSidebarMargin = 120, nbformat, onNbformatChange, toolbarComponent, themeVariant, colorMode, collaborationProvider, }) {
59
59
  // The `nbformat` passed to the `Notebook` component MUST stay a stable
60
60
  // reference for the lifetime of a given `notebookId`: the underlying
61
61
  // `useNotebookModel` hook rebuilds the notebook model (and its context /
@@ -139,7 +139,8 @@ export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride,
139
139
  }
140
140
  try {
141
141
  const token = String(selectedRuntime?.token || '').trim();
142
- const wsUrl = String(selectedRuntime?.wsUrl || '').trim() || baseUrl.replace(/^http/, 'ws');
142
+ const wsUrl = String(selectedRuntime?.wsUrl || '').trim() ||
143
+ baseUrl.replace(/^http/, 'ws');
143
144
  const serverSettings = ServerConnection.makeSettings({
144
145
  baseUrl,
145
146
  wsUrl,
@@ -236,10 +237,12 @@ export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride,
236
237
  // Resolve the active theme/color-mode exactly like the notebook editor
237
238
  // (NotebookEditorPanel) so the notebook honours dark / branded themes
238
239
  // instead of always rendering light.
239
- const { colorMode, theme: themeVariant } = useThemeStore();
240
+ const { colorMode: storeColorMode, theme: storeThemeVariant } = useThemeStore();
241
+ const effectiveColorMode = colorMode ?? storeColorMode;
242
+ const effectiveThemeVariant = themeVariant ?? storeThemeVariant;
240
243
  const systemMode = useSystemColorMode();
241
- const themeConfig = getThemeConfig(themeVariant);
242
- const resolvedMode = colorMode === 'auto' ? systemMode : colorMode;
244
+ const themeConfig = getThemeConfig(effectiveThemeVariant);
245
+ const resolvedMode = effectiveColorMode === 'auto' ? systemMode : effectiveColorMode;
243
246
  const modeStyles = resolvedMode === 'dark'
244
247
  ? themeConfig.themeStyles.dark
245
248
  : themeConfig.themeStyles.light;
@@ -252,7 +255,7 @@ export function EphemeralNotebook({ notebookId, runtimePodName, runtimeOverride,
252
255
  position: 'relative',
253
256
  overflow: 'hidden',
254
257
  bg: 'canvas.default',
255
- }, children: activeServiceManager ? (_jsx(DatalayerThemeProvider, { colorMode: colorMode, theme: themeConfig.primerTheme, themeStyles: themeConfig.themeStyles, children: _jsx(JupyterReactTheme, { colormode: resolvedMode, backgroundColor: themeBackground, children: _jsx(Box, { sx: {
258
+ }, children: activeServiceManager ? (_jsx(DatalayerThemeProvider, { colorMode: effectiveColorMode, theme: themeConfig.primerTheme, themeStyles: themeConfig.themeStyles, children: _jsx(JupyterReactTheme, { colormode: resolvedMode, backgroundColor: themeBackground, children: _jsx(Box, { sx: {
256
259
  position: 'absolute',
257
260
  inset: 0,
258
261
  display: 'flex',
@@ -76,7 +76,7 @@ export function InputPrompt({ variant = 'text', placeholder = 'Ask anything…',
76
76
  transition: 'border-color 0.2s ease',
77
77
  '&:focus-within': {
78
78
  borderColor: 'accent.fg',
79
- boxShadow: (t) => `0 0 0 1px ${t?.colors?.accent?.fg ?? '#0969da'}`,
79
+ boxShadow: (t) => `0 0 0 1px ${t?.colors?.accent?.fg ?? '#16A085'}`,
80
80
  },
81
81
  }, children: [_jsx(InputPromptHeader, { children: headerContent }), variant === 'lexical' ? (_jsx(InputPromptLexical, { value: input, onChange: setInput, placeholder: placeholder, disabled: isLoading || disabled, readOnly: readOnly, onSubmit: handleSend, autoFocus: autoFocus })) : (_jsx(InputPromptText, { value: input, onChange: setInput, placeholder: placeholder, disabled: isLoading || disabled, readOnly: readOnly, onSubmit: handleSend, inputRef: inputRef })), _jsx(InputPromptFooter, { isLoading: isLoading, isKernelBusy: isKernelBusy, sendDisabled: !input.trim() || disabled || readOnly, onSend: handleSend, onStop: handleStop, rightContent: footerRightContent, children: footerContent })] }) }) }));
82
82
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Live subagent activity panel.
3
+ *
4
+ * Renders the streamed interaction timeline for a `delegate_task` tool call:
5
+ * text/thinking deltas, nested tool calls and results, and the final output.
6
+ * Events are sourced from the agent runtime store, keyed by the parent
7
+ * delegation tool call id.
8
+ *
9
+ * @module chat/tools/SubagentActivity
10
+ */
11
+ import React from 'react';
12
+ export interface SubagentActivityProps {
13
+ /** Parent `delegate_task` tool call id used to look up streamed events. */
14
+ toolCallId: string;
15
+ }
16
+ /**
17
+ * Displays the live activity timeline for a delegated subagent run.
18
+ * Renders nothing until the first event for `toolCallId` arrives.
19
+ */
20
+ export declare function SubagentActivity({ toolCallId, }: SubagentActivityProps): React.ReactElement | null;
@@ -0,0 +1,154 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2025-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ /**
7
+ * Live subagent activity panel.
8
+ *
9
+ * Renders the streamed interaction timeline for a `delegate_task` tool call:
10
+ * text/thinking deltas, nested tool calls and results, and the final output.
11
+ * Events are sourced from the agent runtime store, keyed by the parent
12
+ * delegation tool call id.
13
+ *
14
+ * @module chat/tools/SubagentActivity
15
+ */
16
+ import { useMemo, useState } from 'react';
17
+ import { Text } from '@primer/react';
18
+ import { Box } from '@datalayer/primer-addons';
19
+ import { ChevronDownIcon, ChevronRightIcon, DependabotIcon, ToolsIcon, CheckCircleIcon, AlertIcon, LightBulbIcon, } from '@primer/octicons-react';
20
+ import { useAgentRuntimeSubagentActivity } from '../../stores/agentRuntimeStore';
21
+ /**
22
+ * Collapse the ordered event stream into render segments, merging consecutive
23
+ * text/thinking deltas into single blocks.
24
+ */
25
+ function buildSegments(events) {
26
+ const segments = [];
27
+ for (const event of events) {
28
+ const phase = event.phase;
29
+ if (phase === 'text' || phase === 'thinking') {
30
+ const kind = phase;
31
+ const last = segments[segments.length - 1];
32
+ if (last && last.kind === kind) {
33
+ last.text = (last.text ?? '') + (event.text ?? '');
34
+ }
35
+ else {
36
+ segments.push({ kind, text: event.text ?? '' });
37
+ }
38
+ }
39
+ else if (phase === 'tool_call') {
40
+ segments.push({
41
+ kind: 'tool_call',
42
+ toolName: event.toolName,
43
+ toolArgs: event.toolArgs,
44
+ });
45
+ }
46
+ else if (phase === 'tool_result') {
47
+ segments.push({
48
+ kind: 'tool_result',
49
+ toolName: event.toolName,
50
+ result: event.result,
51
+ });
52
+ }
53
+ else if (phase === 'error') {
54
+ segments.push({ kind: 'error', error: event.error });
55
+ }
56
+ // `start` and `end` phases are represented by header/status, not segments.
57
+ }
58
+ return segments;
59
+ }
60
+ /**
61
+ * Displays the live activity timeline for a delegated subagent run.
62
+ * Renders nothing until the first event for `toolCallId` arrives.
63
+ */
64
+ export function SubagentActivity({ toolCallId, }) {
65
+ const events = useAgentRuntimeSubagentActivity(toolCallId);
66
+ const [expanded, setExpanded] = useState(true);
67
+ const subagentName = useMemo(() => {
68
+ for (const event of events) {
69
+ if (event.subagentName)
70
+ return event.subagentName;
71
+ }
72
+ return 'subagent';
73
+ }, [events]);
74
+ const isDone = useMemo(() => events.some(e => e.phase === 'end' || e.phase === 'error'), [events]);
75
+ const hasError = useMemo(() => events.some(e => e.phase === 'error'), [events]);
76
+ const segments = useMemo(() => buildSegments(events), [events]);
77
+ if (events.length === 0) {
78
+ return null;
79
+ }
80
+ const StatusIcon = hasError
81
+ ? AlertIcon
82
+ : isDone
83
+ ? CheckCircleIcon
84
+ : DependabotIcon;
85
+ const statusColor = hasError
86
+ ? 'danger.fg'
87
+ : isDone
88
+ ? 'success.fg'
89
+ : 'accent.fg';
90
+ return (_jsxs(Box, { sx: {
91
+ mt: 1,
92
+ ml: 2,
93
+ borderLeft: '2px solid',
94
+ borderColor: 'border.muted',
95
+ pl: 2,
96
+ }, children: [_jsxs(Box, { as: "button", onClick: () => setExpanded(prev => !prev), sx: {
97
+ display: 'flex',
98
+ alignItems: 'center',
99
+ gap: 1,
100
+ width: '100%',
101
+ border: 'none',
102
+ background: 'transparent',
103
+ cursor: 'pointer',
104
+ p: 0,
105
+ color: 'fg.muted',
106
+ textAlign: 'left',
107
+ }, children: [expanded ? (_jsx(ChevronDownIcon, { size: 12 })) : (_jsx(ChevronRightIcon, { size: 12 })), _jsx(Box, { sx: { color: statusColor, display: 'flex' }, children: _jsx(StatusIcon, { size: 14 }) }), _jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold', color: 'fg.default' }, children: subagentName }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: hasError ? 'failed' : isDone ? 'done' : 'working…' })] }), expanded && (_jsx(Box, { sx: { mt: 1, display: 'flex', flexDirection: 'column', gap: 1 }, children: segments.map((segment, index) => (_jsx(SubagentSegmentView, { segment: segment }, index))) }))] }));
108
+ }
109
+ function SubagentSegmentView({ segment, }) {
110
+ switch (segment.kind) {
111
+ case 'text':
112
+ if (!segment.text)
113
+ return null;
114
+ return (_jsx(Text, { sx: {
115
+ fontSize: 0,
116
+ color: 'fg.default',
117
+ whiteSpace: 'pre-wrap',
118
+ wordBreak: 'break-word',
119
+ }, children: segment.text }));
120
+ case 'thinking':
121
+ if (!segment.text)
122
+ return null;
123
+ return (_jsxs(Box, { sx: { display: 'flex', gap: 1, color: 'fg.muted' }, children: [_jsx(Box, { sx: { mt: '2px', flexShrink: 0 }, children: _jsx(LightBulbIcon, { size: 12 }) }), _jsx(Text, { sx: {
124
+ fontSize: 0,
125
+ fontStyle: 'italic',
126
+ whiteSpace: 'pre-wrap',
127
+ wordBreak: 'break-word',
128
+ }, children: segment.text })] }));
129
+ case 'tool_call':
130
+ return (_jsxs(Box, { sx: { display: 'flex', gap: 1, color: 'fg.muted' }, children: [_jsx(Box, { sx: { mt: '2px', flexShrink: 0 }, children: _jsx(ToolsIcon, { size: 12 }) }), _jsxs(Box, { sx: { minWidth: 0 }, children: [_jsx(Text, { sx: { fontSize: 0, fontWeight: 'bold' }, children: segment.toolName ?? 'tool' }), segment.toolArgs && Object.keys(segment.toolArgs).length > 0 && (_jsx(Text, { as: "pre", sx: {
131
+ fontSize: 0,
132
+ fontFamily: 'mono',
133
+ m: 0,
134
+ mt: '2px',
135
+ whiteSpace: 'pre-wrap',
136
+ wordBreak: 'break-word',
137
+ color: 'fg.muted',
138
+ }, children: JSON.stringify(segment.toolArgs) }))] })] }));
139
+ case 'tool_result':
140
+ if (!segment.result)
141
+ return null;
142
+ return (_jsxs(Box, { sx: { display: 'flex', gap: 1, color: 'fg.muted' }, children: [_jsx(Box, { sx: { mt: '2px', flexShrink: 0, color: 'success.fg' }, children: _jsx(CheckCircleIcon, { size: 12 }) }), _jsx(Text, { as: "pre", sx: {
143
+ fontSize: 0,
144
+ fontFamily: 'mono',
145
+ m: 0,
146
+ whiteSpace: 'pre-wrap',
147
+ wordBreak: 'break-word',
148
+ }, children: segment.result })] }));
149
+ case 'error':
150
+ return (_jsxs(Box, { sx: { display: 'flex', gap: 1, color: 'danger.fg' }, children: [_jsx(Box, { sx: { mt: '2px', flexShrink: 0 }, children: _jsx(AlertIcon, { size: 12 }) }), _jsx(Text, { sx: { fontSize: 0 }, children: segment.error ?? 'Subagent failed' })] }));
151
+ default:
152
+ return null;
153
+ }
154
+ }
@@ -4,5 +4,6 @@
4
4
  * @module chat/tools
5
5
  */
6
6
  export { ToolCallDisplay, type ToolCallDisplayProps, type ErrorType, } from './ToolCallDisplay';
7
+ export { SubagentActivity, type SubagentActivityProps, } from './SubagentActivity';
7
8
  export { ToolApprovalBanner, type ToolApprovalBannerProps, type PendingApproval, } from './ToolApprovalBanner';
8
9
  export { ToolApprovalDialog, useToolApprovalDialog, type ToolApprovalDialogProps, } from './ToolApprovalDialog';
@@ -8,5 +8,6 @@
8
8
  * @module chat/tools
9
9
  */
10
10
  export { ToolCallDisplay, } from './ToolCallDisplay';
11
+ export { SubagentActivity, } from './SubagentActivity';
11
12
  export { ToolApprovalBanner, } from './ToolApprovalBanner';
12
13
  export { ToolApprovalDialog, useToolApprovalDialog, } from './ToolApprovalDialog';