@datalayer/agent-runtimes 1.3.114 → 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 (73) 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 +71 -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/specs/agents/agents.js +338 -169
  53. package/lib/specs/apps.js +47 -0
  54. package/lib/specs/appspecSchema.js +16 -0
  55. package/lib/specs/cogs.js +6 -3
  56. package/lib/specs/index.d.ts +2 -1
  57. package/lib/specs/index.js +2 -1
  58. package/lib/specs/protocols.d.ts +24 -0
  59. package/lib/specs/protocols.js +197 -0
  60. package/lib/specs/ui.d.ts +21 -0
  61. package/lib/specs/{uiPlugins.js → ui.js} +14 -14
  62. package/lib/types/agentspecs.d.ts +51 -5
  63. package/lib/types/messages.d.ts +7 -0
  64. package/lib/types/protocol.d.ts +8 -0
  65. package/package.json +2 -2
  66. package/scripts/codegen/generate_agents.py +43 -8
  67. package/scripts/codegen/generate_protocols.py +207 -0
  68. package/scripts/codegen/generate_sandbox_agents.py +1 -1
  69. package/scripts/codegen/{generate_ui_plugins.py → generate_ui.py} +40 -40
  70. package/scripts/gen_workers.py +2 -2
  71. package/lib/chat/base/loopMessage.d.ts +0 -37
  72. package/lib/chat/base/loopMessage.js +0 -37
  73. package/lib/specs/uiPlugins.d.ts +0 -21
@@ -1,12 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useMemo, useSyncExternalStore } from 'react';
2
+ import { useSyncExternalStore } from 'react';
3
3
  import { IconButton, Text } from '@primer/react';
4
4
  import { XIcon } from '@primer/octicons-react';
5
5
  import { Box } from '@datalayer/primer-addons';
6
6
  import { closeLoopElement, onLoopElements, openLoopElements, } from '../../../chat/base/loopElement';
7
- import { InlineSurface, SURFACE_CATALOG_ID, } from '../a2ui-surface/InlineSurface';
8
- import { answerAction, readA2uiToolResult } from '../a2ui-surface/toolResult';
9
- import { useOwnCatalog } from '../a2ui-surface/ownComponents';
7
+ import { AnswerShowsView } from '../a2ui-surface/AnswerShows';
10
8
  /** How wide the side panel is, at most. */
11
9
  export const APP_PANEL_WIDTH = 380;
12
10
  /** What is open now: the panels in the order they opened, and the last page. */
@@ -18,22 +16,9 @@ export function elementsByPlace(open) {
18
16
  };
19
17
  }
20
18
  function ElementBody({ element, send, }) {
21
- const parsed = useMemo(() => readA2uiToolResult(element.shows, SURFACE_CATALOG_ID), [element.shows]);
22
- // With the components its developer wrote (P-17).
23
- const catalog = useOwnCatalog();
24
- const onAction = (action) => {
25
- // A button of what its code shows: its action goes to the application,
26
- // as a button of an answer does (LOOP P-04).
27
- const pressed = answerAction(action);
28
- if (pressed)
29
- send?.(pressed.message, pressed.forwardedProps);
30
- };
31
- if (!parsed?.messages || parsed.messages.length === 0) {
32
- return _jsx(Text, { sx: { color: 'fg.muted' }, children: "Nothing to show." });
33
- }
34
- return (_jsx(InlineSurface
35
- // Drawn again whole when the code changes it.
36
- , { messages: parsed.messages, onAction: onAction, catalog: catalog }, JSON.stringify(element.shows)));
19
+ // What its code shows, drawn as an answer's display is: its buttons press
20
+ // what the display offered (LOOP P-04, REACTOR_UI RU-2).
21
+ return (_jsx(AnswerShowsView, { display: element.shows, send: (message, forwardedProps) => send !== undefined && !send(message, forwardedProps) }));
37
22
  }
