@datalayer/agent-runtimes 1.5.1 → 1.5.2

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.
@@ -9,6 +9,7 @@ import type { AssistantCharacter } from '../../chat/assistant/characters';
9
9
  import type { AssistantCharacterData } from '../../chat/assistant/formats/types';
10
10
  import type { PresenceState } from '../../chat/presence/presenceStatus';
11
11
  import type { ChatWords } from '../../chat/words';
12
+ import type { ChatViewMode } from '../../types/chat';
12
13
  /** Lifecycle of the sandbox a workspace is attached to. */
13
14
  export type SandboxState = 'idle' | 'starting' | 'running' | 'stopping' | 'error';
14
15
  /** What the workspace knows about the sandbox behind it. */
@@ -196,6 +197,21 @@ export type LoopWorkspaceContext = {
196
197
  * part of the page and the chat's stay together at the trailing edge.
197
198
  */
198
199
  chatHeaderActions?: ReactNode;
200
+ /**
201
+ * The chat's view, as the host keeps it: the chat's title bar offers the
202
+ * views with its view-mode toggle (`ChatViewModeToggle`). Unsaid, the
203
+ * title bar offers none.
204
+ */
205
+ chatViewModes?: LoopChatViewModes;
206
+ };
207
+ /** The chat's view in a workspace whose host keeps it (`chatViewModes`). */
208
+ export type LoopChatViewModes = {
209
+ /** The view the chat is in. */
210
+ value: ChatViewMode;
211
+ /** The person picked another view. */
212
+ onChange: (mode: ChatViewMode) => void;
213
+ /** The views offered, in the toggle's order; all of them when unsaid. */
214
+ offered?: readonly ChatViewMode[];
199
215
  };
200
216
  /**
201
217
  * How a prompt typed in the shell reaches whatever should answer it.
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module apps
8
8
  */
9
- export { LoopCommand, LoopDocumentToolbar, LoopMention, LoopNotebookToolbar, LoopRunProps, LoopSlots, LoopViewType, canOpenView, createPromptChannel, parseCommand, runForwardedProps, type CommandArgSpec, type CommandContribution, type CommandResult, type EditorToolbarContext, type EditorToolbarContribution, type LoopCommandContext, type LoopViewProps, type LoopWorkspaceContext, type MentionCandidate, type MentionContribution, type PromptChannel, type RunPropsContribution, type SandboxSnapshot, type SandboxState, type ViewControls, type ViewTypeContribution, useLoopPromptStore, suggestLoopPrompt, focusPrompt, onPromptFocusRequest, type LoopPromptState, type SuggestedPrompt, } from './core';
9
+ export { LoopCommand, LoopDocumentToolbar, LoopMention, LoopNotebookToolbar, LoopRunProps, LoopSlots, LoopViewType, canOpenView, createPromptChannel, parseCommand, runForwardedProps, type CommandArgSpec, type CommandContribution, type CommandResult, type EditorToolbarContext, type EditorToolbarContribution, type LoopCommandContext, type LoopViewProps, type LoopWorkspaceContext, type LoopChatViewModes, type MentionCandidate, type MentionContribution, type PromptChannel, type RunPropsContribution, type SandboxSnapshot, type SandboxState, type ViewControls, type ViewTypeContribution, useLoopPromptStore, suggestLoopPrompt, focusPrompt, onPromptFocusRequest, type LoopPromptState, type SuggestedPrompt, } from './core';
10
10
  export { useEditorToolbar } from './core/toolbar';
11
11
  export { LoopWorkspace, PluginToggles, ViewSwitcher, WorkspaceFullScreenAction, buildLoopReactor, useWorkspaceFullScreen, type LoopWorkspaceProps, type PluginTogglesProps, type ViewSwitcherProps, } from './shell';
12
12
  export { A2uiPlugin, A2UI_PLUGIN_NAME } from './plugins/a2ui';
@@ -1845,7 +1845,19 @@ export default function ChatView({ workspace }) {
1845
1845
  showNewChat: config?.headerButtons?.newChat ?? false,
1846
1846
  showClear: config?.headerButtons?.clear ?? false,
1847
1847
  }, renderHeader: HeaderComponent
