@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
package/src/index.js
ADDED
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AURA Scout SDK
|
|
3
|
+
*
|
|
4
|
+
* Build buying agents that participate in agentic commerce.
|
|
5
|
+
* Scouts represent users in the AURA ecosystem, expressing intent
|
|
6
|
+
* and negotiating with Beacons through the neutral Core broker.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```js
|
|
10
|
+
* import { createScout } from '@aura-labs-ai/scout';
|
|
11
|
+
*
|
|
12
|
+
* // Zero config — auto-generates Ed25519 identity and registers with Core
|
|
13
|
+
* const scout = createScout();
|
|
14
|
+
* await scout.ready();
|
|
15
|
+
*
|
|
16
|
+
* // Express purchase intent with constraints
|
|
17
|
+
* const session = await scout.intent('I need 500 widgets', {
|
|
18
|
+
* maxBudget: 50000,
|
|
19
|
+
* deliveryBy: new Date('2026-03-01'),
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Wait for offers (polling)
|
|
23
|
+
* const offers = await session.waitForOffers();
|
|
24
|
+
*
|
|
25
|
+
* // Commit to best offer that meets constraints
|
|
26
|
+
* if (session.bestOffer) {
|
|
27
|
+
* const tx = await session.commit(session.bestOffer.id);
|
|
28
|
+
* console.log('Transaction:', tx.id);
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { ScoutClient } from './client.js';
|
|
34
|
+
import { Session, Constraints } from './session.js';
|
|
35
|
+
import { KeyManager, MemoryStorage } from './key-manager.js';
|
|
36
|
+
import {
|
|
37
|
+
ScoutError,
|
|
38
|
+
ConnectionError,
|
|
39
|
+
AuthenticationError,
|
|
40
|
+
SessionError,
|
|
41
|
+
ConstraintError,
|
|
42
|
+
OfferError,
|
|
43
|
+
} from './errors.js';
|
|
44
|
+
import { ScoutActivityLogger, ScoutActivityEventTypes } from './activity.js';
|
|
45
|
+
import { IntentSession } from './intent-session.js';
|
|
46
|
+
|
|
47
|
+
// Storage adapters (re-exported from @aura-labs-ai/sdk-common)
|
|
48
|
+
import { FileStorage, KeychainStorage, createStorage } from '@aura-labs-ai/sdk-common';
|
|
49
|
+
|
|
50
|
+
// Protocol Integrations
|
|
51
|
+
import { MCPClient } from './mcp/client.js';
|
|
52
|
+
import { AP2Mandates, generateKeyPair as generateAP2KeyPair } from './ap2/mandates.js';
|
|
53
|
+
import { VisaTAP, TAPError } from './tap/visa.js';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a new Scout instance
|
|
57
|
+
*
|
|
58
|
+
* @param {ScoutConfig} config - Scout configuration
|
|
59
|
+
* @returns {Scout} Configured Scout instance
|
|
60
|
+
*/
|
|
61
|
+
export function createScout(config) {
|
|
62
|
+
return new Scout(config);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Scout - User-sovereign buying agent
|
|
67
|
+
*
|
|
68
|
+
* The Scout represents a user's interests in the AURA commerce ecosystem.
|
|
69
|
+
* It handles:
|
|
70
|
+
* - Expressing purchase intent in natural language
|
|
71
|
+
* - Managing commerce sessions
|
|
72
|
+
* - Evaluating offers against user-defined constraints
|
|
73
|
+
* - Committing to transactions
|
|
74
|
+
*/
|
|
75
|
+
export class Scout {
|
|
76
|
+
#client;
|
|
77
|
+
#config;
|
|
78
|
+
#keyManager;
|
|
79
|
+
#sessions = new Map();
|
|
80
|
+
#registered = false;
|
|
81
|
+
#agentId = null;
|
|
82
|
+
#readyPromise = null;
|
|
83
|
+
#activity;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {ScoutConfig} config
|
|
87
|
+
* @param {string} [config.apiKey] - Optional API key (legacy — for developer analytics/billing)
|
|
88
|
+
* @param {string} [config.coreUrl] - AURA Core API URL
|
|
89
|
+
* @param {number} [config.timeout] - Request timeout in ms
|
|
90
|
+
* @param {object} [config.storage] - Storage adapter with get/set/remove methods
|
|
91
|
+
* @param {object} [config.constraints] - Default constraints for all sessions
|
|
92
|
+
* @param {object} [config.logger] - External logger instance (optional)
|
|
93
|
+
*/
|
|
94
|
+
constructor(config = {}) {
|
|
95
|
+
this.#config = {
|
|
96
|
+
coreUrl: 'https://aura-labsai-production.up.railway.app',
|
|
97
|
+
timeout: 30000,
|
|
98
|
+
constraints: {},
|
|
99
|
+
...config,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Initialize key manager with provided storage (or in-memory default)
|
|
103
|
+
this.#keyManager = new KeyManager({
|
|
104
|
+
storage: this.#config.storage,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Initialize activity logger
|
|
108
|
+
this.#activity = new ScoutActivityLogger({
|
|
109
|
+
maxEvents: this.#config.maxActivityEvents || 5000,
|
|
110
|
+
logger: this.#config.logger || null,
|
|
111
|
+
scoutContext: {},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
this.#client = new ScoutClient(this.#config, this.#activity);
|
|
115
|
+
|
|
116
|
+
this.#activity.record(ScoutActivityEventTypes.SCOUT_CREATED, {
|
|
117
|
+
metadata: {
|
|
118
|
+
coreUrl: this.#config.coreUrl,
|
|
119
|
+
timeout: this.#config.timeout,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Initialize the Scout — generates keys and registers with AURA Core
|
|
126
|
+
*
|
|
127
|
+
* Call this once before using the Scout. It generates Ed25519 keys (if new)
|
|
128
|
+
* and registers with Core via POST /agents/register (if not already registered).
|
|
129
|
+
*
|
|
130
|
+
* This is idempotent — safe to call multiple times.
|
|
131
|
+
*
|
|
132
|
+
* @returns {Promise<Scout>} Returns self for chaining
|
|
133
|
+
*/
|
|
134
|
+
async ready() {
|
|
135
|
+
// Deduplicate concurrent ready() calls
|
|
136
|
+
if (this.#readyPromise) return this.#readyPromise;
|
|
137
|
+
|
|
138
|
+
const finish = this.#activity.startTimer(ScoutActivityEventTypes.SCOUT_READY);
|
|
139
|
+
|
|
140
|
+
this.#readyPromise = this.#initialize();
|
|
141
|
+
try {
|
|
142
|
+
await this.#readyPromise;
|
|
143
|
+
finish({ success: true });
|
|
144
|
+
return this;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
this.#readyPromise = null;
|
|
147
|
+
this.#activity.record(ScoutActivityEventTypes.SCOUT_READY_FAILED, {
|
|
148
|
+
success: false,
|
|
149
|
+
error: error.message,
|
|
150
|
+
});
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Read-only connectivity check against AURA Core
|
|
157
|
+
*
|
|
158
|
+
* Calls GET /health/ready to verify Core is reachable and its
|
|
159
|
+
* dependencies (database, redis) are healthy. Does NOT require
|
|
160
|
+
* prior ready() or register() calls. Does NOT send auth headers.
|
|
161
|
+
* Safe to call in a loop for monitoring.
|
|
162
|
+
*
|
|
163
|
+
* @returns {Promise<PingResponse>} Health status with latency
|
|
164
|
+
*/
|
|
165
|
+
async ping() {
|
|
166
|
+
const start = performance.now();
|
|
167
|
+
const timestamp = new Date().toISOString();
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
const url = `${this.#config.coreUrl}/health/ready`;
|
|
171
|
+
const response = await fetch(url, {
|
|
172
|
+
method: 'GET',
|
|
173
|
+
headers: {
|
|
174
|
+
'X-Request-ID': crypto.randomUUID(),
|
|
175
|
+
'X-Scout-SDK': '@aura-labs-ai/scout/0.1.0',
|
|
176
|
+
},
|
|
177
|
+
signal: AbortSignal.timeout(this.#config.timeout),
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const latency_ms = Math.round(performance.now() - start);
|
|
181
|
+
const body = await response.json();
|
|
182
|
+
|
|
183
|
+
const result = {
|
|
184
|
+
status: response.ok ? 'ok' : 'degraded',
|
|
185
|
+
core: {
|
|
186
|
+
status: body.status,
|
|
187
|
+
checks: body.checks || {},
|
|
188
|
+
},
|
|
189
|
+
latency_ms,
|
|
190
|
+
timestamp,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
this.#activity.record(ScoutActivityEventTypes.PING_SUCCESS, {
|
|
194
|
+
metadata: { latency_ms, coreStatus: body.status },
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return result;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
const latency_ms = Math.round(performance.now() - start);
|
|
200
|
+
|
|
201
|
+
const code =
|
|
202
|
+
error.name === 'TimeoutError' || error.name === 'AbortError'
|
|
203
|
+
? 'CORE_TIMEOUT'
|
|
204
|
+
: 'CORE_UNREACHABLE';
|
|
205
|
+
|
|
206
|
+
const result = {
|
|
207
|
+
status: 'error',
|
|
208
|
+
code,
|
|
209
|
+
message: `Could not connect to AURA Core at ${this.#config.coreUrl}`,
|
|
210
|
+
latency_ms,
|
|
211
|
+
timestamp,
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
this.#activity.record(ScoutActivityEventTypes.PING_FAILED, {
|
|
215
|
+
metadata: { latency_ms, code, error: error.message },
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Register this Scout with AURA Core
|
|
224
|
+
*
|
|
225
|
+
* Called automatically by ready(), but can be called explicitly
|
|
226
|
+
* to re-register or update metadata.
|
|
227
|
+
*
|
|
228
|
+
* Uses /agents/register with Ed25519 proof-of-possession.
|
|
229
|
+
* The legacy /scouts/register endpoint has been removed (DEC-015).
|
|
230
|
+
*
|
|
231
|
+
* @param {object} metadata - Optional metadata about this Scout
|
|
232
|
+
* @returns {Promise<{agentId: string}>}
|
|
233
|
+
*/
|
|
234
|
+
async register(metadata = {}) {
|
|
235
|
+
if (this.#registered && this.#agentId) {
|
|
236
|
+
return { agentId: this.#agentId };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const finish = this.#activity.startTimer(ScoutActivityEventTypes.SCOUT_REGISTERED);
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
// Ensure keys are initialized
|
|
243
|
+
if (!this.#keyManager.isInitialized) {
|
|
244
|
+
await this.#keyManager.init();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const publicKey = this.#keyManager.publicKey;
|
|
248
|
+
|
|
249
|
+
// Build registration body
|
|
250
|
+
const body = {
|
|
251
|
+
publicKey,
|
|
252
|
+
type: 'scout',
|
|
253
|
+
manifest: {
|
|
254
|
+
name: metadata.name || 'AURA Scout',
|
|
255
|
+
version: '0.1.0',
|
|
256
|
+
platform: metadata.platform || 'node-sdk',
|
|
257
|
+
sdkVersion: '0.1.0',
|
|
258
|
+
capabilities: ['intent', 'compare', 'mandate.sign'],
|
|
259
|
+
protocolVersions: ['ap2-v1', 'tap-v1'],
|
|
260
|
+
...metadata,
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// Sign the body for proof-of-possession
|
|
265
|
+
const bodyString = JSON.stringify(body);
|
|
266
|
+
const signature = this.#keyManager.sign(bodyString);
|
|
267
|
+
|
|
268
|
+
const result = await this.#client.postSigned('/agents/register', body, {
|
|
269
|
+
'X-Agent-Signature': signature,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
this.#agentId = result.agentId;
|
|
273
|
+
this.#registered = true;
|
|
274
|
+
|
|
275
|
+
// Persist agentId for next launch
|
|
276
|
+
await this.#keyManager.setAgentId(this.#agentId);
|
|
277
|
+
|
|
278
|
+
// Configure client to sign subsequent requests
|
|
279
|
+
this.#client.setKeyManager(this.#keyManager, this.#agentId);
|
|
280
|
+
|
|
281
|
+
// Update activity context with assigned agentId
|
|
282
|
+
this.#activity.setScoutContext({
|
|
283
|
+
agentId: this.#agentId,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
finish({
|
|
287
|
+
success: true,
|
|
288
|
+
metadata: {
|
|
289
|
+
agentId: this.#agentId,
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
return { agentId: this.#agentId };
|
|
294
|
+
} catch (error) {
|
|
295
|
+
this.#activity.record(ScoutActivityEventTypes.SCOUT_REGISTRATION_FAILED, {
|
|
296
|
+
success: false,
|
|
297
|
+
error: error.message,
|
|
298
|
+
});
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Express purchase intent and create a commerce session
|
|
305
|
+
*
|
|
306
|
+
* Intent is expressed in natural language. AURA Core interprets the
|
|
307
|
+
* intent and matches it against Beacon capabilities.
|
|
308
|
+
*
|
|
309
|
+
* @param {string} intent - Natural language description of what you want
|
|
310
|
+
* @param {IntentOptions} options - Constraints and preferences
|
|
311
|
+
* @returns {Promise<Session>}
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```js
|
|
315
|
+
* // Simple intent
|
|
316
|
+
* const session = await scout.intent('I want to buy a laptop');
|
|
317
|
+
*
|
|
318
|
+
* // Intent with constraints
|
|
319
|
+
* const session = await scout.intent('I need office supplies', {
|
|
320
|
+
* maxBudget: 500,
|
|
321
|
+
* deliveryBy: new Date('2026-02-15'),
|
|
322
|
+
* hardConstraints: [
|
|
323
|
+
* { field: 'sustainable', operator: 'eq', value: true }
|
|
324
|
+
* ],
|
|
325
|
+
* softPreferences: [
|
|
326
|
+
* { field: 'rating', operator: 'gte', value: 4.5, weight: 10 }
|
|
327
|
+
* ]
|
|
328
|
+
* });
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
async intent(intent, options = {}) {
|
|
332
|
+
// Auto-initialize if needed
|
|
333
|
+
if (!this.#registered) {
|
|
334
|
+
await this.ready();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const finish = this.#activity.startTimer(ScoutActivityEventTypes.INTENT_CREATED, {
|
|
338
|
+
metadata: { intentText: intent.substring(0, 100) },
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
try {
|
|
342
|
+
// Merge session-specific constraints with defaults
|
|
343
|
+
const constraints = {
|
|
344
|
+
...this.#config.constraints,
|
|
345
|
+
...options,
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// Agent identity is conveyed via Ed25519 signature headers, not the body.
|
|
349
|
+
// The server extracts agent ID from the verified X-Agent-Id header.
|
|
350
|
+
const response = await this.#client.post('/sessions', {
|
|
351
|
+
intent,
|
|
352
|
+
constraints: {
|
|
353
|
+
maxBudget: constraints.maxBudget,
|
|
354
|
+
deliveryBy: constraints.deliveryBy,
|
|
355
|
+
hardConstraints: constraints.hardConstraints,
|
|
356
|
+
softPreferences: constraints.softPreferences,
|
|
357
|
+
},
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
const sessionConfig = {
|
|
361
|
+
...this.#config,
|
|
362
|
+
constraints,
|
|
363
|
+
activityLogger: this.#activity,
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
const session = new Session(response, this.#client, sessionConfig);
|
|
367
|
+
this.#sessions.set(session.id, session);
|
|
368
|
+
|
|
369
|
+
finish({
|
|
370
|
+
success: true,
|
|
371
|
+
metadata: {
|
|
372
|
+
sessionId: session.id,
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
return session;
|
|
377
|
+
} catch (error) {
|
|
378
|
+
this.#activity.record(ScoutActivityEventTypes.INTENT_FAILED, {
|
|
379
|
+
success: false,
|
|
380
|
+
error: error.message,
|
|
381
|
+
metadata: { intentText: intent.substring(0, 100) },
|
|
382
|
+
});
|
|
383
|
+
throw error;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Create a conversational intent session for completeness checking.
|
|
389
|
+
*
|
|
390
|
+
* The IntentSession accumulates text across multiple submit() calls,
|
|
391
|
+
* checks completeness via @aura-labs-ai/nlp, and generates clarification
|
|
392
|
+
* questions. When complete, call scout.intent() with the full text
|
|
393
|
+
* and the completeness attestation.
|
|
394
|
+
*
|
|
395
|
+
* This is additive — the existing scout.intent() API is unchanged.
|
|
396
|
+
*
|
|
397
|
+
* @param {Object} [options]
|
|
398
|
+
* @param {Object} [options.provider] — Optional LLM provider for model-based detection
|
|
399
|
+
* @returns {IntentSession}
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* ```js
|
|
403
|
+
* const session = scout.createIntentSession();
|
|
404
|
+
*
|
|
405
|
+
* let result = await session.submit('I need keyboards');
|
|
406
|
+
* // result.complete === false, result.question === "How many would you like?"
|
|
407
|
+
*
|
|
408
|
+
* result = await session.submit('50 units under $5000');
|
|
409
|
+
* // result.complete === true
|
|
410
|
+
*
|
|
411
|
+
* // Now submit to Core with completeness attestation
|
|
412
|
+
* await scout.intent(session.getText(), {
|
|
413
|
+
* completeness: session.getAttestation(),
|
|
414
|
+
* });
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
createIntentSession(options = {}) {
|
|
418
|
+
return new IntentSession({
|
|
419
|
+
...options,
|
|
420
|
+
activityLogger: this.#activity,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Resume an existing session by ID
|
|
426
|
+
*
|
|
427
|
+
* @param {string} sessionId
|
|
428
|
+
* @returns {Promise<Session>}
|
|
429
|
+
*/
|
|
430
|
+
async resumeSession(sessionId) {
|
|
431
|
+
if (this.#sessions.has(sessionId)) {
|
|
432
|
+
return this.#sessions.get(sessionId);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const finish = this.#activity.startTimer(ScoutActivityEventTypes.SESSION_RESUMED, {
|
|
436
|
+
sessionId,
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
try {
|
|
440
|
+
const response = await this.#client.get(`/sessions/${sessionId}`);
|
|
441
|
+
const sessionConfig = {
|
|
442
|
+
...this.#config,
|
|
443
|
+
activityLogger: this.#activity,
|
|
444
|
+
};
|
|
445
|
+
const session = new Session(response, this.#client, sessionConfig);
|
|
446
|
+
this.#sessions.set(session.id, session);
|
|
447
|
+
|
|
448
|
+
finish({
|
|
449
|
+
success: true,
|
|
450
|
+
sessionId,
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
return session;
|
|
454
|
+
} catch (error) {
|
|
455
|
+
this.#activity.record(ScoutActivityEventTypes.SESSION_RESUME_FAILED, {
|
|
456
|
+
sessionId,
|
|
457
|
+
success: false,
|
|
458
|
+
error: error.message,
|
|
459
|
+
});
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* List active sessions
|
|
466
|
+
*
|
|
467
|
+
* @returns {Session[]}
|
|
468
|
+
*/
|
|
469
|
+
get activeSessions() {
|
|
470
|
+
return Array.from(this.#sessions.values()).filter(s => s.isActive);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Set default constraints for all sessions
|
|
475
|
+
*
|
|
476
|
+
* @param {object} constraints
|
|
477
|
+
*/
|
|
478
|
+
setDefaultConstraints(constraints) {
|
|
479
|
+
this.#config.constraints = {
|
|
480
|
+
...this.#config.constraints,
|
|
481
|
+
...constraints,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Get Scout's registration status
|
|
487
|
+
*/
|
|
488
|
+
get isRegistered() {
|
|
489
|
+
return this.#registered;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Get Agent ID (null if not registered)
|
|
494
|
+
*/
|
|
495
|
+
get id() {
|
|
496
|
+
return this.#agentId;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Get the agent's public key (base64-encoded Ed25519)
|
|
501
|
+
*/
|
|
502
|
+
get publicKey() {
|
|
503
|
+
return this.#keyManager.publicKey;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Get Core URL
|
|
508
|
+
*/
|
|
509
|
+
get coreUrl() {
|
|
510
|
+
return this.#client.coreUrl;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Access the activity logger for observability
|
|
515
|
+
*
|
|
516
|
+
* @example
|
|
517
|
+
* ```js
|
|
518
|
+
* // Subscribe to events
|
|
519
|
+
* scout.activity.on('intent.created', (event) => {
|
|
520
|
+
* console.log(`Intent created in ${event.durationMs}ms`);
|
|
521
|
+
* });
|
|
522
|
+
*
|
|
523
|
+
* // Get summary stats
|
|
524
|
+
* const stats = scout.activity.getSummary();
|
|
525
|
+
*
|
|
526
|
+
* // Query recent errors
|
|
527
|
+
* const errors = scout.activity.getEvents({ type: '*.error' });
|
|
528
|
+
* ```
|
|
529
|
+
*/
|
|
530
|
+
get activity() {
|
|
531
|
+
return this.#activity;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// ─── Private ────────────────────────────────────────────────────────
|
|
535
|
+
|
|
536
|
+
async #initialize() {
|
|
537
|
+
// Step 1: Initialize key manager (generate or load keys)
|
|
538
|
+
const { isNew } = await this.#keyManager.init();
|
|
539
|
+
|
|
540
|
+
// Step 2: Check if already registered (agentId in storage)
|
|
541
|
+
const storedAgentId = await this.#keyManager.getAgentId();
|
|
542
|
+
if (storedAgentId) {
|
|
543
|
+
this.#agentId = storedAgentId;
|
|
544
|
+
this.#registered = true;
|
|
545
|
+
this.#client.setKeyManager(this.#keyManager, this.#agentId);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Step 3: Register with Core
|
|
550
|
+
await this.register();
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Re-export classes
|
|
555
|
+
export { Session, Constraints } from './session.js';
|
|
556
|
+
export { KeyManager, MemoryStorage } from './key-manager.js';
|
|
557
|
+
export { FileStorage, KeychainStorage, createStorage };
|
|
558
|
+
export {
|
|
559
|
+
ScoutError,
|
|
560
|
+
ConnectionError,
|
|
561
|
+
AuthenticationError,
|
|
562
|
+
SessionError,
|
|
563
|
+
ConstraintError,
|
|
564
|
+
OfferError,
|
|
565
|
+
} from './errors.js';
|
|
566
|
+
export { ScoutActivityLogger, ScoutActivityEventTypes, ActivityEvent } from './activity.js';
|
|
567
|
+
export { IntentSession } from './intent-session.js';
|
|
568
|
+
|
|
569
|
+
// =========================================================================
|
|
570
|
+
// Protocol Integrations
|
|
571
|
+
// =========================================================================
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* MCP (Model Context Protocol) Client
|
|
575
|
+
*
|
|
576
|
+
* Connect to MCP servers to access external tools and context.
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* ```js
|
|
580
|
+
* import { MCPClient } from '@aura-labs-ai/scout';
|
|
581
|
+
*
|
|
582
|
+
* const mcp = new MCPClient();
|
|
583
|
+
* await mcp.connect('https://mcp.example.com/sse');
|
|
584
|
+
* const tools = await mcp.listAllTools();
|
|
585
|
+
* const result = await mcp.callTool('server-uri', 'search', { query: 'laptops' });
|
|
586
|
+
* ```
|
|
587
|
+
*/
|
|
588
|
+
export { MCPClient };
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* AP2 Mandates - Google's Agent Payments Protocol
|
|
592
|
+
*
|
|
593
|
+
* Create user-signed mandates that authorize agent actions:
|
|
594
|
+
* - Intent Mandate: Authorizes shopping within constraints
|
|
595
|
+
* - Cart Mandate: Authorizes specific purchase
|
|
596
|
+
* - Payment Mandate: Authorization for payment networks
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```js
|
|
600
|
+
* import { AP2Mandates, generateAP2KeyPair } from '@aura-labs-ai/scout';
|
|
601
|
+
*
|
|
602
|
+
* const { publicKey, privateKey } = generateAP2KeyPair();
|
|
603
|
+
*
|
|
604
|
+
* const intentMandate = await AP2Mandates.createIntent({
|
|
605
|
+
* agentId: 'scout-123',
|
|
606
|
+
* userId: 'user-456',
|
|
607
|
+
* userKey: privateKey,
|
|
608
|
+
* constraints: {
|
|
609
|
+
* maxAmount: 5000,
|
|
610
|
+
* currency: 'USD',
|
|
611
|
+
* categories: ['electronics'],
|
|
612
|
+
* validUntil: '2026-03-01T00:00:00Z',
|
|
613
|
+
* },
|
|
614
|
+
* });
|
|
615
|
+
* ```
|
|
616
|
+
*/
|
|
617
|
+
export { AP2Mandates, generateAP2KeyPair };
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Visa TAP - Trusted Agent Protocol
|
|
621
|
+
*
|
|
622
|
+
* Agent identity verification for commerce transactions.
|
|
623
|
+
* Allows payment networks to verify agent authenticity.
|
|
624
|
+
*
|
|
625
|
+
* @example
|
|
626
|
+
* ```js
|
|
627
|
+
* import { VisaTAP } from '@aura-labs-ai/scout';
|
|
628
|
+
*
|
|
629
|
+
* // Generate keys and register agent
|
|
630
|
+
* const keyPair = VisaTAP.generateKeyPair();
|
|
631
|
+
* const registration = await VisaTAP.register({
|
|
632
|
+
* agentId: 'my-scout-agent',
|
|
633
|
+
* publicKey: keyPair.publicKey,
|
|
634
|
+
* metadata: { name: 'Shopping Agent', operator: 'AURA Labs' },
|
|
635
|
+
* });
|
|
636
|
+
*
|
|
637
|
+
* // Sign HTTP requests for TAP verification
|
|
638
|
+
* const signedRequest = await VisaTAP.signRequest(
|
|
639
|
+
* { method: 'POST', url: '/api/pay', body: { amount: 100 } },
|
|
640
|
+
* { tapId: registration.tapId, privateKey: keyPair.privateKey, keyId: keyPair.keyId }
|
|
641
|
+
* );
|
|
642
|
+
* ```
|
|
643
|
+
*/
|
|
644
|
+
export { VisaTAP, TAPError };
|
|
645
|
+
|
|
646
|
+
// Default export
|
|
647
|
+
export default {
|
|
648
|
+
createScout,
|
|
649
|
+
Scout,
|
|
650
|
+
KeyManager,
|
|
651
|
+
// Protocols
|
|
652
|
+
MCPClient,
|
|
653
|
+
AP2Mandates,
|
|
654
|
+
VisaTAP,
|
|
655
|
+
};
|