38
23
  function ElementHeader({ element }) {
39
24
  return (_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2, mb: 2, children: [_jsx(Text, { as: "h2", sx: { fontSize: 2, fontWeight: 'bold', m: 0 }, children: element.title }), _jsx(IconButton, { icon: XIcon, variant: "invisible", size: "small", "aria-label": `Close ${element.title}`, onClick: () => closeLoopElement(element.id) })] }));
@@ -0,0 +1,28 @@
1
+ /**
2
+ * What an application's code asks, drawn from its display (REACTOR_UI
3
+ * RU-4): `application/vnd.datalayer.loop.question+json`, shown under the
4
+ * message that asks it in words. A choice is its buttons — a rule's prompt
5
+ * is Allow and Refuse — the words a field, a form its fields; each press of
6
+ * it is `reactor.answer`, through the display's `act`, which the chat sends
7
+ * up the conversation's ui socket. A file is attached in the composer (until
8
+ * RU-6). Answered, it says what answered it, and offers nothing.
9
+ *
10
+ * @module apps/plugins/app-elements/QuestionView
11
+ */
12
+ import type { JSX } from 'react';
13
+ import { type Display } from '@datalayer/reactor/ui';
14
+ import type { RendererProps } from '@datalayer/reactor/ui/react';
15
+ /** The display type of what an application's code asks (`QuestionShown`). */
16
+ export declare const QUESTION_DISPLAY_TYPE = "application/vnd.datalayer.loop.question+json";
17
+ /** A question as its display says it. Throws for a display that is not one. */
18
+ export declare function questionOf(display: Display): {
19
+ kind: 'text' | 'choice' | 'file' | 'form';
20
+ prompt: string;
21
+ options: string[];
22
+ accept: string[];
23
+ form: Record<string, unknown>;
24
+ answered: string | null;
25
+ answerable: boolean;
26
+ };
27
+ export declare function QuestionView({ display, act }: RendererProps): JSX.Element;
28
+ export default QuestionView;
@@ -0,0 +1,57 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { lazy, Suspense, useState } from 'react';
3
+ import { Box, Button, Text, TextInput } from '@primer/react';
4
+ import { ANSWER_ACTION } from '@datalayer/reactor/ui';
5
+ /** The display type of what an application's code asks (`QuestionShown`). */
6
+ export const QUESTION_DISPLAY_TYPE = 'application/vnd.datalayer.loop.question+json';
7
+ const SchemaForm = lazy(() => import('../../../components/a2ui/datalayer/SchemaForm'));
8
+ /** A question as its display says it. Throws for a display that is not one. */
9
+ export function questionOf(display) {
10
+ const data = display.data ?? {};
11
+ const kind = data.kind;
12
+ if (display.type !== QUESTION_DISPLAY_TYPE ||
13
+ (kind !== 'text' &&
14
+ kind !== 'choice' &&
15
+ kind !== 'file' &&
16
+ kind !== 'form') ||
17
+ typeof data.prompt !== 'string') {
18
+ throw new Error(`Display ${display.id} is not a question`);
19
+ }
20
+ const strings = (value) => Array.isArray(value)
21
+ ? value.filter((item) => typeof item === 'string')
22
+ : [];
23
+ return {
24
+ kind,
25
+ prompt: data.prompt,
26
+ options: strings(data.options),
27
+ accept: strings(data.accept),
28
+ form: data.form && typeof data.form === 'object'
29
+ ? data.form
30
+ : {},
31
+ answered: typeof data.answered === 'string' ? data.answered : null,
32
+ answerable: (display.actions ?? []).some(offer => offer.name === ANSWER_ACTION),
33
+ };
34
+ }
35
+ export function QuestionView({ display, act }) {
36
+ const question = questionOf(display);
37
+ const [words, setWords] = useState('');
38
+ const [said, setSaid] = useState(null);
39
+ const answer = (value) => {
40
+ if (!act) {
41
+ setSaid('The chat cannot take an answer here.');
42
+ return;
43
+ }
44
+ setSaid(null);
45
+ void Promise.resolve(act({ action: ANSWER_ACTION, payload: { value } })).catch((failure) => setSaid(failure instanceof Error ? failure.message : String(failure)));
46
+ };
47
+ if (question.answered !== null) {
48
+ return (_jsxs(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: ["Answered: ", question.answered] }));
49
+ }
50
+ const live = question.answerable && !!act;
51
+ return (_jsxs(Box, { display: "flex", flexDirection: "column", gap: 2, "data-question-kind": question.kind, children: [question.kind === 'choice' ? (_jsx(Box, { display: "flex", gap: 2, flexWrap: "wrap", children: question.options.map(option => (_jsx(Button, { size: "small", disabled: !live, onClick: () => answer(option), children: option }, option))) })) : null, question.kind === 'text' ? (_jsxs(Box, { as: "form", display: "flex", gap: 2, onSubmit: (event) => {
52
+ event.preventDefault();
53
+ if (words.trim())
54
+ answer(words.trim());
55
+ }, children: [_jsx(TextInput, { "aria-label": question.prompt, value: words, disabled: !live, onChange: event => setWords(event.target.value) }), _jsx(Button, { type: "submit", size: "small", disabled: !live || !words.trim(), children: "Answer" })] })) : null, question.kind === 'form' ? (_jsx(Suspense, { fallback: null, children: _jsx(SchemaForm, { schema: question.form, disabled: !live, onSubmit: ({ formData }) => answer(formData ?? {}) }) })) : null, question.kind === 'file' ? (_jsxs(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: ["Attach the file in the message box", question.accept.length ? ` (${question.accept.join(', ')})` : '', "."] })) : null, said ? (_jsx(Text, { as: "p", sx: { color: 'danger.fg', fontSize: 1, m: 0 }, children: said })) : null] }));
56
+ }
57
+ export default QuestionView;
@@ -5,10 +5,12 @@
5
5
  * code (`session.close`) or by the person. Inline, an element is a message,
