@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,197 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export const A2A_PROTOCOL_0_0_1 = {
6
+ id: 'a2a',
7
+ version: '0.0.1',
8
+ name: 'Agent2Agent',
9
+ description: "How agents talk to agents: teams and scenes talk over it, an application's route serves it, and its Agent Card advertises its extensions.",
10
+ publisher: 'Google, now the Linux Foundation',
11
+ layer: 'transport',
12
+ specUrl: 'https://a2a-protocol.org',
13
+ specVersion: '1.0',
14
+ status: 'shipped',
15
+ connects: 'Other agents, each at its address with its Agent Card',
16
+ packages: {
17
+ python: ['fasta2a', 'a2a-sdk'],
18
+ typescript: ['@a2a-js/sdk'],
19
+ },
20
+ protocolTools: [],
21
+ appspecBlock: 'a2a',
22
+ };
23
+ export const A2UI_PROTOCOL_0_0_1 = {
24
+ id: 'a2ui',
25
+ version: '0.0.1',
26
+ name: 'A2UI',
27
+ description: "How an agent's answer becomes an interface: components the host renders from a declarative surface.",
28
+ publisher: 'Google',
29
+ layer: 'ui',
30
+ specUrl: 'https://a2ui.org',
31
+ specVersion: '0.9',
32
+ status: 'shipped',
33
+ connects: 'The person, through components an answer draws',
34
+ packages: {
35
+ python: ['agent-runtimes'],
36
+ typescript: ['@a2ui/react', '@a2ui/web_core'],
37
+ },
38
+ protocolTools: [],
39
+ };
40
+ export const ACP_PROTOCOL_0_0_1 = {
41
+ id: 'acp',
42
+ version: '0.0.1',
43
+ name: 'Agentic Commerce Protocol',
44
+ description: 'Checkout sessions at a seller, completed with a delegated payment token the model never sees. Planned in applications: the client exists, purchases wait on a source of payment tokens.',
45
+ publisher: 'OpenAI, Stripe',
46
+ layer: 'commerce',
47
+ specUrl: 'https://github.com/agentic-commerce-protocol/agentic-commerce-protocol',
48
+ specVersion: '2026-04-17',
49
+ status: 'planned',
50
+ connects: 'Sellers, to check out with a delegated payment',
51
+ packages: {
52
+ python: ['agent-runtimes'],
53
+ typescript: ['@datalayer/agent-runtimes'],
54
+ },
55
+ protocolTools: ['agentic-commerce'],
56
+ };
57
+ export const AG_UI_PROTOCOL_0_0_1 = {
58
+ id: 'ag-ui',
59
+ version: '0.0.1',
60
+ name: 'AG-UI',
61
+ description: 'How an agent streams its run to a page: messages, tool calls and state as events.',
62
+ publisher: 'CopilotKit',
63
+ layer: 'ui',
64
+ specUrl: 'https://docs.ag-ui.com',
65
+ specVersion: '0.0.57 (@ag-ui/core)',
66
+ status: 'shipped',
67
+ connects: 'The page a person talks to the agent on',
68
+ packages: {
69
+ python: ['ag-ui-protocol'],
70
+ typescript: ['@ag-ui/client', '@ag-ui/core'],
71
+ },
72
+ protocolTools: [],
73
+ };
74
+ export const MCP_PROTOCOL_0_0_1 = {
75
+ id: 'mcp',
76
+ version: '0.0.1',
77
+ name: 'Model Context Protocol',
78
+ description: 'How an agent calls tools and reads resources: clients and servers in both languages, and the MCP gateway every connection goes through.',
79
+ publisher: 'Anthropic',
80
+ layer: 'transport',
81
+ specUrl: 'https://modelcontextprotocol.io/specification',
82
+ specVersion: '2026-07-28 (Python), 2025-11-25 (TypeScript)',
83
+ status: 'shipped',
84
+ connects: 'Tools, resources and prompts served by MCP servers',
85
+ packages: {
86
+ python: ['mcp'],
87
+ typescript: ['@modelcontextprotocol/sdk', '@mcp-ui/client'],
88
+ },
89
+ protocolTools: [],
90
+ };
91
+ export const PACT_PROTOCOL_0_0_1 = {
92
+ id: 'pact',
93
+ version: '0.0.1',
94
+ name: 'Personal Agent Consent & Trust',
95
+ description: "A personal agent asking a business's agent over A2A, first as itself, then for a person who delegated some of their permissions.",
96
+ publisher: 'Decagon, Instinct',
97
+ layer: 'consent',
98
+ specUrl: 'https://openpactprotocol.org',
99
+ specVersion: '1.0',
100
+ status: 'shipped',
101
+ connects: "Businesses' agents, asked for a person with their delegation",
102
+ packages: {
103
+ python: ['agent-runtimes'],
104
+ typescript: ['@datalayer/agent-runtimes'],
105
+ },
106
+ protocolTools: ['pact'],
107
+ appspecBlock: 'pact',
108
+ };
109
+ export const PAP_PROTOCOL_0_0_1 = {
110
+ id: 'pap',
111
+ version: '0.0.1',
112
+ name: 'Personal Agent Protocol',
113
+ description: "A person's agent working with a company for them — signed out, then signed in at the company, its changes confirmed by the person — and an application being a company personal agents reach.",
114
+ publisher: 'Sierra, Meta',
115
+ layer: 'consent',
116
+ specUrl: 'https://poppy.md',
117
+ specVersion: 'draft 0.1',
118
+ status: 'shipped',
119
+ connects: "Companies, as a person's agent there, or being one",
120
+ packages: {
121
+ python: ['personal-agent-protocol'],
122
+ typescript: ['@datalayer/personal-agent-protocol'],
123
+ },
124
+ protocolTools: ['pap'],
125
+ appspecBlock: 'pap',
126
+ };
127
+ export const TAP_PROTOCOL_0_0_1 = {
128
+ id: 'tap',
129
+ version: '0.0.1',
130
+ name: 'Trusted Agent Protocol',
131
+ description: 'An agent-recognition profile over Web Bot Auth for merchants. Planned: nothing is built until its profile is confirmed.',
132
+ publisher: 'Visa',
133
+ layer: 'identity',
134
+ specUrl: 'https://developer.visa.com',
135
+ specVersion: 'none yet',
136
+ status: 'planned',
137
+ connects: 'Merchants that recognise an agent by its signature',
138
+ packages: {
139
+ python: [],
140
+ typescript: [],
141
+ },
142
+ protocolTools: [],
143
+ };
144
+ export const UCP_PROTOCOL_0_0_1 = {
145
+ id: 'ucp',
146
+ version: '0.0.1',
147
+ name: 'Universal Commerce Protocol',
148
+ description: 'Shopping at a merchant: catalogue, checkout and orders, every purchase an exact proposal the person approves. Planned in applications: the client exists, purchases wait on a source of payment tokens.',
149
+ publisher: 'Google, with Shopify and retailers',
150
+ layer: 'commerce',
151
+ specUrl: 'https://github.com/Universal-Commerce-Protocol/ucp',
152
+ specVersion: '2026-08-25',
153
+ status: 'planned',
154
+ connects: 'Merchants, to search, check out and follow orders',
155
+ packages: {
156
+ python: ['ucp-sdk', 'agent-runtimes'],
157
+ typescript: ['@ucp-js/sdk', '@datalayer/agent-runtimes'],
158
+ },
159
+ protocolTools: ['ucp'],
160
+ };
161
+ export const WEB_BOT_AUTH_PROTOCOL_0_0_1 = {
162
+ id: 'web-bot-auth',
163
+ version: '0.0.1',
164
+ name: 'Web Bot Auth',
165
+ description: 'Signed outbound requests (RFC 9421) and the key directory a website checks them against.',
166
+ publisher: 'Cloudflare (IETF draft)',
167
+ layer: 'identity',
168
+ specUrl: 'https://datatracker.ietf.org/doc/draft-ietf-webbotauth-httpsig-protocol/',
169
+ specVersion: 'draft-ietf-webbotauth-httpsig-protocol-00',
170
+ status: 'shipped',
171
+ connects: "Websites, which can tell the application's requests from someone pretending",
172
+ packages: {
173
+ python: ['agent-runtimes'],
174
+ typescript: ['@datalayer/agent-runtimes', 'web-bot-auth'],
175
+ },
176
+ protocolTools: [],
177
+ };
178
+ export const PROTOCOL_CATALOGUE = {
179
+ a2a: A2A_PROTOCOL_0_0_1,
180
+ a2ui: A2UI_PROTOCOL_0_0_1,
181
+ acp: ACP_PROTOCOL_0_0_1,
182
+ 'ag-ui': AG_UI_PROTOCOL_0_0_1,
183
+ mcp: MCP_PROTOCOL_0_0_1,
184
+ pact: PACT_PROTOCOL_0_0_1,
185
+ pap: PAP_PROTOCOL_0_0_1,
186
+ tap: TAP_PROTOCOL_0_0_1,
187
+ ucp: UCP_PROTOCOL_0_0_1,
188
+ 'web-bot-auth': WEB_BOT_AUTH_PROTOCOL_0_0_1,
189
+ };
190
+ /** A protocol by id. */
191
+ export function getProtocol(protocolId) {
192
+ return PROTOCOL_CATALOGUE[protocolId];
193
+ }
194
+ /** Every protocol of the catalogue. */
195
+ export function listProtocolSpecs() {
196
+ return Object.values(PROTOCOL_CATALOGUE);
197
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * UI Catalog.
3
+ *
4
+ * How an agent's answer becomes an interface: the protocols a host renders.
5
+ *
6
+ * This file is AUTO-GENERATED from YAML specifications.
7
+ * DO NOT EDIT MANUALLY - run 'make specs' to regenerate.
8
+ */
9
+ import type { ComponentSpec, UISpec } from '../types/agentspecs';
10
+ export declare const A2UI_UI_0_0_1: UISpec;
11
+ export declare const MCP_APPS_UI_0_0_1: UISpec;
12
+ export declare const MCP_UI_UI_0_0_1: UISpec;
13
+ export declare const UI_CATALOGUE: Record<string, UISpec>;
14
+ /** The UI an agent spec's `ui` names, or undefined. */
15
+ export declare function getUI(pluginId: string): UISpec | undefined;
16
+ export declare function listUI(): UISpec[];
17
+ /** The visual components the enabled UI specs render, by the name a surface gives them (LOOP C-13). */
18
+ export declare const COMPONENT_CATALOGUE: Record<string, ComponentSpec>;
19
+ /** The component a layout names, or undefined. */
20
+ export declare function getComponent(name: string): ComponentSpec | undefined;
21
+ export declare function listComponents(): ComponentSpec[];
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) 2025-2026 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- export const A2UI_UI_PLUGIN_0_0_1 = {
5
+ export const A2UI_UI_0_0_1 = {
6
6
  id: 'a2ui',
7
7
  version: '0.0.1',
8
8
  name: 'A2UI',
@@ -1055,7 +1055,7 @@ export const A2UI_UI_PLUGIN_0_0_1 = {
1055
1055
  },
1056
1056
  ],
1057
1057
  };
