@aura-labs-ai/scout 0.2.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/README.md +237 -0
- package/bin/scout-cli.js +325 -0
- package/examples/basic-purchase.js +112 -0
- package/examples/protocol-integration.js +294 -0
- package/package.json +63 -0
- package/src/activity.js +420 -0
- package/src/ap2/mandates.js +366 -0
- package/src/client.js +217 -0
- package/src/errors.js +66 -0
- package/src/index.js +655 -0
- package/src/intent-session.js +233 -0
- package/src/key-manager.js +204 -0
- package/src/key-manager.test.js +293 -0
- package/src/mcp/client.js +458 -0
- package/src/session.js +603 -0
- package/src/tap/visa.js +345 -0
- package/src/tests/README.md +157 -0
- package/src/tests/ap2-mandates.test.js +413 -0
- package/src/tests/intent-session.test.js +292 -0
- package/src/tests/mcp-client.test.js +224 -0
- package/src/tests/ping.test.js +282 -0
- package/src/tests/run-protocol-tests.js +57 -0
- package/src/tests/scenarios/ap2-scenarios.test.js +422 -0
- package/src/tests/scenarios/index.js +60 -0
- package/src/tests/scenarios/integration-scenarios.test.js +514 -0
- package/src/tests/scenarios/mcp-scenarios.test.js +419 -0
- package/src/tests/scenarios/tap-scenarios.test.js +461 -0
- package/src/tests/visa-tap.test.js +376 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-End Integration Scenario Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests that verify MCP, AP2, and Visa TAP work together in realistic
|
|
5
|
+
* agentic commerce flows.
|
|
6
|
+
*
|
|
7
|
+
* Run:
|
|
8
|
+
* node --test src/tests/scenarios/integration-scenarios.test.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { test, describe } from 'node:test';
|
|
12
|
+
import assert from 'node:assert';
|
|
13
|
+
import { MCPClient } from '../../mcp/client.js';
|
|
14
|
+
import { AP2Mandates, generateKeyPair as generateAP2KeyPair } from '../../ap2/mandates.js';
|
|
15
|
+
import { VisaTAP } from '../../tap/visa.js';
|
|
16
|
+
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Test Setup
|
|
19
|
+
// =============================================================================
|
|
20
|
+
|
|
21
|
+
const userKeys = generateAP2KeyPair();
|
|
22
|
+
const agentKeyPair = VisaTAP.generateKeyPair();
|
|
23
|
+
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Scenario 1: Complete Shopping Flow with All Protocols
|
|
26
|
+
// =============================================================================
|
|
27
|
+
|
|
28
|
+
describe('Scenario: Complete Agentic Shopping Flow', () => {
|
|
29
|
+
// Shared state across test steps
|
|
30
|
+
let mcpClient;
|
|
31
|
+
let tapRegistration;
|
|
32
|
+
let tapCredentials;
|
|
33
|
+
let intentMandate;
|
|
34
|
+
let cartMandate;
|
|
35
|
+
let paymentMandate;
|
|
36
|
+
let signedPaymentRequest;
|
|
37
|
+
|
|
38
|
+
test('Step 1: Initialize MCP client for external context', () => {
|
|
39
|
+
mcpClient = new MCPClient({
|
|
40
|
+
clientInfo: {
|
|
41
|
+
name: 'shopping-scout',
|
|
42
|
+
version: '1.0.0',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
assert.strictEqual(mcpClient.isConnected, false);
|
|
47
|
+
assert.ok(mcpClient.capabilities.tools);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('Step 2: Register agent with Visa TAP', async () => {
|
|
51
|
+
tapRegistration = await VisaTAP.register({
|
|
52
|
+
agentId: 'integrated-shopping-scout',
|
|
53
|
+
publicKey: agentKeyPair.publicKey,
|
|
54
|
+
metadata: {
|
|
55
|
+
name: 'Integrated Shopping Scout',
|
|
56
|
+
operator: 'AURA Labs',
|
|
57
|
+
capabilities: ['shopping', 'comparison', 'checkout', 'payments'],
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
tapCredentials = VisaTAP.createCredentials({
|
|
62
|
+
tapId: tapRegistration.tapId,
|
|
63
|
+
keyPair: agentKeyPair,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
assert.ok(tapRegistration.tapId);
|
|
67
|
+
assert.strictEqual(tapRegistration.status, 'active');
|
|
68
|
+
assert.ok(tapCredentials.keyId);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('Step 3: User creates intent mandate authorizing agent', async () => {
|
|
72
|
+
intentMandate = await AP2Mandates.createIntent({
|
|
73
|
+
agentId: tapRegistration.tapId, // Use TAP ID as agent identifier
|
|
74
|
+
userId: 'user-integrated-001',
|
|
75
|
+
userKey: userKeys.privateKey,
|
|
76
|
+
constraints: {
|
|
77
|
+
maxAmount: 1000,
|
|
78
|
+
currency: 'USD',
|
|
79
|
+
categories: ['electronics', 'office-supplies'],
|
|
80
|
+
validUntil: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
|
|
81
|
+
},
|
|
82
|
+
metadata: {
|
|
83
|
+
purpose: 'Work laptop accessories',
|
|
84
|
+
tapRegistration: tapRegistration.tapId,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
assert.strictEqual(intentMandate.type, 'intent');
|
|
89
|
+
assert.strictEqual(intentMandate.subject.id, tapRegistration.tapId);
|
|
90
|
+
assert.ok(intentMandate.proof.proofValue);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('Step 4: Agent discovers offer and validates against mandate', () => {
|
|
94
|
+
// Simulate offer from a Beacon
|
|
95
|
+
const offer = {
|
|
96
|
+
id: 'offer-int-001',
|
|
97
|
+
beaconId: 'beacon-office-depot',
|
|
98
|
+
beaconName: 'Office Depot',
|
|
99
|
+
product: { name: 'USB-C Hub', sku: 'USB-HUB-7P' },
|
|
100
|
+
unitPrice: 49.99,
|
|
101
|
+
quantity: 2,
|
|
102
|
+
totalPrice: 99.98,
|
|
103
|
+
currency: 'USD',
|
|
104
|
+
deliveryDate: '2026-02-20',
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
108
|
+
totalAmount: offer.totalPrice,
|
|
109
|
+
currency: offer.currency,
|
|
110
|
+
category: 'electronics',
|
|
111
|
+
merchantId: offer.beaconId,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
assert.strictEqual(validation.valid, true);
|
|
115
|
+
assert.strictEqual(validation.errors.length, 0);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('Step 5: User approves purchase with cart mandate', async () => {
|
|
119
|
+
const offer = {
|
|
120
|
+
id: 'offer-int-001',
|
|
121
|
+
beaconId: 'beacon-office-depot',
|
|
122
|
+
beaconName: 'Office Depot',
|
|
123
|
+
product: { name: 'USB-C Hub', sku: 'USB-HUB-7P' },
|
|
124
|
+
unitPrice: 49.99,
|
|
125
|
+
quantity: 2,
|
|
126
|
+
totalPrice: 99.98,
|
|
127
|
+
currency: 'USD',
|
|
128
|
+
deliveryDate: '2026-02-20',
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
cartMandate = await AP2Mandates.createCart({
|
|
132
|
+
sessionId: 'session-integrated-001',
|
|
133
|
+
offer,
|
|
134
|
+
userKey: userKeys.privateKey,
|
|
135
|
+
userId: 'user-integrated-001',
|
|
136
|
+
intentMandateId: intentMandate.id,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
assert.strictEqual(cartMandate.type, 'cart');
|
|
140
|
+
assert.strictEqual(cartMandate.intentMandateRef, intentMandate.id);
|
|
141
|
+
assert.strictEqual(cartMandate.cart.totalAmount, 99.98);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('Step 6: Agent creates payment mandate with TAP credentials', async () => {
|
|
145
|
+
paymentMandate = await AP2Mandates.createPayment({
|
|
146
|
+
cartMandate,
|
|
147
|
+
paymentMethod: { type: 'card', network: 'visa' },
|
|
148
|
+
agentId: tapRegistration.tapId,
|
|
149
|
+
agentKey: agentKeyPair.privateKey,
|
|
150
|
+
tapCredentials: {
|
|
151
|
+
tapId: tapRegistration.tapId,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
assert.strictEqual(paymentMandate.type, 'payment');
|
|
156
|
+
assert.strictEqual(paymentMandate.cartMandateRef, cartMandate.id);
|
|
157
|
+
assert.strictEqual(paymentMandate.agent.tapId, tapRegistration.tapId);
|
|
158
|
+
assert.strictEqual(paymentMandate.paymentMethod.network, 'visa');
|
|
159
|
+
assert.ok(paymentMandate.riskSignals.intentMandatePresent);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('Step 7: Sign payment request with Visa TAP', async () => {
|
|
163
|
+
const paymentRequest = {
|
|
164
|
+
method: 'POST',
|
|
165
|
+
url: 'https://payments.visa.com/api/v1/process',
|
|
166
|
+
headers: {
|
|
167
|
+
'Content-Type': 'application/json',
|
|
168
|
+
},
|
|
169
|
+
body: {
|
|
170
|
+
amount: paymentMandate.transaction.amount,
|
|
171
|
+
currency: paymentMandate.transaction.currency,
|
|
172
|
+
merchantId: paymentMandate.transaction.merchantId,
|
|
173
|
+
mandateChain: {
|
|
174
|
+
paymentMandateId: paymentMandate.id,
|
|
175
|
+
cartMandateId: paymentMandate.cartMandateRef,
|
|
176
|
+
intentMandateRef: cartMandate.intentMandateRef,
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
signedPaymentRequest = await VisaTAP.signRequest(paymentRequest, tapCredentials);
|
|
182
|
+
|
|
183
|
+
assert.strictEqual(signedPaymentRequest.headers['X-TAP-Agent-Id'], tapCredentials.tapId);
|
|
184
|
+
assert.ok(signedPaymentRequest.headers['X-TAP-Timestamp']);
|
|
185
|
+
assert.ok(signedPaymentRequest.headers['X-TAP-Nonce']);
|
|
186
|
+
assert.ok(signedPaymentRequest.headers['Signature']);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('Step 8: Verify complete audit trail', () => {
|
|
190
|
+
// Intent -> Cart -> Payment chain
|
|
191
|
+
assert.strictEqual(cartMandate.intentMandateRef, intentMandate.id);
|
|
192
|
+
assert.strictEqual(paymentMandate.cartMandateRef, cartMandate.id);
|
|
193
|
+
|
|
194
|
+
// TAP identity flows through
|
|
195
|
+
assert.strictEqual(intentMandate.subject.id, tapRegistration.tapId);
|
|
196
|
+
assert.strictEqual(paymentMandate.agent.tapId, tapRegistration.tapId);
|
|
197
|
+
assert.strictEqual(signedPaymentRequest.headers['X-TAP-Agent-Id'], tapRegistration.tapId);
|
|
198
|
+
|
|
199
|
+
// All cryptographic proofs present
|
|
200
|
+
assert.ok(intentMandate.proof.proofValue);
|
|
201
|
+
assert.ok(cartMandate.proof.proofValue);
|
|
202
|
+
assert.ok(paymentMandate.proof.proofValue);
|
|
203
|
+
assert.ok(signedPaymentRequest.headers['Signature']);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// =============================================================================
|
|
208
|
+
// Scenario 2: Multi-Offer Comparison with Constraints
|
|
209
|
+
// =============================================================================
|
|
210
|
+
|
|
211
|
+
describe('Scenario: Multi-Offer Comparison with Mandate Constraints', () => {
|
|
212
|
+
let intentMandate;
|
|
213
|
+
|
|
214
|
+
test('Setup: Create restrictive intent mandate', async () => {
|
|
215
|
+
intentMandate = await AP2Mandates.createIntent({
|
|
216
|
+
agentId: 'comparison-scout',
|
|
217
|
+
userId: 'user-comparison-001',
|
|
218
|
+
userKey: userKeys.privateKey,
|
|
219
|
+
constraints: {
|
|
220
|
+
maxAmount: 200,
|
|
221
|
+
currency: 'USD',
|
|
222
|
+
categories: ['office-supplies'],
|
|
223
|
+
merchantBlocklist: ['sketchy-vendor'],
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test('Agent filters multiple offers against mandate', () => {
|
|
229
|
+
const offers = [
|
|
230
|
+
{
|
|
231
|
+
id: 'offer-1',
|
|
232
|
+
beaconId: 'good-vendor',
|
|
233
|
+
totalPrice: 150,
|
|
234
|
+
currency: 'USD',
|
|
235
|
+
category: 'office-supplies',
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: 'offer-2',
|
|
239
|
+
beaconId: 'expensive-vendor',
|
|
240
|
+
totalPrice: 300, // Over budget
|
|
241
|
+
currency: 'USD',
|
|
242
|
+
category: 'office-supplies',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
id: 'offer-3',
|
|
246
|
+
beaconId: 'sketchy-vendor', // Blocklisted
|
|
247
|
+
totalPrice: 100,
|
|
248
|
+
currency: 'USD',
|
|
249
|
+
category: 'office-supplies',
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: 'offer-4',
|
|
253
|
+
beaconId: 'electronics-store',
|
|
254
|
+
totalPrice: 180,
|
|
255
|
+
currency: 'USD',
|
|
256
|
+
category: 'electronics', // Wrong category
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
id: 'offer-5',
|
|
260
|
+
beaconId: 'euro-store',
|
|
261
|
+
totalPrice: 100,
|
|
262
|
+
currency: 'EUR', // Wrong currency
|
|
263
|
+
category: 'office-supplies',
|
|
264
|
+
},
|
|
265
|
+
];
|
|
266
|
+
|
|
267
|
+
const validOffers = offers.filter(offer => {
|
|
268
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
269
|
+
totalAmount: offer.totalPrice,
|
|
270
|
+
currency: offer.currency,
|
|
271
|
+
category: offer.category,
|
|
272
|
+
merchantId: offer.beaconId,
|
|
273
|
+
});
|
|
274
|
+
return validation.valid;
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
assert.strictEqual(validOffers.length, 1);
|
|
278
|
+
assert.strictEqual(validOffers[0].id, 'offer-1');
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// =============================================================================
|
|
283
|
+
// Scenario 3: Payment Network Verification
|
|
284
|
+
// =============================================================================
|
|
285
|
+
|
|
286
|
+
describe('Scenario: Payment Network Verifies Agent Identity', () => {
|
|
287
|
+
test('Payment network can verify TAP-signed request', async () => {
|
|
288
|
+
// Agent registration
|
|
289
|
+
const agentKeyPair = VisaTAP.generateKeyPair();
|
|
290
|
+
const registration = await VisaTAP.register({
|
|
291
|
+
agentId: 'payment-verification-agent',
|
|
292
|
+
publicKey: agentKeyPair.publicKey,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const credentials = VisaTAP.createCredentials({
|
|
296
|
+
tapId: registration.tapId,
|
|
297
|
+
keyPair: agentKeyPair,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Agent signs a request
|
|
301
|
+
const request = {
|
|
302
|
+
method: 'POST',
|
|
303
|
+
url: 'https://payments.example.com/process',
|
|
304
|
+
body: { amount: 100, currency: 'USD' },
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const signedRequest = await VisaTAP.signRequest(request, credentials);
|
|
308
|
+
|
|
309
|
+
// Payment network verifies
|
|
310
|
+
const verifyRequest = {
|
|
311
|
+
method: signedRequest.method,
|
|
312
|
+
url: signedRequest.url,
|
|
313
|
+
body: signedRequest.body,
|
|
314
|
+
headers: {
|
|
315
|
+
'x-tap-agent-id': signedRequest.headers['X-TAP-Agent-Id'],
|
|
316
|
+
'x-tap-timestamp': signedRequest.headers['X-TAP-Timestamp'],
|
|
317
|
+
'x-tap-nonce': signedRequest.headers['X-TAP-Nonce'],
|
|
318
|
+
'signature': signedRequest.headers['Signature'],
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const publicKeyLookup = async (tapId) => {
|
|
323
|
+
if (tapId === registration.tapId) return agentKeyPair.publicKey;
|
|
324
|
+
throw new Error('Agent not found');
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const result = await VisaTAP.verifyRequest(verifyRequest, publicKeyLookup);
|
|
328
|
+
|
|
329
|
+
// Verification result should have valid property
|
|
330
|
+
assert.ok(result.valid !== undefined);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// =============================================================================
|
|
335
|
+
// Scenario 4: MCP Context Enriches Intent
|
|
336
|
+
// =============================================================================
|
|
337
|
+
|
|
338
|
+
describe('Scenario: MCP Context Enriches Shopping Intent', () => {
|
|
339
|
+
test('Agent aggregates context before shopping', async () => {
|
|
340
|
+
const mcp = new MCPClient();
|
|
341
|
+
|
|
342
|
+
// In real scenario, agent would connect to context servers
|
|
343
|
+
// For testing, we verify the pattern works
|
|
344
|
+
|
|
345
|
+
const context = await mcp.aggregateContext({
|
|
346
|
+
includeResources: true,
|
|
347
|
+
resourcePatterns: ['calendar://', 'preferences://'],
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Context would inform intent creation
|
|
351
|
+
const enhancedIntent = {
|
|
352
|
+
rawIntent: 'I need a laptop for my upcoming trip',
|
|
353
|
+
context: {
|
|
354
|
+
availableTools: context.tools,
|
|
355
|
+
userResources: context.resources,
|
|
356
|
+
// In real scenario: calendar shows trip dates, preferences show past purchases
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
assert.ok(enhancedIntent.context);
|
|
361
|
+
assert.ok(Array.isArray(enhancedIntent.context.availableTools));
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// =============================================================================
|
|
366
|
+
// Scenario 5: Error Recovery Flow
|
|
367
|
+
// =============================================================================
|
|
368
|
+
|
|
369
|
+
describe('Scenario: Error Recovery in Protocol Chain', () => {
|
|
370
|
+
test('Agent handles mandate validation failure gracefully', async () => {
|
|
371
|
+
const intentMandate = await AP2Mandates.createIntent({
|
|
372
|
+
agentId: 'error-recovery-agent',
|
|
373
|
+
userId: 'user-error-001',
|
|
374
|
+
userKey: userKeys.privateKey,
|
|
375
|
+
constraints: {
|
|
376
|
+
maxAmount: 100,
|
|
377
|
+
currency: 'USD',
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// Offer exceeds budget
|
|
382
|
+
const expensiveOffer = {
|
|
383
|
+
totalAmount: 500,
|
|
384
|
+
currency: 'USD',
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, expensiveOffer);
|
|
388
|
+
|
|
389
|
+
// Agent should handle this gracefully
|
|
390
|
+
if (!validation.valid) {
|
|
391
|
+
// Agent could:
|
|
392
|
+
// 1. Request new intent mandate with higher budget
|
|
393
|
+
// 2. Search for cheaper alternatives
|
|
394
|
+
// 3. Inform user of constraint violation
|
|
395
|
+
|
|
396
|
+
const errorReport = {
|
|
397
|
+
type: 'constraint_violation',
|
|
398
|
+
violations: validation.errors,
|
|
399
|
+
suggestedAction: 'find_cheaper_alternative',
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
assert.strictEqual(errorReport.type, 'constraint_violation');
|
|
403
|
+
assert.ok(errorReport.violations.length > 0);
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test('Agent handles TAP verification failure', async () => {
|
|
408
|
+
// Missing TAP headers
|
|
409
|
+
const badRequest = {
|
|
410
|
+
method: 'POST',
|
|
411
|
+
url: 'https://payments.example.com/process',
|
|
412
|
+
headers: {},
|
|
413
|
+
body: { amount: 100 },
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const result = await VisaTAP.verifyRequest(badRequest, async () => null);
|
|
417
|
+
|
|
418
|
+
// Should fail gracefully
|
|
419
|
+
assert.strictEqual(result.valid, false);
|
|
420
|
+
assert.ok(result.error);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// =============================================================================
|
|
425
|
+
// Scenario 6: Time-Sensitive Transaction
|
|
426
|
+
// =============================================================================
|
|
427
|
+
|
|
428
|
+
describe('Scenario: Time-Sensitive Transaction Flow', () => {
|
|
429
|
+
test('Complete flow within mandate validity window', async () => {
|
|
430
|
+
// Short-lived intent mandate (1 hour)
|
|
431
|
+
const intentMandate = await AP2Mandates.createIntent({
|
|
432
|
+
agentId: 'time-sensitive-agent',
|
|
433
|
+
userId: 'user-time-001',
|
|
434
|
+
userKey: userKeys.privateKey,
|
|
435
|
+
constraints: {
|
|
436
|
+
maxAmount: 500,
|
|
437
|
+
validUntil: new Date(Date.now() + 60 * 60 * 1000).toISOString(), // 1 hour
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// Immediate validation passes
|
|
442
|
+
const validation = AP2Mandates.validateIntentCoverage(intentMandate, {
|
|
443
|
+
totalAmount: 100,
|
|
444
|
+
});
|
|
445
|
+
assert.strictEqual(validation.valid, true);
|
|
446
|
+
|
|
447
|
+
// Cart mandate has 30 minute expiry
|
|
448
|
+
const cartMandate = await AP2Mandates.createCart({
|
|
449
|
+
sessionId: 'session-time-001',
|
|
450
|
+
offer: {
|
|
451
|
+
id: 'offer-time-001',
|
|
452
|
+
beaconId: 'fast-vendor',
|
|
453
|
+
beaconName: 'Fast Vendor',
|
|
454
|
+
product: { name: 'Quick Item' },
|
|
455
|
+
unitPrice: 100,
|
|
456
|
+
quantity: 1,
|
|
457
|
+
totalPrice: 100,
|
|
458
|
+
currency: 'USD',
|
|
459
|
+
},
|
|
460
|
+
userKey: userKeys.privateKey,
|
|
461
|
+
userId: 'user-time-001',
|
|
462
|
+
intentMandateId: intentMandate.id,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
const expiresAt = new Date(cartMandate.expiresAt);
|
|
466
|
+
const now = new Date();
|
|
467
|
+
const minutesUntilExpiry = (expiresAt - now) / (1000 * 60);
|
|
468
|
+
|
|
469
|
+
assert.ok(minutesUntilExpiry > 25 && minutesUntilExpiry <= 31);
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// =============================================================================
|
|
474
|
+
// Scenario 7: Agent Capabilities Advertisement
|
|
475
|
+
// =============================================================================
|
|
476
|
+
|
|
477
|
+
describe('Scenario: Agent Capabilities for Protocol Negotiation', () => {
|
|
478
|
+
test('Agent advertises supported protocols', async () => {
|
|
479
|
+
const agentCapabilities = {
|
|
480
|
+
mcp: {
|
|
481
|
+
version: '2024-11-05',
|
|
482
|
+
clientInfo: { name: 'aura-scout', version: '1.0.0' },
|
|
483
|
+
supportedFeatures: ['tools', 'resources', 'prompts'],
|
|
484
|
+
},
|
|
485
|
+
ap2: {
|
|
486
|
+
version: '1.0',
|
|
487
|
+
supportedMandateTypes: ['intent', 'cart', 'payment'],
|
|
488
|
+
supportedConstraints: [
|
|
489
|
+
'maxAmount',
|
|
490
|
+
'currency',
|
|
491
|
+
'categories',
|
|
492
|
+
'merchantAllowlist',
|
|
493
|
+
'merchantBlocklist',
|
|
494
|
+
'validUntil',
|
|
495
|
+
],
|
|
496
|
+
},
|
|
497
|
+
tap: {
|
|
498
|
+
version: '1.0',
|
|
499
|
+
algorithm: 'ed25519',
|
|
500
|
+
signatureFormat: 'http-message-signatures',
|
|
501
|
+
},
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
// Verify all protocols represented
|
|
505
|
+
assert.ok(agentCapabilities.mcp);
|
|
506
|
+
assert.ok(agentCapabilities.ap2);
|
|
507
|
+
assert.ok(agentCapabilities.tap);
|
|
508
|
+
|
|
509
|
+
// Verify versions
|
|
510
|
+
assert.strictEqual(agentCapabilities.mcp.version, '2024-11-05');
|
|
511
|
+
assert.strictEqual(agentCapabilities.ap2.version, '1.0');
|
|
512
|
+
assert.strictEqual(agentCapabilities.tap.algorithm, 'ed25519');
|
|
513
|
+
});
|
|
514
|
+
});
|