6
6
  * which the chat draws (P-04); this plugin draws the other two.
7
7
  *
8
- * The chat keeps what is open (`chat/base/loopElement`), from the session
9
- * API's `loop.element` events; this plugin draws it from the workspace's
10
- * root slot, positioned against the workspace, so that nothing is laid out
11
- * while nothing is open.
8
+ * The chat keeps what is open (`chat/base/loopElement`), from the session's
9
+ * ui socket (REACTOR_UI RU-3, RU-W); this plugin draws it from the
10
+ * workspace's root slot, positioned against the workspace, so that nothing
11
+ * is laid out while nothing is open. It also contributes the renderer of
12
+ * what the code asks (`QuestionView`, RU-4), drawn under the message that
13
+ * asks it.
12
14
  *
13
15
  * @module apps/plugins/app-elements
14
16
  */
@@ -17,4 +19,5 @@ export declare const APP_ELEMENTS_PLUGIN_NAME = "@datalayer/loop-plugin-app-elem
17
19
  /** The plugin that draws an application's side panel and pages. */
18
20
  export declare const AppElementsPlugin: ReactorPlugin<Record<string, never>, unknown, unknown>;
19
21
  export { AppElements, APP_PANEL_WIDTH, elementsByPlace } from './AppElements';
22
+ export { QUESTION_DISPLAY_TYPE, QuestionView, questionOf, } from './QuestionView';
20
23
  export default AppElementsPlugin;
@@ -9,17 +9,22 @@
9
9
  * code (`session.close`) or by the person. Inline, an element is a message,
10
10
  * which the chat draws (P-04); this plugin draws the other two.
11
11
  *
12
- * The chat keeps what is open (`chat/base/loopElement`), from the session
13
- * API's `loop.element` events; this plugin draws it from the workspace's
14
- * root slot, positioned against the workspace, so that nothing is laid out
15
- * while nothing is open.
12
+ * The chat keeps what is open (`chat/base/loopElement`), from the session's
13
+ * ui socket (REACTOR_UI RU-3, RU-W); this plugin draws it from the
14
+ * workspace's root slot, positioned against the workspace, so that nothing
15
+ * is laid out while nothing is open. It also contributes the renderer of
16
+ * what the code asks (`QuestionView`, RU-4), drawn under the message that
17
+ * asks it.
16
18
  *
