@datalayer/agent-runtimes 1.3.111 → 1.3.112

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 (44) hide show
  1. package/dist-embed/datalayer-app-main.js +4 -4
  2. package/lib/apps/apps/appspec.js +2 -0
  3. package/lib/apps/apps/checks.js +10 -6
  4. package/lib/examples/PapSignInDisplayExample.d.ts +4 -0
  5. package/lib/examples/PapSignInDisplayExample.js +23 -0
  6. package/lib/examples/example-selector.js +1 -0
  7. package/lib/examples/index.d.ts +1 -0
  8. package/lib/examples/index.js +1 -0
  9. package/lib/examples/main.js +2 -0
  10. package/lib/examples/pap/PapSignInDisplayView.d.ts +15 -0
  11. package/lib/examples/pap/PapSignInDisplayView.js +49 -0
  12. package/lib/examples/pap/PapTraceView.d.ts +2 -3
  13. package/lib/examples/pap/PapTraceView.js +3 -4
  14. package/lib/examples/pap/papSignInCases.d.ts +12 -0
  15. package/lib/examples/pap/papSignInCases.js +88 -0
  16. package/lib/protocols/a2a/index.d.ts +52 -0
  17. package/lib/protocols/a2a/index.js +164 -0
  18. package/lib/protocols/agentProtocols.d.ts +15 -0
  19. package/lib/protocols/agentProtocols.js +47 -0
  20. package/lib/protocols/agentic-commerce/index.d.ts +86 -0
  21. package/lib/protocols/agentic-commerce/index.js +267 -0
  22. package/lib/protocols/agentic-commerce/models.d.ts +3292 -0
  23. package/lib/protocols/agentic-commerce/models.js +10 -0
  24. package/lib/protocols/commerce.d.ts +42 -0
  25. package/lib/protocols/commerce.js +47 -0
  26. package/lib/protocols/core.d.ts +44 -0
  27. package/lib/protocols/core.js +62 -0
  28. package/lib/protocols/mcp/index.d.ts +4 -0
  29. package/lib/protocols/mcp/index.js +37 -0
  30. package/lib/protocols/pact/index.d.ts +139 -0
  31. package/lib/protocols/pact/index.js +357 -0
  32. package/lib/protocols/ucp/index.d.ts +79 -0
  33. package/lib/protocols/ucp/index.js +277 -0
  34. package/lib/protocols/web-bot-auth/index.d.ts +161 -0
  35. package/lib/protocols/web-bot-auth/index.js +427 -0
  36. package/lib/specs/actions.js +4 -0
  37. package/lib/specs/apps.d.ts +2 -0
  38. package/lib/specs/apps.js +481 -0
  39. package/lib/specs/appspecSchema.js +200 -2
  40. package/lib/types/agentspecs.d.ts +2 -0
  41. package/package.json +4 -1
  42. package/scripts/codegen/generate_agentic_commerce.sh +74 -0
  43. package/scripts/codegen/generate_apps.py +11 -0
  44. package/scripts/validate_pap_examples.py +27 -2
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The Agentic Commerce Protocol, `2026-04-17`, as a Reactor Plugin and a
3
+ * client (AGENT_PROTOCOLS PR-40 to PR-42) — the twin of
4
+ * `agent_runtimes.protocols.agentic_commerce`. Never `acp` in code: that is
5
+ * the Agent Client Protocol (`../ACPAdapter`).
6
+ *
7
+ * Types are generated from the specification's JSON Schema (`./models`,
8
+ * `scripts/codegen/generate_agentic_commerce.sh`). A purchase goes as every
9
+ * purchase does (`../commerce`): an exact, revisioned proposal, approved by
10
+ * the person through `agentic_commerce.approver`, paid with the host's
11
+ * delegated token (`agentic_commerce.paymentData`), completed once.
12
+ *
13
+ * @module protocols/agentic-commerce
14
+ */
15
+ import { type ReactorPlatformView } from '@datalayer/reactor';
16
+ import { type CheckoutApprover, type CheckoutProposal, type ProposalStore } from '../commerce';
17
+ import type { CheckoutSessionBase, CheckoutSessionCreateRequest, DiscoveryResponse, PaymentData as PaymentDataModel } from './models';
18
+ import { AGENTIC_COMMERCE_VERSION } from './models';
19
+ export { AGENTIC_COMMERCE_VERSION };
20
+ export declare const DISCOVERY_PATH = "/.well-known/acp.json";
21
+ export declare const AGENTIC_COMMERCE_PLUGIN = "agent-runtimes.protocols.agentic-commerce";
22
+ /** Each operation's action class (F-10), for Rules (R-05). */
23
+ export declare const AGENTIC_COMMERCE_ACTION_CLASSES: {
24
+ readonly proposeCompletion: "read";
25
+ readonly getCheckout: "read";
26
+ readonly createCheckout: "write";
27
+ readonly updateCheckout: "write";
28
+ readonly cancelCheckout: "write";
29
+ readonly complete: "buy";
30
+ };
31
+ export declare class AgenticCommerceError extends Error {
32
+ }
33
+ type Json = Record<string, any>;
34
+ /** The agent's bearer credential with one seller, held by the host. */
35
+ export interface SellerCredentials {
36
+ bearer(seller: string): Promise<string>;
37
+ }
38
+ /** The delegated payment data of an approved proposal, from the host's custody. */
39
+ export interface PaymentData {
40
+ paymentData(proposal: CheckoutProposal, handlers: Json[]): Promise<PaymentDataModel>;
41
+ }
42
+ /** An implementation of one extension of the protocol, by the name sellers declare. */
43
+ export interface AgenticCommerceExtension {
44
+ name: string;
45
+ }
46
+ export declare const AgenticCommerceApprovers: import("@datalayer/reactor").ContributionPoint<CheckoutApprover>;
47
+ export declare const AgenticCommercePaymentData: import("@datalayer/reactor").ContributionPoint<PaymentData>;
48
+ export declare const AgenticCommerceCredentials: import("@datalayer/reactor").ContributionPoint<SellerCredentials>;
49
+ export declare const AgenticCommerceProposalStores: import("@datalayer/reactor").ContributionPoint<ProposalStore>;
50
+ export declare const AgenticCommerceDiscountExtensions: import("@datalayer/reactor").ContributionPoint<AgenticCommerceExtension>;
51
+ export declare const AgenticCommerceOtherExtensions: import("@datalayer/reactor").ContributionPoint<AgenticCommerceExtension>;
52
+ export declare const AgenticCommercePlugin: import("@datalayer/reactor").ReactorPlugin<Record<string, never>, unknown, unknown>;
53
+ /** The extensions an agent declares to a seller: those contributed here. */
54
+ export declare function declaredExtensions(reactor: ReactorPlatformView): string[];
55
+ /** `line_items` as the 2026-04-17 schema writes them: one `Item` per unit (it has no `quantity`). */
56
+ export declare function itemsOf(items: Array<{
57
+ id: string;
58
+ quantity?: number;
59
+ }>): CheckoutSessionCreateRequest['line_items'];
60
+ /** The revision of what a session buys; the same digest as Python's `revision_of`. */
61
+ export declare function revisionOf(session: Json): Promise<string>;
62
+ /** What an agent may see of a session: no payment token. */
63
+ export declare function sessionSummary(session: Json): Json;
64
+ /** An agent's client of one seller, over REST. */
65
+ export declare class AgenticCommerceClient {
66
+ private readonly seller;
67
+ private readonly reactor;
68
+ private readonly fetchImpl;
69
+ private apiBaseUrl?;
70
+ private readonly domain;
71
+ constructor(seller: string, reactor: ReactorPlatformView, fetchImpl?: typeof fetch);
72
+ /** Read and check the seller's discovery document: the version, REST, checkout. */
73
+ discover(): Promise<DiscoveryResponse>;
74
+ private call;
75
+ createCheckout(items: Array<{
76
+ id: string;
77
+ quantity?: number;
78
+ }>, currency: string, buyer?: Json): Promise<CheckoutSessionBase>;
79
+ updateCheckout(id: string, update: Json): Promise<CheckoutSessionBase>;
80
+ getCheckout(id: string): Promise<CheckoutSessionBase>;
81
+ cancelCheckout(id: string): Promise<CheckoutSessionBase>;
82
+ /** The exact purchase a `ready_for_payment` session would make. */
83
+ proposeCompletion(id: string): Promise<CheckoutProposal>;
84
+ /** Complete an approved proposal, once: refused if spent, declined, changed or expired. */
85
+ complete(proposal: CheckoutProposal): Promise<Json>;
86
+ }
@@ -0,0 +1,267 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * The Agentic Commerce Protocol, `2026-04-17`, as a Reactor Plugin and a
7
+ * client (AGENT_PROTOCOLS PR-40 to PR-42) — the twin of
8
+ * `agent_runtimes.protocols.agentic_commerce`. Never `acp` in code: that is
9
+ * the Agent Client Protocol (`../ACPAdapter`).
10
+ *
11
+ * Types are generated from the specification's JSON Schema (`./models`,
12
+ * `scripts/codegen/generate_agentic_commerce.sh`). A purchase goes as every
13
+ * purchase does (`../commerce`): an exact, revisioned proposal, approved by
14
+ * the person through `agentic_commerce.approver`, paid with the host's
15
+ * delegated token (`agentic_commerce.paymentData`), completed once.
16
+ *
17
+ * @module protocols/agentic-commerce
18
+ */
19
+ import { contribution, defineContributionPoint, definePlugin, } from '@datalayer/reactor';
20
+ import { InMemoryProposalStore, digest, } from '../commerce';
21
+ import { DEFAULT_ORDER, ProtocolDescriptions, firstContribution, } from '../core';
22
+ import { AGENTIC_COMMERCE_VERSION } from './models';
23
+ export { AGENTIC_COMMERCE_VERSION };
24
+ export const DISCOVERY_PATH = '/.well-known/acp.json';
25
+ export const AGENTIC_COMMERCE_PLUGIN = 'agent-runtimes.protocols.agentic-commerce';
26
+ /** Each operation's action class (F-10), for Rules (R-05). */
27
+ export const AGENTIC_COMMERCE_ACTION_CLASSES = {
28
+ proposeCompletion: 'read',
29
+ getCheckout: 'read',
30
+ createCheckout: 'write',
31
+ updateCheckout: 'write',
32
+ cancelCheckout: 'write',
33
+ complete: 'buy',
34
+ };
35
+ export class AgenticCommerceError extends Error {
36
+ }
37
+ export const AgenticCommerceApprovers = defineContributionPoint('agentic_commerce.approver');
38
+ export const AgenticCommercePaymentData = defineContributionPoint('agentic_commerce.paymentData');
39
+ export const AgenticCommerceCredentials = defineContributionPoint('agentic_commerce.credentials');
40
+ export const AgenticCommerceProposalStores = defineContributionPoint('agentic_commerce.proposalStore');
41
+ export const AgenticCommerceDiscountExtensions = defineContributionPoint('agentic_commerce.extension.discount');
42
+ export const AgenticCommerceOtherExtensions = defineContributionPoint('agentic_commerce.extension.other');
43
+ const POINTS = [
44
+ AgenticCommerceApprovers,
45
+ AgenticCommercePaymentData,
46
+ AgenticCommerceCredentials,
47
+ AgenticCommerceProposalStores,
48
+ AgenticCommerceDiscountExtensions,
49
+ AgenticCommerceOtherExtensions,
50
+ ];
51
+ export const AgenticCommercePlugin = definePlugin({
52
+ name: AGENTIC_COMMERCE_PLUGIN,
53
+ version: '1.0.0',
54
+ description: `Agentic Commerce Protocol ${AGENTIC_COMMERCE_VERSION}: buy once approved.`,
55
+ contributionPoints: POINTS,
56
+ contributes: [
57
+ contribution(ProtocolDescriptions, {
58
+ id: 'agentic_commerce',
59
+ name: 'Agentic Commerce Protocol',
60
+ layer: 'commerce',
61
+ version: AGENTIC_COMMERCE_VERSION,
62
+ roles: ['buyer'],
63
+ status: 'partial',
64
+ specification: `https://github.com/agentic-commerce-protocol/agentic-commerce-protocol/tree/main/spec/${AGENTIC_COMMERCE_VERSION}`,
65
+ plugin: AGENTIC_COMMERCE_PLUGIN,
66
+ points: POINTS.map(point => point.id),
67
+ }, { id: 'agentic_commerce', order: DEFAULT_ORDER }),
68
+ ],
69
+ // One store per reactor, not one per module: a store is state.
70
+ register: ctx => {
71
+ ctx.contribute(AgenticCommerceProposalStores, new InMemoryProposalStore(), {
72
+ id: 'memory',
73
+ order: DEFAULT_ORDER,
74
+ });
75
+ },
76
+ });
77
+ /** The extensions an agent declares to a seller: those contributed here. */
78
+ export function declaredExtensions(reactor) {
79
+ const names = [];
80
+ const [discount] = reactor.getContributions(AgenticCommerceDiscountExtensions);
81
+ if (discount) {
82
+ names.push(discount.value.name);
83
+ }
84
+ names.push(...reactor
85
+ .getContributions(AgenticCommerceOtherExtensions)
86
+ .map(c => c.value.name));
87
+ return [...new Set(names)];
88
+ }
89
+ /** `line_items` as the 2026-04-17 schema writes them: one `Item` per unit (it has no `quantity`). */
90
+ export function itemsOf(items) {
91
+ return items.flatMap(item => Array.from({ length: item.quantity ?? 1 }, () => ({ id: item.id })));
92
+ }
93
+ /** The revision of what a session buys; the same digest as Python's `revision_of`. */
94
+ export function revisionOf(session) {
95
+ return digest({
96
+ id: session.id,
97
+ currency: session.currency,
98
+ line_items: (session.line_items ?? []).map((line) => ({
99
+ item: line.item?.id ?? null,
100
+ price: line.item?.unit_amount ?? null,
101
+ quantity: line.quantity,
102
+ })),
103
+ totals: (session.totals ?? []).map((total) => ({
104
+ type: total.type,
105
+ amount: total.amount,
106
+ })),
107
+ });
108
+ }
109
+ /** What an agent may see of a session: no payment token. */
110
+ export function sessionSummary(session) {
111
+ return {
112
+ id: session.id,
113
+ status: session.status,
114
+ currency: session.currency,
115
+ lines: (session.line_items ?? []).map((line) => ({
116
+ title: line.name ?? line.item?.name ?? line.item?.id,
117
+ quantity: line.quantity,
118
+ price: line.item?.unit_amount,
119
+ })),
120
+ totals: Object.fromEntries((session.totals ?? []).map((t) => [t.type, t.amount])),
121
+ messages: (session.messages ?? []).map((m) => m.content),
122
+ extensions: (session.capabilities?.extensions ?? []).map((e) => e.name),
123
+ ...(session.order
124
+ ? {
125
+ order: {
126
+ id: session.order.id,
127
+ permalink_url: session.order.permalink_url,
128
+ },
129
+ }
130
+ : {}),
131
+ };
132
+ }
133
+ /** An agent's client of one seller, over REST. */
134
+ export class AgenticCommerceClient {
135
+ seller;
136
+ reactor;
137
+ fetchImpl;
138
+ apiBaseUrl;
139
+ domain;
140
+ constructor(seller, reactor, fetchImpl = (input, init) => fetch(input, init)) {
141
+ this.seller = seller;
142
+ this.reactor = reactor;
143
+ this.fetchImpl = fetchImpl;
144
+ this.domain = new URL(seller).hostname;
145
+ }
146
+ /** Read and check the seller's discovery document: the version, REST, checkout. */
147
+ async discover() {
148
+ const answer = await this.fetchImpl(`${this.seller.replace(/\/$/, '')}${DISCOVERY_PATH}`);
149
+ if (answer.status !== 200) {
150
+ throw new AgenticCommerceError(`${DISCOVERY_PATH} answered ${answer.status}`);
151
+ }
152
+ const document = (await answer.json());
153
+ if (document.protocol?.name !== 'acp' ||
154
+ !document.protocol.supported_versions.includes(AGENTIC_COMMERCE_VERSION)) {
155
+ throw new AgenticCommerceError(`the seller does not support ${AGENTIC_COMMERCE_VERSION}`);
156
+ }
157
+ if (!document.transports.includes('rest')) {
158
+ throw new AgenticCommerceError('the seller offers no REST transport');
159
+ }
160
+ if (!document.capabilities.services.includes('checkout')) {
161
+ throw new AgenticCommerceError('the seller offers no checkout');
162
+ }
163
+ this.apiBaseUrl = String(document.api_base_url).replace(/\/$/, '');
164
+ return document;
165
+ }
166
+ async call(method, path, body, key) {
167
+ if (!this.apiBaseUrl) {
168
+ await this.discover();
169
+ }
170
+ const credentials = firstContribution(this.reactor, AgenticCommerceCredentials, 'Agentic Commerce credentials');
171
+ const headers = {
172
+ Authorization: `Bearer ${await credentials.bearer(this.domain)}`,
173
+ 'API-Version': AGENTIC_COMMERCE_VERSION,
174
+ 'Content-Type': 'application/json',
175
+ 'Request-Id': crypto.randomUUID(),
176
+ };
177
+ if (method === 'POST') {
178
+ headers['Idempotency-Key'] = key ?? crypto.randomUUID();
179
+ }
180
+ const answer = await this.fetchImpl(`${this.apiBaseUrl}${path}`, {
181
+ method,
182
+ headers,
183
+ body: body === undefined ? undefined : JSON.stringify(body),
184
+ });
185
+ if (answer.status === 409) {
186
+ throw new AgenticCommerceError('the idempotency key was reused with another request');
187
+ }
188
+ if (answer.status >= 400) {
189
+ throw new AgenticCommerceError(`${method} ${path} answered ${answer.status}`);
190
+ }
191
+ return answer.json();
192
+ }
193
+ async createCheckout(items, currency, buyer) {
194
+ const extensions = declaredExtensions(this.reactor);
195
+ const request = {
196
+ line_items: itemsOf(items),
197
+ currency,
198
+ capabilities: extensions.length ? { extensions } : {},
199
+ ...(buyer ? { buyer } : {}),
200
+ };
201
+ return (await this.call('POST', '/checkout_sessions', request));
202
+ }
203
+ async updateCheckout(id, update) {
204
+ const body = { ...update };
205
+ if (body.line_items) {
206
+ body.line_items = itemsOf(body.line_items);
207
+ }
208
+ return (await this.call('POST', `/checkout_sessions/${id}`, body));
209
+ }
210
+ async getCheckout(id) {
211
+ return (await this.call('GET', `/checkout_sessions/${id}`));
212
+ }
213
+ async cancelCheckout(id) {
214
+ return (await this.call('POST', `/checkout_sessions/${id}/cancel`, {}));
215
+ }
216
+ /** The exact purchase a `ready_for_payment` session would make. */
217
+ async proposeCompletion(id) {
218
+ const session = (await this.getCheckout(id));
219
+ if (session.status !== 'ready_for_payment') {
220
+ throw new AgenticCommerceError(`the session is ${session.status}, not ready_for_payment`);
221
+ }
222
+ const total = session.totals.find(t => t.type === 'total');
223
+ if (!total) {
224
+ throw new AgenticCommerceError('the session says no total');
225
+ }
226
+ return {
227
+ id: crypto.randomUUID(),
228
+ merchant: this.domain,
229
+ checkoutId: session.id,
230
+ revision: await revisionOf(session),
231
+ currency: String(session.currency).toUpperCase(),
232
+ total: total.amount,
233
+ lines: session.line_items.map(line => ({
234
+ title: line.name ?? line.item?.name ?? line.item?.id,
235
+ quantity: line.quantity,
236
+ price: line.item?.unit_amount ?? 0,
237
+ })),
238
+ expiresAt: session.expires_at,
239
+ };
240
+ }
241
+ /** Complete an approved proposal, once: refused if spent, declined, changed or expired. */
242
+ async complete(proposal) {
243
+ if (proposal.expiresAt &&
244
+ new Date(proposal.expiresAt).getTime() <= Date.now()) {
245
+ throw new AgenticCommerceError('the proposal has expired');
246
+ }
247
+ const approver = firstContribution(this.reactor, AgenticCommerceApprovers, 'Agentic Commerce approver');
248
+ const payment = firstContribution(this.reactor, AgenticCommercePaymentData, 'Agentic Commerce payment data');
249
+ const store = firstContribution(this.reactor, AgenticCommerceProposalStores, 'Agentic Commerce proposal store');
250
+ // Spent before the person is asked: a declined proposal is proposed again.
251
+ if (!(await store.take(proposal.id))) {
252
+ throw new AgenticCommerceError('this proposal was used already');
253
+ }
254
+ if (!(await approver.approve(proposal))) {
255
+ throw new AgenticCommerceError('the person did not approve this purchase');
256
+ }
257
+ const session = (await this.getCheckout(proposal.checkoutId));
258
+ if (session.status !== 'ready_for_payment') {
259
+ throw new AgenticCommerceError(`the session is ${session.status}, not ready_for_payment`);
260
+ }
261
+ if ((await revisionOf(session)) !== proposal.revision) {
262
+ throw new AgenticCommerceError('the session changed since it was proposed: propose it again');
263
+ }
264
+ const data = await payment.paymentData(proposal, session.capabilities?.payment?.handlers ?? []);
265
+ return this.call('POST', `/checkout_sessions/${proposal.checkoutId}/complete`, { payment_data: data }, proposal.id);
266
+ }
267
+ }