@atrib/agent 0.1.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.
- package/LICENSE +190 -0
- package/README.md +333 -0
- package/dist/adapters/cloudflare-agent.d.ts +46 -0
- package/dist/adapters/cloudflare-agent.d.ts.map +1 -0
- package/dist/adapters/cloudflare-agent.js +124 -0
- package/dist/adapters/cloudflare-agent.js.map +1 -0
- package/dist/adapters/langchain-mcp.d.ts +172 -0
- package/dist/adapters/langchain-mcp.d.ts.map +1 -0
- package/dist/adapters/langchain-mcp.js +145 -0
- package/dist/adapters/langchain-mcp.js.map +1 -0
- package/dist/adapters/mcp-client.d.ts +94 -0
- package/dist/adapters/mcp-client.d.ts.map +1 -0
- package/dist/adapters/mcp-client.js +91 -0
- package/dist/adapters/mcp-client.js.map +1 -0
- package/dist/adapters/vercel-ai-sdk-mcp.d.ts +129 -0
- package/dist/adapters/vercel-ai-sdk-mcp.d.ts.map +1 -0
- package/dist/adapters/vercel-ai-sdk-mcp.js +115 -0
- package/dist/adapters/vercel-ai-sdk-mcp.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +53 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +268 -0
- package/dist/middleware.js.map +1 -0
- package/dist/policy.d.ts +28 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +196 -0
- package/dist/policy.js.map +1 -0
- package/dist/session.d.ts +50 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +141 -0
- package/dist/session.js.map +1 -0
- package/dist/transaction.d.ts +52 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +123 -0
- package/dist/transaction.js.map +1 -0
- package/package.json +50 -0
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CreatorPolicyEntry, SessionPolicyRecord } from '@atrib/verify';
|
|
2
|
+
export type { CreatorPolicyEntry, SessionPolicyRecord };
|
|
3
|
+
/** A fetched policy document shape for the fetch/parse layer (§4.2). */
|
|
4
|
+
export interface PolicyDocument {
|
|
5
|
+
spec_version: string;
|
|
6
|
+
edge_weights?: Record<string, number>;
|
|
7
|
+
modifiers?: unknown[];
|
|
8
|
+
constraints?: {
|
|
9
|
+
minimum_share?: number;
|
|
10
|
+
maximum_share?: number;
|
|
11
|
+
minimum_own_share?: number;
|
|
12
|
+
maximum_total_share?: number;
|
|
13
|
+
};
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
/** Options for session initialization. */
|
|
17
|
+
export interface PolicyInitOptions {
|
|
18
|
+
contextId: string;
|
|
19
|
+
merchantDomain?: string | undefined;
|
|
20
|
+
/** Server URLs for all tools the agent intends to call. */
|
|
21
|
+
serverUrls?: string[] | undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Run session initialization: fetch policies and negotiate (§5.4.2).
|
|
25
|
+
* Must complete within 3 seconds.
|
|
26
|
+
*/
|
|
27
|
+
export declare function initializeSessionPolicy(options: PolicyInitOptions): Promise<SessionPolicyRecord>;
|
|
28
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAI5E,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,CAAA;AAMvD,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAA;IACrB,WAAW,CAAC,EAAE;QACZ,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAC7B,CAAA;IACD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAgDD,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;CAClC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CA4D9B"}
|
package/dist/policy.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Policy negotiation and session policy record (§4.5, §5.4.2, §5.4.6).
|
|
4
|
+
*/
|
|
5
|
+
import { sha256, hexEncode } from '@atrib/mcp';
|
|
6
|
+
import canonicalize from 'canonicalize';
|
|
7
|
+
const POLICY_FETCH_TIMEOUT_MS = 1000;
|
|
8
|
+
const INIT_BUDGET_MS = 3000;
|
|
9
|
+
const POLICY_PATH = '/.well-known/atrib-policy.json';
|
|
10
|
+
/**
|
|
11
|
+
* Fetch a policy document from a URL with timeout.
|
|
12
|
+
* Returns null on any error (404, timeout, parse error).
|
|
13
|
+
*/
|
|
14
|
+
async function fetchPolicy(url) {
|
|
15
|
+
try {
|
|
16
|
+
// Validate URL scheme to prevent SSRF via crafted merchantDomain/serverUrls
|
|
17
|
+
const parsed = new URL(url);
|
|
18
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:')
|
|
19
|
+
return null;
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
const timeoutId = setTimeout(() => controller.abort(), POLICY_FETCH_TIMEOUT_MS);
|
|
22
|
+
let response;
|
|
23
|
+
try {
|
|
24
|
+
response = await fetch(url, { signal: controller.signal });
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
clearTimeout(timeoutId);
|
|
28
|
+
}
|
|
29
|
+
if (!response.ok)
|
|
30
|
+
return null;
|
|
31
|
+
const doc = (await response.json());
|
|
32
|
+
// §4.5.2 Rule 6: reject contradictory constraints
|
|
33
|
+
if (doc.constraints) {
|
|
34
|
+
const { minimum_share, maximum_share } = doc.constraints;
|
|
35
|
+
if (minimum_share !== undefined &&
|
|
36
|
+
maximum_share !== undefined &&
|
|
37
|
+
minimum_share > maximum_share) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
// Reject negative values
|
|
41
|
+
for (const val of Object.values(doc.constraints)) {
|
|
42
|
+
if (typeof val === 'number' && val < 0)
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return doc;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Run session initialization: fetch policies and negotiate (§5.4.2).
|
|
54
|
+
* Must complete within 3 seconds.
|
|
55
|
+
*/
|
|
56
|
+
export async function initializeSessionPolicy(options) {
|
|
57
|
+
const warnings = [];
|
|
58
|
+
const startTime = Date.now();
|
|
59
|
+
// Step 1: Fetch merchant policy
|
|
60
|
+
let merchantPolicyDoc = null;
|
|
61
|
+
let merchantPolicyUrl = 'default';
|
|
62
|
+
if (options.merchantDomain) {
|
|
63
|
+
merchantPolicyUrl = `${options.merchantDomain}${POLICY_PATH}`;
|
|
64
|
+
merchantPolicyDoc = await fetchPolicy(merchantPolicyUrl);
|
|
65
|
+
if (!merchantPolicyDoc) {
|
|
66
|
+
merchantPolicyUrl = 'default';
|
|
67
|
+
warnings.push(`merchant policy not found at ${options.merchantDomain}${POLICY_PATH}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Step 2: Fetch creator policies concurrently (§5.4.2 step 4)
|
|
71
|
+
const creatorEntries = [];
|
|
72
|
+
if (options.serverUrls && options.serverUrls.length > 0) {
|
|
73
|
+
const fetches = options.serverUrls.map(async (serverUrl) => {
|
|
74
|
+
const policyUrl = `${serverUrl}${POLICY_PATH}`;
|
|
75
|
+
const doc = await fetchPolicy(policyUrl);
|
|
76
|
+
return { serverUrl, policyUrl, doc };
|
|
77
|
+
});
|
|
78
|
+
const results = await Promise.allSettled(fetches);
|
|
79
|
+
for (const result of results) {
|
|
80
|
+
if (result.status === 'fulfilled') {
|
|
81
|
+
const { serverUrl, policyUrl, doc } = result.value;
|
|
82
|
+
creatorEntries.push({
|
|
83
|
+
server_url: serverUrl,
|
|
84
|
+
policy_url: policyUrl,
|
|
85
|
+
status: doc ? 'compatible' : 'not_found',
|
|
86
|
+
...(doc ? { policy: doc } : {}),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Check init budget
|
|
92
|
+
if (Date.now() - startTime > INIT_BUDGET_MS) {
|
|
93
|
+
warnings.push('negotiation_skipped: session initialization exceeded 3-second budget');
|
|
94
|
+
return buildSessionPolicyRecord(options.contextId, 'default', creatorEntries, {}, warnings);
|
|
95
|
+
}
|
|
96
|
+
// Step 3: Conflict resolution (§4.5.2)
|
|
97
|
+
const { agreedPolicy, minimumFloors, negotiationWarnings } = negotiatePolicies(merchantPolicyDoc, merchantPolicyUrl, creatorEntries);
|
|
98
|
+
warnings.push(...negotiationWarnings);
|
|
99
|
+
return buildSessionPolicyRecord(options.contextId, agreedPolicy, creatorEntries, minimumFloors, warnings);
|
|
100
|
+
}
|
|
101
|
+
/** Run the 7-rule conflict resolution (§4.5.2). */
|
|
102
|
+
function negotiatePolicies(merchantPolicy, merchantPolicyUrl, creatorEntries) {
|
|
103
|
+
const warnings = [];
|
|
104
|
+
const minimumFloors = {};
|
|
105
|
+
const merchantCap = merchantPolicy?.constraints?.maximum_total_share;
|
|
106
|
+
// Collect creator floors
|
|
107
|
+
let floorSum = 0;
|
|
108
|
+
for (const entry of creatorEntries) {
|
|
109
|
+
if (entry.policy?.constraints?.minimum_own_share !== undefined) {
|
|
110
|
+
const floor = entry.policy.constraints.minimum_own_share;
|
|
111
|
+
minimumFloors[entry.server_url] = floor;
|
|
112
|
+
floorSum += floor;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Rule 5: Creator floors summing to >1.0 are irreconcilable
|
|
116
|
+
if (floorSum > 1.0) {
|
|
117
|
+
warnings.push(`creator minimum floors sum to ${floorSum} (>1.0), falling back to default policy. ` +
|
|
118
|
+
`Contributors: ${Object.keys(minimumFloors).join(', ')}`);
|
|
119
|
+
for (const entry of creatorEntries) {
|
|
120
|
+
if (entry.status === 'compatible' && entry.policy) {
|
|
121
|
+
entry.status = 'conflict_defaulted';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { agreedPolicy: 'default', minimumFloors: {}, negotiationWarnings: warnings };
|
|
125
|
+
}
|
|
126
|
+
// Rule 3: Check if single creator floor exceeds merchant cap (BEFORE scaling)
|
|
127
|
+
// Must check before Rule 2 scaling. a single floor > cap is irreconcilable
|
|
128
|
+
if (merchantCap !== undefined) {
|
|
129
|
+
for (const entry of creatorEntries) {
|
|
130
|
+
const floor = entry.policy?.constraints?.minimum_own_share;
|
|
131
|
+
if (floor !== undefined && floor > merchantCap) {
|
|
132
|
+
warnings.push(`creator ${entry.server_url} minimum floor ${floor} exceeds merchant cap ${merchantCap}, ` +
|
|
133
|
+
`falling back to default`);
|
|
134
|
+
// Only mark creators whose floor actually exceeds the cap as
|
|
135
|
+
// conflict_defaulted. creators with floors that fit are not at fault.
|
|
136
|
+
for (const e of creatorEntries) {
|
|
137
|
+
const eFloor = e.policy?.constraints?.minimum_own_share;
|
|
138
|
+
if (e.status !== 'not_found' && eFloor !== undefined && eFloor > merchantCap) {
|
|
139
|
+
e.status = 'conflict_defaulted';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { agreedPolicy: 'default', minimumFloors: {}, negotiationWarnings: warnings };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Rule 1 & 2: Merchant cap + creator floor scaling
|
|
147
|
+
// Multiple floors that individually fit the cap but sum > cap get scaled down proportionally
|
|
148
|
+
if (merchantCap !== undefined && floorSum > merchantCap) {
|
|
149
|
+
const scaleFactor = merchantCap / floorSum;
|
|
150
|
+
for (const [url, floor] of Object.entries(minimumFloors)) {
|
|
151
|
+
minimumFloors[url] = floor * scaleFactor;
|
|
152
|
+
}
|
|
153
|
+
warnings.push(`creator minimum floors scaled by ${scaleFactor.toFixed(4)} to fit merchant cap of ${merchantCap}`);
|
|
154
|
+
for (const entry of creatorEntries) {
|
|
155
|
+
if (entry.status === 'compatible' && minimumFloors[entry.server_url] !== undefined) {
|
|
156
|
+
entry.status = 'floor_scaled';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Rule 4: Edge weight disagreements. merchant governs (advisory only for creators)
|
|
161
|
+
const agreedPolicy = merchantPolicyUrl !== 'default' ? merchantPolicyUrl : 'default';
|
|
162
|
+
return { agreedPolicy, minimumFloors, negotiationWarnings: warnings };
|
|
163
|
+
}
|
|
164
|
+
/** Build the session policy record (§4.5.3). */
|
|
165
|
+
function buildSessionPolicyRecord(contextId, agreedPolicy, creatorEntries, minimumFloors, warnings) {
|
|
166
|
+
// Build the record without record_id first, then compute it
|
|
167
|
+
const record = {
|
|
168
|
+
spec_version: 'atrib/1.0',
|
|
169
|
+
record_id: '', // placeholder
|
|
170
|
+
context_id: contextId,
|
|
171
|
+
created_at: Date.now(),
|
|
172
|
+
merchant_policy: agreedPolicy === 'default' ? 'default' : agreedPolicy,
|
|
173
|
+
creator_policies: creatorEntries.map(({ server_url, policy_url, status }) => ({
|
|
174
|
+
server_url,
|
|
175
|
+
policy_url,
|
|
176
|
+
status,
|
|
177
|
+
})),
|
|
178
|
+
agreed_policy: agreedPolicy,
|
|
179
|
+
applied_constraints: {
|
|
180
|
+
minimum_floors: minimumFloors,
|
|
181
|
+
},
|
|
182
|
+
warnings,
|
|
183
|
+
};
|
|
184
|
+
// Compute record_id = sha256 of JCS canonical form, excluding record_id
|
|
185
|
+
// and warnings (warnings are mutable. runtime warnings are appended after
|
|
186
|
+
// negotiation, so including them would make record_id stale).
|
|
187
|
+
const { record_id: _, warnings: _w, ...forHashing } = record;
|
|
188
|
+
const canonical = canonicalize(forHashing);
|
|
189
|
+
if (canonical) {
|
|
190
|
+
const encoder = new TextEncoder();
|
|
191
|
+
const hash = sha256(encoder.encode(canonical));
|
|
192
|
+
record.record_id = `sha256:${hexEncode(hash)}`;
|
|
193
|
+
}
|
|
194
|
+
return record;
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { GapNode } from '@atrib/verify';
|
|
2
|
+
/** The latest attribution context from the most recent tool response. */
|
|
3
|
+
export interface LatestContext {
|
|
4
|
+
recordHash: Uint8Array;
|
|
5
|
+
creatorKey: Uint8Array;
|
|
6
|
+
}
|
|
7
|
+
/** Mutable session state, evolved by each tool call/response. */
|
|
8
|
+
export interface SessionState {
|
|
9
|
+
contextId: string;
|
|
10
|
+
sessionToken: string;
|
|
11
|
+
latestContext: LatestContext | null;
|
|
12
|
+
initialized: boolean;
|
|
13
|
+
/** The record_id from the session policy record, set after init. */
|
|
14
|
+
policyRecordId: string | null;
|
|
15
|
+
/** Task IDs from tasks/create responses (§5.7). */
|
|
16
|
+
taskIds: Set<string>;
|
|
17
|
+
/** Unsigned hops recorded during this session (§1.6). */
|
|
18
|
+
gapNodes: GapNode[];
|
|
19
|
+
warnings: string[];
|
|
20
|
+
}
|
|
21
|
+
/** Options for creating a session. */
|
|
22
|
+
export interface SessionOptions {
|
|
23
|
+
/** Session token for cross-trace linking. Auto-generated if absent. */
|
|
24
|
+
sessionToken?: string | undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a new session state.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createSession(options: SessionOptions): SessionState;
|
|
30
|
+
/**
|
|
31
|
+
* Build the outbound _meta for a tools/call request (§5.4.3).
|
|
32
|
+
* Attaches attribution context, traceparent, session_token, and policy record ID.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Build the outbound _meta for a tools/call request (§5.4.3).
|
|
36
|
+
* Attaches attribution context, traceparent, session_token, and policy record ID.
|
|
37
|
+
*
|
|
38
|
+
* Merges with the caller's existing _meta:
|
|
39
|
+
* - `baggage` and `tracestate` are APPENDED (W3C semantics, multi-vendor safe)
|
|
40
|
+
* - `traceparent` is overwritten only if the caller has not supplied one
|
|
41
|
+
* - `atrib` and `X-Atrib-Chain` are set (atrib-owned keys)
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildOutboundMeta(session: SessionState, existing?: Record<string, unknown>): Record<string, string>;
|
|
44
|
+
/**
|
|
45
|
+
* Read inbound attribution context from a tool response (§5.4.4).
|
|
46
|
+
* Updates session state with the latest context.
|
|
47
|
+
* Returns true if an attribution token was found.
|
|
48
|
+
*/
|
|
49
|
+
export declare function accumulateInboundContext(session: SessionState, responseMeta: Record<string, unknown> | undefined): boolean;
|
|
50
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE5C,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAA;IACtB,UAAU,EAAE,UAAU,CAAA;CACvB;AAED,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,aAAa,GAAG,IAAI,CAAA;IACnC,WAAW,EAAE,OAAO,CAAA;IACpB,oEAAoE;IACpE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,mDAAmD;IACnD,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACpB,yDAAyD;IACzD,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAClC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,YAAY,CA0BnE;AAED;;;GAGG;AACH;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmDxB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,YAAY,EACrB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAChD,OAAO,CAwCT"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Agent session state management (§5.4).
|
|
4
|
+
*
|
|
5
|
+
* Tracks the latest attribution context across sequential tool calls
|
|
6
|
+
* within a session. The session is initialized lazily on the first
|
|
7
|
+
* outbound tool call.
|
|
8
|
+
*/
|
|
9
|
+
import { base64urlEncode, hexEncode, decodeToken, mergeTracestate, mergeBaggageAtribSession, } from '@atrib/mcp';
|
|
10
|
+
/**
|
|
11
|
+
* Create a new session state.
|
|
12
|
+
*/
|
|
13
|
+
export function createSession(options) {
|
|
14
|
+
// Generate context_id (random 16-byte hex if no OTel trace available)
|
|
15
|
+
const contextIdBytes = new Uint8Array(16);
|
|
16
|
+
crypto.getRandomValues(contextIdBytes);
|
|
17
|
+
const contextId = hexEncode(contextIdBytes);
|
|
18
|
+
// Generate or use provided session_token
|
|
19
|
+
let sessionToken;
|
|
20
|
+
if (options.sessionToken) {
|
|
21
|
+
sessionToken = options.sessionToken;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const tokenBytes = new Uint8Array(16);
|
|
25
|
+
crypto.getRandomValues(tokenBytes);
|
|
26
|
+
sessionToken = base64urlEncode(tokenBytes);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
contextId,
|
|
30
|
+
sessionToken,
|
|
31
|
+
latestContext: null,
|
|
32
|
+
initialized: false,
|
|
33
|
+
policyRecordId: null,
|
|
34
|
+
taskIds: new Set(),
|
|
35
|
+
gapNodes: [],
|
|
36
|
+
warnings: [],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the outbound _meta for a tools/call request (§5.4.3).
|
|
41
|
+
* Attaches attribution context, traceparent, session_token, and policy record ID.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Build the outbound _meta for a tools/call request (§5.4.3).
|
|
45
|
+
* Attaches attribution context, traceparent, session_token, and policy record ID.
|
|
46
|
+
*
|
|
47
|
+
* Merges with the caller's existing _meta:
|
|
48
|
+
* - `baggage` and `tracestate` are APPENDED (W3C semantics, multi-vendor safe)
|
|
49
|
+
* - `traceparent` is overwritten only if the caller has not supplied one
|
|
50
|
+
* - `atrib` and `X-Atrib-Chain` are set (atrib-owned keys)
|
|
51
|
+
*/
|
|
52
|
+
export function buildOutboundMeta(session, existing = {}) {
|
|
53
|
+
const meta = {};
|
|
54
|
+
// §1.5.3.1: Set X-atrib-Context on every outbound request.
|
|
55
|
+
// The value is the raw 32-char hex context_id (not the propagation token).
|
|
56
|
+
meta['X-atrib-Context'] = session.contextId;
|
|
57
|
+
// §1.5.4: traceparent. only set if caller has not provided one.
|
|
58
|
+
// If they have one, the trace-id should already match session.contextId
|
|
59
|
+
// (since the session adopted it), so we leave it untouched.
|
|
60
|
+
if (typeof existing.traceparent === 'string') {
|
|
61
|
+
meta.traceparent = existing.traceparent;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const parentIdBytes = new Uint8Array(8);
|
|
65
|
+
crypto.getRandomValues(parentIdBytes);
|
|
66
|
+
const parentId = hexEncode(parentIdBytes);
|
|
67
|
+
meta.traceparent = `00-${session.contextId}-${parentId}-01`;
|
|
68
|
+
}
|
|
69
|
+
// §5.4.3: baggage gets atrib-session prepended (most-recent vendor first
|
|
70
|
+
// per W3C). mergeBaggageAtribSession dedupes prior atrib-session entries
|
|
71
|
+
// and enforces the W3C 64-list-member and 8192-byte limits, evicting
|
|
72
|
+
// entries from the rightmost end if needed.
|
|
73
|
+
//
|
|
74
|
+
// policy is added as a separate, non-evictable entry. We add it after the
|
|
75
|
+
// session merge to ensure both atrib entries are leftmost.
|
|
76
|
+
const existingBaggage = typeof existing.baggage === 'string' ? existing.baggage : '';
|
|
77
|
+
let baggage = mergeBaggageAtribSession(session.sessionToken, existingBaggage);
|
|
78
|
+
if (session.policyRecordId) {
|
|
79
|
+
baggage = `atrib-policy=${session.policyRecordId},${baggage}`;
|
|
80
|
+
}
|
|
81
|
+
meta.baggage = baggage;
|
|
82
|
+
// Attach latest attribution token if available
|
|
83
|
+
if (session.latestContext) {
|
|
84
|
+
const token = `${base64urlEncode(session.latestContext.recordHash)}.${base64urlEncode(session.latestContext.creatorKey)}`;
|
|
85
|
+
meta.atrib = token;
|
|
86
|
+
meta['X-Atrib-Chain'] = token;
|
|
87
|
+
// §5.4.3: tracestate gets `atrib=<token>` PREPENDED so atrib appears
|
|
88
|
+
// leftmost (W3C "most recent vendor first" convention). mergeTracestate
|
|
89
|
+
// dedupes any prior atrib entry and enforces the W3C 32-list-member
|
|
90
|
+
// maximum, evicting from the rightmost end if needed.
|
|
91
|
+
const existingTracestate = typeof existing.tracestate === 'string' ? existing.tracestate : '';
|
|
92
|
+
meta.tracestate = mergeTracestate(`atrib=${token}`, existingTracestate);
|
|
93
|
+
}
|
|
94
|
+
else if (typeof existing.tracestate === 'string') {
|
|
95
|
+
// Preserve caller's tracestate if no atrib token to add
|
|
96
|
+
meta.tracestate = existing.tracestate;
|
|
97
|
+
}
|
|
98
|
+
return meta;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Read inbound attribution context from a tool response (§5.4.4).
|
|
102
|
+
* Updates session state with the latest context.
|
|
103
|
+
* Returns true if an attribution token was found.
|
|
104
|
+
*/
|
|
105
|
+
export function accumulateInboundContext(session, responseMeta) {
|
|
106
|
+
if (!responseMeta)
|
|
107
|
+
return false;
|
|
108
|
+
// Priority: _meta.atrib > tracestate atrib= > X-Atrib-Chain
|
|
109
|
+
let decoded = null;
|
|
110
|
+
if (typeof responseMeta.atrib === 'string') {
|
|
111
|
+
decoded = decodeToken(responseMeta.atrib);
|
|
112
|
+
}
|
|
113
|
+
if (!decoded && typeof responseMeta.tracestate === 'string') {
|
|
114
|
+
// W3C Trace Context list-member grammar allows OWS around `=`. Be lenient
|
|
115
|
+
// about whitespace and accept the entry whether it's leftmost or not.
|
|
116
|
+
for (const entry of responseMeta.tracestate.split(',')) {
|
|
117
|
+
const trimmed = entry.trim();
|
|
118
|
+
const match = trimmed.match(/^atrib\s*=\s*(.*)$/);
|
|
119
|
+
if (match && match[1] !== undefined) {
|
|
120
|
+
decoded = decodeToken(match[1].trim());
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (!decoded) {
|
|
126
|
+
const xAtribChain = responseMeta['X-Atrib-Chain'] ?? responseMeta['x-atrib-chain'];
|
|
127
|
+
if (typeof xAtribChain === 'string') {
|
|
128
|
+
decoded = decodeToken(xAtribChain);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (decoded) {
|
|
132
|
+
session.latestContext = {
|
|
133
|
+
recordHash: decoded.recordHash,
|
|
134
|
+
creatorKey: decoded.creatorKey,
|
|
135
|
+
};
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
// No token → tool doesn't have @atrib/mcp. Gap node in graph. Session continues.
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction detection (§5.4.5).
|
|
3
|
+
*
|
|
4
|
+
* Detects transaction events from response shapes for ACP, UCP, x402, MPP,
|
|
5
|
+
* AP2, and heuristic tool name matching.
|
|
6
|
+
*
|
|
7
|
+
* Protocol shape sources (verified 2026-04-06):
|
|
8
|
+
* - ACP: github.com/agentic-commerce-protocol/agentic-commerce-protocol
|
|
9
|
+
* rfcs/rfc.agentic_checkout.md
|
|
10
|
+
* - UCP: github.com/universal-commerce-protocol/ucp
|
|
11
|
+
* docs/specification/checkout-rest.md (version 2026-01-11)
|
|
12
|
+
* - AP2: github.com/google-agentic-commerce/ap2 (v0.1). A2A Message with a
|
|
13
|
+
* DataPart containing the key `ap2.mandates.PaymentMandate`. AP2 does
|
|
14
|
+
* NOT currently use W3C Verifiable Credentials despite earlier drafts
|
|
15
|
+
* of this code and the atrib spec assuming it would.
|
|
16
|
+
* - a2a-x402: github.com/google-agentic-commerce/a2a-x402. extension that
|
|
17
|
+
* layers x402 crypto payments over A2A. Detection signal is
|
|
18
|
+
* `status.message.metadata["x402.payment.status"] === "payment-completed"`
|
|
19
|
+
* with at least one `success: true` entry in
|
|
20
|
+
* `status.message.metadata["x402.payment.receipts"]`. Both shapes are
|
|
21
|
+
* reported as `protocol: 'AP2'` since a2a-x402 IS the AP2 crypto path.
|
|
22
|
+
* - x402: github.com/coinbase/x402. response header `PAYMENT-RESPONSE` (v2)
|
|
23
|
+
* or `X-PAYMENT-RESPONSE` (v1 legacy). Value is base64-encoded JSON
|
|
24
|
+
* with shape { success: bool, transaction, network, payer, requirements }.
|
|
25
|
+
* - MPP: IETF draft-ryan-httpauth-payment-01 ("The 'Payment' HTTP Authentication
|
|
26
|
+
* Scheme"), per Section 5.3. Response header is `Payment-Receipt` on a
|
|
27
|
+
* 200 success after the client retries with Authorization: Payment.
|
|
28
|
+
* Value is base64url-nopad JSON with required field { status: "success",
|
|
29
|
+
* method, timestamp, reference }.
|
|
30
|
+
*
|
|
31
|
+
* x402 and MPP are DIFFERENT protocols that use DIFFERENT headers. Earlier
|
|
32
|
+
* versions of this code conflated them on a fictitious shared `Payment-Receipt`
|
|
33
|
+
* header. see DECISIONS.md D016 for the verification trail.
|
|
34
|
+
*/
|
|
35
|
+
export type TransactionProtocol = 'ACP' | 'UCP' | 'x402' | 'MPP' | 'AP2' | 'heuristic';
|
|
36
|
+
export interface TransactionDetection {
|
|
37
|
+
detected: boolean;
|
|
38
|
+
protocol: TransactionProtocol | null;
|
|
39
|
+
/**
|
|
40
|
+
* For Path 2 content_id derivation (§5.4.5):
|
|
41
|
+
* - ACP/UCP: the order permalink URL from the response (if present)
|
|
42
|
+
* - x402/MPP: not available here (caller must use HTTP endpoint URL)
|
|
43
|
+
* - AP2: not available here (caller uses MCP server URL)
|
|
44
|
+
* - Heuristic: not available here (caller uses MCP server URL)
|
|
45
|
+
*/
|
|
46
|
+
checkoutUrl: string | null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Detect whether a tool call response contains a transaction signal (§5.4.5).
|
|
50
|
+
*/
|
|
51
|
+
export declare function detectTransaction(toolName: string, response: unknown, headers?: Record<string, string | undefined>): TransactionDetection;
|
|
52
|
+
//# sourceMappingURL=transaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAA;AAEtF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAA;IACpC;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAWD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,EACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC3C,oBAAoB,CAkItB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
const HEURISTIC_KEYWORDS = [
|
|
3
|
+
'create_order',
|
|
4
|
+
'complete_checkout',
|
|
5
|
+
'process_payment',
|
|
6
|
+
'place_order',
|
|
7
|
+
'purchase',
|
|
8
|
+
'checkout',
|
|
9
|
+
];
|
|
10
|
+
/**
|
|
11
|
+
* Detect whether a tool call response contains a transaction signal (§5.4.5).
|
|
12
|
+
*/
|
|
13
|
+
export function detectTransaction(toolName, response, headers) {
|
|
14
|
+
const resp = response;
|
|
15
|
+
// ACP / UCP completion response shape:
|
|
16
|
+
// { id: "...", status: "completed", order: { id, permalink_url? }, ... }
|
|
17
|
+
// UCP additionally has a top-level `ucp: { version, capabilities }` envelope.
|
|
18
|
+
// Both shapes are produced by POST /checkout_sessions/{id}/complete (ACP)
|
|
19
|
+
// or POST /checkout-sessions/{id}/complete (UCP).
|
|
20
|
+
if (resp) {
|
|
21
|
+
const status = resp['status'];
|
|
22
|
+
const order = resp['order'];
|
|
23
|
+
if (status === 'completed' && order && typeof order['id'] === 'string') {
|
|
24
|
+
const ucpEnvelope = resp['ucp'];
|
|
25
|
+
const isUcp = !!ucpEnvelope && typeof ucpEnvelope['version'] === 'string';
|
|
26
|
+
const checkoutUrl = typeof order['permalink_url'] === 'string' ? order['permalink_url'] : null;
|
|
27
|
+
return { detected: true, protocol: isUcp ? 'UCP' : 'ACP', checkoutUrl };
|
|
28
|
+
}
|
|
29
|
+
// ACP webhook event shapes (server → merchant): order_create / order_update.
|
|
30
|
+
// { type: "order_create", data: { type: "order", checkout_session_id, permalink_url, status, refunds } }
|
|
31
|
+
if (resp['type'] === 'order_create' || resp['type'] === 'order_update') {
|
|
32
|
+
const data = resp['data'];
|
|
33
|
+
const checkoutUrl = typeof data?.['permalink_url'] === 'string' ? data['permalink_url'] : null;
|
|
34
|
+
return { detected: true, protocol: 'ACP', checkoutUrl };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// x402 and MPP: distinct protocols, distinct response headers.
|
|
38
|
+
//
|
|
39
|
+
// x402 v2 → PAYMENT-RESPONSE (renamed from v1 X-PAYMENT-RESPONSE)
|
|
40
|
+
// MPP → Payment-Receipt (per draft-ryan-httpauth-payment-01 §5.3)
|
|
41
|
+
//
|
|
42
|
+
// HTTP header names are case-insensitive per RFC 7230, so we accept any
|
|
43
|
+
// letter casing. JS object keys are not case-insensitive, so we lower-case
|
|
44
|
+
// the lookup table once and probe by lowercase key.
|
|
45
|
+
if (headers) {
|
|
46
|
+
const lower = {};
|
|
47
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
48
|
+
if (typeof v === 'string')
|
|
49
|
+
lower[k.toLowerCase()] = v;
|
|
50
|
+
}
|
|
51
|
+
// x402. accept v2 and v1 names
|
|
52
|
+
if (lower['payment-response'] || lower['x-payment-response']) {
|
|
53
|
+
return { detected: true, protocol: 'x402', checkoutUrl: null };
|
|
54
|
+
}
|
|
55
|
+
// MPP. IETF draft Payment-Receipt header
|
|
56
|
+
if (lower['payment-receipt']) {
|
|
57
|
+
return { detected: true, protocol: 'MPP', checkoutUrl: null };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// AP2 v0.1. PaymentMandate Message inside an A2A DataPart.
|
|
61
|
+
// Source: github.com/google-agentic-commerce/ap2 docs/specification.md
|
|
62
|
+
// Shape: { ..., parts: [{ kind: "data", data: { "ap2.mandates.PaymentMandate": {...} } }, ...] }
|
|
63
|
+
if (resp) {
|
|
64
|
+
const parts = resp['parts'];
|
|
65
|
+
if (Array.isArray(parts)) {
|
|
66
|
+
for (const part of parts) {
|
|
67
|
+
if (part && typeof part === 'object') {
|
|
68
|
+
const data = part['data'];
|
|
69
|
+
if (data &&
|
|
70
|
+
typeof data === 'object' &&
|
|
71
|
+
'ap2.mandates.PaymentMandate' in data) {
|
|
72
|
+
return { detected: true, protocol: 'AP2', checkoutUrl: null };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// a2a-x402 extension. payment-completed via A2A task status metadata.
|
|
78
|
+
// Source: github.com/google-agentic-commerce/a2a-x402 spec/v0.1/spec.md
|
|
79
|
+
// Shape: { kind: "task", status: { message: { metadata: { "x402.payment.status": "payment-completed", "x402.payment.receipts": [{success, transaction, ...}] } } } }
|
|
80
|
+
// Guard on kind === "task" to prevent false positives from responses
|
|
81
|
+
// that incidentally contain matching metadata keys.
|
|
82
|
+
if (resp['kind'] === 'task') {
|
|
83
|
+
const status = resp['status'];
|
|
84
|
+
const statusMessage = status?.['message'];
|
|
85
|
+
const metadata = statusMessage?.['metadata'];
|
|
86
|
+
if (metadata && metadata['x402.payment.status'] === 'payment-completed') {
|
|
87
|
+
const receipts = metadata['x402.payment.receipts'];
|
|
88
|
+
if (Array.isArray(receipts) &&
|
|
89
|
+
receipts.some((r) => r !== null &&
|
|
90
|
+
typeof r === 'object' &&
|
|
91
|
+
r['success'] === true)) {
|
|
92
|
+
return { detected: true, protocol: 'AP2', checkoutUrl: null };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Legacy: W3C Verifiable Credential PaymentMandate. AP2 v0.1 does NOT use
|
|
97
|
+
// VCs, but research forks and earlier drafts may. Kept as a backward-
|
|
98
|
+
// compatible fallback. Accepts both VC v2 array form and v1 string form.
|
|
99
|
+
const respType = resp['type'];
|
|
100
|
+
const credentialSubject = resp['credentialSubject'];
|
|
101
|
+
const subjectType = credentialSubject?.['type'];
|
|
102
|
+
const isVcArray = Array.isArray(respType) &&
|
|
103
|
+
respType.includes('VerifiableCredential') &&
|
|
104
|
+
respType.some((t) => typeof t === 'string' && /paymentmandate/i.test(t));
|
|
105
|
+
const isVcStringLegacy = respType === 'VerifiableCredential';
|
|
106
|
+
const subjectIsPaymentMandate = (typeof subjectType === 'string' && /paymentmandate/i.test(subjectType)) ||
|
|
107
|
+
(Array.isArray(subjectType) &&
|
|
108
|
+
subjectType.some((t) => typeof t === 'string' && /paymentmandate/i.test(t)));
|
|
109
|
+
// For v2 array form: the PaymentMandate type is in the type array itself,
|
|
110
|
+
// so no credentialSubject check needed. For v1 string form: type is just
|
|
111
|
+
// "VerifiableCredential" so we need credentialSubject to confirm it's a PaymentMandate.
|
|
112
|
+
if (isVcArray || (isVcStringLegacy && subjectIsPaymentMandate)) {
|
|
113
|
+
return { detected: true, protocol: 'AP2', checkoutUrl: null };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Heuristic: tool name keywords (last resort)
|
|
117
|
+
const lowerName = toolName.toLowerCase();
|
|
118
|
+
if (HEURISTIC_KEYWORDS.some((k) => lowerName.includes(k))) {
|
|
119
|
+
return { detected: true, protocol: 'heuristic', checkoutUrl: null };
|
|
120
|
+
}
|
|
121
|
+
return { detected: false, protocol: null, checkoutUrl: null };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=transaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"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"}
|