17
19
  * @module apps/plugins/app-elements
18
20
  */
19
- import { definePlugin } from '@datalayer/reactor';
21
+ import { contribution, definePlugin, } from '@datalayer/reactor';
22
+ import { Renderers } from '@datalayer/reactor/ui';
23
+ import { defineRenderer } from '@datalayer/reactor/ui/react';
20
24
  import { clearLoopElements } from '../../../chat/base/loopElement';
21
25
  import { LoopSlots } from '../../core';
22
26
  import { AppElements } from './AppElements';
27
+ import { QUESTION_DISPLAY_TYPE, QuestionView } from './QuestionView';
23
28
  export const APP_ELEMENTS_PLUGIN_NAME = '@datalayer/loop-plugin-app-elements';
24
29
  /** The plugin that draws an application's side panel and pages. */
25
30
  export const AppElementsPlugin = definePlugin({
@@ -27,6 +32,9 @@ export const AppElementsPlugin = definePlugin({
27
32
  displayName: 'Side panel and pages',
28
33
  description: 'What an application opens beside the conversation: a side panel, or a page of its own.',
29
34
  octicon: 'sidebar-expand',
35
+ contributes: [
36
+ contribution(Renderers, defineRenderer({ type: QUESTION_DISPLAY_TYPE, component: QuestionView }), { id: 'app-elements:question' }),
37
+ ],
30
38
  build: () => ({
31
39
  components: [
32
40
  {
@@ -40,4 +48,5 @@ export const AppElementsPlugin = definePlugin({
40
48
  register: () => clearLoopElements,
41
49
  });
42
50
  export { AppElements, APP_PANEL_WIDTH, elementsByPlace } from './AppElements';
51
+ export { QUESTION_DISPLAY_TYPE, QuestionView, questionOf, } from './QuestionView';
43
52
  export default AppElementsPlugin;
@@ -1,6 +1,6 @@
1
1
  /**
2
- * The Canvas's palette as a contribution point (LOOP C-12): each UI plugin of
3
- * the catalogue that renders components (`agentspecs/ui-plugins`, C-13) is a
2
+ * The Canvas's palette as a contribution point (LOOP C-12): each UI of
3
+ * the catalogue that renders components (`agentspecs/ui`, C-13) is a
4
4
  * Reactor plugin contributing its components to `loop.canvas.block`. The
5
5
  * palette lists what the enabled plugins contribute, and nothing else; a
6
6
  * plugin disabled takes its blocks off it, and an application that uses one
@@ -12,7 +12,7 @@
12
12
  * @module apps/plugins/canvas-blocks
13
13
  */
14
14
  import { type ReactorPlatform, type ReactorPlugin } from '@datalayer/reactor';
15
- import type { AppSpec, ComponentSpec, UIPluginSpec } from '../../../types/agentspecs';
15
+ import type { AppSpec, ComponentSpec, UISpec } from '../../../types/agentspecs';
16
16
  import { LoopCanvasBlock, type CanvasBlockContribution } from '../../core/canvasBlocks';
17
17
  /** What is read of a reactor here: its contributions to the point, and who is enabled. */
18
18
  type BlocksReader = {
@@ -20,12 +20,12 @@ type BlocksReader = {
20
20
  value: CanvasBlockContribution;
21
21
  }>;
22
22
  };
23
- /** The name of the Reactor plugin that contributes a UI plugin's blocks. */
24
- export declare const canvasBlocksPluginName: (uiPlugin: string) => string;
25
- /** A UI plugin of the catalogue as the Reactor plugin contributing its components as blocks. */
26
- export declare function uiPluginBlocks(uiPlugin: UIPluginSpec): ReactorPlugin<Record<string, never>, unknown, unknown>;
23
+ /** The name of the Reactor plugin that contributes a UI's blocks. */
24
+ export declare const canvasBlocksPluginName: (ui: string) => string;
25
+ /** A UI of the catalogue as the Reactor plugin contributing its components as blocks. */
26
+ export declare function uiPluginBlocks(ui: UISpec): ReactorPlugin<Record<string, never>, unknown, unknown>;
27
27
  /**
28
- * The plugins of the catalogue's UI plugins that render components and may
28
+ * The plugins of the catalogue's UI specs that render components and may
29
29
  * be named today (`enabled` in the catalogue).
30
30
  */
31
31
  export declare const CANVAS_BLOCK_PLUGINS: ReactorPlugin<Record<string, never>, unknown, unknown>[];
@@ -35,16 +35,16 @@ export declare const CANVAS_BLOCK_PLUGINS: ReactorPlugin<Record<string, never>,
35
35
  */
36
36
  export declare function canvasBlocksReactor(disabled?: readonly string[], plugins?: ReactorPlugin<any, any, any>[]): ReactorPlatform;
37
37
  /**
38
- * The palette of an organization: the block plugins of the UI plugins it has
38
+ * The palette of an organization: the block plugins of the UI specs it has
39
39
  * turned off (`plugins_off` in IAM, catalogue ids such as 'a2ui') switched
40
- * off. A UI plugin of the catalogue that contributes no block takes nothing
40
+ * off. A UI of the catalogue that contributes no block takes nothing
41
41
  * off; an id the catalogue does not have is said by `unknownPluginsOff`.
42
42
  */
43
43
  export declare function canvasBlocksReactorOf(pluginsOff: readonly string[]): ReactorPlatform;
44
- /** The ids an organization turns off that no UI plugin of the catalogue has. */
44
+ /** The ids an organization turns off that no UI of the catalogue has. */
45
45
  export declare function unknownPluginsOff(pluginsOff: readonly string[]): string[];
46
46
  /**
47
- * What an application's page uses from a UI plugin its organization has
47
+ * What an application's page uses from a UI its organization has
48
48
  * turned off, as its setup notes say it (`blockSetupNotes`, on the palette of
49
49
  * `canvasBlocksReactorOf`).
50
50
  */
@@ -55,7 +55,7 @@ export declare function canvasBlocksOf(reactor: BlocksReader): ComponentSpec[];
55
55
  export declare function componentsUsedBy(app: Pick<AppSpec, 'interface'>): string[];
56
56
  /**
57
57
  * What an application's page uses that no enabled plugin contributes, as its
58
- * setup notes say it: one sentence per UI plugin of the catalogue whose
58
+ * setup notes say it: one sentence per UI of the catalogue whose
59
59
  * blocks it uses while its plugin is off. A component the catalogue does not
60
60
  * have is not a note but a problem of the instant checks.
61
61
  */
@@ -3,8 +3,8 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  /**
6
- * The Canvas's palette as a contribution point (LOOP C-12): each UI plugin of
7
- * the catalogue that renders components (`agentspecs/ui-plugins`, C-13) is a
6
+ * The Canvas's palette as a contribution point (LOOP C-12): each UI of
7
+ * the catalogue that renders components (`agentspecs/ui`, C-13) is a
8
8
  * Reactor plugin contributing its components to `loop.canvas.block`. The
9
9
  * palette lists what the enabled plugins contribute, and nothing else; a
10
10
  * plugin disabled takes its blocks off it, and an application that uses one
@@ -16,26 +16,26 @@
16
16
  * @module apps/plugins/canvas-blocks
17
17
  */
18
18
  import { buildReactorFromPlugins, contribution, definePlugin, } from '@datalayer/reactor';
19
- import { listUIPlugins } from '../../../specs/uiPlugins';
19
+ import { listUI } from '../../../specs/ui';
20
20
  import { LoopCanvasBlock, } from '../../core/canvasBlocks';
21
- /** The name of the Reactor plugin that contributes a UI plugin's blocks. */
22
- export const canvasBlocksPluginName = (uiPlugin) => `@datalayer/loop-plugin-ui-${uiPlugin}`;
23
- /** A UI plugin of the catalogue as the Reactor plugin contributing its components as blocks. */
24
- export function uiPluginBlocks(uiPlugin) {
21
+ /** The name of the Reactor plugin that contributes a UI's blocks. */
22
+ export const canvasBlocksPluginName = (ui) => `@datalayer/loop-plugin-ui-${ui}`;
23
+ /** A UI of the catalogue as the Reactor plugin contributing its components as blocks. */
24
+ export function uiPluginBlocks(ui) {
25
25
  return definePlugin({
26
- name: canvasBlocksPluginName(uiPlugin.id),
27
- displayName: uiPlugin.name,
28
- description: `The blocks of ${uiPlugin.name} on the Canvas: ${uiPlugin.components.map(component => component.name).join(', ')}.`,
26
+ name: canvasBlocksPluginName(ui.id),
27
+ displayName: ui.name,
28
+ description: `The blocks of ${ui.name} on the Canvas: ${ui.components.map(component => component.name).join(', ')}.`,
29
29
  octicon: 'apps',
30
- contributes: uiPlugin.components.map(component => contribution(LoopCanvasBlock, { id: component.id, uiPlugin: uiPlugin.id, component }, { id: component.id })),
30
+ contributes: ui.components.map(component => contribution(LoopCanvasBlock, { id: component.id, ui: ui.id, component }, { id: component.id })),
31
31
  });
32
32
  }
33
33
  /**
34
- * The plugins of the catalogue's UI plugins that render components and may
34
+ * The plugins of the catalogue's UI specs that render components and may
35
35
  * be named today (`enabled` in the catalogue).
36
36
  */
37
- export const CANVAS_BLOCK_PLUGINS = listUIPlugins()
38
- .filter(uiPlugin => uiPlugin.enabled && uiPlugin.components.length > 0)
37
+ export const CANVAS_BLOCK_PLUGINS = listUI()
38
+ .filter(ui => ui.enabled && ui.components.length > 0)
39
39
  .map(uiPluginBlocks);
40
40
  /**
41
41
  * A reactor holding the block plugins given, started, with those named in
@@ -53,9 +53,9 @@ export function canvasBlocksReactor(disabled = [], plugins = CANVAS_BLOCK_PLUGIN
53
53
  return reactor;
54
54
  }
55
55
  /**
56
- * The palette of an organization: the block plugins of the UI plugins it has
56
+ * The palette of an organization: the block plugins of the UI specs it has
57
57
  * turned off (`plugins_off` in IAM, catalogue ids such as 'a2ui') switched
58
- * off. A UI plugin of the catalogue that contributes no block takes nothing
58
+ * off. A UI of the catalogue that contributes no block takes nothing
59
59
  * off; an id the catalogue does not have is said by `unknownPluginsOff`.
60
60
  */
61
61
  export function canvasBlocksReactorOf(pluginsOff) {
@@ -64,13 +64,13 @@ export function canvasBlocksReactorOf(pluginsOff) {
64
64
  .map(canvasBlocksPluginName)
65
65
  .filter(name => blockPlugins.has(name)));
66
66
  }
67
- /** The ids an organization turns off that no UI plugin of the catalogue has. */
67
+ /** The ids an organization turns off that no UI of the catalogue has. */
68
68
  export function unknownPluginsOff(pluginsOff) {
69
- const known = new Set(listUIPlugins().map(uiPlugin => uiPlugin.id));
69
+ const known = new Set(listUI().map(ui => ui.id));
70
70
  return pluginsOff.filter(id => !known.has(id));
71
71
  }
72
72
  /**
73
- * What an application's page uses from a UI plugin its organization has
73
+ * What an application's page uses from a UI its organization has
74
74
  * turned off, as its setup notes say it (`blockSetupNotes`, on the palette of
75
75
  * `canvasBlocksReactorOf`).
76
76
  */
@@ -96,7 +96,7 @@ export function componentsUsedBy(app) {
96
96
  }
97
97
  /**
98
98
  * What an application's page uses that no enabled plugin contributes, as its
99
- * setup notes say it: one sentence per UI plugin of the catalogue whose
99
+ * setup notes say it: one sentence per UI of the catalogue whose
100
100
  * blocks it uses while its plugin is off. A component the catalogue does not
101
101
  * have is not a note but a problem of the instant checks.
102
102
  */
@@ -107,12 +107,12 @@ export function blockSetupNotes(app, reactor) {
107
107
  if (contributed.has(name)) {
108
108
  continue;
109
109
  }
110
- for (const uiPlugin of listUIPlugins()) {
111
- const component = uiPlugin.components.find(each => each.id === name);
110
+ for (const ui of listUI()) {
111
+ const component = ui.components.find(each => each.id === name);
112
112
  if (component) {
113
- off.set(uiPlugin, [...(off.get(uiPlugin) ?? []), component.name]);
113
+ off.set(ui, [...(off.get(ui) ?? []), component.name]);
114
114
  }
115
115
  }
116
116
  }
117
- return [...off.entries()].map(([uiPlugin, names]) => `The UI plugin “${uiPlugin.name}” is not enabled, and its page uses its ${names.length === 1 ? 'block' : 'blocks'} ${names.join(', ')}: ${names.length === 1 ? 'it is' : 'they are'} off the Canvas until it is.`);
117
+ return [...off.entries()].map(([ui, names]) => `The UI “${ui.name}” is not enabled, and its page uses its ${names.length === 1 ? 'block' : 'blocks'} ${names.join(', ')}: ${names.length === 1 ? 'it is' : 'they are'} off the Canvas until it is.`);
118
118
  }
@@ -15,7 +15,7 @@ type PartsReader = {
15
15
  }>;
16
16
  };
17
17
  /** The short ids an organization turns off, and the plugin each names. */
18
- export declare const CANVAS_PART_SOURCES: readonly ["connections", "skills", "models", "rules", "tests", "events"];
18
+ export declare const CANVAS_PART_SOURCES: readonly ["connections", "skills", "models", "rules", "tests", "events", "protocols", "ui", "characters"];
19
19
  export type CanvasPartSource = (typeof CANVAS_PART_SOURCES)[number];
20
20
  export declare const canvasPartsPluginName: (source: CanvasPartSource) => string;
21
21
  /** A connection to each server of the catalogue: read-only, as its owner, every tool. */
@@ -30,6 +30,12 @@ export declare const RULE_PARTS: CanvasPartContribution[];
30
30
  export declare const TEST_PARTS: CanvasPartContribution[];
31
31
  /** The events an application answers (C-21): on a schedule, on an event, once. */
32
32
  export declare const EVENT_PARTS: CanvasPartContribution[];
33
+ /** Each protocol of the catalogue (AGENT_PROTOCOLS PS-04): a planned one offered, not enabled. */
34
+ export declare const PROTOCOL_PARTS: CanvasPartContribution[];
35
+ /** Each UI of the catalogue its answers may render in (AGENT_PROTOCOLS PS-04). */
36
+ export declare const UI_PARTS: CanvasPartContribution[];
37
+ /** Datalayer's characters for its floating assistant, dropped on the agent (AGENT_PROTOCOLS PS-05). */
38
+ export declare const CHARACTER_PARTS: CanvasPartContribution[];
33
39
  export declare const CANVAS_PART_PLUGINS: ReactorPlugin<Record<string, never>, unknown, unknown>[];
34
40
  /** The toolbox's reactor, its named plugins disabled; a name no plugin has is refused. */
35
41
  export declare function canvasPartsReactor(disabled?: readonly string[], plugins?: ReactorPlugin<any, any, any>[]): ReactorPlatform;
@@ -15,6 +15,9 @@ import { buildReactorFromPlugins, contribution, definePlugin, } from '@datalayer
15
15
  import { MCP_SERVER_LIBRARY } from '../../../specs/mcpServers';
16
16
  import { listChatModels } from '../../../specs/models';
17
17
  import { getSkillSpecs } from '../../../specs/skills';
18
+ import { listProtocolSpecs } from '../../../specs/protocols';
19
+ import { listUI } from '../../../specs/ui';
20
+ import { ASSISTANT_CHARACTERS } from '../../../chat/assistant/characters';
18
21
  import { LoopCanvasPart, } from '../../core/canvasParts';
19
22
  /** The short ids an organization turns off, and the plugin each names. */
20
23
  export const CANVAS_PART_SOURCES = [
@@ -24,6 +27,9 @@ export const CANVAS_PART_SOURCES = [
24
27
  'rules',
25
28
  'tests',
26
29
  'events',
30
+ 'protocols',
31
+ 'ui',
32
+ 'characters',
27
33
  ];
28
34
  export const canvasPartsPluginName = (source) => `@datalayer/loop-plugin-parts-${source}`;
29
35
  const partsPlugin = (source, displayName, parts) => definePlugin({
@@ -172,6 +178,33 @@ export const EVENT_PARTS = [
172
178
  enabled: true,
173
179
  },
174
180
  ];
181
+ /** Each protocol of the catalogue (AGENT_PROTOCOLS PS-04): a planned one offered, not enabled. */
182
+ export const PROTOCOL_PARTS = listProtocolSpecs().map(protocol => ({
183
+ id: `protocol:${protocol.id}`,
184
+ kind: 'protocol',
185
+ label: protocol.name,
186
+ says: protocol.connects,
187
+ example: protocol.id,
188
+ enabled: protocol.status === 'shipped',
189
+ }));
190
+ /** Each UI of the catalogue its answers may render in (AGENT_PROTOCOLS PS-04). */
191
+ export const UI_PARTS = listUI().map(ui => ({
192
+ id: `ui:${ui.id}`,
193
+ kind: 'ui',
194
+ label: ui.name,
195
+ says: ui.description,
196
+ example: ui.id,
197
+ enabled: ui.enabled,
198
+ }));
199
+ /** Datalayer's characters for its floating assistant, dropped on the agent (AGENT_PROTOCOLS PS-05). */
200
+ export const CHARACTER_PARTS = ASSISTANT_CHARACTERS.map(character => ({
201
+ id: `character:${character.id}`,
202
+ kind: 'character',
203
+ label: character.name,
204
+ says: `Its floating assistant shows ${character.name}.`,
205
+ example: character.id,
206
+ enabled: true,
207
+ }));
175
208
  export const CANVAS_PART_PLUGINS = [
176
209
  partsPlugin('connections', 'Connections', CONNECTION_PARTS),
177
210
  partsPlugin('skills', 'Skills', SKILL_PARTS),
@@ -179,6 +212,9 @@ export const CANVAS_PART_PLUGINS = [
179
212
  partsPlugin('rules', 'Rules', RULE_PARTS),
180
213
  partsPlugin('tests', 'Tests', TEST_PARTS),
181
214
  partsPlugin('events', 'Events', EVENT_PARTS),
215
+ partsPlugin('protocols', 'Protocols', PROTOCOL_PARTS),
216
+ partsPlugin('ui', 'UI', UI_PARTS),
217
+ partsPlugin('characters', 'Characters', CHARACTER_PARTS),
182
218
  ];
183
219
  /** The toolbox's reactor, its named plugins disabled; a name no plugin has is refused. */
184
220
  export function canvasPartsReactor(disabled = [], plugins = CANVAS_PART_PLUGINS) {
@@ -1374,6 +1374,13 @@ export default function ChatView({ workspace }) {
1374
1374
  ? `${agentServerUrl}/api/v1/apps/agents/${encodeURIComponent(agentId)}/ag-ui/`
1375
1375
  : `${agentServerUrl}/api/v1/ag-ui/${agentId}/`,
1376
1376
  ...(runsApp && iamToken ? { authToken: iamToken } : {}),
1377
+ // Its session's ui channel (REACTOR_UI RU-W): what its answers
1378
+ // show, its steps and its elements, beside the run's text.
1379
+ ...(runsApp
1380
+ ? {
1381
+ uiSocket: `${agentServerUrl.replace(/^http/, 'ws')}/api/v1/apps/ui`,
1382
+ }
1383
+ : {}),
1377
1384
  agentId,
1378
1385
  // `/api/v1/configure`, not `/api/v1/configure/config`: the hooks
1379
1386
  // strip one trailing `config`/`configure` segment to find the API