@datalayer/agent-runtimes 1.3.112 → 1.3.114

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.
@@ -196,6 +196,8 @@ const KNOWN_KEYS = [
196
196
  'contents',
197
197
  'connections',
198
198
  'pap',
199
+ 'pact',
200
+ 'a2a',
199
201
  'rules',
200
202
  'permissions',
201
203
  'interface',
@@ -312,6 +314,50 @@ function dumpPap(pap) {
312
314
  .text('summary', operation.summary, '\u0000')
313
315
  .value('user_approval_required', operation.userApprovalRequired, true).data)).data).data;
314
316
  }
317
+ /** PACT (AGENT_PROTOCOLS PI-01): the businesses it asks for each person. */
318
+ function parsePact(data) {
319
+ return {
320
+ connections: records(data.connections).map(connection => ({
321
+ id: text(connection.id),
322
+ brand: text(connection.brand),
323
+ audience: text(connection.audience),
324
+ access: oneOf(connection.access, ['read', 'write'], 'read'),
325
+ scopes: texts(connection.scopes),
326
+ })),
327
+ };
328
+ }
329
+ /** PACT as its document says it, nothing at its default. */
330
+ function dumpPact(pact) {
331
+ if (!pact)
332
+ return {};
333
+ return new Writer().list('connections', pact.connections.map(connection => new Writer()
334
+ .text('id', connection.id, '\u0000')
335
+ .text('brand', connection.brand, '\u0000')
336
+ .text('audience', connection.audience, '\u0000')
337
+ .value('access', connection.access, 'read')
338
+ .list('scopes', connection.scopes).data)).data;
339
+ }
340
+ /** A2A (AGENT_PROTOCOLS PR-02): the extensions its Agent Card advertises. */
341
+ function parseA2A(data) {
342
+ return {
343
+ extensions: records(data.extensions).map(extension => ({
344
+ uri: text(extension.uri),
345
+ description: text(extension.description),
346
+ required: flag(extension.required, false),
347
+ params: isData(extension.params) ? { ...extension.params } : {},
348
+ })),
349
+ };
350
+ }
351
+ /** A2A as its document says it, nothing at its default. */
352
+ function dumpA2A(a2a) {
353
+ if (!a2a)
354
+ return {};
355
+ return new Writer().list('extensions', a2a.extensions.map(extension => new Writer()
356
+ .text('uri', extension.uri, '\u0000')
357
+ .text('description', extension.description)
358
+ .value('required', extension.required, false)
359
+ .part('params', extension.params).data)).data;
360
+ }
315
361
  function parseRule(data) {
316
362
  return {
317
363
  action: text(data.action),
@@ -842,6 +888,12 @@ export function parseAppspec(document) {
842
888
  if (isData(data.pap)) {
843
889
  app.pap = parsePap(data.pap);
844
890
  }
891
+ if (isData(data.pact)) {
892
+ app.pact = parsePact(data.pact);
893
+ }
894
+ if (isData(data.a2a)) {
895
+ app.a2a = parseA2A(data.a2a);
896
+ }
845
897
  return { app, problems };
846
898
  }
847
899
  // --- writing --------------------------------------------------------------------------
@@ -1097,6 +1149,8 @@ export function dumpAppspec(app) {
1097
1149
  .value('as', connection.as, 'owner')
1098
1150
  .list('only', connection.only).data))
1099
1151
  .part('pap', dumpPap(app.pap))
1152
+ .part('pact', dumpPact(app.pact))
1153
+ .part('a2a', dumpA2A(app.a2a))
1100
1154
  .list('rules', app.rules.map(rule => ({
1101
1155
  action: rule.action,
1102
1156
  // One target is written alone when it is a class, as a person would.
@@ -19,15 +19,11 @@ import { AGENTIC_COMMERCE_VERSION } from './models';
19
19
  export { AGENTIC_COMMERCE_VERSION };
20
20
  export declare const DISCOVERY_PATH = "/.well-known/acp.json";
21
21
  export declare const AGENTIC_COMMERCE_PLUGIN = "agent-runtimes.protocols.agentic-commerce";
22
- /** Each operation's action class (F-10), for Rules (R-05). */
23
- export declare const AGENTIC_COMMERCE_ACTION_CLASSES: {
24
- readonly proposeCompletion: "read";
25
- readonly getCheckout: "read";
26
- readonly createCheckout: "write";
27
- readonly updateCheckout: "write";
28
- readonly cancelCheckout: "write";
29
- readonly complete: "buy";
30
- };
22
+ /**
23
+ * Each operation's action class (F-10), for Rules (R-05): agentspecs'
24
+ * `protocol-tools/agentic-commerce.yaml` (AGENT_PROTOCOLS PR-54).
25
+ */
26
+ export declare const AGENTIC_COMMERCE_ACTION_CLASSES: Record<string, import("../../types").ActionClass>;
31
27
  export declare class AgenticCommerceError extends Error {
32
28
  }
33
29
  type Json = Record<string, any>;
@@ -17,21 +17,17 @@
17
17
  * @module protocols/agentic-commerce
18
18
  */
19
19
  import { contribution, defineContributionPoint, definePlugin, } from '@datalayer/reactor';
20
- import { InMemoryProposalStore, digest, } from '../commerce';
20
+ import { InMemoryProposalStore, digest, operationClasses, } from '../commerce';
21
21
  import { DEFAULT_ORDER, ProtocolDescriptions, firstContribution, } from '../core';
22
22
  import { AGENTIC_COMMERCE_VERSION } from './models';
23
23
  export { AGENTIC_COMMERCE_VERSION };
24
24
  export const DISCOVERY_PATH = '/.well-known/acp.json';
25
25
  export const AGENTIC_COMMERCE_PLUGIN = 'agent-runtimes.protocols.agentic-commerce';
26
- /** Each operation's action class (F-10), for Rules (R-05). */
27
- export const AGENTIC_COMMERCE_ACTION_CLASSES = {
28
- proposeCompletion: 'read',
29
- getCheckout: 'read',
30
- createCheckout: 'write',
31
- updateCheckout: 'write',
32
- cancelCheckout: 'write',
33
- complete: 'buy',
34
- };
26
+ /**
27
+ * Each operation's action class (F-10), for Rules (R-05): agentspecs'
28
+ * `protocol-tools/agentic-commerce.yaml` (AGENT_PROTOCOLS PR-54).
29
+ */
30
+ export const AGENTIC_COMMERCE_ACTION_CLASSES = operationClasses('agentic-commerce');
35
31
  export class AgenticCommerceError extends Error {
36
32
  }
37
33
  export const AgenticCommerceApprovers = defineContributionPoint('agentic_commerce.approver');
@@ -1,14 +1,13 @@
1
+ import type { ActionClass } from '../types/agentspecs';
2
+ type Json = Record<string, any>;
1
3
  /**
2
- * What every commerce protocol shares (AGENT_PROTOCOLS §3, one approval
3
- * model) — the twin of `agent_runtimes.protocols.commerce`. A purchase over
4
- * UCP or the Agentic Commerce Protocol is an exact, revisioned
5
- * {@link CheckoutProposal}, approved by the person through the host's
6
- * {@link CheckoutApprover} (contributed to each plugin's `<protocol>.approver`),
7
- * and completed once ({@link ProposalStore}).
8
- *
9
- * @module protocols/commerce
4
+ * Each operation's action class (F-10) for Rules (R-05), as agentspecs
5
+ * classes a protocol's tools (`protocol-tools/<protocol>.yaml`,
6
+ * AGENT_PROTOCOLS PR-54), named as the TypeScript client names them
7
+ * (`complete_checkout` → `completeCheckout`). A commerce operation does one
8
+ * thing: one with several classes, or none, throws rather than guess.
10
9
  */
11
- type Json = Record<string, any>;
10
+ export declare function operationClasses(protocol: string): Record<string, ActionClass>;
12
11
  /** One exact purchase, proposed to a person before it is made. */
13
12
  export interface CheckoutProposal {
14
13
  id: string;
@@ -2,6 +2,35 @@
2
2
  * Copyright (c) 2025-2026 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
+ /**
6
+ * What every commerce protocol shares (AGENT_PROTOCOLS §3, one approval
7
+ * model) — the twin of `agent_runtimes.protocols.commerce`. A purchase over
8
+ * UCP or the Agentic Commerce Protocol is an exact, revisioned
9
+ * {@link CheckoutProposal}, approved by the person through the host's
10
+ * {@link CheckoutApprover} (contributed to each plugin's `<protocol>.approver`),
11
+ * and completed once ({@link ProposalStore}).
12
+ *
13
+ * @module protocols/commerce
14
+ */
15
+ import { PROTOCOL_TOOL_CLASSES } from '../specs/actions';
16
+ /**
17
+ * Each operation's action class (F-10) for Rules (R-05), as agentspecs
18
+ * classes a protocol's tools (`protocol-tools/<protocol>.yaml`,
19
+ * AGENT_PROTOCOLS PR-54), named as the TypeScript client names them
20
+ * (`complete_checkout` → `completeCheckout`). A commerce operation does one
21
+ * thing: one with several classes, or none, throws rather than guess.
22
+ */
23
+ export function operationClasses(protocol) {
24
+ const out = {};
25
+ for (const [name, classes] of Object.entries(PROTOCOL_TOOL_CLASSES[protocol].tools)) {
26
+ if (classes.length !== 1) {
27
+ throw new Error(`${protocol} ${name} is classed ${classes}: one class each`);
28
+ }
29
+ out[name.replace(/_([a-z])/g, (_, c) => c.toUpperCase())] =
30
+ classes[0];
31
+ }
32
+ return out;
33
+ }
5
34
  /** A proposal in words, for the person and the model: never a credential. */
6
35
  export function proposalSummary(proposal) {
7
36
  const items = proposal.lines
@@ -133,6 +133,8 @@ export declare class PactPersonalAgent {
133
133
  }): Promise<Reply | StepUp>;
134
134
  private verifyReceipt;
135
135
  requestSignIn(user: string, scopes: string[]): Promise<SignIn>;
136
+ /** Ask once whether the person approved: the scopes granted, or `undefined` while pending. */
137
+ pollSignIn(user: string, signIn: SignIn): Promise<string[] | undefined>;
136
138
  /** Poll until the person approved; the scopes they actually granted. */
137
139
  finishSignIn(user: string, signIn: SignIn, intervalMs?: number, attempts?: number): Promise<string[]>;
138
140
  }
@@ -315,42 +315,48 @@ export class PactPersonalAgent {
315
315
  reference,
316
316
  };
317
317
  }
318
- /** Poll until the person approved; the scopes they actually granted. */
319
- async finishSignIn(user, signIn, intervalMs = 5000, attempts = 120) {
318
+ /** Ask once whether the person approved: the scopes granted, or `undefined` while pending. */
319
+ async pollSignIn(user, signIn) {
320
320
  const card = this.card;
321
321
  const deviceCode = this.pending.get(signIn.reference);
322
322
  if (!deviceCode) {
323
323
  throw new PactError('no sign-in pending under this reference');
324
324
  }
325
+ const answer = await this.fetch(card.delegation.tokenUrl, {
326
+ method: 'POST',
327
+ headers: {
328
+ Authorization: `Bearer ${await this.jwt(user)}`,
329
+ 'Content-Type': 'application/x-www-form-urlencoded',
330
+ },
331
+ body: new URLSearchParams({
332
+ grant_type: DEVICE_CODE_GRANT,
333
+ device_code: deviceCode,
334
+ client_id: this.options.issuer,
335
+ }).toString(),
336
+ });
337
+ const body = await answer.json();
338
+ if (body.error === 'authorization_pending' || body.error === 'slow_down') {
339
+ return undefined;
340
+ }
341
+ if (body.error) {
342
+ this.pending.delete(signIn.reference);
343
+ throw new PactError(`the sign-in ended: ${body.error}`);
344
+ }
345
+ const granted = String(body.scope ?? '')
346
+ .split(' ')
347
+ .filter(Boolean);
348
+ await this.delegations().put(card.interfaceUrl, user, body.access_token, granted);
349
+ this.pending.delete(signIn.reference);
350
+ return granted;
351
+ }
352
+ /** Poll until the person approved; the scopes they actually granted. */
353
+ async finishSignIn(user, signIn, intervalMs = 5000, attempts = 120) {
325
354
  for (let i = 0; i < attempts; i++) {
326
- const answer = await this.fetch(card.delegation.tokenUrl, {
327
- method: 'POST',
328
- headers: {
329
- Authorization: `Bearer ${await this.jwt(user)}`,
330
- 'Content-Type': 'application/x-www-form-urlencoded',
331
- },
332
- body: new URLSearchParams({
333
- grant_type: DEVICE_CODE_GRANT,
334
- device_code: deviceCode,
335
- client_id: this.options.issuer,
336
- }).toString(),
337
- });
338
- const body = await answer.json();
339
- if (body.error === 'authorization_pending' ||
340
- body.error === 'slow_down') {
341
- await new Promise(resolve => setTimeout(resolve, intervalMs));
342
- continue;
355
+ const granted = await this.pollSignIn(user, signIn);
356
+ if (granted) {
357
+ return granted;
343
358
  }
344
- if (body.error) {
345
- this.pending.delete(signIn.reference);
346
- throw new PactError(`the sign-in ended: ${body.error}`);
347
- }
348
- const granted = String(body.scope ?? '')
349
- .split(' ')
350
- .filter(Boolean);
351
- await this.delegations().put(card.interfaceUrl, user, body.access_token, granted);
352
- this.pending.delete(signIn.reference);
353
- return granted;
359
+ await new Promise(resolve => setTimeout(resolve, intervalMs));
354
360
  }
355
361
  throw new PactError('the person did not sign in in time');
356
362
  }
@@ -18,16 +18,11 @@ export declare const SHOPPING_SERVICE = "dev.ucp.shopping";
18
18
  export declare const CHECKOUT_CAPABILITY = "dev.ucp.shopping.checkout";
19
19
  export declare const PROFILE_PATH = "/.well-known/ucp";
20
20
  export declare const UCP_PLUGIN = "agent-runtimes.protocols.ucp";
21
- /** Each operation's action class (F-10), for Rules (R-05). */
22
- export declare const UCP_ACTION_CLASSES: {
23
- readonly search: "read";
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
- };
21
+ /**
22
+ * Each operation's action class (F-10), for Rules (R-05): agentspecs'
23
+ * `protocol-tools/ucp.yaml` (AGENT_PROTOCOLS PR-54).
24
+ */
25
+ export declare const UCP_ACTION_CLASSES: Record<string, import("../../types").ActionClass>;
31
26
  export { InMemoryProposalStore, proposalSummary, type CheckoutApprover, type CheckoutProposal, type ProposalStore, } from '../commerce';
32
27
  export declare class UcpError extends Error {
33
28
  }
@@ -17,23 +17,18 @@
17
17
  */
18
18
  import { contribution, defineContributionPoint, definePlugin, } from '@datalayer/reactor';
19
19
  import { ExtendedCheckoutResponseSchema } from '@ucp-js/sdk';
20
- import { InMemoryProposalStore, digest, } from '../commerce';
20
+ import { InMemoryProposalStore, digest, operationClasses, } from '../commerce';
21
21
  import { DEFAULT_ORDER, ProtocolDescriptions, firstContribution, } from '../core';
22
22
  export const UCP_VERSION = '2026-08-25';
23
23
  export const SHOPPING_SERVICE = 'dev.ucp.shopping';
24
24
  export const CHECKOUT_CAPABILITY = 'dev.ucp.shopping.checkout';
25
25
  export const PROFILE_PATH = '/.well-known/ucp';
26
26
  export const UCP_PLUGIN = 'agent-runtimes.protocols.ucp';
27
- /** Each operation's action class (F-10), for Rules (R-05). */
28
- export const UCP_ACTION_CLASSES = {
29
- search: 'read',
30
- proposeCompletion: 'read',
31
- getCheckout: 'read',
32
- createCheckout: 'write',
33
- updateCheckout: 'write',
34
- cancelCheckout: 'write',
35
- complete: 'buy',
36
- };
27
+ /**
28
+ * Each operation's action class (F-10), for Rules (R-05): agentspecs'
29
+ * `protocol-tools/ucp.yaml` (AGENT_PROTOCOLS PR-54).
30
+ */
31
+ export const UCP_ACTION_CLASSES = operationClasses('ucp');
37
32
  export { InMemoryProposalStore, proposalSummary, } from '../commerce';
38
33
  export class UcpError extends Error {
39
34
  }
@@ -122,7 +122,7 @@ export async function signRequest(request, signer, options) {
122
122
  label,
123
123
  nonce: options.nonce ?? generateNonce(),
124
124
  signatureAgentKey: label,
125
- additionalComponents: (options.components ?? ['@method', '@path']).filter(name => name !== '@authority'),
125
+ additionalComponents: (options.components ?? ['@method', '@path', '@query']).filter(name => name !== '@authority'),
126
126
  });
127
127
  return {
128
128
  'Signature-Agent': agentHeader,
@@ -17,6 +17,14 @@ export declare const BACKEND_TOOL_ACTIONS: Record<string, ActionClass[]>;
17
17
  * names were read off the running server; absent when nobody looked.
18
18
  */
19
19
  export declare const SERVER_ACTIONS: Record<string, ServerActionsSpec>;
20
+ /**
21
+ * What each agent protocol's tools do, by protocol id: the prefix its
22
+ * connections take (`pap:<domain>`) and each tool's classes (PR-54).
23
+ */
24
+ export declare const PROTOCOL_TOOL_CLASSES: Record<string, {
25
+ connection: string;
26
+ tools: Record<string, ActionClass[]>;
27
+ }>;
20
28
  /**
21
29
  * What each application of the catalogue does about each classed tool of the
22
30
  * servers it connects to, as agentspecs decides it. What the rules engine has
@@ -663,6 +663,60 @@ export const SERVER_ACTIONS = {
663
663
  signs: {},
664
664
  },
665
665
  };
666
+ /**
667
+ * What each agent protocol's tools do, by protocol id: the prefix its
668
+ * connections take (`pap:<domain>`) and each tool's classes (PR-54).
669
+ */
670
+ export const PROTOCOL_TOOL_CLASSES = {
671
+ 'agentic-commerce': {
672
+ connection: 'acp',
673
+ tools: {
674
+ propose_completion: ['read'],
675
+ get_checkout: ['read'],
676
+ create_checkout: ['write'],
677
+ update_checkout: ['write'],
678
+ cancel_checkout: ['write'],
679
+ complete: ['buy'],
680
+ },
681
+ },
682
+ pact: {
683
+ connection: 'pact',
684
+ tools: {
685
+ pact_brand: ['read'],
686
+ pact_ask: ['read'],
687
+ pact_sign_in: ['read'],
688
+ pact_sign_in_status: ['read'],
689
+ pact_ask_for_person: ['write'],
690
+ pact_disconnect: ['write'],
691
+ },
692
+ },
693
+ pap: {
694
+ connection: 'pap',
695
+ tools: {
696
+ pap_company: ['read'],
697
+ pap_ask: ['read'],
698
+ pap_sign_in: ['read'],
699
+ pap_sign_in_status: ['read'],
700
+ pap_read: ['read'],
701
+ pap_mcp_tools: ['read'],
702
+ pap_mcp_call: ['write'],
703
+ pap_confirm: ['write', 'buy'],
704
+ pap_disconnect: ['write'],
705
+ },
706
+ },
707
+ ucp: {
708
+ connection: 'ucp',
709
+ tools: {
710
+ search: ['read'],
711
+ propose_completion: ['read'],
712
+ get_checkout: ['read'],
713
+ create_checkout: ['write'],
714
+ update_checkout: ['write'],
715
+ cancel_checkout: ['write'],
716
+ complete: ['buy'],
717
+ },
718
+ },
719
+ };
666
720
  /**
667
721
  * What each application of the catalogue does about each classed tool of the
668
722
  * servers it connects to, as agentspecs decides it. What the rules engine has
@@ -922,6 +976,7 @@ export const APP_BEHAVIOURS = {
922
976
  'ship-or-fix': {},
923
977
  'supplier-comparison': {},
924
978
  'support-desk': {},
979
+ 'travel-desk': {},
925
980
  'web-research': {
926
981
  'tavily.tavily_crawl': 'do_it',
927
982
  'tavily.tavily_extract': 'do_it',
@@ -988,5 +1043,6 @@ export const APP_ESCALATIONS = {
988
1043
  'ship-or-fix': {},
989
1044
  'supplier-comparison': {},
990
1045
  'support-desk': {},
1046
+ 'travel-desk': {},
991
1047
  'web-research': {},
992
1048
  };
@@ -28,6 +28,7 @@ export declare const SALES_APP_0_0_1: AppSpec;
28
28
  export declare const SHIP_OR_FIX_APP_0_0_1: AppSpec;
29
29
  export declare const SUPPLIER_COMPARISON_APP_0_0_1: AppSpec;
30
30
  export declare const SUPPORT_DESK_APP_0_0_1: AppSpec;
31
+ export declare const TRAVEL_DESK_APP_0_0_1: AppSpec;
31
32
  export declare const WEB_RESEARCH_APP_0_0_1: AppSpec;
32
33
  export declare const APP_CATALOGUE: Record<string, AppSpec>;
33
34
  /** An application, by `id` or `id:version`, or undefined. */