apcore-a2a 0.4.4 → 0.6.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 (49) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/agent-card.d.ts.map +1 -1
  3. package/dist/adapters/agent-card.js +15 -0
  4. package/dist/adapters/agent-card.js.map +1 -1
  5. package/dist/adapters/card-visibility.d.ts +148 -0
  6. package/dist/adapters/card-visibility.d.ts.map +1 -0
  7. package/dist/adapters/card-visibility.js +237 -0
  8. package/dist/adapters/card-visibility.js.map +1 -0
  9. package/dist/adapters/errors.d.ts +82 -0
  10. package/dist/adapters/errors.d.ts.map +1 -1
  11. package/dist/adapters/errors.js +165 -8
  12. package/dist/adapters/errors.js.map +1 -1
  13. package/dist/adapters/skill-mapper.d.ts +27 -0
  14. package/dist/adapters/skill-mapper.d.ts.map +1 -1
  15. package/dist/adapters/skill-mapper.js +61 -0
  16. package/dist/adapters/skill-mapper.js.map +1 -1
  17. package/dist/client/client.d.ts +15 -0
  18. package/dist/client/client.d.ts.map +1 -1
  19. package/dist/client/client.js +137 -14
  20. package/dist/client/client.js.map +1 -1
  21. package/dist/client/exceptions.d.ts +31 -0
  22. package/dist/client/exceptions.d.ts.map +1 -1
  23. package/dist/client/exceptions.js +40 -0
  24. package/dist/client/exceptions.js.map +1 -1
  25. package/dist/client/index.d.ts +1 -1
  26. package/dist/client/index.d.ts.map +1 -1
  27. package/dist/client/index.js +1 -1
  28. package/dist/client/index.js.map +1 -1
  29. package/dist/index.d.ts +2 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/serve.d.ts +12 -0
  34. package/dist/serve.d.ts.map +1 -1
  35. package/dist/serve.js +1 -0
  36. package/dist/serve.js.map +1 -1
  37. package/dist/server/context.d.ts +68 -0
  38. package/dist/server/context.d.ts.map +1 -0
  39. package/dist/server/context.js +80 -0
  40. package/dist/server/context.js.map +1 -0
  41. package/dist/server/executor.d.ts +8 -0
  42. package/dist/server/executor.d.ts.map +1 -1
  43. package/dist/server/executor.js +78 -1
  44. package/dist/server/executor.js.map +1 -1
  45. package/dist/server/factory.d.ts +24 -0
  46. package/dist/server/factory.d.ts.map +1 -1
  47. package/dist/server/factory.js +138 -19
  48. package/dist/server/factory.js.map +1 -1
  49. package/package.json +9 -5