1848
- ? headerProps => (_jsx(HeaderComponent, { workspace: workspace, header: headerProps }))
1848
+ ? headerProps => (_jsx(HeaderComponent, { workspace: workspace, header:
1849
+ /* The chat's view, when the host keeps it: the
1850
+ title bar's toggle, given to the header only —
1851
+ the chat itself stays where the workspace
1852
+ places it, whichever view is picked. */
1853
+ workspace.chatViewModes
1854
+ ? {
1855
+ ...headerProps,
1856
+ chatViewMode: workspace.chatViewModes.value,
1857
+ onChatViewModeChange: workspace.chatViewModes.onChange,
1858
+ offeredViewModes: workspace.chatViewModes.offered,
1859
+ }
1860
+ : headerProps }))
1849
1861
  : undefined,
1850
1862
  /*
1851
1863
  The (i), which opens the agent's details over the transcript.
@@ -22,7 +22,7 @@
22
22
  import type { JSX } from 'react';
23
23
  import type { ReactNode } from 'react';
24
24
  import { type PlatformInput, type PluginRef, type ReactorPlatform } from '@datalayer/reactor';
25
- import { type LoopWorkspaceContext, type SandboxSnapshot } from '../core';
25
+ import { type LoopChatViewModes, type LoopWorkspaceContext, type SandboxSnapshot } from '../core';
26
26
  export type LoopWorkspaceProps = {
27
27
  /** Server backing this session. */
28
28
  serverUrl: string;
