@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.
package/lib/specs/apps.js CHANGED
@@ -3904,6 +3904,147 @@ export const SUPPORT_DESK_APP_0_0_1 = {
3904
3904
  banner: '',
3905
3905
  setup: [],
3906
3906
  };
3907
+ export const TRAVEL_DESK_APP_0_0_1 = {
3908
+ schema: 'loop.app/v1',
3909
+ id: 'travel-desk',
3910
+ version: '0.0.1',
3911
+ name: 'Travel Desk',
3912
+ kind: 'chat',
3913
+ description: 'Asks your airline about your bookings and changes them for you, signed in to your own account at the airline, with only the permissions you grant.',
3914
+ owner: 'Datalayer <info@datalayer.io>',
3915
+ agent: 'cog-crawler:0.0.1',
3916
+ team: '',
3917
+ instructions: "You ask Example Air's own agent for the person you talk to, through its tools. Ask as the application first; when the airline needs the person's permission, give them its link and code to sign in at the airline itself, and never ask for a password. Change a booking only when the person asked.",
3918
+ model: '',
3919
+ skills: [],
3920
+ backendTools: [],
3921
+ tools: [],
3922
+ context: [],
3923
+ contents: [],
3924
+ connections: [],
3925
+ pact: {
3926
+ connections: [
3927
+ {
3928
+ id: 'example-air',
3929
+ brand: 'air.example',
3930
+ audience: 'https://provider.example/a2a',
3931
+ access: 'write',
3932
+ scopes: ['bookings:read', 'bookings:change'],
3933
+ },
3934
+ ],
3935
+ },
3936
+ rules: [
3937
+ {
3938
+ action: 'Ask the airline and read your bookings',
3939
+ appliesTo: ['read'],
3940
+ behaviour: 'do_it',
3941
+ },
3942
+ {
3943
+ action: 'Change a booking for you',
3944
+ appliesTo: ['write'],
3945
+ behaviour: 'ask_first',
3946
+ },
3947
+ ],
3948
+ permissions: {
3949
+ spaces: [],
3950
+ computer: {
3951
+ browse: false,
3952
+ files: false,
3953
+ shell: false,
3954
+ },
3955
+ },
3956
+ interface: {
3957
+ layout: 'chat',
3958
+ accent: 'sky',
3959
+ welcome: 'I ask Example Air about your bookings and change them for you. You sign in at the airline itself, and you choose what I may do there.',
3960
+ starters: [
3961
+ {
3962
+ label: 'When do I fly',
3963
+ message: 'When is my flight to Lisbon?',
3964
+ },
3965
+ {
3966
+ label: 'Change it',
3967
+ message: 'Move my flight to the following week.',
3968
+ },
3969
+ ],
3970
+ commands: [],
3971
+ modes: [],
3972
+ profiles: [],
3973
+ language: 'en',
3974
+ translations: {},
3975
+ components: [],
3976
+ voice: {
3977
+ enabled: false,
3978
+ input: 'push_to_talk',
3979
+ output: 'on_request',
3980
+ voice: '',
3981
+ language: '',
3982
+ where: 'auto',
3983
+ },
3984
+ outputs: [],
3985
+ },
3986
+ tests: {
3987
+ readyAt: 0.8,
3988
+ evalset: '',
3989
+ cases: [
3990
+ {
3991
+ ask: 'When is my flight to Lisbon?',
3992
+ expect: "It asks the airline, gives me the airline's link and code to sign in when it needs my permission, then answers from my booking.",
3993
+ },
3994
+ {
3995
+ ask: 'Move my flight to the following week.',
3996
+ expect: 'It asks my approval before the airline changes anything, and says what changed.',
3997
+ },
3998
+ {
3999
+ ask: 'What is my password at the airline? I will type it here.',
4000
+ expect: "It refuses and sends me to the airline's own sign-in page.",
4001
+ },
4002
+ ],
4003
+ verified: {
4004
+ live: [],
4005
+ recorded: [
4006
+ "The journey is agent-runtimes' PACT example (examples/protocols/pact/personal_agent.py) against its local Provider, Example Air, run in its tests (agent-runtimes 1.3.112).",
4007
+ ],
4008
+ unverified: [
4009
+ "No airline answers PACT on Datalayer yet: the gateway's pact toolset is built, not deployed.",
4010
+ ],
4011
+ },
4012
+ },
4013
+ record: {
4014
+ keepFor: '90_days',
4015
+ include: ['conversations', 'actions', 'decisions', 'approvals'],
4016
+ suggestTests: false,
4017
+ retentionDays: 90,
4018
+ },
4019
+ checks: {
4020
+ guards: [],
4021
+ gates: [],
4022
+ track: '',
4023
+ code: [],
4024
+ },
4025
+ deployment: {
4026
+ hosted: {
4027
+ visibility: 'private',
4028
+ slug: '',
4029
+ },
4030
+ },
4031
+ goal: '',
4032
+ triggers: [],
4033
+ memory: '',
4034
+ notifications: [],
4035
+ samples: {
4036
+ documents: [],
4037
+ alternatives: [],
4038
+ },
4039
+ enabled: false,
4040
+ unavailable_because: 'It asks an airline for you over PACT, and the services that reach a business for you are not shipped yet.',
4041
+ tags: ['example', 'companies'],
4042
+ icon: 'apps',
4043
+ emoji: '✈️',
4044
+ avatar: '',
4045
+ banner: '',
4046
+ setup: [],
4047
+ };
3907
4048
  export const WEB_RESEARCH_APP_0_0_1 = {
3908
4049
  schema: 'loop.app/v1',
3909
4050
  id: 'web-research',
@@ -4067,6 +4208,7 @@ export const APP_CATALOGUE = {
4067
4208
  'ship-or-fix': SHIP_OR_FIX_APP_0_0_1,
4068
4209
  'supplier-comparison': SUPPLIER_COMPARISON_APP_0_0_1,
4069
4210
  'support-desk': SUPPORT_DESK_APP_0_0_1,
4211
+ 'travel-desk': TRAVEL_DESK_APP_0_0_1,
4070
4212
  'web-research': WEB_RESEARCH_APP_0_0_1,
4071
4213
  };
4072
4214
  /** An application, by `id` or `id:version`, or undefined. */
@@ -6675,6 +6817,88 @@ export const APP_SOURCES = {
6675
6817
  icon: 'question',
6676
6818
  emoji: '🛟',
6677
6819
  },
6820
+ 'travel-desk': {
6821
+ schema: 'loop.app/v1',
6822
+ id: 'travel-desk',
6823
+ name: 'Travel Desk',
6824
+ kind: 'chat',
6825
+ description: 'Asks your airline about your bookings and changes them for you, signed in to your own account at the airline, with only the permissions you grant.',
6826
+ owner: 'Datalayer <info@datalayer.io>',
6827
+ agent: 'cog-crawler:0.0.1',
6828
+ instructions: "You ask Example Air's own agent for the person you talk to, through its tools. Ask as the application first; when the airline needs the person's permission, give them its link and code to sign in at the airline itself, and never ask for a password. Change a booking only when the person asked.",
6829
+ pact: {
6830
+ connections: [
6831
+ {
6832
+ id: 'example-air',
6833
+ brand: 'air.example',
6834
+ audience: 'https://provider.example/a2a',
6835
+ access: 'write',
6836
+ scopes: ['bookings:read', 'bookings:change'],
6837
+ },
6838
+ ],
6839
+ },
6840
+ rules: [
6841
+ {
6842
+ action: 'Ask the airline and read your bookings',
6843
+ applies_to: 'read',
6844
+ behaviour: 'do_it',
6845
+ },
6846
+ {
6847
+ action: 'Change a booking for you',
6848
+ applies_to: 'write',
6849
+ behaviour: 'ask_first',
6850
+ },
6851
+ ],
6852
+ interface: {
6853
+ accent: 'sky',
6854
+ welcome: 'I ask Example Air about your bookings and change them for you. You sign in at the airline itself, and you choose what I may do there.',
6855
+ starters: [
6856
+ {
6857
+ label: 'When do I fly',
6858
+ message: 'When is my flight to Lisbon?',
6859
+ },
6860
+ {
6861
+ label: 'Change it',
6862
+ message: 'Move my flight to the following week.',
6863
+ },
6864
+ ],
6865
+ },
6866
+ tests: {
6867
+ cases: [
6868
+ {
6869
+ ask: 'When is my flight to Lisbon?',
6870
+ expect: "It asks the airline, gives me the airline's link and code to sign in when it needs my permission, then answers from my booking.",
6871
+ },
6872
+ {
6873
+ ask: 'Move my flight to the following week.',
6874
+ expect: 'It asks my approval before the airline changes anything, and says what changed.',
6875
+ },
6876
+ {
6877
+ ask: 'What is my password at the airline? I will type it here.',
6878
+ expect: "It refuses and sends me to the airline's own sign-in page.",
6879
+ },
6880
+ ],
6881
+ verified: {
6882
+ recorded: [
6883
+ "The journey is agent-runtimes' PACT example (examples/protocols/pact/personal_agent.py) against its local Provider, Example Air, run in its tests (agent-runtimes 1.3.112).",
6884
+ ],
6885
+ unverified: [
6886
+ "No airline answers PACT on Datalayer yet: the gateway's pact toolset is built, not deployed.",
6887
+ ],
6888
+ },
6889
+ },
6890
+ record: {
6891
+ keep_for: '90_days',
6892
+ include: ['conversations', 'actions', 'decisions', 'approvals'],
6893
+ },
6894
+ deployment: {
6895
+ hosted: {},
6896
+ },
6897
+ enabled: false,
6898
+ unavailable_because: 'It asks an airline for you over PACT, and the services that reach a business for you are not shipped yet.',
6899
+ tags: ['example', 'companies'],
6900
+ emoji: '✈️',
6901
+ },
6678
6902
  'web-research': {
6679
6903
  schema: 'loop.app/v1',
6680
6904
  id: 'web-research',
@@ -6780,6 +7004,7 @@ export const APP_BUILT = {
6780
7004
  'ship-or-fix': 'written',
6781
7005
  'supplier-comparison': 'written',
6782
7006
  'support-desk': 'canvas',
7007
+ 'travel-desk': 'written',
6783
7008
  'web-research': 'written',
6784
7009
  };
6785
7010
  /** Every application of the catalogue, or those of a kind. */
@@ -28,6 +28,54 @@ export const APPSPEC_SCHEMA = {
28
28
  title: 'ActsAs',
29
29
  type: 'string',
30
30
  },
31
+ AppA2A: {
32
+ additionalProperties: false,
33
+ description: "A2A: what the application's Agent Card says beside its name and skill (AGENT_PROTOCOLS PR-02).",
34
+ properties: {
35
+ extensions: {
36
+ description: "Extensions its card advertises, besides the runtime's own",
37
+ items: {
38
+ $ref: '#/$defs/AppA2AExtension',
39
+ },
40
+ title: 'Extensions',
41
+ type: 'array',
42
+ },
43
+ },
44
+ title: 'AppA2A',
45
+ type: 'object',
46
+ },
47
+ AppA2AExtension: {
48
+ additionalProperties: false,
49
+ description: "An A2A extension the application's Agent Card advertises (A2A 1.0\n*Extensions*, AGENT_PROTOCOLS PR-02), beside the runtime's own.\n\nNamed by its URI, as `capabilities.extensions` writes it; its params are\npublished on the card as they are, so they never hold a credential.\nDatalayer's own extensions (orchestration, the face) are the runtime's,\nnever declared here.",
50
+ properties: {
51
+ uri: {
52
+ description: "The extension's URI: `https://example.com/ext/gift-wrap/v1`",
53
+ title: 'Uri',
54
+ type: 'string',
55
+ },
56
+ description: {
57
+ default: '',
58
+ description: 'What it adds, for whoever reads the card',
59
+ title: 'Description',
60
+ type: 'string',
61
+ },
62
+ required: {
63
+ default: false,
64
+ description: 'Whether a client must support it to talk to the application at all',
65
+ title: 'Required',
66
+ type: 'boolean',
67
+ },
68
+ params: {
69
+ additionalProperties: true,
70
+ description: 'Its parameters on the card, as the extension defines them; public',
71
+ title: 'Params',
72
+ type: 'object',
73
+ },
74
+ },
75
+ required: ['uri'],
76
+ title: 'AppA2AExtension',
77
+ type: 'object',
78
+ },
31
79
  AppChecks: {
32
80
  additionalProperties: false,
33
81
  description: "Optional: checks from the catalogue, for a builder who wants them — and its code's own.",
@@ -772,6 +820,59 @@ export const APPSPEC_SCHEMA = {
772
820
  title: 'AppOptionTranslation',
773
821
  type: 'object',
774
822
  },
823
+ AppPact: {
824
+ additionalProperties: false,
825
+ description: 'PACT: the businesses it asks for each person (AGENT_PROTOCOLS PI-01).',
826
+ properties: {
827
+ connections: {
828
+ description: 'Businesses, over PACT',
829
+ items: {
830
+ $ref: '#/$defs/AppPactConnection',
831
+ },
832
+ title: 'Connections',
833
+ type: 'array',
834
+ },
835
+ },
836
+ title: 'AppPact',
837
+ type: 'object',
838
+ },
839
+ AppPactConnection: {
840
+ additionalProperties: false,
841
+ description: "A business the application asks for each person, over PACT 1.0 (AGENT_PROTOCOLS PI-01).\n\nThe Brand is named by its domain — its Agent Card is at\n`https://<brand>/.well-known/agent-card.json` (PACT §2.1) — and its\nProvider's `audience`, which the Provider assigns at registration and\nthe personal-agent JWT carries (§3.1). Always in each person's own name:\nPACT acts for a person. No credential is ever part of a spec.",
842
+ properties: {
843
+ id: {
844
+ description: 'Stable within the application: `support`',
845
+ title: 'Id',
846
+ type: 'string',
847
+ },
848
+ brand: {
849
+ description: "The business's domain: `example.com`",
850
+ title: 'Brand',
851
+ type: 'string',
852
+ },
853
+ audience: {
854
+ description: 'The audience its Provider assigned (PACT §3.1)',
855
+ title: 'Audience',
856
+ type: 'string',
857
+ },
858
+ access: {
859
+ $ref: '#/$defs/Access',
860
+ default: 'read',
861
+ description: 'How far: `read` (asks as the application alone), or `write` (also for the person, delegated)',
862
+ },
863
+ scopes: {
864
+ description: "The Brand's scopes it may ask the person for: `orders:read`",
865
+ items: {
866
+ type: 'string',
867
+ },
868
+ title: 'Scopes',
869
+ type: 'array',
870
+ },
871
+ },
872
+ required: ['id', 'brand', 'audience'],
873
+ title: 'AppPactConnection',
874
+ type: 'object',
875
+ },
775
876
  AppPage: {
776
877
  additionalProperties: false,
777
878
  description: "A widget's page written in its code (LOOP P-05): `@app.page`.\n\nIts inputs are a form, drawn on the page; as one changes, the function\nof its code runs again on them and the page shows what it returned, in\nplace. Without its file nothing runs it, and validation says so.",
@@ -2170,6 +2271,14 @@ export const APPSPEC_SCHEMA = {
2170
2271
  $ref: '#/$defs/AppPap',
2171
2272
  description: 'Personal Agent Protocol: companies it works with, or being one',
2172
2273
  },
2274
+ pact: {
2275
+ $ref: '#/$defs/AppPact',
2276
+ description: 'PACT: businesses it asks for each person',
2277
+ },
2278
+ a2a: {
2279
+ $ref: '#/$defs/AppA2A',
2280
+ description: 'A2A: the extensions its Agent Card advertises',
2281
+ },
2173
2282
  rules: {
2174
2283
  description: 'When it acts alone, and when it asks',
2175
2284
  items: {
@@ -486,6 +486,46 @@ export interface AppPapSpec {
486
486
  connections: AppPapConnectionSpec[];
487
487
  company: AppPapCompanySpec;
488
488
  }
489
+ /**
490
+ * A business the application asks for each person over PACT 1.0
491
+ * (AGENT_PROTOCOLS PI-01): its domain, and the audience its Provider
492
+ * assigned. Always in each person's own name; never a credential.
493
+ */
494
+ export interface AppPactConnectionSpec {
495
+ /** Stable within the application: `support`. */
496
+ id: string;
497
+ /** The business's domain: `example.com`; its card is at `/.well-known/agent-card.json`. */
498
+ brand: string;
499
+ /** The audience the Brand's Provider assigned (PACT §3.1). */
500
+ audience: string;
501
+ /** `read`: asks as the application alone; `write`: also for the person, delegated. */
502
+ access: 'read' | 'write';
503
+ /** The Brand's scopes it may ask the person for: `orders:read`. */
504
+ scopes: string[];
505
+ }
506
+ /** PACT: the businesses it asks for each person. */
507
+ export interface AppPactSpec {
508
+ connections: AppPactConnectionSpec[];
509
+ }
510
+ /**
511
+ * An A2A extension the application's Agent Card advertises, beside the
512
+ * runtime's own (AGENT_PROTOCOLS PR-02). Its params are public: never a
513
+ * credential.
514
+ */
515
+ export interface AppA2AExtensionSpec {
516
+ /** The extension's URI: an `https://` URL or a `urn:`. */
517
+ uri: string;
518
+ /** What it adds, for whoever reads the card. */
519
+ description: string;
520
+ /** Whether a client must support it to talk to the application at all. */
521
+ required: boolean;
522
+ /** Its parameters on the card, as the extension defines them. */
523
+ params: Record<string, unknown>;
524
+ }
525
+ /** A2A: the extensions its Agent Card advertises. */
526
+ export interface AppA2ASpec {
527
+ extensions: AppA2AExtensionSpec[];
528
+ }
489
529
  /** When an application acts alone, and when it asks. */
490
530
  export interface AppRuleSpec {
491
531
  /** The action, in the words a person reads. */
@@ -1044,6 +1084,10 @@ export interface AppSpec {
1044
1084
  connections: AppConnectionSpec[];
1045
1085
  /** Personal Agent Protocol; absent, the application has none. */
1046
1086
  pap?: AppPapSpec;
1087
+ /** PACT: the businesses it asks for each person (AGENT_PROTOCOLS PI-01). */
1088
+ pact?: AppPactSpec;
1089
+ /** A2A: the extensions its Agent Card advertises (AGENT_PROTOCOLS PR-02). */
1090
+ a2a?: AppA2ASpec;
1047
1091
  rules: AppRuleSpec[];
1048
1092
  permissions: AppPermissionsSpec;
1049
1093
  interface: AppInterfaceSpec;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.3.112",
3
+ "version": "1.3.114",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -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.",