1058
- export const MCP_APPS_UI_PLUGIN_0_0_1 = {
1058
+ export const MCP_APPS_UI_0_0_1 = {
1059
1059
  id: 'mcp-apps',
1060
1060
  version: '0.0.1',
1061
1061
  name: 'MCP Apps',
@@ -1065,7 +1065,7 @@ export const MCP_APPS_UI_PLUGIN_0_0_1 = {
1065
1065
  catalog: '',
1066
1066
  components: [],
1067
1067
  };
1068
- export const MCP_UI_UI_PLUGIN_0_0_1 = {
1068
+ export const MCP_UI_UI_0_0_1 = {
1069
1069
  id: 'mcp-ui',
1070
1070
  version: '0.0.1',
1071
1071
  name: 'MCP UI',
@@ -1075,20 +1075,20 @@ export const MCP_UI_UI_PLUGIN_0_0_1 = {
1075
1075
  catalog: '',
1076
1076
  components: [],
1077
1077
  };
1078
- export const UI_PLUGIN_CATALOGUE = {
1079
- a2ui: A2UI_UI_PLUGIN_0_0_1,
1080
- 'mcp-apps': MCP_APPS_UI_PLUGIN_0_0_1,
1081
- 'mcp-ui': MCP_UI_UI_PLUGIN_0_0_1,
1078
+ export const UI_CATALOGUE = {
1079
+ a2ui: A2UI_UI_0_0_1,
1080
+ 'mcp-apps': MCP_APPS_UI_0_0_1,
1081
+ 'mcp-ui': MCP_UI_UI_0_0_1,
1082
1082
  };
1083
- /** The plugin an agent spec's `uiPlugin` names, or undefined. */
1084
- export function getUIPlugin(pluginId) {
1085
- return UI_PLUGIN_CATALOGUE[pluginId];
1083
+ /** The UI an agent spec's `ui` names, or undefined. */
1084
+ export function getUI(pluginId) {
1085
+ return UI_CATALOGUE[pluginId];
1086
1086
  }
1087
- export function listUIPlugins() {
1088
- return Object.values(UI_PLUGIN_CATALOGUE);
1087
+ export function listUI() {
1088
+ return Object.values(UI_CATALOGUE);
1089
1089
  }
1090
- /** The visual components the enabled UI plugins render, by the name a surface gives them (LOOP C-13). */
1091
- export const COMPONENT_CATALOGUE = Object.fromEntries(Object.values(UI_PLUGIN_CATALOGUE)
1090
+ /** The visual components the enabled UI specs render, by the name a surface gives them (LOOP C-13). */
1091
+ export const COMPONENT_CATALOGUE = Object.fromEntries(Object.values(UI_CATALOGUE)
1092
1092
  .filter(plugin => plugin.enabled)
1093
1093
  .flatMap(plugin => plugin.components.map(component => [component.id, component])));
1094
1094
  /** The component a layout names, or undefined. */
@@ -107,10 +107,10 @@ export interface ComponentSpec {
107
107
  }
108
108
  /**
109
109
  * How an agent's answer becomes an interface: a protocol the host renders
110
- * (`agentspecs/ui-plugins`). An agent spec's `uiPlugin` names one.
110
+ * (`agentspecs/ui`). An agent spec's `ui` names one.
111
111
  */
112
- export interface UIPluginSpec {
113
- /** What an agent spec's `uiPlugin` names (e.g. 'a2ui'). */
112
+ export interface UISpec {
113
+ /** What an agent spec's `ui` names (e.g. 'a2ui'). */
114
114
  id: string;
115
115
  version: string;
116
116
  name: string;
@@ -125,6 +125,39 @@ export interface UIPluginSpec {
125
125
  /** The visual components it renders (LOOP C-13). */
126
126
  components: ComponentSpec[];
127
127
  }
128
+ /** The layer of an agent's visit a protocol answers (AGENT_PROTOCOLS §1). */
129
+ export type ProtocolLayer = 'transport' | 'consent' | 'identity' | 'commerce' | 'ui';
130
+ /**
131
+ * An agent protocol Datalayer targets (`agentspecs/protocols`, AGENT_PROTOCOLS
132
+ * PS-01). An agent spec's or an application's `protocols` names the ones it speaks.
133
+ */
134
+ export interface ProtocolSpec {
135
+ /** What `protocols` lists (e.g. 'pap'). */
136
+ id: string;
137
+ version: string;
138
+ name: string;
139
+ description: string;
140
+ /** Who publishes the specification. */
141
+ publisher: string;
142
+ layer: ProtocolLayer;
143
+ /** The specification. */
144
+ specUrl: string;
145
+ /** The version implemented. */
146
+ specVersion: string;
147
+ /** Implemented by agent-runtimes today, or only planned: an application cannot ship a planned one. */
148
+ status: 'shipped' | 'planned';
149
+ /** What it connects an agent to. */
150
+ connects: string;
151
+ /** The packages implementing it, by language. */
152
+ packages: {
153
+ python: string[];
154
+ typescript: string[];
155
+ };
156
+ /** Its tools' action-class tables (`agentspecs/protocol-tools`). */
157
+ protocolTools: string[];
158
+ /** The Appspec block it configures, if any: refused unless `protocols` lists it. */
159
+ appspecBlock?: 'pap' | 'pact' | 'a2a';
160
+ }
128
161
  /** A check a Frame requires of the output of work done under it. */
129
162
  export interface FrameGuardSpec {
130
163
  id: string;
@@ -507,6 +540,25 @@ export interface AppPactConnectionSpec {
507
540
  export interface AppPactSpec {
508
541
  connections: AppPactConnectionSpec[];
509
542
  }
543
+ /**
544
+ * An A2A extension the application's Agent Card advertises, beside the
545
+ * runtime's own (AGENT_PROTOCOLS PR-02). Its params are public: never a
546
+ * credential.
547
+ */
548
+ export interface AppA2AExtensionSpec {
549
+ /** The extension's URI: an `https://` URL or a `urn:`. */
550
+ uri: string;
551
+ /** What it adds, for whoever reads the card. */
552
+ description: string;
553
+ /** Whether a client must support it to talk to the application at all. */
554
+ required: boolean;
555
+ /** Its parameters on the card, as the extension defines them. */
556
+ params: Record<string, unknown>;
557
+ }
558
+ /** A2A: the extensions its Agent Card advertises. */
559
+ export interface AppA2ASpec {
560
+ extensions: AppA2AExtensionSpec[];
561
+ }
510
562
  /** When an application acts alone, and when it asks. */
511
563
  export interface AppRuleSpec {
512
564
  /** The action, in the words a person reads. */
@@ -1063,10 +1115,20 @@ export interface AppSpec {
1063
1115
  /** The documents and datasets it answers from. */
1064
1116
  contents: string[];
1065
1117
  connections: AppConnectionSpec[];
1118
+ /**
1119
+ * The agent protocols it speaks, ids of `agentspecs/protocols` (AGENT_PROTOCOLS
1120
+ * PS-02): its `pap`, `pact` and `a2a` blocks are refused unless their protocol
1121
+ * is listed, and a planned one only while it is not offered.
1122
+ */
1123
+ protocols: string[];
1124
+ /** The UI its answers render in, ids of `agentspecs/ui` (AGENT_PROTOCOLS PS-04). */
1125
+ ui: string[];
1066
1126
  /** Personal Agent Protocol; absent, the application has none. */
1067
1127
  pap?: AppPapSpec;
1068
1128
  /** PACT: the businesses it asks for each person (AGENT_PROTOCOLS PI-01). */
1069
1129
  pact?: AppPactSpec;
1130
+ /** A2A: the extensions its Agent Card advertises (AGENT_PROTOCOLS PR-02). */
1131
+ a2a?: AppA2ASpec;
1070
1132
  rules: AppRuleSpec[];
1071
1133
  permissions: AppPermissionsSpec;
1072
1134
  interface: AppInterfaceSpec;
@@ -1187,8 +1249,13 @@ export interface Agentspec {
1187
1249
  delegable?: AgentCapability[];
1188
1250
  /** Communication protocol (e.g., 'ag-ui', 'acp', 'a2a', 'vercel-ai') */
1189
1251
  protocol?: string;
1190
- /** UI plugin (e.g., 'a2ui', 'mcp-apps'), one of the `UI_PLUGIN_CATALOGUE`. */
1191
- uiPlugin?: string;
1252
+ /**
1253
+ * The agent protocols it speaks, ids of `agentspecs/protocols` (AGENT_PROTOCOLS
1254
+ * PS-02). `protocol` says how a page reaches it; this, what it speaks to the world.
1255
+ */
1256
+ protocols?: string[];
1257
+ /** The UI its answers render in (e.g., 'a2ui', 'mcp-apps'), one of the `UI_CATALOGUE`. */
1258
+ ui?: string;
1192
1259
  /** Trigger configuration (type, cron, event source, prompt) */
1193
1260
  trigger?: AgentTriggerConfig;
1194
1261
  /** Model configuration (temperature, max_tokens) */
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * @module types/messages
6
6
  */
7
+ import type { Display } from '@datalayer/reactor/ui';
7
8
  /**
8
9
  * Message role enumeration
9
10
  */
@@ -121,6 +122,12 @@ export interface ChatMessage {
121
122
  note?: 'waiting' | 'failed' | 'stopped';
122
123
  /** Optional metadata */
123
124
  metadata?: Record<string, unknown>;
125
+ /**
126
+ * What the message shows besides its words: the displays sent under it
127
+ * (`reactor.ui`, REACTOR_UI RU-2), in the order they came; each drawn by
128
+ * the renderer a plugin contributed for its type.
129
+ */
130
+ displays?: Display[];
124
131
  /** Tool calls for assistant messages */
125
132
  toolCalls?: ToolCallContentPart[];
126
133
  /** For activity messages (A2A, A2UI, etc.) */
@@ -44,6 +44,14 @@ export interface ProtocolConfig {
44
44
  enableConfigQuery?: boolean;
45
45
  /** Config endpoint URL for non-Jupyter protocols (if not set, uses Jupyter requestAPI) */
46
46
  configEndpoint?: string;
47
+ /**
48
+ * The ui channel's WebSocket (`ws://` or `wss://`, REACTOR_UI RU-W): an
49
+ * application's session says on it what its messages show, its steps, its
50
+ * elements, its authors and its window messages, and takes the presses of
51
+ * what they offered. Set for an application's agent; one connection per
52
+ * conversation, its thread the scope.
53
+ */
54
+ uiSocket?: string;
47
55
  /** Additional protocol options */
48
56
  options?: Record<string, unknown>;
49
57
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.3.113",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -161,7 +161,7 @@
161
161
  "@datalayer/primer-addons": "^1.0.39",
162
162
  "@datalayer/primer-rjsf": "^1.0.3",
163
163
  "@datalayer/personal-agent-protocol": "^0.6.0",
164
- "@datalayer/reactor": "^1.0.4",
164
+ "@datalayer/reactor": "^1.2.0",
165
165
  "@datalayer/reactor-commands": "^1.0.4",
166
166
  "@datalayer/reactor-manager": "^1.0.4",
167
167
  "@datalayer/reactor-shell": "^1.0.4",
@@ -235,7 +235,10 @@ def load_fragments(specs_dir: Path) -> List[Dict[str, Any]]:
235
235
 
236
236
 
237
237
  def refuse_tools_field(spec: Dict[str, Any], path: Path) -> None:
238
- """Refuse an agent spec that still says `tools`: it is `backend_tools` now."""
238
+ """Refuse an agent spec that still says `tools` (it is `backend_tools` now) or
239
+ `ui_plugin` (it is `ui` now, AGENT_PROTOCOLS PS-03)."""
240
+ if "ui_plugin" in spec:
241
+ raise SystemExit(f"Error: {path} says `ui_plugin`: the field is `ui`, one of agentspecs/ui")
239
242
  if "tools" in spec:
240
243
  raise SystemExit(
241
244
  f"Error: {path} says `tools`: the field is `backend_tools` — the tools "
@@ -288,9 +291,37 @@ def load_yaml_specs(specs_dir: Path) -> List[tuple[str, Dict[str, Any]]]:
288
291
  resolved.append((subfolder, spec))
289
292
 
290
293
  check_model_additionals(resolved, load_model_ids(specs_dir))
294
+ check_protocols(resolved, load_protocol_ids(specs_dir))
291
295
  return resolved
292
296
 
293
297
 
298
+ def load_protocol_ids(specs_dir: Path) -> set[str]:
299
+ """Every id of the protocols catalogue (`agentspecs/protocols`, AGENT_PROTOCOLS PS-01)."""
300
+ ids: set[str] = set()
301
+ for yaml_file in sorted((specs_dir.parent / "protocols").glob("*.yaml")):
302
+ protocol = yaml.safe_load(yaml_file.read_text()) or {}
303
+ if protocol.get("id"):
304
+ ids.add(str(protocol["id"]))
305
+ return ids
306
+
307
+
308
+ def check_protocols(specs: List[tuple[str, Dict[str, Any]]], protocol_ids: set[str]) -> None:
309
+ """Refuse an agent whose `protocols` is not a list of the catalogue's ids, each once (PS-02)."""
310
+ problems = []
311
+ for _, spec in specs:
312
+ said = spec.get("protocols")
313
+ if said is None:
314
+ continue
315
+ if not isinstance(said, list) or len(set(map(str, said))) != len(said):
316
+ problems.append(f"{spec.get('id')}: protocols is a list of protocol ids, each once")
317
+ continue
318
+ unknown = [str(p) for p in said if str(p) not in protocol_ids]
319
+ if unknown:
320
+ problems.append(f"{spec.get('id')}: protocols names what the catalogue does not know: {', '.join(unknown)}")
321
+ if problems:
322
+ raise SystemExit("\n".join(problems))
323
+
324
+
294
325
  def load_model_ids(specs_dir: Path) -> set[str]:
295
326
  """Every id the models catalogue answers to: its ids and their aliases."""
296
327
  ids: set[str] = set()
@@ -508,8 +539,8 @@ from agent_runtimes.types import (
508
539
  protocol_val = spec.get("protocol")
509
540
  protocol_str = f'"{protocol_val}"' if protocol_val else "None"
510
541
  delegable_str = _fmt_py_delegable(spec.get("delegable", []))
511
- ui_plugin = spec.get("ui_plugin")
512
- ui_plugin_str = f'"{ui_plugin}"' if ui_plugin else "None"
542
+ ui_id = spec.get("ui")
543
+ ui_str = f'"{ui_id}"' if ui_id else "None"
513
544
  trigger_val = spec.get("trigger")
514
545
  model_cfg = spec.get("model_config")
515
546
  mcp_srv_tools = spec.get("mcp_server_tools")
@@ -620,7 +651,8 @@ from agent_runtimes.types import (
620
651
  goal={goal_str},
621
652
  delegable={delegable_str},
622
653
  protocol={protocol_str},
623
- ui_plugin={ui_plugin_str},
654
+ ui={ui_str},
655
+ protocols={_fmt_list([str(p) for p in spec.get("protocols") or []])},
624
656
  trigger={_fmt_py_literal(trigger_val)},
625
657
  model_configuration={_fmt_py_literal(model_cfg)},
626
658
  mcp_server_tools={_fmt_py_literal(mcp_srv_tools)},
@@ -1135,8 +1167,8 @@ const FRONTEND_TOOL_MAP: Record<string, any> = {
1135
1167
  protocol_val = spec.get("protocol")
1136
1168
  protocol_ts = f"'{protocol_val}'" if protocol_val else "undefined"
1137
1169
  delegable_ts = _fmt_ts_delegable(spec.get("delegable", []))
1138
- ui_plugin = spec.get("ui_plugin")
1139
- ui_plugin_ts = f"'{ui_plugin}'" if ui_plugin else "undefined"
1170
+ ui_id = spec.get("ui")
1171
+ ui_ts = f"'{ui_id}'" if ui_id else "undefined"
1140
1172
  trigger_val = spec.get("trigger")
1141
1173
  model_cfg = spec.get("model_config")
1142
1174
  mcp_srv_tools = spec.get("mcp_server_tools")
@@ -1195,7 +1227,8 @@ const FRONTEND_TOOL_MAP: Record<string, any> = {
1195
1227
  goal: {goal_ts},
1196
1228
  delegable: {delegable_ts},
1197
1229
  protocol: {protocol_ts},
1198
- uiPlugin: {ui_plugin_ts},
1230
+ ui: {ui_ts},
1231
+ protocols: {_fmt_ts_literal([str(p) for p in spec.get("protocols") or []])},
1199
1232
  trigger: {_fmt_ts_literal(trigger_val)},
1200
1233
  modelConfig: {_fmt_ts_literal(model_cfg)},
1201
1234
  mcpServerTools: {_fmt_ts_literal(mcp_srv_tools)},
@@ -1635,11 +1668,13 @@ export * from './memory';
1635
1668
  export * from './models';
1636
1669
  export * from './modelProviders';
1637
1670
  export * from './notifications';
1671
+ export * from './voices';
1638
1672
  export * from './outputs';
1639
1673
  export * from './skills';
1640
1674
  export * from './backendTools';
1641
1675
  export * from './triggers';
1642
- export * from './uiPlugins';
1676
+ export * from './ui';
1677
+ export * from './protocols';
1643
1678
  export * from './frames';
1644
1679
  export * from './cogs';
1645
1680
  export * from './guards';
@@ -152,8 +152,16 @@ def load_specs(specs_dir: Path) -> tuple[list[dict[str, Any]], dict[str, Any]]:
152
152
  # Personal Agent Protocol only when the application says something of it:
153
153
  # an Appspec that does not mention `pap` reads back with none (the TypeScript
154
154
  # reader's rule), so the catalogue leaves the defaults out too.
155
- if "pap" in spec and spec["pap"] == type(app.pap)().model_dump(mode="json", by_alias=True):
155
+ if "pap" in spec and spec["pap"] == type(app.pap)().model_dump(
156
+ mode="json", by_alias=True
157
+ ):
156
158
  spec.pop("pap")
159
+ # PACT and A2A's extensions the same way (AGENT_PROTOCOLS PI-01, PR-02).
160
+ for block in ("pact", "a2a"):
161
+ if block in spec and spec[block] == type(getattr(app, block))().model_dump(
162
+ mode="json", by_alias=True
163
+ ):
164
+ spec.pop(block)
157
165
  for key in ("description", "instructions", "goal"):
158
166
  spec[key] = _flat(spec.get(key))
159
167
  spec["interface"]["welcome"] = _flat(spec["interface"].get("welcome"))
@@ -198,8 +206,24 @@ def load_specs(specs_dir: Path) -> tuple[list[dict[str, Any]], dict[str, Any]]:
198
206
  if (signs := actions_module.server_tool_signs(server, name))
199
207
  },
200
208
  }
209
+ # The agent protocols' tools (AGENT_PROTOCOLS PR-54): by protocol, the
210
+ # connection prefix its connections take and what each tool can do.
211
+ protocols = {
212
+ identity: {
213
+ "connection": spec["connection"],
214
+ "tools": {
215
+ name: [
216
+ item.value
217
+ for item in actions_module.protocol_tool_classes(identity, name)
218
+ ]
219
+ for name in actions_module.protocol_tool_names(identity)
220
+ },
221
+ }
222
+ for identity, spec in sorted(actions_module.protocol_tool_specs().items())
223
+ }
201
224
  actions = {
202
225
  "classes": [item.value for item in actions_module.ActionClass],
226
+ "protocols": protocols,
203
227
  "tools": tools,
204
228
  "servers": servers,
205
229
  "behaviours": behaviours,
@@ -419,6 +443,10 @@ def generate_actions_python_code(actions: dict[str, Any]) -> str:
419
443
  [
420
444
  "}",
421
445
  "",
446
+ "#: What each agent protocol's tools do, by protocol id: the prefix its",
447
+ "#: connections take (`pap:<domain>`) and each tool's classes (PR-54).",
448
+ f"PROTOCOL_TOOL_CLASSES: Dict[str, Dict[str, Any]] = {actions['protocols']!r}",
449
+ "",
422
450
  "#: What each application of the catalogue does about each classed tool of the",
423
451
  "#: servers it connects to, as agentspecs decides it: `do_it`, `if_asked`,",
424
452
  "#: `ask_first` or `leave_to_me`. What the rules engine has to reproduce.",
@@ -471,6 +499,15 @@ def generate_actions_typescript_code(actions: dict[str, Any]) -> str:
471
499
  + ";",
472
500
  "",
473
501
  "/**",
502
+ " * What each agent protocol's tools do, by protocol id: the prefix its",
503
+ " * connections take (`pap:<domain>`) and each tool's classes (PR-54).",
504
+ " */",
505
+ "export const PROTOCOL_TOOL_CLASSES: Record<",
506
+ " string,",
507
+ " { connection: string; tools: Record<string, ActionClass[]> }",
508
+ "> = " + json.dumps(actions["protocols"], indent=2) + ";",
509
+ "",
510
+ "/**",
474
511
  " * What each application of the catalogue does about each classed tool of the",
475
512
  " * servers it connects to, as agentspecs decides it. What the rules engine has",
476
513
  " * to reproduce.",