@datalayer/agent-runtimes 1.3.113 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist-embed/chunks/{ChatView-D41Nx5rC.js → ChatView-BpKZPdcp.js} +4 -4
  2. package/dist-embed/datalayer-app-main.js +150 -150
  3. package/lib/apps/apps/appspec.d.ts +13 -0
  4. package/lib/apps/apps/appspec.js +125 -0
  5. package/lib/apps/apps/checks.d.ts +1 -1
  6. package/lib/apps/apps/checks.js +2 -2
  7. package/lib/apps/apps/customComponents.js +1 -1
  8. package/lib/apps/core/canvasBlocks.d.ts +3 -3
  9. package/lib/apps/core/canvasParts.d.ts +6 -4
  10. package/lib/apps/embed/AppEmbed.js +3 -7
  11. package/lib/apps/embed/embedSession.d.ts +8 -4
  12. package/lib/apps/embed/embedSession.js +16 -9
  13. package/lib/apps/plugins/a2ui-surface/AnswerShows.d.ts +21 -0
  14. package/lib/apps/plugins/a2ui-surface/AnswerShows.js +29 -0
  15. package/lib/apps/plugins/a2ui-surface/SurfaceToolResult.js +4 -7
  16. package/lib/apps/plugins/a2ui-surface/index.d.ts +2 -1
  17. package/lib/apps/plugins/a2ui-surface/index.js +10 -1
  18. package/lib/apps/plugins/a2ui-surface/toolResult.d.ts +20 -11
  19. package/lib/apps/plugins/a2ui-surface/toolResult.js +27 -11
  20. package/lib/apps/plugins/app-components/index.d.ts +1 -1
  21. package/lib/apps/plugins/app-components/index.js +2 -2
  22. package/lib/apps/plugins/app-elements/AppElements.d.ts +3 -3
  23. package/lib/apps/plugins/app-elements/AppElements.js +5 -20
  24. package/lib/apps/plugins/app-elements/QuestionView.d.ts +28 -0
  25. package/lib/apps/plugins/app-elements/QuestionView.js +57 -0
  26. package/lib/apps/plugins/app-elements/index.d.ts +7 -4
  27. package/lib/apps/plugins/app-elements/index.js +14 -5
  28. package/lib/apps/plugins/canvas-blocks/index.d.ts +13 -13
  29. package/lib/apps/plugins/canvas-blocks/index.js +24 -24
  30. package/lib/apps/plugins/canvas-parts/index.d.ts +7 -1
  31. package/lib/apps/plugins/canvas-parts/index.js +36 -0
  32. package/lib/apps/plugins/chat/ChatView.js +7 -0
  33. package/lib/chat/base/ChatBase.js +234 -43
  34. package/lib/chat/base/loopElement.d.ts +16 -17
  35. package/lib/chat/base/loopElement.js +11 -27
  36. package/lib/chat/base/loopStep.d.ts +15 -15
  37. package/lib/chat/base/loopStep.js +10 -13
  38. package/lib/chat/base/loopWindow.d.ts +15 -20
  39. package/lib/chat/base/loopWindow.js +26 -27
  40. package/lib/chat/base/uiOps.d.ts +96 -0
  41. package/lib/chat/base/uiOps.js +251 -0
  42. package/lib/chat/messages/ChatMessageList.d.ts +8 -1
  43. package/lib/chat/messages/ChatMessageList.js +4 -4
  44. package/lib/components/a2ui/datalayer/Chart.d.ts +1 -1
  45. package/lib/components/a2ui/datalayer/schema.js +1 -1
  46. package/lib/components/teams/AnswerSurfaces.d.ts +3 -2
  47. package/lib/components/teams/AnswerSurfaces.js +7 -7
  48. package/lib/components/teams/useA2ATeam.d.ts +1 -1
  49. package/lib/config/AgentConfiguration.d.ts +1 -1
  50. package/lib/protocols/AGUIAdapter.d.ts +7 -0
  51. package/lib/protocols/AGUIAdapter.js +43 -3
  52. package/lib/protocols/agentic-commerce/index.d.ts +5 -9
  53. package/lib/protocols/agentic-commerce/index.js +6 -10
  54. package/lib/protocols/commerce.d.ts +8 -9
  55. package/lib/protocols/commerce.js +29 -0
  56. package/lib/protocols/ucp/index.d.ts +5 -10
  57. package/lib/protocols/ucp/index.js +6 -11
  58. package/lib/specs/actions.d.ts +8 -0
  59. package/lib/specs/actions.js +56 -0
  60. package/lib/specs/agents/agents.js +338 -169
  61. package/lib/specs/apps.d.ts +1 -0
  62. package/lib/specs/apps.js +272 -0
  63. package/lib/specs/appspecSchema.js +125 -0
  64. package/lib/specs/cogs.js +6 -3
  65. package/lib/specs/index.d.ts +2 -1
  66. package/lib/specs/index.js +2 -1
  67. package/lib/specs/protocols.d.ts +24 -0
  68. package/lib/specs/protocols.js +197 -0
  69. package/lib/specs/ui.d.ts +21 -0
  70. package/lib/specs/{uiPlugins.js → ui.js} +14 -14
  71. package/lib/types/agentspecs.d.ts +72 -5
  72. package/lib/types/messages.d.ts +7 -0
  73. package/lib/types/protocol.d.ts +8 -0
  74. package/package.json +2 -2
  75. package/scripts/codegen/generate_agents.py +43 -8
  76. package/scripts/codegen/generate_apps.py +38 -1
  77. package/scripts/codegen/generate_protocols.py +207 -0
  78. package/scripts/codegen/generate_sandbox_agents.py +1 -1
  79. package/scripts/codegen/{generate_ui_plugins.py → generate_ui.py} +40 -40
  80. package/scripts/gen_workers.py +2 -2
  81. package/lib/chat/base/loopMessage.d.ts +0 -37
  82. package/lib/chat/base/loopMessage.js +0 -37
  83. package/lib/specs/uiPlugins.d.ts +0 -21