@@ -93,6 +93,13 @@ export type LoopWorkspaceProps = {
93
93
  * to `LoopSlots.chatHeader` instead, and both end up in the same row.
94
94
  */
95
95
  chatHeaderActions?: ReactNode;
96
+ /**
97
+ * The chat's view, kept by the host: offered in the chat's title bar by
98
+ * its view-mode toggle. The host draws the view picked — for the
99
+ * assistant, a chat layout (`LoopChatLayout`) that hands the transcript
100
+ * and the composer to `ChatFloating`'s assistant mode.
101
+ */
102
+ chatViewModes?: LoopChatViewModes;
96
103
  /**
97
104
  * The host's own controls for the workspace header row.
98
105
  *
@@ -13,21 +13,21 @@ export function buildLoopReactor(extensions) {
13
13
  return buildReactorFromPlugins(extensions);
14
14
  }
15
15
  export function LoopWorkspace(props) {
16
- const { serverUrl, agentId, conversationId, model, sandbox = { state: 'idle' }, extensions = [], reactor: providedReactor, manageReactor = true, initialViewType, onSend, layout = 'page', showViewSelector = true, showHeader = true, chatHeaderActions, headerActions, headerContainer, sidebarRail = false, } = props;
16
+ const { serverUrl, agentId, conversationId, model, sandbox = { state: 'idle' }, extensions = [], reactor: providedReactor, manageReactor = true, initialViewType, onSend, layout = 'page', showViewSelector = true, showHeader = true, chatHeaderActions, chatViewModes, headerActions, headerContainer, sidebarRail = false, } = props;
17
17
  // Building the platform is a one-time act: rebuilding it on every render
18
18
  // would restart every plugin.
19
19
  const reactor = useMemo(() => providedReactor ?? buildLoopReactor(extensions),
20
20
  // eslint-disable-next-line react-hooks/exhaustive-deps
21
21
  [providedReactor]);
22
22
  useReactor(reactor, { autoStart: manageReactor });
23
- return (_jsx(WorkspaceBody, { serverUrl: serverUrl, agentId: agentId, conversationId: conversationId, model: model, initialSandbox: sandbox, initialViewType: initialViewType, onSend: onSend, layout: layout, showViewSelector: showViewSelector, showHeader: showHeader, chatHeaderActions: chatHeaderActions, headerActions: headerActions, headerContainer: headerContainer, sidebarRail: sidebarRail }));
23
+ return (_jsx(WorkspaceBody, { serverUrl: serverUrl, agentId: agentId, conversationId: conversationId, model: model, initialSandbox: sandbox, initialViewType: initialViewType, onSend: onSend, layout: layout, showViewSelector: showViewSelector, showHeader: showHeader, chatHeaderActions: chatHeaderActions, chatViewModes: chatViewModes, headerActions: headerActions, headerContainer: headerContainer, sidebarRail: sidebarRail }));
24
24
  }
25
25
  /**
26
26
  * Split from `LoopWorkspace` so the hooks below run with the platform already
27
27
  * registered — `useContributions` needs a reactor in the store, and `useReactor`
28
28
  * registers it during the parent's render.
29
29
  */
30
- function WorkspaceBody({ serverUrl, agentId: initialAgentId, conversationId, model, initialSandbox, initialViewType, onSend, layout = 'page', showViewSelector = true, showHeader = true, chatHeaderActions, headerActions, headerContainer, sidebarRail = false, }) {
30
+ function WorkspaceBody({ serverUrl, agentId: initialAgentId, conversationId, model, initialSandbox, initialViewType, onSend, layout = 'page', showViewSelector = true, showHeader = true, chatHeaderActions, chatViewModes, headerActions, headerContainer, sidebarRail = false, }) {
31
31
  /*
32
32
  * Which agent the session is talking to.
33
33
  *
@@ -119,6 +119,7 @@ function WorkspaceBody({ serverUrl, agentId: initialAgentId, conversationId, mod
119
119
  viewControls,
120
120
  setViewControls,
121
121
  chatHeaderActions,
122
+ chatViewModes,
122
123
  }), [
123
124
  serverUrl,
124
125
  agentId,
@@ -131,6 +132,7 @@ function WorkspaceBody({ serverUrl, agentId: initialAgentId, conversationId, mod
131
132
  viewControls,
132
133
  setViewControls,
133
134
  chatHeaderActions,
135
+ chatViewModes,
134
136
  ]);
135
137
  // `submit` must not be rebuilt whenever the workspace object changes — the
136
138
  // chat holds on to it — so it reads the current values through refs.
@@ -69,6 +69,8 @@ export interface ChatBaseHeaderProps {
69
69
  onChatViewModeChange?: (mode: ChatViewMode) => void;
70
70
  /** Modes shown greyed out: the sidebar, when the host has no mount point. */
71
71
  disabledViewModes?: readonly ChatViewMode[];
72
+ /** The modes the toggle offers; all of them when unsaid. */
73
+ offeredViewModes?: readonly ChatViewMode[];
72
74
  /** Show the companion-surface segmented control (None / Notebook / Document). */
73
75
  showEphemeralSurfaceControl?: boolean;
74
76
  /** Whether the Notebook option is available in the surface control. */
@@ -80,5 +82,5 @@ export interface ChatBaseHeaderProps {
80
82
  /** Callback fired when the user changes the companion-surface mode. */
81
83
  onEphemeralSurfaceModeChange?: (mode: EphemeralSurfaceMode) => void;
82
84
  }
83
- export declare function ChatBaseHeader({ title, subtitle, disableReason, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, kernelIndicatorPlacement, runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, disabledViewModes, showEphemeralSurfaceControl, enableEphemeralNotebookOption, enableEphemeralDocumentOption, ephemeralSurfaceMode, onEphemeralSurfaceModeChange, }: ChatBaseHeaderProps): import("react").JSX.Element;
85
+ export declare function ChatBaseHeader({ title, subtitle, disableReason, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, kernelIndicatorPlacement, runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, disabledViewModes, offeredViewModes, showEphemeralSurfaceControl, enableEphemeralNotebookOption, enableEphemeralDocumentOption, ephemeralSurfaceMode, onEphemeralSurfaceModeChange, }: ChatBaseHeaderProps): import("react").JSX.Element;
84
86
  export {};
@@ -31,7 +31,7 @@ export function toRuntimeExecutionState(runtimeStatus) {
31
31
  // ---------------------------------------------------------------------------
32
32
  // Component
33
33
  // ---------------------------------------------------------------------------
34
- export function ChatBaseHeader({ title, subtitle, disableReason, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, kernelIndicatorPlacement = 'left', runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, disabledViewModes = [], showEphemeralSurfaceControl = false, enableEphemeralNotebookOption = false, enableEphemeralDocumentOption = false, ephemeralSurfaceMode = 'none', onEphemeralSurfaceModeChange, }) {
34
+ export function ChatBaseHeader({ title, subtitle, disableReason, brandIcon, headerContent, headerActions, showInformation, onInformationClick, padding, kernelIndicatorState, kernelIndicatorPlacement = 'left', runtimeStatus, kernel, kernelEnvironmentName, kernelCpu, kernelMemory, kernelGpu, headerButtons, messageCount, onNewChat, onClear, chatViewMode, onChatViewModeChange, disabledViewModes = [], offeredViewModes, showEphemeralSurfaceControl = false, enableEphemeralNotebookOption = false, enableEphemeralDocumentOption = false, ephemeralSurfaceMode = 'none', onEphemeralSurfaceModeChange, }) {
35
35
  const effectiveIndicatorState = kernelIndicatorState ?? toRuntimeExecutionState(runtimeStatus);
36
36
  /*
37
37
  * No indicator where there is nothing to indicate.
@@ -58,5 +58,5 @@ export function ChatBaseHeader({ title, subtitle, disableReason, brandIcon, head
58
58
  color: 'fg.muted',
59
59
  minWidth: 0,
60
60
  maxWidth: '100%',
61
- }, children: _jsx(Truncate, { title: subtitle, maxWidth: "40ch", children: subtitle }) }))] })), disableReason && (_jsx(Label, { variant: "attention", sx: { flexShrink: 0 }, children: disableReason })), headerContent, showInformation && (_jsx(IconButton, { icon: InfoIcon, "aria-label": "Information", variant: "invisible", size: "small", onClick: onInformationClick })), kernelIndicatorPlacement === 'center' && kernelIndicatorElement] }), _jsxs(Box, { 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(EphemeralSurfaceControl, { mode: ephemeralSurfaceMode, onChange: onEphemeralSurfaceModeChange, enableNotebook: enableEphemeralNotebookOption, enableDocument: enableEphemeralDocumentOption })), chatViewMode && onChatViewModeChange && (_jsx(ChatViewModeToggle, { value: chatViewMode, onChange: onChatViewModeChange, disabledModes: disabledViewModes })), headerActions] })] }) }));
61
+ }, children: _jsx(Truncate, { title: subtitle, maxWidth: "40ch", children: subtitle }) }))] })), disableReason && (_jsx(Label, { variant: "attention", sx: { flexShrink: 0 }, children: disableReason })), headerContent, showInformation && (_jsx(IconButton, { icon: InfoIcon, "aria-label": "Information", variant: "invisible", size: "small", onClick: onInformationClick })), kernelIndicatorPlacement === 'center' && kernelIndicatorElement] }), _jsxs(Box, { 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(EphemeralSurfaceControl, { mode: ephemeralSurfaceMode, onChange: onEphemeralSurfaceModeChange, enableNotebook: enableEphemeralNotebookOption, enableDocument: enableEphemeralDocumentOption })), chatViewMode && onChatViewModeChange && (_jsx(ChatViewModeToggle, { value: chatViewMode, onChange: onChatViewModeChange, disabledModes: disabledViewModes, modes: offeredViewModes })), headerActions] })] }) }));
62
62
  }
@@ -23,7 +23,13 @@ export type ChatViewModeToggleProps = {
23
23
  onChange: (mode: ChatViewMode) => void;
24
24
  /** Modes shown greyed out: the sidebar, when the host has no mount point. */
25
25
  disabledModes?: readonly ChatViewMode[];
26
+ /**
27
+ * The modes offered, in `CHAT_VIEW_MODES` order whatever order they are
28
+ * given in: all of them when unsaid. A host that places only some of them
29
+ * — the workspace: its sidebar, or the assistant over it — leaves the rest out.
30
+ */
31
+ modes?: readonly ChatViewMode[];
26
32
  /** Where the tooltips open. Above by default; below for a control at the top of its window. */
27
33
  tooltipDirection?: 'n' | 's';
28
34
  };
29
- export declare function ChatViewModeToggle({ value, onChange, disabledModes, tooltipDirection, }: ChatViewModeToggleProps): JSX.Element;
35
+ export declare function ChatViewModeToggle({ value, onChange, disabledModes, modes, tooltipDirection, }: ChatViewModeToggleProps): JSX.Element;
@@ -11,8 +11,11 @@ export const VIEW_MODE_ICONS = {
11
11
  assistant: PaperclipIcon,
12
12
  sidebar: SidebarExpandIcon,
13
13
  };
14
- export function ChatViewModeToggle({ value, onChange, disabledModes = [], tooltipDirection = 'n', }) {
15
- return (_jsx(Box, { role: "group", "aria-label": "Display mode", "data-chat-view-mode-toggle": "", display: "inline-flex", alignItems: "center", bg: "neutral.muted", borderRadius: "6px", p: "2px", gap: "1px", children: CHAT_VIEW_MODES.map(({ mode, label }) => {
14
+ export function ChatViewModeToggle({ value, onChange, disabledModes = [], modes, tooltipDirection = 'n', }) {
15
+ const offered = modes
16
+ ? CHAT_VIEW_MODES.filter(option => modes.includes(option.mode))
17
+ : CHAT_VIEW_MODES;
18
+ return (_jsx(Box, { role: "group", "aria-label": "Display mode", "data-chat-view-mode-toggle": "", display: "inline-flex", alignItems: "center", bg: "neutral.muted", borderRadius: "6px", p: "2px", gap: "1px", children: offered.map(({ mode, label }) => {
16
19
  const ModeIcon = VIEW_MODE_ICONS[mode];
17
20
  const selected = value === mode;
18
21
  /* Greyed rather than left out: the person sees the mode exists, and
@@ -15,6 +15,7 @@ import { AgenticCommercePlugin } from './agentic-commerce';
15
15
  import { ProtocolsCorePlugin } from './core';
16
16
  import { McpPlugin } from './mcp';
17
17
  import { PactPlugin } from './pact';
18
+ import { PapPlugin } from './pap';
18
19
  import { UcpPlugin } from './ucp';
19
20
  import { WebBotAuthPlugin } from './web-bot-auth';
20
21
  export const AGENT_PROTOCOLS_EXTENSION = 'agent-protocols';
@@ -22,7 +23,7 @@ export const AgentProtocolsExtension = defineExtension({
22
23
  name: AGENT_PROTOCOLS_EXTENSION,
23
24
  version: '1.0.0',
24
25
  displayName: 'Agent protocols',
25
- description: 'MCP, A2A, Web Bot Auth, UCP, the Agentic Commerce Protocol and PACT, each a plugin; their extensions its contribution points.',
26
+ description: 'MCP, A2A, Web Bot Auth, UCP, the Agentic Commerce Protocol, PACT and PAP, each a plugin; their extensions its contribution points.',
26
27
  plugins: [
27
28
  ProtocolsCorePlugin,
28
29
  McpPlugin,
@@ -31,6 +32,7 @@ export const AgentProtocolsExtension = defineExtension({
31
32
  UcpPlugin,
32
33
  AgenticCommercePlugin,
33
34
  PactPlugin,
35
+ PapPlugin,
34
36
  ],
35
37
  });
36
38
  /**
@@ -0,0 +1,4 @@
1
+ export declare const PAP_PLUGIN = "agent-runtimes.protocols.pap";
2
+ /** The PAP draft the SDK implements (its `PROTOCOL_PROFILE`; Python reads it from the SDK). */
3
+ export declare const PAP_PROTOCOL_PROFILE = "0.1";
4
+ export declare const PapPlugin: import("@datalayer/reactor").ReactorPlugin<Record<string, never>, unknown, unknown>;
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * The Personal Agent Protocol as a Reactor Plugin of the `agent-protocols`
7
+ * Extension. PAP's own plugins and points (`pap.*`, `pap.company.*`) come
8
+ * with its SDK, registered on the PAP Reactor a personal agent or a company
9
+ * builds; this plugin says what a runtime implements of PAP on
10
+ * `protocols.description`. It declares no point here: the one the Python
11
+ * runtime adds, `pap.company.operationTickets`, is where a perform turn
12
+ * redeems its ticket, and a TypeScript runtime performs no company
13
+ * operation. The twin of `agent_runtimes.protocols.pap`.
14
+ *
15
+ * @module protocols/pap
16
+ */
17
+ import { contribution, definePlugin } from '@datalayer/reactor';
18
+ import { DEFAULT_ORDER, ProtocolDescriptions } from '../core';
19
+ export const PAP_PLUGIN = 'agent-runtimes.protocols.pap';
20
+ /** The PAP draft the SDK implements (its `PROTOCOL_PROFILE`; Python reads it from the SDK). */
21
+ export const PAP_PROTOCOL_PROFILE = '0.1';
22
+ export const PapPlugin = definePlugin({
23
+ name: PAP_PLUGIN,
24
+ version: '1.0.0',
25
+ description: "Personal Agent Protocol: a person's agent at companies, and an application as a company, over the PAP SDK.",
26
+ contributionPoints: [],
27
+ contributes: [
28
+ contribution(ProtocolDescriptions, {
29
+ id: 'pap',
30
+ name: 'Personal Agent Protocol',
31
+ layer: 'consent',
32
+ version: PAP_PROTOCOL_PROFILE,
33
+ roles: ['personal-agent', 'company'],
34
+ status: 'implemented',
35
+ specification: 'https://personalagentprotocol.org/docs/spec',
36
+ plugin: PAP_PLUGIN,
37
+ catalogue: 'pap',
38
+ points: [],
39
+ }, { id: 'pap', order: DEFAULT_ORDER }),
40
+ ],
41
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -160,7 +160,7 @@
160
160
  "@datalayer/lexical-loro": "^1.0.6",
161
161
  "@datalayer/primer-addons": "^1.0.39",
162
162
  "@datalayer/primer-rjsf": "^1.0.3",
163
- "@datalayer/personal-agent-protocol": "^0.6.0",
163
+ "@datalayer/personal-agent-protocol": "^0.15.0",
164
164
  "@datalayer/reactor": "^1.3.0",
165
165
  "@datalayer/reactor-commands": "^1.0.4",
166
166
  "@datalayer/reactor-manager": "^1.0.4",