@agenticprimitives/a2a 0.0.0-alpha.3 → 0.0.0-alpha.30
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/CLAUDE.md +60 -21
- package/README.md +2 -0
- package/bin/a2a-conform.mjs +17 -0
- package/dist/agent.d.ts +183 -3
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +361 -62
- package/dist/agent.js.map +1 -1
- package/dist/auth.d.ts +72 -9
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +62 -19
- package/dist/auth.js.map +1 -1
- package/dist/authority-extension.d.ts +58 -0
- package/dist/authority-extension.d.ts.map +1 -0
- package/dist/authority-extension.js +70 -0
- package/dist/authority-extension.js.map +1 -0
- package/dist/card-audience.d.ts +87 -0
- package/dist/card-audience.d.ts.map +1 -0
- package/dist/card-audience.js +135 -0
- package/dist/card-audience.js.map +1 -0
- package/dist/client.d.ts +23 -8
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +74 -13
- package/dist/client.js.map +1 -1
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +10 -2
- package/dist/cloudflare/index.js.map +1 -1
- package/dist/conform/index.d.ts +36 -0
- package/dist/conform/index.d.ts.map +1 -0
- package/dist/conform/index.js +232 -0
- package/dist/conform/index.js.map +1 -0
- package/dist/discovery.d.ts +4 -0
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +6 -2
- package/dist/discovery.js.map +1 -1
- package/dist/engagement.d.ts +37 -0
- package/dist/engagement.d.ts.map +1 -0
- package/dist/engagement.js +83 -0
- package/dist/engagement.js.map +1 -0
- package/dist/grant.d.ts +4 -2
- package/dist/grant.d.ts.map +1 -1
- package/dist/grant.js +21 -13
- package/dist/grant.js.map +1 -1
- package/dist/handoff.d.ts +42 -0
- package/dist/handoff.d.ts.map +1 -0
- package/dist/handoff.js +28 -0
- package/dist/handoff.js.map +1 -0
- package/dist/index.d.ts +26 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -3
- package/dist/index.js.map +1 -1
- package/dist/payment-gate.d.ts +88 -0
- package/dist/payment-gate.d.ts.map +1 -0
- package/dist/payment-gate.js +47 -0
- package/dist/payment-gate.js.map +1 -0
- package/dist/run-provenance-extension.d.ts +22 -0
- package/dist/run-provenance-extension.d.ts.map +1 -0
- package/dist/run-provenance-extension.js +23 -0
- package/dist/run-provenance-extension.js.map +1 -0
- package/dist/runtime.d.ts +13 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +35 -10
- package/dist/runtime.js.map +1 -1
- package/dist/session-wire.d.ts +90 -0
- package/dist/session-wire.d.ts.map +1 -0
- package/dist/session-wire.js +226 -0
- package/dist/session-wire.js.map +1 -0
- package/dist/skill-handler.d.ts +26 -1
- package/dist/skill-handler.d.ts.map +1 -1
- package/dist/skill-handler.js.map +1 -1
- package/dist/standard/app-delegation.d.ts +60 -0
- package/dist/standard/app-delegation.d.ts.map +1 -0
- package/dist/standard/app-delegation.js +40 -0
- package/dist/standard/app-delegation.js.map +1 -0
- package/dist/standard/caller.d.ts +107 -0
- package/dist/standard/caller.d.ts.map +1 -0
- package/dist/standard/caller.js +176 -0
- package/dist/standard/caller.js.map +1 -0
- package/dist/standard/client.d.ts +53 -0
- package/dist/standard/client.d.ts.map +1 -0
- package/dist/standard/client.js +88 -0
- package/dist/standard/client.js.map +1 -0
- package/dist/standard/delegated.d.ts +121 -0
- package/dist/standard/delegated.d.ts.map +1 -0
- package/dist/standard/delegated.js +170 -0
- package/dist/standard/delegated.js.map +1 -0
- package/dist/standard/errors.d.ts +31 -0
- package/dist/standard/errors.d.ts.map +1 -0
- package/dist/standard/errors.js +75 -0
- package/dist/standard/errors.js.map +1 -0
- package/dist/standard/from-agent.d.ts +41 -0
- package/dist/standard/from-agent.d.ts.map +1 -0
- package/dist/standard/from-agent.js +133 -0
- package/dist/standard/from-agent.js.map +1 -0
- package/dist/standard/index.d.ts +10 -0
- package/dist/standard/index.d.ts.map +1 -0
- package/dist/standard/index.js +14 -0
- package/dist/standard/index.js.map +1 -0
- package/dist/standard/mount.d.ts +94 -0
- package/dist/standard/mount.d.ts.map +1 -0
- package/dist/standard/mount.js +186 -0
- package/dist/standard/mount.js.map +1 -0
- package/dist/standard/server.d.ts +130 -0
- package/dist/standard/server.d.ts.map +1 -0
- package/dist/standard/server.js +497 -0
- package/dist/standard/server.js.map +1 -0
- package/dist/standard/types.d.ts +186 -0
- package/dist/standard/types.d.ts.map +1 -0
- package/dist/standard/types.js +14 -0
- package/dist/standard/types.js.map +1 -0
- package/dist/subject-ask.d.ts +96 -0
- package/dist/subject-ask.d.ts.map +1 -0
- package/dist/subject-ask.js +45 -0
- package/dist/subject-ask.js.map +1 -0
- package/dist/subject-hop.d.ts +117 -0
- package/dist/subject-hop.d.ts.map +1 -0
- package/dist/subject-hop.js +187 -0
- package/dist/subject-hop.js.map +1 -0
- package/dist/task-store.d.ts +9 -3
- package/dist/task-store.d.ts.map +1 -1
- package/dist/task-store.js +12 -6
- package/dist/task-store.js.map +1 -1
- package/dist/wire-verify.d.ts +35 -0
- package/dist/wire-verify.d.ts.map +1 -0
- package/dist/wire-verify.js +51 -0
- package/dist/wire-verify.js.map +1 -0
- package/package.json +35 -12
- package/dist/jsonrpc.d.ts +0 -25
- package/dist/jsonrpc.d.ts.map +0 -1
- package/dist/jsonrpc.js +0 -52
- package/dist/jsonrpc.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-wire.d.ts","sourceRoot":"","sources":["../src/session-wire.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAmD,KAAK,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAC/F,OAAO,EAAmD,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAGjH,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,GAAG,CAAC;IACf,OAAO,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,IAAI,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,GAAG,CAAC;CAChB;AAED;;4CAE4C;AAC5C,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAU/C,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,CAE1E;AAED;mDACmD;AACnD,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,IAAI,CAS3G;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,gBAAgB,GAAG,UAAU,CAShE;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,GAAG,gBAAgB,CAMhE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,EACxD,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACxB,MAAM,GAAG,IAAI,CA2Bf;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CAAC,IAAI,EAAE;IACxD,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,mBAAmB,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,SAAS,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,OAAO,CAAC,CAuBnB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,4BAA4B,CAAC,IAAI,EAAE;IACvD,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,GAAG,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,SAAS,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChD,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBzB;AAED,qGAAqG;AACrG,eAAO,MAAM,eAAe,SAAU,OAAO,KAAG,GAAuD,CAAC"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// SESSION WIRES — how an agent signs as an identity whose key it does not hold. Spec 350 §8 / spec 326.
|
|
2
|
+
//
|
|
3
|
+
// THE CALLER-SIGNATURE GAP, RESOLVED (spec 329 §3.1, generalized). A runtime holds no key for the identity
|
|
4
|
+
// it acts as — an org's DO holds no org key, a relying service must never custody the service agent it
|
|
5
|
+
// acts as (ADR-0019: a relying key is always a DELEGATE, never a custodian), a skills worker signs as
|
|
6
|
+
// `skills-agent` without holding it. Yet A2A needs per-message sender signatures and per-poll caller
|
|
7
|
+
// signatures that verify against THAT identity. A ceremony therefore mints a NARROW delegation —
|
|
8
|
+
// delegator = the identity, delegate = a KMS session key, allowedMethods = a pinned set of skill
|
|
9
|
+
// selectors (never the any-skill sentinel), allowedTargets pinned, timestamp-bounded — signed by the
|
|
10
|
+
// identity's own custody credential. The runtime stores the wire; NO raw key ever rests there; the KMS
|
|
11
|
+
// key signs each digest on demand.
|
|
12
|
+
//
|
|
13
|
+
// ON THE WIRE such a signature is the SESSION-WRAPPED form: `0x51` (a type byte no on-chain validator
|
|
14
|
+
// accepts — it fails closed anywhere but a gate that understands it) followed by hex(utf8(JSON({ wire,
|
|
15
|
+
// sig }))). A gate verifies it fail-closed PER MESSAGE: delegator === the claimed signer; timestamp window
|
|
16
|
+
// live; a pinned selector set that names the requested skill and never A2A_ANY_SKILL; the raw ECDSA sig
|
|
17
|
+
// recovers to the wire's delegate; the wire's own signature ERC-1271-verifies against the delegator; AND
|
|
18
|
+
// the wire is unrevoked on chain — so a custodian's revocation kills the authority at every gate, now.
|
|
19
|
+
//
|
|
20
|
+
// WHY THIS IS HERE. Four copies of this file existed across two repos (demo-a2a's session-wire.ts and
|
|
21
|
+
// org-wire.ts, skills-a2a's service-wire.ts, and a sibling worker's). "Copy the wire implementation, do not
|
|
22
|
+
// invent a third" was the instruction, and the count had already reached four. It is an A2A signature
|
|
23
|
+
// format that consumes this package's own `skillSelector`; it belongs here, and the apps now consume it.
|
|
24
|
+
// What STAYS in the apps is policy — which caveat SHAPE counts as stewardship vs member access, which
|
|
25
|
+
// contracts a stewardship wire must pin. `org-wire.ts`'s `hasStewardshipShape` is a positive identity
|
|
26
|
+
// test no generic layer can express, and it does not move.
|
|
27
|
+
import { hashMessage, keccak256, recoverAddress, toBytes } from 'viem';
|
|
28
|
+
import { decodeAllowedMethodsTerms, decodeTimestampTerms } from '@agenticprimitives/delegation';
|
|
29
|
+
import { A2A_ANY_SKILL, skillSelector } from './grant.js';
|
|
30
|
+
/** Signature type byte for the session-wrapped form. Unknown to AgentAccount `_validateSig` (fails closed
|
|
31
|
+
* on chain) and to every other verifier — only a gate that calls `verifySessionWrappedSignature` accepts
|
|
32
|
+
* it, and only after full verification. */
|
|
33
|
+
export const SESSION_WRAPPED_SIG_TYPE = '0x51';
|
|
34
|
+
const utf8ToHex = (s) => `0x${Array.from(new TextEncoder().encode(s), (b) => b.toString(16).padStart(2, '0')).join('')}`;
|
|
35
|
+
const hexToUtf8 = (h) => {
|
|
36
|
+
const clean = h.startsWith('0x') ? h.slice(2) : h;
|
|
37
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
38
|
+
for (let i = 0; i < bytes.length; i++)
|
|
39
|
+
bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
40
|
+
return new TextDecoder().decode(bytes);
|
|
41
|
+
};
|
|
42
|
+
/** Wrap a raw session-key ECDSA signature with the wire that authorizes it. */
|
|
43
|
+
export function wrapSessionSignature(wire, sig) {
|
|
44
|
+
return (SESSION_WRAPPED_SIG_TYPE + utf8ToHex(JSON.stringify({ wire, sig })).slice(2));
|
|
45
|
+
}
|
|
46
|
+
/** Parse the session-wrapped form; null for any other signature shape (callers then use the standard
|
|
47
|
+
* ERC-1271 path — one detector, no ambiguity). */
|
|
48
|
+
export function parseSessionWrappedSignature(signature) {
|
|
49
|
+
if (!signature?.startsWith(SESSION_WRAPPED_SIG_TYPE) || signature.length <= SESSION_WRAPPED_SIG_TYPE.length)
|
|
50
|
+
return null;
|
|
51
|
+
try {
|
|
52
|
+
const parsed = JSON.parse(hexToUtf8(`0x${signature.slice(SESSION_WRAPPED_SIG_TYPE.length)}`));
|
|
53
|
+
if (!parsed?.wire?.delegator || !parsed.wire.delegate || !parsed.wire.signature || !parsed.sig)
|
|
54
|
+
return null;
|
|
55
|
+
return { wire: parsed.wire, sig: parsed.sig };
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function wireToDelegation(w) {
|
|
62
|
+
return {
|
|
63
|
+
delegator: w.delegator,
|
|
64
|
+
delegate: w.delegate,
|
|
65
|
+
authority: w.authority,
|
|
66
|
+
caveats: w.caveats.map((c) => ({ enforcer: c.enforcer, terms: c.terms, args: (c.args ?? '0x') })),
|
|
67
|
+
salt: BigInt(w.salt),
|
|
68
|
+
signature: w.signature,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function delegationToWire(d) {
|
|
72
|
+
return {
|
|
73
|
+
delegator: d.delegator, delegate: d.delegate, authority: d.authority,
|
|
74
|
+
caveats: d.caveats.map((c) => ({ enforcer: c.enforcer, terms: c.terms, ...(c.args && c.args !== '0x' ? { args: c.args } : {}) })),
|
|
75
|
+
salt: d.salt.toString(), signature: d.signature,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Shape check for a session wire (at ceremony store time AND at every gate hit): timestamp-bounded, a
|
|
80
|
+
* pinned allowedMethods set that never carries the any-skill sentinel and — when `skill` is given — names
|
|
81
|
+
* that skill's selector.
|
|
82
|
+
*
|
|
83
|
+
* `skill` should be passed wherever the request names one: a wire minted for one rail must not authorize
|
|
84
|
+
* another. It is omitted only on the read/control path (`tasks/get`, `tasks/cancel`,
|
|
85
|
+
* `pushNotificationConfig/set`), whose digest binds a method and a taskId, not a skill. That omission is
|
|
86
|
+
* narrow rather than lax — the wire must still be pinned, live, ERC-1271-valid and unrevoked, and the task
|
|
87
|
+
* runtime independently requires the caller to BE a party to the task.
|
|
88
|
+
*/
|
|
89
|
+
export function checkSessionWireShape(wire, enforcers, nowSec, opts) {
|
|
90
|
+
const byEnforcer = (addr) => (wire.caveats ?? []).find((c) => (c.enforcer ?? '').toLowerCase() === addr.toLowerCase());
|
|
91
|
+
const tsCav = byEnforcer(enforcers.timestamp);
|
|
92
|
+
if (!tsCav?.terms)
|
|
93
|
+
return 'session wire must be timestamp-bounded';
|
|
94
|
+
try {
|
|
95
|
+
const win = decodeTimestampTerms(tsCav.terms);
|
|
96
|
+
const now = BigInt(nowSec);
|
|
97
|
+
if (now < win.validAfter || now >= win.validUntil)
|
|
98
|
+
return 'session wire outside its timestamp window';
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return 'session wire timestamp terms undecodable';
|
|
102
|
+
}
|
|
103
|
+
const amCav = byEnforcer(enforcers.allowedMethods);
|
|
104
|
+
if (!amCav?.terms)
|
|
105
|
+
return 'session wire must carry an allowedMethods caveat';
|
|
106
|
+
try {
|
|
107
|
+
const selectors = decodeAllowedMethodsTerms(amCav.terms).map((s) => s.toLowerCase());
|
|
108
|
+
// A PINNED SET, never the any-skill sentinel. A leaked delegate key can send only what the custodian
|
|
109
|
+
// enumerated; `A2A_ANY_SKILL` is the line between "these operations" and "anything this agent can do".
|
|
110
|
+
if (selectors.some((s) => s === A2A_ANY_SKILL.toLowerCase()))
|
|
111
|
+
return 'session wire must never carry the any-skill sentinel';
|
|
112
|
+
if (selectors.length === 0)
|
|
113
|
+
return 'session wire allowedMethods must name at least one selector';
|
|
114
|
+
if (opts?.skill) {
|
|
115
|
+
const want = skillSelector(opts.skill).toLowerCase();
|
|
116
|
+
if (!selectors.includes(want))
|
|
117
|
+
return `session wire allowedMethods does not name the ${opts.skill} selector`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return 'session wire allowedMethods terms undecodable';
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Verify a session-wrapped signature for `signer` over `digest`, fail-closed on every leg. The on-chain
|
|
127
|
+
* checks are the SAME injected ones the standard gate uses (`OnChainChecks`) — revocation is immediate.
|
|
128
|
+
* Pass `skill` whenever the request names one.
|
|
129
|
+
*/
|
|
130
|
+
export async function verifySessionWrappedSignature(args) {
|
|
131
|
+
const parsed = parseSessionWrappedSignature(args.signature);
|
|
132
|
+
if (!parsed)
|
|
133
|
+
return false;
|
|
134
|
+
const { wire, sig } = parsed;
|
|
135
|
+
if (wire.delegator.toLowerCase() !== args.signer.toLowerCase())
|
|
136
|
+
return false;
|
|
137
|
+
const shapeOpts = args.skill ? { skill: args.skill } : undefined;
|
|
138
|
+
if (checkSessionWireShape(wire, args.enforcers, Math.floor((args.now ?? Date.now()) / 1000), shapeOpts) !== null)
|
|
139
|
+
return false;
|
|
140
|
+
// The raw sig must recover to the wire's delegate (the KMS session key). Accept both raw-digest and
|
|
141
|
+
// eth-signed-message recovery, mirroring AgentAccount._verifyEcdsa.
|
|
142
|
+
const delegate = wire.delegate.toLowerCase();
|
|
143
|
+
let recovered = false;
|
|
144
|
+
try {
|
|
145
|
+
recovered = (await recoverAddress({ hash: args.digest, signature: sig })).toLowerCase() === delegate;
|
|
146
|
+
}
|
|
147
|
+
catch { /* try wrapped */ }
|
|
148
|
+
if (!recovered) {
|
|
149
|
+
try {
|
|
150
|
+
recovered = (await recoverAddress({ hash: hashMessage({ raw: toBytes(args.digest) }), signature: sig })).toLowerCase() === delegate;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (!recovered)
|
|
157
|
+
return false;
|
|
158
|
+
const d = wireToDelegation(wire);
|
|
159
|
+
try {
|
|
160
|
+
if (await args.isRevoked(d))
|
|
161
|
+
return false; // custodian revoke ⇒ immediate kill at every gate
|
|
162
|
+
return await args.verifyDelegationSig(d);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return false; // fail-closed on chain-read failure (ADR-0013)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Verify a session-wrapped signature over a digest THAT WAS SIGNED AT A KNOWN TIME — a release, an attestation, anything
|
|
170
|
+
* that must keep verifying for as long as it is served, long after the time-boxed leaf that signed it expired (spec 412
|
|
171
|
+
* W5 / spec 413). Every leg of `verifySessionWrappedSignature` except two:
|
|
172
|
+
* • the timestamp window is judged AT `at` (when the thing was signed), not now — back-dating widens nothing, because
|
|
173
|
+
* the leaf must still verify ERC-1271 against the signer and the key must still recover;
|
|
174
|
+
* • no skill selector is required: a message gate asks "may this key send THIS skill"; a signed artifact asks only
|
|
175
|
+
* "did the signer's agent sign it while its leaf was live".
|
|
176
|
+
* Revocation is read NOW: a leaf the custodian revoked stops vouching for anything it ever signed.
|
|
177
|
+
* Returns null when every leg holds, else the leg that failed, in words. Fail-closed on a chain-read failure.
|
|
178
|
+
*/
|
|
179
|
+
export async function verifySessionLeafSignatureAt(args) {
|
|
180
|
+
const parsed = parseSessionWrappedSignature(args.signature);
|
|
181
|
+
if (!parsed)
|
|
182
|
+
return 'not a session-wrapped signature';
|
|
183
|
+
const { wire, sig } = parsed;
|
|
184
|
+
if (wire.delegator.toLowerCase() !== args.signer.toLowerCase())
|
|
185
|
+
return 'the leaf is not the signer\'s';
|
|
186
|
+
const delegate = wire.delegate.toLowerCase();
|
|
187
|
+
let recovered = false;
|
|
188
|
+
try {
|
|
189
|
+
recovered = (await recoverAddress({ hash: args.digest, signature: sig })).toLowerCase() === delegate;
|
|
190
|
+
}
|
|
191
|
+
catch { /* try the eth-signed form */ }
|
|
192
|
+
if (!recovered) {
|
|
193
|
+
try {
|
|
194
|
+
recovered = (await recoverAddress({ hash: hashMessage({ raw: toBytes(args.digest) }), signature: sig })).toLowerCase() === delegate;
|
|
195
|
+
}
|
|
196
|
+
catch { /* no */ }
|
|
197
|
+
}
|
|
198
|
+
if (!recovered)
|
|
199
|
+
return 'the signature does not recover to the leaf\'s session key';
|
|
200
|
+
const tsCav = (wire.caveats ?? []).find((c) => (c.enforcer ?? '').toLowerCase() === args.timestampEnforcer.toLowerCase());
|
|
201
|
+
if (!tsCav?.terms)
|
|
202
|
+
return 'the leaf carries no timestamp caveat';
|
|
203
|
+
try {
|
|
204
|
+
const win = decodeTimestampTerms(tsCav.terms);
|
|
205
|
+
const at = BigInt(Math.floor(args.at / 1000));
|
|
206
|
+
if (at < win.validAfter || at >= win.validUntil)
|
|
207
|
+
return 'the leaf was not live when the digest was signed';
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return 'the leaf\'s timestamp terms are undecodable';
|
|
211
|
+
}
|
|
212
|
+
const d = wireToDelegation(wire);
|
|
213
|
+
try {
|
|
214
|
+
if (await args.isRevoked(d))
|
|
215
|
+
return 'the leaf was revoked on chain';
|
|
216
|
+
if (!(await args.verifyDelegationSig(d)))
|
|
217
|
+
return 'the leaf does not verify ERC-1271 against the signer';
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
return `the chain could not be read (${e instanceof Error ? e.message : 'unknown'})`;
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
/** keccak over stable-JSON — the a2a body-hash convention (equals the task runtime's `hashBody`). */
|
|
225
|
+
export const sessionBodyHash = (data) => keccak256(toBytes(JSON.stringify(data ?? null)));
|
|
226
|
+
//# sourceMappingURL=session-wire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-wire.js","sourceRoot":"","sources":["../src/session-wire.ts"],"names":[],"mappings":"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"}
|
package/dist/skill-handler.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Address, Hex } from '@agenticprimitives/types';
|
|
2
2
|
import type { Delegation } from '@agenticprimitives/delegation';
|
|
3
3
|
import type { VaultRef } from './types.js';
|
|
4
|
+
import type { SkillPayment } from './payment-gate.js';
|
|
4
5
|
/** Minimal vault seam — the consumer wires demo-mcp vault read/write over a delegation. FR-3.4: a handler
|
|
5
6
|
* delivers a result into ANOTHER principal's vault by passing a `delegation` THAT principal granted
|
|
6
7
|
* (delegator == the record owner); the consumer routes it through `callMcpToolViaDelegation` so demo-mcp
|
|
@@ -16,11 +17,16 @@ export interface VaultClient {
|
|
|
16
17
|
delegation?: Delegation;
|
|
17
18
|
}): Promise<VaultRef>;
|
|
18
19
|
}
|
|
19
|
-
/** Minimal MCP seam — call a tool via the delegation token (reuses the a2a→mcp leg, W4).
|
|
20
|
+
/** Minimal MCP seam — call a tool via the delegation token (reuses the a2a→mcp leg, W4). Symmetric with
|
|
21
|
+
* `VaultClient`: pass the task's `delegation` (the grant THAT principal signed) so the composed MCP call
|
|
22
|
+
* rides the on-chain authority (ADR-0041); the consumer routes it through `callMcpToolViaDelegation`. Omit
|
|
23
|
+
* `delegation` only for an agent-self call that needs no principal grant. This is the port the Ring-0
|
|
24
|
+
* orchestration loop's `ToolInvoker` wraps (ADR-0044). */
|
|
20
25
|
export interface McpClient {
|
|
21
26
|
callTool(args: {
|
|
22
27
|
tool: string;
|
|
23
28
|
toolArgs?: Record<string, unknown>;
|
|
29
|
+
delegation?: Delegation;
|
|
24
30
|
}): Promise<unknown>;
|
|
25
31
|
}
|
|
26
32
|
/** Thrown by `requestAuth` to suspend a task pending a fresh/again-scoped delegation (FR-3.5). The
|
|
@@ -67,6 +73,8 @@ export interface SkillContext {
|
|
|
67
73
|
bodyContentType?: string;
|
|
68
74
|
disclosurePolicy?: string;
|
|
69
75
|
caseId?: Hex;
|
|
76
|
+
/** URI-keyed A2A extension metadata to record on the artifact (e.g. skill-provenance). */
|
|
77
|
+
metadata?: Record<string, unknown>;
|
|
70
78
|
}): Promise<Hex>;
|
|
71
79
|
/** Suspend pending a fresh grant — throws `AuthRequired`. */
|
|
72
80
|
requestAuth(reason: string): never;
|
|
@@ -79,8 +87,25 @@ export interface SkillResult {
|
|
|
79
87
|
artifactIds?: Hex[];
|
|
80
88
|
error?: string;
|
|
81
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Who may SEE a skill on an agent card (spec 338 §8, ADR-0056 §6). Mirrors `surface-catalog`'s
|
|
92
|
+
* `SurfaceExposure` structurally — not imported, so `a2a` stays dependency-light.
|
|
93
|
+
*
|
|
94
|
+
* Absent ⇒ `public`, preserving pre-spec-338 behaviour. Visibility is NOT authorization: a skill
|
|
95
|
+
* hidden from a card is still gated by delegation + policy if someone guesses its name, and a skill
|
|
96
|
+
* shown on a card grants nothing.
|
|
97
|
+
*/
|
|
98
|
+
export type SkillExposure = 'public' | 'authenticated' | 'private' | 'service-only';
|
|
82
99
|
export interface SkillHandler {
|
|
83
100
|
skill: string;
|
|
101
|
+
/** Card visibility. Omit ⇒ `public`. See `SkillExposure`. */
|
|
102
|
+
exposure?: SkillExposure;
|
|
103
|
+
/** For `exposure: 'private'` — canonical ids permitted to see it. Empty/absent ⇒ nobody. */
|
|
104
|
+
audience?: readonly string[];
|
|
105
|
+
/** PAY-A2A-1 — optional price. A priced skill is gated by the injected `PaymentGate` BEFORE `handle`
|
|
106
|
+
* runs; an unpaid request parks `input-required` with `x402.payment.*` metadata (the handler is never
|
|
107
|
+
* reached). Free skills omit this. */
|
|
108
|
+
payment?: SkillPayment;
|
|
84
109
|
handle(ctx: SkillContext): Promise<SkillResult>;
|
|
85
110
|
}
|
|
86
111
|
/** Index handlers by skill name; reject duplicate registrations. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-handler.d.ts","sourceRoot":"","sources":["../src/skill-handler.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"skill-handler.d.ts","sourceRoot":"","sources":["../src/skill-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-handler.js","sourceRoot":"","sources":["../src/skill-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"skill-handler.js","sourceRoot":"","sources":["../src/skill-handler.ts"],"names":[],"mappings":"AA2BA;yEACyE;AACzE,MAAM,OAAO,YAAa,SAAQ,KAAK;IACT;IAA5B,YAA4B,UAAkB;QAC5C,KAAK,CAAC,kBAAkB,UAAU,EAAE,CAAC,CAAC;QADZ,eAAU,GAAV,UAAU,CAAQ;QAE5C,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAcD;;mFAEmF;AACnF,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACb;IAA5B,YAA4B,OAAuB;QACjD,KAAK,CAAC,sBAAsB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QADpB,YAAO,GAAP,OAAO,CAAgB;QAEjD,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AA6DD,oEAAoE;AACpE,MAAM,UAAU,kBAAkB,CAAC,QAAwB;IACzD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QAC7E,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Hex } from '@agenticprimitives/types';
|
|
2
|
+
import type { DelegationWireV1 } from '../session-wire.js';
|
|
3
|
+
/** The capability the person's agent runs for an engagement — one message to another agent, sent as the asker. */
|
|
4
|
+
export declare const ENGAGEMENT_INVOKE_CAPABILITY = "engagement.agent.invoke";
|
|
5
|
+
export interface AppDelegationAskInput {
|
|
6
|
+
/** The person's ask-as-me wire: delegator = the person, delegate = this app's ask key, caveat `harness.ask`. */
|
|
7
|
+
wire: DelegationWireV1;
|
|
8
|
+
/** The person's words, verbatim. */
|
|
9
|
+
question: string;
|
|
10
|
+
/** The service the person's agent engages (a registry name: `catalog.svc`). */
|
|
11
|
+
service: string;
|
|
12
|
+
/** A fresh nonce per ask (the runtime's assertion ledger spends it once). Default: 16 hex chars from `crypto`. */
|
|
13
|
+
nonce?: string;
|
|
14
|
+
}
|
|
15
|
+
/** The `/harness/ask` body, as a stable string — the assertion's `bodyHash` is over THESE bytes, so the caller posts
|
|
16
|
+
* this string unchanged. */
|
|
17
|
+
export declare function appDelegationAskBody(input: AppDelegationAskInput): string;
|
|
18
|
+
/**
|
|
19
|
+
* ONE signed ask: the body plus the `A2A-Session` headers — a caller assertion by the app's ask key (the wire's
|
|
20
|
+
* delegate), wrapped with the wire so the runtime can verify the delegation it rides. `signDigest` is the app's
|
|
21
|
+
* signer for that key (an AKCS delegate, a KMS key — never a person's key); `audience` is the person agent's origin.
|
|
22
|
+
*/
|
|
23
|
+
export declare function appDelegationAsk(input: AppDelegationAskInput & {
|
|
24
|
+
audience: string;
|
|
25
|
+
signDigest: (digest: Hex) => Promise<Hex>;
|
|
26
|
+
now?: () => number;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
raw: string;
|
|
29
|
+
headers: Record<string, string>;
|
|
30
|
+
}>;
|
|
31
|
+
/** The reply shape `/harness/ask` answers with, as far as an engaging client reads it. */
|
|
32
|
+
export interface AppDelegationReplyV1 {
|
|
33
|
+
ok?: boolean;
|
|
34
|
+
error?: string;
|
|
35
|
+
runRef?: string;
|
|
36
|
+
hasProvenance?: unknown;
|
|
37
|
+
reply?: {
|
|
38
|
+
kind?: string;
|
|
39
|
+
runRef?: string;
|
|
40
|
+
text?: string;
|
|
41
|
+
summary?: string;
|
|
42
|
+
error?: string;
|
|
43
|
+
results?: Array<{
|
|
44
|
+
toolId: string;
|
|
45
|
+
result: unknown;
|
|
46
|
+
}>;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* What the engaged service answered, as the person's agent recorded it: the result of the `engagement.agent.invoke`
|
|
51
|
+
* step (the service's own answer, an observation of the person's agent — never authority), the agent's words, and
|
|
52
|
+
* the run that did it. `null` when the reply carries no engagement.
|
|
53
|
+
*/
|
|
54
|
+
export declare function engagementHopOf(out: AppDelegationReplyV1 | null | undefined): {
|
|
55
|
+
said: string;
|
|
56
|
+
runRef?: string;
|
|
57
|
+
hop: Record<string, unknown> | null;
|
|
58
|
+
hasProvenance?: unknown;
|
|
59
|
+
} | null;
|
|
60
|
+
//# sourceMappingURL=app-delegation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-delegation.d.ts","sourceRoot":"","sources":["../../src/standard/app-delegation.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,kHAAkH;AAClH,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AAEtE,MAAM,WAAW,qBAAqB;IACpC,gHAAgH;IAChH,IAAI,EAAE,gBAAgB,CAAC;IACvB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;IAChB,kHAAkH;IAClH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;6BAC6B;AAC7B,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CASzE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,qBAAqB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAE,GACjH,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAK3D;AAED,0FAA0F;AAC1F,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;CACnJ;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAMpL"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { STANDARD_SURFACE_SKILL, sessionWireSigner } from './caller.js';
|
|
2
|
+
/** The capability the person's agent runs for an engagement — one message to another agent, sent as the asker. */
|
|
3
|
+
export const ENGAGEMENT_INVOKE_CAPABILITY = 'engagement.agent.invoke';
|
|
4
|
+
/** The `/harness/ask` body, as a stable string — the assertion's `bodyHash` is over THESE bytes, so the caller posts
|
|
5
|
+
* this string unchanged. */
|
|
6
|
+
export function appDelegationAskBody(input) {
|
|
7
|
+
const nonce = input.nonce ?? [...crypto.getRandomValues(new Uint8Array(8))].map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
8
|
+
return JSON.stringify({
|
|
9
|
+
method: STANDARD_SURFACE_SKILL,
|
|
10
|
+
nonce,
|
|
11
|
+
addressee: input.wire.delegator,
|
|
12
|
+
message: `ask ${input.service}: ${input.question}`,
|
|
13
|
+
plan: { steps: [{ toolId: ENGAGEMENT_INVOKE_CAPABILITY, args: { agent: input.service, message: input.question } }] },
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* ONE signed ask: the body plus the `A2A-Session` headers — a caller assertion by the app's ask key (the wire's
|
|
18
|
+
* delegate), wrapped with the wire so the runtime can verify the delegation it rides. `signDigest` is the app's
|
|
19
|
+
* signer for that key (an AKCS delegate, a KMS key — never a person's key); `audience` is the person agent's origin.
|
|
20
|
+
*/
|
|
21
|
+
export async function appDelegationAsk(input) {
|
|
22
|
+
const raw = appDelegationAskBody(input);
|
|
23
|
+
const sign = sessionWireSigner({ agent: input.wire.delegate, wire: input.wire, signDigest: input.signDigest, audience: input.audience, ...(input.now ? { now: input.now } : {}) });
|
|
24
|
+
const headers = await sign(raw, STANDARD_SURFACE_SKILL);
|
|
25
|
+
return { raw, headers: { 'content-type': 'application/json', accept: 'application/json', ...headers } };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* What the engaged service answered, as the person's agent recorded it: the result of the `engagement.agent.invoke`
|
|
29
|
+
* step (the service's own answer, an observation of the person's agent — never authority), the agent's words, and
|
|
30
|
+
* the run that did it. `null` when the reply carries no engagement.
|
|
31
|
+
*/
|
|
32
|
+
export function engagementHopOf(out) {
|
|
33
|
+
if (!out?.ok || !out.reply)
|
|
34
|
+
return null;
|
|
35
|
+
const hop = (out.reply.results ?? []).find((r) => r.toolId === ENGAGEMENT_INVOKE_CAPABILITY)?.result;
|
|
36
|
+
const said = (out.reply.text ?? out.reply.summary ?? '').trim();
|
|
37
|
+
const runRef = out.reply.runRef ?? out.runRef;
|
|
38
|
+
return { said, ...(runRef ? { runRef } : {}), hop: hop && typeof hop === 'object' ? hop : null, ...(out.hasProvenance !== undefined ? { hasProvenance: out.hasProvenance } : {}) };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=app-delegation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-delegation.js","sourceRoot":"","sources":["../../src/standard/app-delegation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type Address, type Hex } from 'viem';
|
|
2
|
+
import type { Delegation } from '@agenticprimitives/delegation';
|
|
3
|
+
import { type DelegationWireV1 } from '../session-wire.js';
|
|
4
|
+
import type { Principal } from './server.js';
|
|
5
|
+
/** The Authorization scheme an agent presents its session wire under. */
|
|
6
|
+
export declare const SESSION_AUTH_SCHEME = "A2A-Session";
|
|
7
|
+
/** The skill a session wire must pin to reach the standard surface: asking this agent, and nothing else.
|
|
8
|
+
* A wire that names other selectors and not this one is refused — pinning is the point. */
|
|
9
|
+
export declare const STANDARD_SURFACE_SKILL = "harness.ask";
|
|
10
|
+
/** What a caller signs. Every field is bound: a captured assertion cannot be replayed onto another method,
|
|
11
|
+
* another body, another host, or a later moment. `issuedAt` is IN the digest and checked (stale / ahead refused,
|
|
12
|
+
* the digest claimed once) — the wire path's freshness field that the deleted JSON-RPC dispatcher once dropped
|
|
13
|
+
* (audit a2a-issuedat-dropped-in-dispatch; the folded wire of spec 372 S4 is where the check lives now). */
|
|
14
|
+
export interface CallerAssertionV1 {
|
|
15
|
+
/** The Smart Agent the caller acts AS — must equal the wire's delegator. */
|
|
16
|
+
agent: string;
|
|
17
|
+
/** The A2A method this assertion is for. */
|
|
18
|
+
method: string;
|
|
19
|
+
/** keccak256 over the raw JSON-RPC request body. */
|
|
20
|
+
bodyHash: Hex;
|
|
21
|
+
/** Seconds since the epoch. */
|
|
22
|
+
issuedAt: number;
|
|
23
|
+
/** The origin the request is addressed to (`https://host`), so an assertion for one agent's host is not
|
|
24
|
+
* usable at another's. */
|
|
25
|
+
audience: string;
|
|
26
|
+
/** The `0x51`-wrapped session signature over `callerAssertionDigest(...)`. */
|
|
27
|
+
signature: string;
|
|
28
|
+
}
|
|
29
|
+
/** The digest a caller signs — keccak over stable JSON, the a2a body-hash convention. */
|
|
30
|
+
export declare function callerAssertionDigest(a: Omit<CallerAssertionV1, 'signature'>): Hex;
|
|
31
|
+
/** keccak over the raw request body, exactly as it arrived — never over a re-serialized parse. */
|
|
32
|
+
export declare const requestBodyHash: (raw: string) => Hex;
|
|
33
|
+
/** Build the `Authorization` header value a runtime sends. */
|
|
34
|
+
export declare function sessionAuthorizationHeader(a: CallerAssertionV1): string;
|
|
35
|
+
/** Read an `A2A-Session` header. Returns null for any other scheme (a `Bearer` is a person's, not ours) and
|
|
36
|
+
* for anything malformed — never a partial assertion. */
|
|
37
|
+
export declare function parseSessionAuthorization(header: string | null | undefined): CallerAssertionV1 | null;
|
|
38
|
+
export interface SessionWirePrincipalDeps {
|
|
39
|
+
/** The enforcer addresses the wire's caveats must carry (this deployment's). */
|
|
40
|
+
enforcers: {
|
|
41
|
+
timestamp: string;
|
|
42
|
+
allowedMethods: string;
|
|
43
|
+
};
|
|
44
|
+
/** ERC-1271 / ECDSA verification of the wire against its delegator. */
|
|
45
|
+
verifyDelegationSig: (d: Delegation) => Promise<boolean>;
|
|
46
|
+
/** On-chain revocation — a custodian's revoke kills the caller at the next request. */
|
|
47
|
+
isRevoked: (d: Delegation) => Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Verify an assertion the agent signed DIRECTLY — ERC-1271 against its own account, no session key in
|
|
50
|
+
* between. Some agents can do that (a relayer holding the SA's credential, a persona in this estate) and
|
|
51
|
+
* before the fold they proved themselves exactly this way, with `caller` + `signature` on the wire.
|
|
52
|
+
*
|
|
53
|
+
* NOT A FALLBACK (ADR-0013). The signature's own type byte chooses: `0x51` is session-wrapped and takes
|
|
54
|
+
* the wire path; anything else takes this one. Neither runs because the other failed, and omitting this
|
|
55
|
+
* means a direct signature is simply not admitted.
|
|
56
|
+
*/
|
|
57
|
+
verifyAgentSignature?: (agent: Address, digest: Hex, signature: Hex) => Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* The skill the wire must pin for this request (default `STANDARD_SURFACE_SKILL`). A function is asked per
|
|
60
|
+
* request with the assertion's `method` and answers the selector to require, or `null` to refuse that method
|
|
61
|
+
* outright — so one principal can admit `harness.ask` under an ask wire and `harness.read` under a read-only
|
|
62
|
+
* wire, and a wire pinned to one never opens the other (spec 433 W2: the Home's runtime reads a self-hosted
|
|
63
|
+
* agent's runs under a wire that can read and cannot ask).
|
|
64
|
+
*/
|
|
65
|
+
skill?: string | ((method: string) => string | null);
|
|
66
|
+
/** How old an assertion may be (default 120 s). */
|
|
67
|
+
maxAgeSec?: number;
|
|
68
|
+
/** Tolerated clock skew for an assertion dated ahead (default 30 s). */
|
|
69
|
+
skewSec?: number;
|
|
70
|
+
now?: () => number;
|
|
71
|
+
/**
|
|
72
|
+
* Spend an assertion, once. Returns true when THIS call claimed it and false when it was already spent.
|
|
73
|
+
* The default is an in-isolate map, which is not replay protection where requests fan out across
|
|
74
|
+
* isolates — bind the estate's single writer (the agent's own object) in production.
|
|
75
|
+
*/
|
|
76
|
+
claim?: (digest: Hex, expiresAtMs: number) => Promise<boolean>;
|
|
77
|
+
/** Told why a caller was refused — for the operator's log, never for the caller (a refusal says only
|
|
78
|
+
* that it was refused; which leg failed is not a fact an unauthenticated caller is owed). */
|
|
79
|
+
onRefused?: (reason: string, agent?: string) => void;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The `principal` implementation for agents. Returns `{ agent, kind: 'agent' }` on every leg passing, and
|
|
83
|
+
* `null` otherwise — the server answers 401 and no method runs.
|
|
84
|
+
*
|
|
85
|
+
* SINGLE-USE. An accepted assertion's digest is SPENT: a captured request cannot be replayed while it is
|
|
86
|
+
* still fresh. With `claim` bound to the estate's single writer this holds everywhere; without it, only
|
|
87
|
+
* within this isolate — which on a fanned-out edge is no protection at all, and was observed live before
|
|
88
|
+
* the ledger existed. The claim happens AFTER the signature verifies, so an unauthenticated caller can
|
|
89
|
+
* spend nothing and write nothing.
|
|
90
|
+
*/
|
|
91
|
+
export declare function sessionWirePrincipal(deps: SessionWirePrincipalDeps): (request: Request) => Promise<Principal | null>;
|
|
92
|
+
/** Re-export so a client can build a wire-signed call without reaching past the standard surface. */
|
|
93
|
+
export type { DelegationWireV1 };
|
|
94
|
+
/** THE CLIENT HALF — what a runtime holds to speak as itself: its agent, its session wire, and a signer over the
|
|
95
|
+
* runtime's OWN key (a port: the private key never enters this package). Returns the per-request header builder
|
|
96
|
+
* `createStandardA2aClient({ signRequest })` takes; each request's assertion binds the method, the body hash, the
|
|
97
|
+
* audience and the moment, and is spent once at the addressed agent (S3c). The same code path the S3c gate drove. */
|
|
98
|
+
export declare function sessionWireSigner(o: {
|
|
99
|
+
agent: Address;
|
|
100
|
+
wire: DelegationWireV1;
|
|
101
|
+
/** Signs a 32-byte digest with the runtime's key; returns the raw 65-byte signature. */
|
|
102
|
+
signDigest: (digest: Hex) => Promise<Hex>;
|
|
103
|
+
/** The origin the requests are addressed to (`https://host`); defaults from the endpoint's origin. */
|
|
104
|
+
audience: string;
|
|
105
|
+
now?: () => number;
|
|
106
|
+
}): (raw: string, method: string) => Promise<Record<string, string>>;
|
|
107
|
+
//# sourceMappingURL=caller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caller.d.ts","sourceRoot":"","sources":["../../src/standard/caller.ts"],"names":[],"mappings":"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"}
|