@@ -0,0 +1,96 @@
1
+ /**
2
+ * What a server says to a conversation's page, as `reactor.ui` ops
3
+ * (REACTOR_UI RU-2, RU-3), and what the page presses back (RU-W).
4
+ *
5
+ * The ops arrive on the conversation's ui socket (Reactor's `UiSocket`,
6
+ * one per session, beside the run stream that carries the conversation's
7
+ * text); `routeUiOp` says where each goes:
8
+ *
9
+ * - a `window` op to the page the conversation sits in (`loopWindow`);
10
+ * - a step's display to its row (`loopStep`), patched as it streams;
11
+ * - a display that says it shows in a panel or on a page to the elements
12
+ * open (`loopElement`), a `remove` of its id closing it;
13
+ * - everything else to the messages (`withUiOp`): a display under a message
14
+ * (`data.message_id`) kept on it (`ChatMessage.displays`) and drawn by the
15
+ * renderer a plugin contributed for its type; a `meta` op's `author` the
16
+ * message's voice; a `remove` of a message's id the message gone.
17
+ *
18
+ * An op about a message that has not arrived on the run stream yet — the
19
+ * two are separate connections — waits until it has (`placeable`). A press
20
+ * of what a display offered goes up the socket (`displayPressOf`), and the
21
+ * run that answers it names it only (`withPress`).
22
+ *
23
+ * Pure: the chat applies it to what it draws, and to its store. Nothing it
24
+ * was not told to expect is guessed at: an op it cannot place throws.
25
+ *
26
+ * @module chat/base/uiOps
27
+ */
28
+ import { type Display, type UiAction, type UiModel, type UiOp } from '@datalayer/reactor/ui';
29
+ import type { MessageSpeaker } from '../../types/messages';
30
+ import { type LoopElementChange } from './loopElement';
31
+ import { type LoopStep } from './loopStep';
32
+ /** The message a display is under: its `data.message_id`. */
33
+ export declare function messageOfDisplay(display: Display): string;
34
+ /** Who a message is by, as the chat draws a named voice. */
35
+ export declare function speakerOf(author: string): MessageSpeaker;
36
+ type WithDisplays = {
37
+ id?: string;
38
+ displays?: Display[];
39
+ speaker?: MessageSpeaker;
40
+ };
41
+ /**
42
+ * The messages with an op applied: a display shown (or asked) kept on its
43
+ * message, replacing one of its id; patched, appended to or removed where it
44
+ * is. A `remove` of a message's own id takes the message away, with what it
45
+ * showed; a `meta` op about a message gives it its `author`. `state` ops are
46
+ * not about the messages: they come back as they were.
47
+ *
48
+ * Throws for a display under no message here, for a change to a display no
49
+ * message shows, for a removal of nothing here, and for a `meta` op that
50
+ * says anything but a message's author: the server said something the page
51
+ * never saw, or does not read.
52
+ */
53
+ export declare function withUiOp<T extends WithDisplays>(items: T[], op: UiOp): T[];
54
+ /** Where an op goes (`routeUiOp`). */
55
+ export type RoutedUiOp = {
56
+ to: 'window';
57
+ data: unknown;
58
+ } | {
59
+ to: 'step';
60
+ step: LoopStep;
61
+ } | {
62
+ to: 'element';
63
+ change: LoopElementChange;
64
+ } | {
65
+ to: 'messages';
66
+ op: UiOp;
67
+ };
68
+ /**
69
+ * Where an op goes, and the steps kept after it: a step's display is kept
70
+ * (in a Reactor `UiModel`) so a patch of its output applies to it.
71
+ *
72
+ * `elements` is the ids of the elements shown in this conversation: a
73
+ * `remove` of one closes it (a no-op when the person closed it already).
74
+ */
75
+ export declare function routeUiOp(op: UiOp, steps: UiModel, elements: ReadonlySet<string>): {
76
+ routed: RoutedUiOp;
77
+ steps: UiModel;
78
+ };
79
+ /**
80
+ * Whether the messages hold what an op is about: the message a display is
81
+ * under, the message a `meta` op names, the display a change is to, what a
82
+ * `remove` takes away. An op about what has not arrived yet waits.
83
+ */
84
+ export declare function placeable<T extends WithDisplays>(items: readonly T[], op: UiOp): boolean;
85
+ /**
86
+ * The press a run's `forwardedProps` carries for a display's button — what
87
+ * `AnswerShowsView` hands the chat — or `null` for a run that presses
88
+ * nothing of a display's. It goes up the ui socket, never in the run.
89
+ */
90
+ export declare function displayPressOf(forwardedProps: Record<string, unknown> | undefined): UiAction | null;
91
+ /**
92
+ * The run's `forwardedProps` once its press was checked on the socket: the
93
+ * press named by the id the runtime answered, the action itself gone.
94
+ */
95
+ export declare function withPress(forwardedProps: Record<string, unknown>, answered: unknown): Record<string, unknown>;
96
+ export {};
@@ -0,0 +1,251 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * What a server says to a conversation's page, as `reactor.ui` ops
7
+ * (REACTOR_UI RU-2, RU-3), and what the page presses back (RU-W).
8
+ *
9
+ * The ops arrive on the conversation's ui socket (Reactor's `UiSocket`,
10
+ * one per session, beside the run stream that carries the conversation's
11
+ * text); `routeUiOp` says where each goes:
12
+ *
13
+ * - a `window` op to the page the conversation sits in (`loopWindow`);
14
+ * - a step's display to its row (`loopStep`), patched as it streams;
15
+ * - a display that says it shows in a panel or on a page to the elements
16
+ * open (`loopElement`), a `remove` of its id closing it;
17
+ * - everything else to the messages (`withUiOp`): a display under a message
18
+ * (`data.message_id`) kept on it (`ChatMessage.displays`) and drawn by the
19
+ * renderer a plugin contributed for its type; a `meta` op's `author` the
20
+ * message's voice; a `remove` of a message's id the message gone.
21
+ *
22
+ * An op about a message that has not arrived on the run stream yet — the
23
+ * two are separate connections — waits until it has (`placeable`). A press
24
+ * of what a display offered goes up the socket (`displayPressOf`), and the
25
+ * run that answers it names it only (`withPress`).
26
+ *
27
+ * Pure: the chat applies it to what it draws, and to its store. Nothing it
28
+ * was not told to expect is guessed at: an op it cannot place throws.
29
+ *
30
+ * @module chat/base/uiOps
31
+ */
32
+ import { applyPatch, applyUiOp, } from '@datalayer/reactor/ui';
33
+ import { elementOfDisplay } from './loopElement';
34
+ import { isStepDisplay, stepOfDisplay } from './loopStep';
35
+ import { windowMessageOf } from './loopWindow';
36
+ /** The message a display is under: its `data.message_id`. */
37
+ export function messageOfDisplay(display) {
38
+ const id = display.data?.message_id;
39
+ if (typeof id !== 'string' || !id) {
40
+ throw new Error(`Display ${display.id} says no message it is under`);
41
+ }
42
+ return id;
43
+ }
44
+ /** Who a message is by, as the chat draws a named voice. */
45
+ export function speakerOf(author) {
46
+ return { id: `author:${author}`, name: author };
47
+ }
48
+ /** The messages with one display changed by `change`, or taken away when it answers nothing. */
49
+ function changed(items, id, change) {
50
+ const at = items.findIndex(item => (item.displays ?? []).some(display => display.id === id));
51
+ if (at < 0) {
52
+ throw new Error(`Display ${id} is shown under no message here`);
53
+ }
54
+ return items.map((item, index) => {
55
+ if (index !== at)
56
+ return item;
57
+ const displays = [];
58
+ for (const display of item.displays ?? []) {
59
+ if (display.id !== id) {
60
+ displays.push(display);
61
+ continue;
62
+ }
63
+ const next = change(display);
64
+ if (next)
65
+ displays.push({ ...next, id });
66
+ }
67
+ return { ...item, displays };
68
+ });
69
+ }
70
+ function replaced(displays, display) {
71
+ const at = displays.findIndex(one => one.id === display.id);
72
+ return at < 0
73
+ ? [...displays, display]
74
+ : displays.map((one, index) => (index === at ? display : one));
75
+ }
76
+ /**
77
+ * The messages with an op applied: a display shown (or asked) kept on its
78
+ * message, replacing one of its id; patched, appended to or removed where it
79
+ * is. A `remove` of a message's own id takes the message away, with what it
80
+ * showed; a `meta` op about a message gives it its `author`. `state` ops are
81
+ * not about the messages: they come back as they were.
82
+ *
83
+ * Throws for a display under no message here, for a change to a display no
84
+ * message shows, for a removal of nothing here, and for a `meta` op that
85
+ * says anything but a message's author: the server said something the page
86
+ * never saw, or does not read.
87
+ */
88
+ export function withUiOp(items, op) {
89
+ switch (op.op) {
90
+ case 'show':
91
+ case 'ask': {
92
+ const shown = op.body;
93
+ const messageId = messageOfDisplay(shown);
94
+ if (!items.some(item => item.id === messageId)) {
95
+ throw new Error(`Display ${shown.id} is under message ${messageId}, which is not here`);
96
+ }
97
+ return items.map(item => item.id === messageId
98
+ ? { ...item, displays: replaced(item.displays ?? [], shown) }
99
+ : item);
100
+ }
101
+ case 'remove': {
102
+ const showsIt = items.some(item => (item.displays ?? []).some(display => display.id === op.id));
103
+ if (showsIt)
104
+ return changed(items, op.id, () => undefined);
105
+ if (!items.some(item => item.id === op.id)) {
106
+ throw new Error(`Nothing here is ${op.id}: it cannot be removed`);
107
+ }
108
+ return items.filter(item => item.id !== op.id);
109
+ }
110
+ case 'patch': {
111
+ const operations = op.body;
112
+ return changed(items, op.id, display => applyPatch(display, operations));
113
+ }
114
+ case 'append': {
115
+ const { path, value } = op.body;
116
+ return changed(items, op.id, display => applyPatch(display, [{ op: 'add', path: `${path}/-`, value }]));
117
+ }
118
+ case 'meta': {
119
+ const author = op.body.author;
120
+ const keys = Object.keys(op.body);
121
+ if (!op.id ||
122
+ keys.length !== 1 ||
123
+ typeof author !== 'string' ||
124
+ !author.trim()) {
125
+ throw new Error(`A meta op says ${JSON.stringify(op.body)}: only a message's author is read`);
126
+ }
127
+ if (!items.some(item => item.id === op.id)) {
128
+ throw new Error(`Message ${op.id} is not here: it has no author to say`);
129
+ }
130
+ return items.map(item => item.id === op.id
131
+ ? { ...item, speaker: speakerOf(author.trim()) }
132
+ : item);
133
+ }
134
+ case 'window':
135
+ throw new Error('A window op is for the page, not the messages');
136
+ default:
137
+ return items;
138
+ }
139
+ }
140
+ /**
141
+ * Where an op goes, and the steps kept after it: a step's display is kept
142
+ * (in a Reactor `UiModel`) so a patch of its output applies to it.
143
+ *
144
+ * `elements` is the ids of the elements shown in this conversation: a
145
+ * `remove` of one closes it (a no-op when the person closed it already).
146
+ */
147
+ export function routeUiOp(op, steps, elements) {
148
+ switch (op.op) {
149
+ case 'window':
150
+ return { routed: { to: 'window', data: windowMessageOf(op) }, steps };
151
+ case 'show':
152
+ case 'ask': {
153
+ if (isStepDisplay(op.body)) {
154
+ const kept = applyUiOp(steps, op);
155
+ return {
156
+ routed: { to: 'step', step: stepOfDisplay(op.body) },
157
+ steps: kept,
158
+ };
159
+ }
160
+ const element = elementOfDisplay(op.body);
161
+ if (element) {
162
+ return { routed: { to: 'element', change: element }, steps };
163
+ }
164
+ return { routed: { to: 'messages', op }, steps };
165
+ }
166
+ case 'patch':
167
+ case 'append': {
168
+ if (op.id in steps.displays) {
169
+ const kept = applyUiOp(steps, op);
170
+ return {
171
+ routed: { to: 'step', step: stepOfDisplay(kept.displays[op.id]) },
172
+ steps: kept,
173
+ };
174
+ }
175
+ return { routed: { to: 'messages', op }, steps };
176
+ }
177
+ case 'remove': {
178
+ if (op.id in steps.displays) {
179
+ throw new Error(`Step ${op.id} is never removed: it ends`);
180
+ }
181
+ if (elements.has(op.id)) {
182
+ return {
183
+ routed: { to: 'element', change: { id: op.id, closed: true } },
184
+ steps,
185
+ };
186
+ }
187
+ return { routed: { to: 'messages', op }, steps };
188
+ }
189
+ default:
190
+ return { routed: { to: 'messages', op }, steps };
191
+ }
192
+ }
193
+ /**
194
+ * Whether the messages hold what an op is about: the message a display is
195
+ * under, the message a `meta` op names, the display a change is to, what a
196
+ * `remove` takes away. An op about what has not arrived yet waits.
197
+ */
198
+ export function placeable(items, op) {
199
+ const hasItem = (id) => !!id && items.some(item => item.id === id);
200
+ const hasDisplay = (id) => !!id &&
201
+ items.some(item => (item.displays ?? []).some(display => display.id === id));
202
+ switch (op.op) {
203
+ case 'show':
204
+ case 'ask': {
205
+ const under = op.body.data?.message_id;
206
+ return typeof under === 'string' && hasItem(under);
207
+ }
208
+ case 'meta':
209
+ return hasItem(op.id);
210
+ case 'patch':
211
+ case 'append':
212
+ return hasDisplay(op.id);
213
+ case 'remove':
214
+ return hasDisplay(op.id) || hasItem(op.id);
215
+ default:
216
+ return true;
217
+ }
218
+ }
219
+ /**
220
+ * The press a run's `forwardedProps` carries for a display's button — what
221
+ * `AnswerShowsView` hands the chat — or `null` for a run that presses
222
+ * nothing of a display's. It goes up the ui socket, never in the run.
223
+ */
224
+ export function displayPressOf(forwardedProps) {
225
+ const loop = forwardedProps?.loop;
226
+ const action = loop?.action;
227
+ if (!action || typeof action.display_id !== 'string')
228
+ return null;
229
+ if (typeof action.name !== 'string' || typeof action.token !== 'string') {
230
+ throw new Error('A press of a display says its action and its token');
231
+ }
232
+ return {
233
+ action: action.name,
234
+ display_id: action.display_id,
235
+ token: action.token,
236
+ payload: action.payload ?? {},
237
+ };
238
+ }
239
+ /**
240
+ * The run's `forwardedProps` once its press was checked on the socket: the
241
+ * press named by the id the runtime answered, the action itself gone.
242
+ */
243
+ export function withPress(forwardedProps, answered) {
244
+ const press = answered?.press;
245
+ if (typeof press !== 'string' || !press) {
246
+ throw new Error('The runtime checked the press but named none');
247
+ }
248
+ const loop = { ...forwardedProps.loop };
249
+ delete loop.action;
250
+ return { ...forwardedProps, loop: { ...loop, press } };
251
+ }
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode, type RefObject } from 'react';
2
+ import { type Display, type UiAct } from '@datalayer/reactor/ui';
2
3
  import { type ChatDensity } from './ChatMarkdown';
