@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.
- package/dist-embed/chunks/{ChatView-D41Nx5rC.js → ChatView-BpKZPdcp.js} +4 -4
- package/dist-embed/datalayer-app-main.js +150 -150
- package/lib/apps/apps/appspec.d.ts +13 -0
- package/lib/apps/apps/appspec.js +125 -0
- package/lib/apps/apps/checks.d.ts +1 -1
- package/lib/apps/apps/checks.js +2 -2
- package/lib/apps/apps/customComponents.js +1 -1
- package/lib/apps/core/canvasBlocks.d.ts +3 -3
- package/lib/apps/core/canvasParts.d.ts +6 -4
- package/lib/apps/embed/AppEmbed.js +3 -7
- package/lib/apps/embed/embedSession.d.ts +8 -4
- package/lib/apps/embed/embedSession.js +16 -9
- package/lib/apps/plugins/a2ui-surface/AnswerShows.d.ts +21 -0
- package/lib/apps/plugins/a2ui-surface/AnswerShows.js +29 -0
- package/lib/apps/plugins/a2ui-surface/SurfaceToolResult.js +4 -7
- package/lib/apps/plugins/a2ui-surface/index.d.ts +2 -1
- package/lib/apps/plugins/a2ui-surface/index.js +10 -1
- package/lib/apps/plugins/a2ui-surface/toolResult.d.ts +20 -11
- package/lib/apps/plugins/a2ui-surface/toolResult.js +27 -11
- package/lib/apps/plugins/app-components/index.d.ts +1 -1
- package/lib/apps/plugins/app-components/index.js +2 -2
- package/lib/apps/plugins/app-elements/AppElements.d.ts +3 -3
- package/lib/apps/plugins/app-elements/AppElements.js +5 -20
- package/lib/apps/plugins/app-elements/QuestionView.d.ts +28 -0
- package/lib/apps/plugins/app-elements/QuestionView.js +57 -0
- package/lib/apps/plugins/app-elements/index.d.ts +7 -4
- package/lib/apps/plugins/app-elements/index.js +14 -5
- package/lib/apps/plugins/canvas-blocks/index.d.ts +13 -13
- package/lib/apps/plugins/canvas-blocks/index.js +24 -24
- package/lib/apps/plugins/canvas-parts/index.d.ts +7 -1
- package/lib/apps/plugins/canvas-parts/index.js +36 -0
- package/lib/apps/plugins/chat/ChatView.js +7 -0
- package/lib/chat/base/ChatBase.js +234 -43
- package/lib/chat/base/loopElement.d.ts +16 -17
- package/lib/chat/base/loopElement.js +11 -27
- package/lib/chat/base/loopStep.d.ts +15 -15
- package/lib/chat/base/loopStep.js +10 -13
- package/lib/chat/base/loopWindow.d.ts +15 -20
- package/lib/chat/base/loopWindow.js +26 -27
- package/lib/chat/base/uiOps.d.ts +96 -0
- package/lib/chat/base/uiOps.js +251 -0
- package/lib/chat/messages/ChatMessageList.d.ts +8 -1
- package/lib/chat/messages/ChatMessageList.js +4 -4
- package/lib/components/a2ui/datalayer/Chart.d.ts +1 -1
- package/lib/components/a2ui/datalayer/schema.js +1 -1
- package/lib/components/teams/AnswerSurfaces.d.ts +3 -2
- package/lib/components/teams/AnswerSurfaces.js +7 -7
- package/lib/components/teams/useA2ATeam.d.ts +1 -1
- package/lib/config/AgentConfiguration.d.ts +1 -1
- package/lib/protocols/AGUIAdapter.d.ts +7 -0
- package/lib/protocols/AGUIAdapter.js +43 -3
- package/lib/protocols/agentic-commerce/index.d.ts +5 -9
- package/lib/protocols/agentic-commerce/index.js +6 -10
- package/lib/protocols/commerce.d.ts +8 -9
- package/lib/protocols/commerce.js +29 -0
- package/lib/protocols/ucp/index.d.ts +5 -10
- package/lib/protocols/ucp/index.js +6 -11
- package/lib/specs/actions.d.ts +8 -0
- package/lib/specs/actions.js +56 -0
- package/lib/specs/agents/agents.js +338 -169
- package/lib/specs/apps.d.ts +1 -0
- package/lib/specs/apps.js +272 -0
- package/lib/specs/appspecSchema.js +125 -0
- package/lib/specs/cogs.js +6 -3
- package/lib/specs/index.d.ts +2 -1
- package/lib/specs/index.js +2 -1
- package/lib/specs/protocols.d.ts +24 -0
- package/lib/specs/protocols.js +197 -0
- package/lib/specs/ui.d.ts +21 -0
- package/lib/specs/{uiPlugins.js → ui.js} +14 -14
- package/lib/types/agentspecs.d.ts +72 -5
- package/lib/types/messages.d.ts +7 -0
- package/lib/types/protocol.d.ts +8 -0
- package/package.json +2 -2
- package/scripts/codegen/generate_agents.py +43 -8
- package/scripts/codegen/generate_apps.py +38 -1
- package/scripts/codegen/generate_protocols.py +207 -0
- package/scripts/codegen/generate_sandbox_agents.py +1 -1
- package/scripts/codegen/{generate_ui_plugins.py → generate_ui.py} +40 -40
- package/scripts/gen_workers.py +2 -2
- package/lib/chat/base/loopMessage.d.ts +0 -37
- package/lib/chat/base/loopMessage.js +0 -37
- 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: "
|
|
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/
|
|
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
|
|
34
|
-
* action that is not one of
|
|
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
|
|
9
|
-
* action that is not one of
|
|
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
|
|
13
|
-
if (!
|
|
12
|
+
const name = action.name.trim();
|
|
13
|
+
if (!name || name === 'submit_a2ui_form') {
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
|
-
const
|
|
16
|
+
const payload = { ...action.context };
|
|
17
17
|
const does = typeof payload.does === 'string' ? payload.does : 'read';
|
|
18
|
-
return { message:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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');
|