package/README.md CHANGED
@@ -40,7 +40,7 @@ Built on [`@a2a-js/sdk`](https://www.npmjs.com/package/@a2a-js/sdk) and [Express
40
40
  ## Requirements
41
41
 
42
42
  - Node.js >= 18.0.0
43
- - `apcore-js` >= 0.22.0
43
+ - `apcore-js` >= 0.28.0
44
44
 
45
45
  ---
46
46
 
@@ -1 +1 @@
1
- {"version":3,"file":"agent-card.d.ts","sourceRoot":"","sources":["../../src/adapters/agent-card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAc,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEvE,MAAM,WAAW,QAAQ;IACvB,IAAI,IAAI,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACzD,QAAQ,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;CACxD;AAqBD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,UAAU,CAA0B;gBAEhC,WAAW,EAAE,WAAW;IAIpC,KAAK,CACH,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,YAAY,EAAE,iBAAiB,CAAC;QAChC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC3C,GACA,SAAS;IAyCZ,gBAAgB,CACd,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,YAAY,EAAE,iBAAiB,CAAC;QAChC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC3C,GACA,SAAS;IAKZ,aAAa,CAAC,QAAQ,EAAE,SAAS,GAAG,SAAS;IAI7C,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,WAAW;CAapB"}
1
+ {"version":3,"file":"agent-card.d.ts","sourceRoot":"","sources":["../../src/adapters/agent-card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAc,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEvE,MAAM,WAAW,QAAQ;IACvB,IAAI,IAAI,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACzD,QAAQ,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;CACxD;AAqBD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,UAAU,CAA0B;gBAEhC,WAAW,EAAE,WAAW;IAIpC,KAAK,CACH,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,YAAY,EAAE,iBAAiB,CAAC;QAChC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC3C,GACA,SAAS;IAwDZ,gBAAgB,CACd,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,YAAY,EAAE,iBAAiB,CAAC;QAChC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC3C,GACA,SAAS;IAKZ,aAAa,CAAC,QAAQ,EAAE,SAAS,GAAG,SAAS;IAI7C,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,WAAW;CAapB"}
@@ -39,6 +39,21 @@ export class AgentCardBuilder {
39
39
  tenant: "",
40
40
  protocolVersion: "1.0",
41
41
  },
42
+ // A2A 0.3 mirror of the same binding. Not decoration: a2a-js runs
43
+ // `validateVersion(requestedVersion, card, "JSONRPC")` before dispatch
44
+ // on both the v1.0 and the v0.3 compat path, and a request with no
45
+ // `A2A-Version` header is a 0.3 request per spec section 3.6.2 -- so
46
+ // without this entry every header-less request is refused -32009,
47
+ // including everything this package's own Explorer and A2AClient send.
48
+ // apcore-a2a-python needs no equivalent because a2a-python's
49
+ // `enable_v0_3_compat` does not consult the card; this entry is what
50
+ // buys apcore-a2a-typescript the same 0.3 acceptance.
51
+ {
52
+ url: opts.url,
53
+ protocolBinding: "JSONRPC",
54
+ tenant: "",
55
+ protocolVersion: "0.3",
56
+ },
42
57
  ],
43
58
  provider: undefined,
44
59
  skills,
@@ -1 +1 @@
1
- {"version":3,"file":"agent-card.js","sourceRoot":"","sources":["../../src/adapters/agent-card.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-card.js","sourceRoot":"","sources":["../../src/adapters/agent-card.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,148 @@
1
+ import type { AgentCard } from "@a2a-js/sdk";
2
+ import { type Identity } from "apcore-js";
3
+ import type { ModuleDescriptor } from "./skill-mapper.js";
4
+ /**
5
+ * Agent Card skill visibility — who gets to see which skills.
6
+ *
7
+ * apcore's ACL is the authority on who may invoke what, and the discovery
8
+ * surface reflects that authority rather than ignoring it. Two surfaces, two
9
+ * answers:
10
+ *
11
+ * - the **public** card (srs FR-AGC-003) answers "what may *anyone* call": every
12
+ * registered skill, minus apcore's reserved `system.*` management namespace,
13
+ * minus those the ACL denies to the anonymous principal, minus those gated
14
+ * behind a human. It resolves exactly one identity, so it is computed once when
15
+ * the card is built. A per-caller filter here
16
+ * would be strictly more accurate and unaffordable: `/.well-known/` is
17
+ * auth-exempt by design, so every anonymous request would drive
18
+ * `skills.length` calls into the consumer's ACL audit sink, each recording a
19
+ * `deny` decision indistinguishable from a real enforcement event, at whatever
20
+ * rate the client chooses.
21
+ *
22
+ * - the **extended** card (srs FR-AGC-004) answers "what may *you* call": the
23
+ * ACL resolved against the authenticated identity, with `requires_approval`
24
+ * skills restored — an approval gate is a prompt the caller can satisfy, not a
25
+ * refusal. Affordable precisely because that endpoint requires credentials.
26
+ *
27
+ * Only the `system.*` subtraction is unconditional. Every other one is
28
+ * governance-shaped, and with no ACL configured they collapse: the ACL predicates
29
+ * are empty and the `requires_approval` annotation covers only
30
+ * `system.control.*`, leaving the six read modules to publish the deployment's
31
+ * module inventory, health and usage to any anonymous caller. `ACL.discover()`
32
+ * yields nothing for a missing root by design, so "no ACL at all" is the default
33
+ * rather than an edge case — which is why the rule that has to hold there keys on
34
+ * apcore's namespace and not on a governance verdict (srs FR-AGC-003 criteria 12
35
+ * and 13).
36
+ *
37
+ * Authorization and approval are two independent results, not one (apcore
38
+ * PROTOCOL_SPEC §6.1.6), and this module reads them apart. `ACL.check` folds
39
+ * them into a boolean that **fails closed** on an approval requirement —
40
+ * correct for a caller about to execute, wrong for a discovery surface, where it
41
+ * would delete a skill from the extended card for the one reason FR-AGC-004 says
42
+ * to keep it. `ACL.checkAccess` carries both axes, so `access` decides
43
+ * visibility and `approvalRequired` decides only whether the public card is the
44
+ * right surface.
45
+ *
46
+ * Before this module, this binding filtered nothing at all: `buildSkills`
47
+ * iterated `registry.list()` and never consulted the ACL, so a module the ACL
48
+ * denied to everyone was still advertised — by id, name, description and full
49
+ * input schema — to any anonymous caller.
50
+ *
51
+ * **Internal module.** The `export` keywords below are module visibility, not a
52
+ * public contract: `package.json` declares only `"."` in `exports`, so a
53
+ * consumer cannot deep-import this file at all, and nothing here appears in
54
+ * `docs/features/public-api.md`. The surface is expected to move —
55
+ * `allowedSkillIds` already changed meaning once (it now reports the
56
+ * authorization axis alone, where it used to fold in the approval gate). Depend
57
+ * on `serve` / `A2AServerFactory` instead.
58
+ */
59
+ /**
60
+ * apcore's reserved namespace for the runtime's own management modules (apcore
61
+ * PROTOCOL_SPEC §6.7) — `system.health.*`, `system.usage.*`, `system.manifest.*`
62
+ * and, under the second opt-in, `system.control.*`. apcore identifies the
63
+ * surface by this prefix itself, in `Executor.governanceState()`, so matching on
64
+ * it conveys apcore's own boundary rather than inventing one.
65
+ */
66
+ export declare const SYSTEM_NAMESPACE = "system.";
67
+ /** Whether `skillId` is one of apcore's management modules. */
68
+ export declare function isSystemSkill(skillId: string): boolean;
69
+ /** The two axes of one ACL decision (apcore PROTOCOL_SPEC §6.8.1). */
70
+ export interface AccessDecisionLike {
71
+ readonly access: "allow" | "deny";
72
+ readonly approvalRequired: boolean;
73
+ }
74
+ /** The minimum surface this module reads off an apcore ACL. */
75
+ export interface AclLike {
76
+ check(callerId: string | null, targetId: string, context?: unknown): boolean;
77
+ checkAccess?(callerId: string | null, targetId: string, context?: unknown): AccessDecisionLike;
78
+ }
79
+ /** The minimum surface this module reads off an apcore Registry. */
80
+ export interface RegistryLike {
81
+ list(): string[];
82
+ getDefinition(moduleId: string): ModuleDescriptor | null | undefined;
83
+ }
84
+ /**
85
+ * The apcore ACL backing `executor`, if one is configured.
86
+ *
87
+ * apcore-js exposes `setAcl` but no getter, so this reads the public property
88
+ * when one appears upstream and falls back to the private field. `null` means
89
+ * "no ACL configured", which is the common case and leaves every card
90
+ * unfiltered.
91
+ */
92
+ export declare function executorAcl(executor: unknown): AclLike | null;
93
+ /**
94
+ * The skills the ACL permits `identity` to invoke, each mapped to whether
95
+ * invoking it needs a human first.
96
+ *
97
+ * With no ACL configured every id is permitted and none is gated, which is what
98
+ * makes this free for the common single-tenant deployment.
99
+ *
100
+ * The ACL is consulted with **no arguments projection**, because a card is
101
+ * discovery and there is no call site yet. An `arguments` condition (§6.1.7) is
102
+ * therefore unevaluable, so a rule carrying one neither denies nor grants — but
103
+ * an `allow` rule's `approval: required` stays *pending* and composes with
104
+ * whatever grants (§6.1.1 rule 5). A skill gated only for some argument shapes
105
+ * thus reports `true` here: at discovery time "this may need approval" is the
106
+ * honest answer, and it is the one that keeps such a skill off the public card.
107
+ *
108
+ * `callerId` is left `null` deliberately. apcore defines it as the *calling
109
+ * module* in a nested call chain, managed by `Context.child`; a top-level
110
+ * inbound request has none, and the ACL maps `null` to `@external`. That is
111
+ * apcore's contract, not a gap — `callers: ["@external"]` is how an operator
112
+ * denies external access, and it has to keep matching an authenticated request
113
+ * or the rule silently stops covering the traffic it was written for. The
114
+ * authenticated principal travels in the context instead, where the
115
+ * `identityTypes` / `roles` conditions see it.
116
+ */
117
+ export declare function skillAccess(executor: unknown, skillIds: readonly string[], identity: Identity | null): Map<string, boolean>;
118
+ /**
119
+ * The subset of `skillIds` the ACL authorizes `identity` to invoke.
120
+ *
121
+ * The authorization axis alone: a skill the ACL allows but gates behind an
122
+ * approval is in this set, because the caller may reach it. Callers that also
123
+ * need the gate read {@link skillAccess}.
124
+ */
125
+ export declare function allowedSkillIds(executor: unknown, skillIds: readonly string[], identity: Identity | null): Set<string>;
126
+ /**
127
+ * The public card: what an unauthenticated caller could actually invoke.
128
+ *
129
+ * `system.*` is removed unconditionally (srs FR-AGC-003 criteria 12 and 13); the
130
+ * remaining subtractions are governance-shaped. See the module docstring for why
131
+ * this is resolved once rather than per caller.
132
+ */
133
+ export declare function buildPublicCard(card: AgentCard, executor: unknown, registry: RegistryLike | null | undefined): AgentCard;
134
+ /**
135
+ * The extended card: what the authenticated caller may invoke.
136
+ *
137
+ * `requires_approval` skills are kept (srs FR-AGC-004 criterion 2), whether the
138
+ * gate comes from the module's annotation or from an ACL rule. Only the
139
+ * authorization axis of the decision filters here — dropping a skill because it
140
+ * needs a human would report a refusal the ACL never issued.
141
+ *
142
+ * `system.*` is kept too (criterion 11), filtered by the ACL like any other
143
+ * skill: the namespace exclusion is a property of the public card, not of the
144
+ * skill, and an authenticated management agent the ACL permits must still be
145
+ * able to discover the surface it is entitled to drive.
146
+ */
147
+ export declare function buildExtendedCard(card: AgentCard, executor: unknown, identity: Identity | null): AgentCard;
148
+ //# sourceMappingURL=card-visibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-visibility.d.ts","sourceRoot":"","sources":["../../src/adapters/card-visibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,aAAa,CAAC;AACzD,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC;AAED,+DAA+D;AAC/D,MAAM,WAAW,OAAO;IACtB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAC7E,WAAW,CAAC,CACV,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO,GAChB,kBAAkB,CAAC;CACvB;AAED,oEAAoE;AACpE,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,MAAM,EAAE,CAAC;IACjB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC;CACtE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAQ7D;AA6CD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,EAAE,QAAQ,GAAG,IAAI,GACxB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAwBtB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,EAAE,QAAQ,GAAG,IAAI,GACxB,GAAG,CAAC,MAAM,CAAC,CAEb;AAOD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GACxC,SAAS,CAqBX;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,QAAQ,GAAG,IAAI,GACxB,SAAS,CAGX"}
@@ -0,0 +1,237 @@
1
+ import { Context } from "apcore-js";
2
+ import { requiresApproval } from "./skill-mapper.js";
3
+ /**
4
+ * Agent Card skill visibility — who gets to see which skills.
5
+ *
6
+ * apcore's ACL is the authority on who may invoke what, and the discovery
7
+ * surface reflects that authority rather than ignoring it. Two surfaces, two
8
+ * answers:
9
+ *
10
+ * - the **public** card (srs FR-AGC-003) answers "what may *anyone* call": every
11
+ * registered skill, minus apcore's reserved `system.*` management namespace,
12
+ * minus those the ACL denies to the anonymous principal, minus those gated
13
+ * behind a human. It resolves exactly one identity, so it is computed once when
14
+ * the card is built. A per-caller filter here
15
+ * would be strictly more accurate and unaffordable: `/.well-known/` is
16
+ * auth-exempt by design, so every anonymous request would drive
17
+ * `skills.length` calls into the consumer's ACL audit sink, each recording a
18
+ * `deny` decision indistinguishable from a real enforcement event, at whatever
19
+ * rate the client chooses.
20
+ *
21
+ * - the **extended** card (srs FR-AGC-004) answers "what may *you* call": the
22
+ * ACL resolved against the authenticated identity, with `requires_approval`
23
+ * skills restored — an approval gate is a prompt the caller can satisfy, not a
24
+ * refusal. Affordable precisely because that endpoint requires credentials.
25
+ *
26
+ * Only the `system.*` subtraction is unconditional. Every other one is
27
+ * governance-shaped, and with no ACL configured they collapse: the ACL predicates
28
+ * are empty and the `requires_approval` annotation covers only
29
+ * `system.control.*`, leaving the six read modules to publish the deployment's
30
+ * module inventory, health and usage to any anonymous caller. `ACL.discover()`
31
+ * yields nothing for a missing root by design, so "no ACL at all" is the default
32
+ * rather than an edge case — which is why the rule that has to hold there keys on
33
+ * apcore's namespace and not on a governance verdict (srs FR-AGC-003 criteria 12
34
+ * and 13).
35
+ *
36
+ * Authorization and approval are two independent results, not one (apcore
37
+ * PROTOCOL_SPEC §6.1.6), and this module reads them apart. `ACL.check` folds
38
+ * them into a boolean that **fails closed** on an approval requirement —
39
+ * correct for a caller about to execute, wrong for a discovery surface, where it
40
+ * would delete a skill from the extended card for the one reason FR-AGC-004 says
41
+ * to keep it. `ACL.checkAccess` carries both axes, so `access` decides
42
+ * visibility and `approvalRequired` decides only whether the public card is the
43
+ * right surface.
44
+ *
45
+ * Before this module, this binding filtered nothing at all: `buildSkills`
46
+ * iterated `registry.list()` and never consulted the ACL, so a module the ACL
47
+ * denied to everyone was still advertised — by id, name, description and full
48
+ * input schema — to any anonymous caller.
49
+ *
50
+ * **Internal module.** The `export` keywords below are module visibility, not a
51
+ * public contract: `package.json` declares only `"."` in `exports`, so a
52
+ * consumer cannot deep-import this file at all, and nothing here appears in
53
+ * `docs/features/public-api.md`. The surface is expected to move —
54
+ * `allowedSkillIds` already changed meaning once (it now reports the
55
+ * authorization axis alone, where it used to fold in the approval gate). Depend
56
+ * on `serve` / `A2AServerFactory` instead.
57
+ */
58
+ /**
59
+ * apcore's reserved namespace for the runtime's own management modules (apcore
60
+ * PROTOCOL_SPEC §6.7) — `system.health.*`, `system.usage.*`, `system.manifest.*`
61
+ * and, under the second opt-in, `system.control.*`. apcore identifies the
62
+ * surface by this prefix itself, in `Executor.governanceState()`, so matching on
63
+ * it conveys apcore's own boundary rather than inventing one.
64
+ */
65
+ export const SYSTEM_NAMESPACE = "system.";
66
+ /** Whether `skillId` is one of apcore's management modules. */
67
+ export function isSystemSkill(skillId) {
68
+ return skillId.startsWith(SYSTEM_NAMESPACE);
69
+ }
70
+ /**
71
+ * The apcore ACL backing `executor`, if one is configured.
72
+ *
73
+ * apcore-js exposes `setAcl` but no getter, so this reads the public property
74
+ * when one appears upstream and falls back to the private field. `null` means
75
+ * "no ACL configured", which is the common case and leaves every card
76
+ * unfiltered.
77
+ */
78
+ export function executorAcl(executor) {
79
+ for (const key of ["acl", "_acl"]) {
80
+ const acl = executor?.[key];
81
+ if (acl && typeof acl.check === "function") {
82
+ return acl;
83
+ }
84
+ }
85
+ return null;
86
+ }
87
+ /**
88
+ * An apcore `Context` carrying `identity`, for conditional ACL rules.
89
+ *
90
+ * An ACL rule's `conditions` block (`identityTypes`, `roles`) is evaluated
91
+ * against the context, and the check returns false without one — so a card
92
+ * filtered with no context would hide every skill a conditional rule allows.
93
+ * Building the context the same way the executor does is what keeps the card and
94
+ * the call path agreeing about the same principal.
95
+ */
96
+ function aclContext(identity) {
97
+ try {
98
+ // apcore-js `Context.create` takes positional arguments (identity first),
99
+ // unlike the Python binding's keyword form. Passing an options object here
100
+ // would silently produce a context with no identity, and every conditional
101
+ // rule would then evaluate false — hiding exactly the skills it allows.
102
+ return Context.create(identity);
103
+ }
104
+ catch {
105
+ return undefined;
106
+ }
107
+ }
108
+ /**
109
+ * `[authorized, approvalRequired]` for one skill, from apcore's ACL.
110
+ *
111
+ * Reads `checkAccess` (apcore-js >= 0.28.0, PROTOCOL_SPEC §6.8.1), which reports
112
+ * the two axes separately. The `check` fallback exists for an ACL that predates
113
+ * the accessor: there `approval` did not exist as a rule field, so `false` is
114
+ * not a guess but the only value such an ACL can mean — and a boolean that
115
+ * already fails closed degrades this surface toward showing less, never more.
116
+ */
117
+ function decide(acl, callerId, skillId, ctx) {
118
+ if (typeof acl.checkAccess !== "function") {
119
+ return [acl.check(callerId, skillId, ctx), false];
120
+ }
121
+ const decision = acl.checkAccess(callerId, skillId, ctx);
122
+ return [decision.access === "allow", decision.approvalRequired === true];
123
+ }
124
+ /**
125
+ * The skills the ACL permits `identity` to invoke, each mapped to whether
126
+ * invoking it needs a human first.
127
+ *
128
+ * With no ACL configured every id is permitted and none is gated, which is what
129
+ * makes this free for the common single-tenant deployment.
130
+ *
131
+ * The ACL is consulted with **no arguments projection**, because a card is
132
+ * discovery and there is no call site yet. An `arguments` condition (§6.1.7) is
133
+ * therefore unevaluable, so a rule carrying one neither denies nor grants — but
134
+ * an `allow` rule's `approval: required` stays *pending* and composes with
135
+ * whatever grants (§6.1.1 rule 5). A skill gated only for some argument shapes
136
+ * thus reports `true` here: at discovery time "this may need approval" is the
137
+ * honest answer, and it is the one that keeps such a skill off the public card.
138
+ *
139
+ * `callerId` is left `null` deliberately. apcore defines it as the *calling
140
+ * module* in a nested call chain, managed by `Context.child`; a top-level
141
+ * inbound request has none, and the ACL maps `null` to `@external`. That is
142
+ * apcore's contract, not a gap — `callers: ["@external"]` is how an operator
143
+ * denies external access, and it has to keep matching an authenticated request
144
+ * or the rule silently stops covering the traffic it was written for. The
145
+ * authenticated principal travels in the context instead, where the
146
+ * `identityTypes` / `roles` conditions see it.
147
+ */
148
+ export function skillAccess(executor, skillIds, identity) {
149
+ const access = new Map();
150
+ const acl = executorAcl(executor);
151
+ if (acl === null) {
152
+ for (const skillId of skillIds)
153
+ access.set(skillId, false);
154
+ return access;
155
+ }
156
+ const base = aclContext(identity);
157
+ for (const skillId of skillIds) {
158
+ const ctx = base && typeof base.child === "function"
159
+ ? base.child(skillId)
160
+ : undefined;
161
+ const callerId = ctx?.callerId ?? null;
162
+ try {
163
+ const [authorized, approvalRequired] = decide(acl, callerId, skillId, ctx);
164
+ if (authorized)
165
+ access.set(skillId, approvalRequired);
166
+ }
167
+ catch {
168
+ // A broken ACL must fail closed: serving MORE than the policy allows is
169
+ // the one outcome that cannot be walked back.
170
+ console.warn(`ACL check raised for skill ${skillId}; withholding it`);
171
+ }
172
+ }
173
+ return access;
174
+ }
175
+ /**
176
+ * The subset of `skillIds` the ACL authorizes `identity` to invoke.
177
+ *
178
+ * The authorization axis alone: a skill the ACL allows but gates behind an
179
+ * approval is in this set, because the caller may reach it. Callers that also
180
+ * need the gate read {@link skillAccess}.
181
+ */
182
+ export function allowedSkillIds(executor, skillIds, identity) {
183
+ return new Set(skillAccess(executor, skillIds, identity).keys());
184
+ }
185
+ function withSkills(card, keep) {
186
+ const skills = (card.skills ?? []).filter((skill) => keep.has(skill.id));
187
+ return { ...card, skills };
188
+ }
189
+ /**
190
+ * The public card: what an unauthenticated caller could actually invoke.
191
+ *
192
+ * `system.*` is removed unconditionally (srs FR-AGC-003 criteria 12 and 13); the
193
+ * remaining subtractions are governance-shaped. See the module docstring for why
194
+ * this is resolved once rather than per caller.
195
+ */
196
+ export function buildPublicCard(card, executor, registry) {
197
+ // The management namespace goes first and unconditionally: it is the only
198
+ // subtraction that survives a deployment with no ACL, and skipping the ACL for
199
+ // these ids also keeps `system.*` out of the audit trail of a decision whose
200
+ // answer cannot change the outcome.
201
+ const ids = (card.skills ?? [])
202
+ .map((skill) => skill.id)
203
+ .filter((id) => !isSystemSkill(id));
204
+ const access = skillAccess(executor, ids, null);
205
+ // Both sources of an approval gate, unioned as PROTOCOL_SPEC §6.9 composes
206
+ // them: the module's own annotation, and an ACL rule carrying
207
+ // `approval: required` for this principal. Since apcore 0.28.0 the annotation
208
+ // is one source among several, so reading it alone would leave a skill on the
209
+ // public card that an anonymous caller cannot in fact just call.
210
+ const keep = new Set();
211
+ for (const [skillId, approvalRequired] of access) {
212
+ if (approvalRequired)
213
+ continue;
214
+ if (registry && requiresApproval(registry.getDefinition(skillId)))
215
+ continue;
216
+ keep.add(skillId);
217
+ }
218
+ return withSkills(card, keep);
219
+ }
220
+ /**
221
+ * The extended card: what the authenticated caller may invoke.
222
+ *
223
+ * `requires_approval` skills are kept (srs FR-AGC-004 criterion 2), whether the
224
+ * gate comes from the module's annotation or from an ACL rule. Only the
225
+ * authorization axis of the decision filters here — dropping a skill because it
226
+ * needs a human would report a refusal the ACL never issued.
227
+ *
228
+ * `system.*` is kept too (criterion 11), filtered by the ACL like any other
229
+ * skill: the namespace exclusion is a property of the public card, not of the
230
+ * skill, and an authenticated management agent the ACL permits must still be
231
+ * able to discover the surface it is entitled to drive.
232
+ */
233
+ export function buildExtendedCard(card, executor, identity) {
234
+ const ids = (card.skills ?? []).map((skill) => skill.id);
235
+ return withSkills(card, allowedSkillIds(executor, ids, identity));
236
+ }
237
+ //# sourceMappingURL=card-visibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-visibility.js","sourceRoot":"","sources":["../../src/adapters/card-visibility.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,94 @@
1
+ /**
2
+ * A2A 1.0 `TaskNotFoundError`. Reserved for an unknown task id or one owned by
3
+ * another principal — deliberately indistinguishable from each other, and no
4
+ * longer produced for an authorization refusal (see {@link CODE_ACCESS_DENIED}).
5
+ */
6
+ export declare const CODE_TASK_NOT_FOUND = -32001;
7
+ export declare const CODE_ACCESS_DENIED = -32040;
8
+ export declare const CODE_APPROVAL_DENIED = -32041;
9
+ export declare const CODE_APPROVAL_TIMEOUT = -32042;
10
+ /** Whether an apcore error code is one of the three governance refusals. */
11
+ export declare function isGovernanceRefusal(code: string | undefined): boolean;
1
12
  export interface JsonRpcError {
2
13
  code: number;
3
14
  message: string;
4
15
  }
5
16
  export declare class ErrorMapper {
17
+ readonly discloseRefusalReason: boolean;
18
+ /**
19
+ * @param discloseRefusalReason Forward apcore's own message for the three
20
+ * governance refusal codes instead of the fixed per-class string
21
+ * (srs FR-ERR-011). Off by default. The code never changes with the flag —
22
+ * what a refusal *is* does not depend on how much a deployment chooses to
23
+ * say about it.
24
+ */
25
+ constructor(discloseRefusalReason?: boolean);
6
26
  /** ErrorFormatter interface for apcore ErrorFormatterRegistry. */
7
27
  format(error: unknown, _context?: unknown): Record<string, unknown>;
8
28
  toJsonRpcError(error: unknown): JsonRpcError;
29
+ /**
30
+ * Caller-facing message for a governance refusal.
31
+ *
32
+ * Default: the fixed per-class string. With `discloseRefusalReason`
33
+ * (srs FR-ERR-011): apcore's own message, through the same sanitizer every
34
+ * other forwarded message goes through. An empty or whitespace-only apcore
35
+ * message falls back to the fixed string rather than sending the caller
36
+ * nothing.
37
+ */
38
+ private refusalMessage;
9
39
  private handleApcoreError;
10
40
  private sanitizeMessage;
11
41
  }
42
+ /**
43
+ * Whether a `SCHEMA_VALIDATION_ERROR` is about something the *server* produced
44
+ * rather than something the caller sent.
45
+ *
46
+ * Reporting an output-validation failure as `-32602 Invalid params` tells the
47
+ * caller to fix a request that was correct, and the default `aiGuidance` apcore
48
+ * attaches to `SchemaValidationError` says "Input validation failed" and points
49
+ * at a `details.errors` field an A2A caller never receives. Those are
50
+ * server-side defects and belong behind the fixed internal string.
51
+ *
52
+ * The direction label apcore puts at the front of the message is the only signal
53
+ * that exists, so this matches that prefix. Anything unrecognized keeps the
54
+ * caller-facing detail -- including a module that raises the code itself with
55
+ * its own wording, whose message srs FR-ERR-002 requires the caller to see.
56
+ * Failing to recognize a server-side error therefore preserves the previous
57
+ * behaviour; it never masks a caller-fixable one by mistake.
58
+ */
59
+ export declare function isServerSideSchemaError(message: string): boolean;
60
+ /**
61
+ * Whether {@link ErrorMapper.toJsonRpcError} forwards this error's own message
62
+ * to the caller (sanitized), or replaces it with a fixed per-class string.
63
+ *
64
+ * This is the partition that decides whether a message may be *widened* -- with
65
+ * `aiGuidance`, or anything else. It is deliberately not `userFixable`, which is
66
+ * a different partition: six apcore codes carry `userFixable === true` while
67
+ * falling into `handleApcoreError`'s catch-all (`VERSION_CONSTRAINT_INVALID`,
68
+ * `BINDING_SCHEMA_INFERENCE_FAILED`, `BINDING_SCHEMA_MODE_CONFLICT`,
69
+ * `BINDING_STRICT_SCHEMA_INCOMPATIBLE`, `DEPENDENCY_NOT_FOUND`,
70
+ * `DEPENDENCY_VERSION_MISMATCH`), and appending guidance to those would extend
71
+ * the fixed "Internal server error" string with internal detail that
72
+ * {@link sanitizeMessage} does not strip (module ids, versions, env-var names,
73
+ * hostnames). `userFixable` is also settable per-error by the module author,
74
+ * which would let any module widen any fixed per-class string at will,
75
+ * including the governance refusals.
76
+ *
77
+ * The three governance codes (`ACL_DENIED`, `APPROVAL_DENIED`,
78
+ * `APPROVAL_TIMEOUT`) are in this partition only when `discloseRefusalReason` is
79
+ * set — the same flag the mapper branches on, so the two surfaces agree under
80
+ * either setting.
81
+ *
82
+ * `errorMapper message policy matches toJsonRpcError` locks this to the
83
+ * branching in `ErrorMapper.handleApcoreError` across every apcore error code
84
+ * and both flag values, so the two cannot drift.
85
+ */
86
+ export declare function carriesCallerDetail(error: unknown, discloseRefusalReason?: boolean): boolean;
87
+ /**
88
+ * Strip file paths, traceback lines and excess whitespace from text bound for a
89
+ * caller, then truncate to 500 characters. Module-level so the task-status
90
+ * surface (`server/executor.ts`) applies exactly the same redaction as the
91
+ * JSON-RPC surface.
92
+ */
93
+ export declare function sanitizeMessage(message: string): string;
12
94
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/adapters/errors.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,WAAW;IACtB,kEAAkE;IAClE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAKnE,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY;IAqB5C,OAAO,CAAC,iBAAiB;IAuDzB,OAAO,CAAC,eAAe;CAOxB"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/adapters/errors.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAc1C,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,qBAAqB,SAAS,CAAC;AAiB5C,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAErE;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,WAAW;IAQV,QAAQ,CAAC,qBAAqB,EAAE,OAAO;IAPnD;;;;;;OAMG;gBACkB,qBAAqB,GAAE,OAAe;IAE3D,kEAAkE;IAClE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAKnE,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY;IAqB5C;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,iBAAiB;IAmEzB,OAAO,CAAC,eAAe;CAGxB;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,qBAAqB,UAAQ,GAAG,OAAO,CAe1F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMvD"}