3
4
  import { type MarkedMcpServer } from '../marks';
4
5
  import type { DisplayItem, AvatarConfig } from '../../types/chat';
@@ -13,6 +14,12 @@ export interface ToolApprovalConfig {
13
14
  export interface ChatMessageListProps {
14
15
  /** All display items (messages + tool calls) */
15
16
  displayItems: DisplayItem[];
17
+ /**
18
+ * How a message's display presses what it offered (REACTOR_UI RU-4, RU-W):
19
+ * the chat sends it up the conversation's ui socket. Absent, its
20
+ * displays offer nothing to press.
21
+ */
22
+ actOn?: (display: Display) => UiAct;
16
23
  /** Whether the agent is loading */
17
24
  isLoading: boolean;
18
25
  /** Whether the agent is currently streaming */
@@ -97,5 +104,5 @@ export interface SubagentChatPanelProps {
97
104
  * approval decisions are sent over the shared monitoring socket.
98
105
  */
99
106
  export declare function SubagentChatPanel({ toolCallId, subagentName: subagentNameHint, height, avatarConfig, }: SubagentChatPanelProps): React.ReactElement | null;
100
- export declare function ChatMessageList({ displayItems, isLoading, isStreaming, showLoadingIndicator, hideMessagesAfterToolUI, avatarConfig, padding, notebookToolSurfacesId, emptyContent, messagesEndRef, onRespond, approvalConfig, showTurnFooters, agentUsage, onRemoveItems, renderMessageFooter, mcpServers, density, }: ChatMessageListProps): import("react").JSX.Element;
107
+ export declare function ChatMessageList({ displayItems, actOn, isLoading, isStreaming, showLoadingIndicator, hideMessagesAfterToolUI, avatarConfig, padding, notebookToolSurfacesId, emptyContent, messagesEndRef, onRespond, approvalConfig, showTurnFooters, agentUsage, onRemoveItems, renderMessageFooter, mcpServers, density, }: ChatMessageListProps): import("react").JSX.Element;
101
108
  export {};
@@ -12,8 +12,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
12
12
  import { MicrophoneIcon } from '@datalayer/icons-react';
13
13
  import { Fragment, lazy, Suspense, useState, useCallback, useEffect, useMemo, useRef, useSyncExternalStore, } from 'react';
14
14
  import { useOptionalReactorPlatform } from '@datalayer/reactor/react';
15
- import { resolveToolResult } from '@datalayer/reactor/ui';
16
- import { ReactorDisplay } from '@datalayer/reactor/ui/react';
15
+ import { resolveToolResult, } from '@datalayer/reactor/ui';
16
+ import { DisplayText, ReactorDisplay } from '@datalayer/reactor/ui/react';
17
17
  import { Text, Spinner, Link, Label, RelativeTime } from '@primer/react';
18
18
  import { ArrowRightIcon, BroadcastIcon, ClockIcon, DependabotIcon, PersonIcon, SkipIcon, ToolsIcon, XCircleFillIcon, } from '@primer/octicons-react';
19
19
  import { Box } from '@datalayer/primer-addons';
@@ -366,7 +366,7 @@ function DefaultToolCallRenderer({ item, onRespond, mcpServers, density, }) {
366
366
  // ---------------------------------------------------------------------------
367
367
  // Component
368
368
  // ---------------------------------------------------------------------------
369
- export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoadingIndicator, hideMessagesAfterToolUI, avatarConfig, padding, notebookToolSurfacesId, emptyContent, messagesEndRef, onRespond, approvalConfig, showTurnFooters = false, agentUsage, onRemoveItems, renderMessageFooter, mcpServers, density = 'comfortable', }) {
369
+ export function ChatMessageList({ displayItems, actOn, isLoading, isStreaming, showLoadingIndicator, hideMessagesAfterToolUI, avatarConfig, padding, notebookToolSurfacesId, emptyContent, messagesEndRef, onRespond, approvalConfig, showTurnFooters = false, agentUsage, onRemoveItems, renderMessageFooter, mcpServers, density = 'comfortable', }) {
370
370
  /*
371
371
  * Who draws a tool call: the Reactor plugins of the page, when it has a
372
372
  * platform. Each plugin binds its own tools (`ToolBindings`) and renders its
@@ -611,7 +611,7 @@ export function ChatMessageList({ displayItems, isLoading, isStreaming, showLoad
611
611
  whiteSpace: 'pre-wrap',
612
612
  wordBreak: 'break-word',
613
613
  }, children: [message.metadata?.input === 'voice' ? (_jsx(Box, { as: "span", "data-spoken": "", title: "Said aloud", "aria-label": "Said aloud:", display: "inline-flex", verticalAlign: "text-bottom", mr: 1, opacity: 0.85, children: _jsx(MicrophoneIcon, { size: 14, "aria-hidden": "true" }) })) : null, text] }));
614
- })()) : message.live && !getMessageText(message) ? (_jsx(TypingDots, { size: 6 })) : (_jsx(ChatMarkdown, { density: density, text: getMessageText(message) || (isStreaming ? '...' : '') }))] }), renderMessageFooter ? (_jsx(Box, { display: "flex", gap: 2, alignItems: "center", mt: 1, flexWrap: "wrap", flexDirection: isUser ? 'row-reverse' : 'row', children: renderMessageFooter(message) })) : null] })] }) }, message.id));
614
+ })()) : message.live && !getMessageText(message) ? (_jsx(TypingDots, { size: 6 })) : (_jsx(ChatMarkdown, { density: density, text: getMessageText(message) || (isStreaming ? '...' : '') }))] }), message.displays?.length ? (_jsx(Box, { "data-chat-displays": "", display: "flex", flexDirection: "column", gap: 2, mt: 2, width: "100%", children: message.displays.map(display => platform ? (_jsx(ReactorDisplay, { display: display, act: actOn?.(display) }, display.id)) : (_jsx(DisplayText, { display: display }, display.id))) })) : null, renderMessageFooter ? (_jsx(Box, { display: "flex", gap: 2, alignItems: "center", mt: 1, flexWrap: "wrap", flexDirection: isUser ? 'row-reverse' : 'row', children: renderMessageFooter(message) })) : null] })] }) }, message.id));
615
615
  };
616
616
  return (_jsxs(_Fragment, { children: [displayItems.map((item, index) => {
617
617
  const itemUI = renderItem(item, index);
@@ -121,7 +121,7 @@ export declare function chartOption(points: Record<string, unknown>[], props: Pi
121
121
  };
122
122
  series: {
123
123
  name: string;
124
- type: "line" | "bar" | "scatter";
124
+ type: "bar" | "line" | "scatter";
125
125
  areaStyle: {} | undefined;
126
126
  data: number[][] | (number | null)[];
127
127
  }[];
@@ -19,7 +19,7 @@
19
19
  */
20
20
  import { z } from 'zod/v3';
21
21
  import { ActionSchema, DataBindingSchema } from '@a2ui/web_core/v0_9';
22
- import { COMPONENT_CATALOGUE } from '../../../specs/uiPlugins';
22
+ import { COMPONENT_CATALOGUE } from '../../../specs/ui';
23
23
  /** The components of Datalayer's own the catalog has, by id. */
24
24
  export const OWN_COMPONENT_IDS = Object.values(COMPONENT_CATALOGUE)
25
25
  .filter(component => !component.standard)
@@ -30,8 +30,9 @@ export type AnswerPressed = {
30
30
  does: string;
31
31
  };
32
32
  /**
33
- * What a button pressed on an answer's surface sends back, or `null` for an
34
- * action that is not one of an answer's buttons (a form's submission).
33
+ * What a button pressed on a member's surface sends back, or `null` for an
34
+ * action that is not one of its buttons (a form's submission). A member's
35
+ * surface is an answer by how it came — an A2A artifact — not by its id.
35
36
  */
36
37
  export declare function pressedOf(action: {
37
38
  name: string;
@@ -1,21 +1,21 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Suspense, lazy } from 'react';
3
3
  import { Text } from '@primer/react';
4
- import { answerAction } from '../../apps/plugins/a2ui-surface/toolResult';
5
4
  /** The renderer itself: A2UI and the catalog, loaded when a surface is drawn. */
6
5
  const AnswerSurfacesView = lazy(() => import('./AnswerSurfacesView'));
7
6
  /**
8
- * What a button pressed on an answer's surface sends back, or `null` for an
9
- * action that is not one of an answer's buttons (a form's submission).
7
+ * What a button pressed on a member's surface sends back, or `null` for an
8
+ * action that is not one of its buttons (a form's submission). A member's
9
+ * surface is an answer by how it came — an A2A artifact — not by its id.
10
10
  */
11
11
  export function pressedOf(action) {
12
- const pressed = answerAction(action);
13
- if (!pressed) {
12
+ const name = action.name.trim();
13
+ if (!name || name === 'submit_a2ui_form') {
14
14
  return null;
15
15
  }
16
- const { name, payload } = pressed.forwardedProps.loop.action;
16
+ const payload = { ...action.context };
17
17
  const does = typeof payload.does === 'string' ? payload.does : 'read';
18
- return { message: pressed.message, action: { name, payload }, does };
18
+ return { message: name, action: { name, payload }, does };
19
19
  }
20
20
  /** The surfaces the members showed, each under who showed it; nothing when there is none. */
21
21
  export function AnswerSurfaces(props) {
@@ -59,7 +59,7 @@ export declare const NOTEBOOK_AND_WORDS: readonly string[];
59
59
  export declare const COMPONENTS_NOTEBOOK_AND_WORDS: readonly string[];
60
60
  /** A surface of components a member showed with an answer: who gave it, and the surface. */
61
61
  export type A2ATeamSurface = {
62
- /** Its surface's id: `answer-…`. */
62
+ /** Its surface's id. */
63
63
  id: string;
64
64
  /** The member that showed it, by its id. */
65
65
  giver: string;
@@ -29,7 +29,7 @@ export interface LibraryAgentspec {
29
29
  welcomeDocument?: string | null;
30
30
  sandboxVariant?: string | null;
31
31
  protocol?: string | null;
32
- uiPlugin?: string | null;
32
+ ui?: string | null;
33
33
  trigger?: Record<string, unknown> | null;
34
34
  modelConfig?: Record<string, unknown> | null;
35
35
  mcpServerTools?: Array<Record<string, unknown>> | null;
@@ -7,6 +7,8 @@ import type { ProtocolAdapterConfig } from '../types';
7
7
  import type { ChatMessage } from '../types/messages';
8
8
  import type { ToolDefinition, ToolExecutionResult } from '../types/tools';
9
9
  import { BaseProtocolAdapter } from './BaseProtocolAdapter';
10
+ /** What the page says when a run's stream closes before the run said how it ended. */
11
+ export declare const RUN_CUT_SHORT = "The run stopped before it finished, without an answer or an error: send it again.";
10
12
  /**
11
13
  * AG-UI specific configuration
12
14
  */
@@ -110,6 +112,11 @@ export declare class AGUIAdapter extends BaseProtocolAdapter {
110
112
  * Parse SSE stream from AG-UI response
111
113
  */
112
114
  private parseSSEStream;
115
+ /**
116
+ * A `reactor.ui` op on the run stream: refused, and said as an error. The
117
+ * ops come over the conversation's ui socket (REACTOR_UI RU-W).
118
+ */
119
+ private refuseUiOnRun;
113
120
  /**
114
121
  * Handle individual AG-UI events
115
122
  *
@@ -5,6 +5,9 @@
5
5
  import { generateMessageId, createAssistantMessage } from '../types/messages';
6
6
  import { agUiRefusal, refusalBody } from './agUiRefusal';
7
7
  import { BaseProtocolAdapter } from './BaseProtocolAdapter';
8
+ import { AGUI_NAME } from '@datalayer/reactor/ui';
9
+ /** What the page says when a run's stream closes before the run said how it ended. */
10
+ export const RUN_CUT_SHORT = 'The run stopped before it finished, without an answer or an error: send it again.';
8
11
  /**
9
12
  * AG-UI protocol adapter
10
13
  * Uses HTTP POST with SSE streaming for responses
@@ -426,11 +429,20 @@ export class AGUIAdapter extends BaseProtocolAdapter {
426
429
  });
427
430
  }
428
431
  this._streamParsingDepth++;
432
+ // Whether the run said how it ended. A stream that closes without
433
+ // RUN_FINISHED or RUN_ERROR is a run cut short — by the runtime, a proxy
434
+ // or the network — and the page says so instead of waiting for an answer
435
+ // that is not coming (a Preview gave no answer for minutes, 2026-10-12).
436
+ let ended = false;
429
437
  try {
430
438
  while (true) {
431
439
  const { done, value } = await reader.read();
432
- if (done)
440
+ if (done) {
441
+ if (!ended) {
442
+ throw new Error(RUN_CUT_SHORT);
443
+ }
433
444
  break;
445
+ }
434
446
  buffer += decoder.decode(value, { stream: true });
435
447
  const lines = buffer.split('\n');
436
448
  buffer = lines.pop() || '';
@@ -444,6 +456,10 @@ export class AGUIAdapter extends BaseProtocolAdapter {
444
456
  const data = line.slice(6);
445
457
  try {
446
458
  const event = JSON.parse(data);
459
+ const kind = event.type;
460
+ if (kind === 'RUN_FINISHED' || kind === 'RUN_ERROR') {
461
+ ended = true;
462
+ }
447
463
  this.handleAGUIEvent(event, {
448
464
  getCurrentMessageId: () => currentMessageId,
449
465
  setCurrentMessageId: id => {
@@ -483,6 +499,17 @@ export class AGUIAdapter extends BaseProtocolAdapter {
483
499
  }
484
500
  }
485
501
  }
502
+ /**
503
+ * A `reactor.ui` op on the run stream: refused, and said as an error. The
504
+ * ops come over the conversation's ui socket (REACTOR_UI RU-W).
505
+ */
506
+ refuseUiOnRun() {
507
+ this.emit({
508
+ type: 'error',
509
+ error: new Error('A reactor.ui op came on the run stream: it comes over the ui socket (REACTOR_UI RU-W).'),
510
+ timestamp: new Date(),
511
+ });
512
+ }
486
513
  /**
487
514
  * Handle individual AG-UI events
488
515
  *
@@ -684,14 +711,27 @@ export class AGUIAdapter extends BaseProtocolAdapter {
684
711
  });
685
712
  break;
686
713
  }
714
+ case 'ACTIVITY_SNAPSHOT':
715
+ case 'ACTIVITY_DELTA': {
716
+ // `reactor.ui` ops come over the conversation's ui socket, never
717
+ // the run stream (REACTOR_UI RU-W): one here is refused. Any other
718
+ // activity is nobody's here.
719
+ if (event.activityType === AGUI_NAME) {
720
+ this.refuseUiOnRun();
721
+ }
722
+ break;
723
+ }
687
724
  case 'CUSTOM': {
688
725
  const name = event.name;
689
- const value = event.value;
726
+ if (name === AGUI_NAME) {
727
+ this.refuseUiOnRun();
728
+ break;
729
+ }
690
730
  this.emit({
691
731
  type: 'activity',
692
732
  activity: {
693
733
  type: name || 'custom',
694
- data: value,
734
+ data: event.value,
695
735
  },
696
736
  timestamp: new Date(),
697
737
  });
@@ -19,15 +19,11 @@ import { AGENTIC_COMMERCE_VERSION } from './models';
19
19
  export { AGENTIC_COMMERCE_VERSION };
20
20
  export declare const DISCOVERY_PATH = "/.well-known/acp.json";
21
21
  export declare const AGENTIC_COMMERCE_PLUGIN = "agent-runtimes.protocols.agentic-commerce";
22
- /** Each operation's action class (F-10), for Rules (R-05). */
23
- export declare const AGENTIC_COMMERCE_ACTION_CLASSES: {
24
- readonly proposeCompletion: "read";
25
- readonly getCheckout: "read";
26
- readonly createCheckout: "write";
27
- readonly updateCheckout: "write";
28
- readonly cancelCheckout: "write";
29
- readonly complete: "buy";
30
- };
22
+ /**
23
+ * Each operation's action class (F-10), for Rules (R-05): agentspecs'
24
+ * `protocol-tools/agentic-commerce.yaml` (AGENT_PROTOCOLS PR-54).
25
+ */
26
+ export declare const AGENTIC_COMMERCE_ACTION_CLASSES: Record<string, import("../../types").ActionClass>;
31
27
  export declare class AgenticCommerceError extends Error {
32
28
  }
33
29
  type Json = Record<string, any>;
@@ -17,21 +17,17 @@
17
17
  * @module protocols/agentic-commerce
18
18
  */
19
19
  import { contribution, defineContributionPoint, definePlugin, } from '@datalayer/reactor';
20
- import { InMemoryProposalStore, digest, } from '../commerce';
20
+ import { InMemoryProposalStore, digest, operationClasses, } from '../commerce';
21
21
  import { DEFAULT_ORDER, ProtocolDescriptions, firstContribution, } from '../core';
22
22
  import { AGENTIC_COMMERCE_VERSION } from './models';
23
23
  export { AGENTIC_COMMERCE_VERSION };
24
24
  export const DISCOVERY_PATH = '/.well-known/acp.json';
25
25
  export const AGENTIC_COMMERCE_PLUGIN = 'agent-runtimes.protocols.agentic-commerce';
26
- /** Each operation's action class (F-10), for Rules (R-05). */
27
- export const AGENTIC_COMMERCE_ACTION_CLASSES = {
28
- proposeCompletion: 'read',
29
- getCheckout: 'read',
30
- createCheckout: 'write',
31
- updateCheckout: 'write',
32
- cancelCheckout: 'write',
33
- complete: 'buy',
34
- };
26
+ /**
27
+ * Each operation's action class (F-10), for Rules (R-05): agentspecs'
28
+ * `protocol-tools/agentic-commerce.yaml` (AGENT_PROTOCOLS PR-54).
29
+ */
30
+ export const AGENTIC_COMMERCE_ACTION_CLASSES = operationClasses('agentic-commerce');
35
31
  export class AgenticCommerceError extends Error {
36
32
  }
37
33
  export const AgenticCommerceApprovers = defineContributionPoint('agentic_commerce.approver');