@agentfield/sdk 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/dist/index.js ADDED
@@ -0,0 +1,2257 @@
1
+ import express from 'express';
2
+ import crypto, { randomUUID } from 'crypto';
3
+ import { AsyncLocalStorage } from 'async_hooks';
4
+ import { generateText, streamText, embed, embedMany } from 'ai';
5
+ import { createOpenAI } from '@ai-sdk/openai';
6
+ import { createAnthropic } from '@ai-sdk/anthropic';
7
+ import os from 'os';
8
+ import axios, { isAxiosError } from 'axios';
9
+ import WebSocket from 'ws';
10
+ import { Buffer } from 'buffer';
11
+
12
+ // src/agent/Agent.ts
13
+
14
+ // src/agent/ReasonerRegistry.ts
15
+ var ReasonerRegistry = class {
16
+ reasoners = /* @__PURE__ */ new Map();
17
+ register(name, handler, options) {
18
+ this.reasoners.set(name, { name, handler, options });
19
+ }
20
+ includeRouter(router) {
21
+ router.reasoners.forEach((reasoner) => {
22
+ this.reasoners.set(reasoner.name, reasoner);
23
+ });
24
+ }
25
+ get(name) {
26
+ return this.reasoners.get(name);
27
+ }
28
+ all() {
29
+ return Array.from(this.reasoners.values());
30
+ }
31
+ };
32
+
33
+ // src/agent/SkillRegistry.ts
34
+ var SkillRegistry = class {
35
+ skills = /* @__PURE__ */ new Map();
36
+ register(name, handler, options) {
37
+ this.skills.set(name, { name, handler, options });
38
+ }
39
+ includeRouter(router) {
40
+ router.skills.forEach((skill) => {
41
+ this.skills.set(skill.name, skill);
42
+ });
43
+ }
44
+ get(name) {
45
+ return this.skills.get(name);
46
+ }
47
+ all() {
48
+ return Array.from(this.skills.values());
49
+ }
50
+ };
51
+ var store = new AsyncLocalStorage();
52
+ var ExecutionContext = class {
53
+ input;
54
+ metadata;
55
+ req;
56
+ res;
57
+ agent;
58
+ constructor(params) {
59
+ this.input = params.input;
60
+ this.metadata = params.metadata;
61
+ this.req = params.req;
62
+ this.res = params.res;
63
+ this.agent = params.agent;
64
+ }
65
+ static run(ctx, fn) {
66
+ return store.run(ctx, fn);
67
+ }
68
+ static getCurrent() {
69
+ return store.getStore();
70
+ }
71
+ };
72
+
73
+ // src/context/ReasonerContext.ts
74
+ var ReasonerContext = class {
75
+ input;
76
+ executionId;
77
+ runId;
78
+ sessionId;
79
+ actorId;
80
+ workflowId;
81
+ parentExecutionId;
82
+ callerDid;
83
+ targetDid;
84
+ agentNodeDid;
85
+ req;
86
+ res;
87
+ agent;
88
+ aiClient;
89
+ memory;
90
+ workflow;
91
+ did;
92
+ constructor(params) {
93
+ this.input = params.input;
94
+ this.executionId = params.executionId;
95
+ this.runId = params.runId;
96
+ this.sessionId = params.sessionId;
97
+ this.actorId = params.actorId;
98
+ this.workflowId = params.workflowId;
99
+ this.parentExecutionId = params.parentExecutionId;
100
+ this.callerDid = params.callerDid;
101
+ this.targetDid = params.targetDid;
102
+ this.agentNodeDid = params.agentNodeDid;
103
+ this.req = params.req;
104
+ this.res = params.res;
105
+ this.agent = params.agent;
106
+ this.aiClient = params.aiClient;
107
+ this.memory = params.memory;
108
+ this.workflow = params.workflow;
109
+ this.did = params.did;
110
+ }
111
+ ai(prompt, options) {
112
+ return this.aiClient.generate(prompt, options);
113
+ }
114
+ aiStream(prompt, options) {
115
+ return this.aiClient.stream(prompt, options);
116
+ }
117
+ call(target, input) {
118
+ return this.agent.call(target, input);
119
+ }
120
+ discover(options) {
121
+ return this.agent.discover(options);
122
+ }
123
+ };
124
+ function getCurrentContext() {
125
+ const execution = ExecutionContext.getCurrent();
126
+ if (!execution) return void 0;
127
+ const { metadata, input, agent, req, res } = execution;
128
+ return new ReasonerContext({
129
+ input,
130
+ executionId: metadata.executionId,
131
+ runId: metadata.runId,
132
+ sessionId: metadata.sessionId,
133
+ actorId: metadata.actorId,
134
+ workflowId: metadata.workflowId,
135
+ parentExecutionId: metadata.parentExecutionId,
136
+ callerDid: metadata.callerDid,
137
+ targetDid: metadata.targetDid,
138
+ agentNodeDid: metadata.agentNodeDid,
139
+ req,
140
+ res,
141
+ agent,
142
+ aiClient: agent.getAIClient(),
143
+ memory: agent.getMemoryInterface(metadata),
144
+ workflow: agent.getWorkflowReporter(metadata),
145
+ did: agent.getDidInterface(metadata, input)
146
+ });
147
+ }
148
+
149
+ // src/context/SkillContext.ts
150
+ var SkillContext = class {
151
+ input;
152
+ executionId;
153
+ sessionId;
154
+ workflowId;
155
+ callerDid;
156
+ agentNodeDid;
157
+ req;
158
+ res;
159
+ agent;
160
+ memory;
161
+ workflow;
162
+ did;
163
+ constructor(params) {
164
+ this.input = params.input;
165
+ this.executionId = params.executionId;
166
+ this.sessionId = params.sessionId;
167
+ this.workflowId = params.workflowId;
168
+ this.callerDid = params.callerDid;
169
+ this.agentNodeDid = params.agentNodeDid;
170
+ this.req = params.req;
171
+ this.res = params.res;
172
+ this.agent = params.agent;
173
+ this.memory = params.memory;
174
+ this.workflow = params.workflow;
175
+ this.did = params.did;
176
+ }
177
+ discover(options) {
178
+ return this.agent.discover(options);
179
+ }
180
+ };
181
+ function getCurrentSkillContext() {
182
+ const execution = ExecutionContext.getCurrent();
183
+ if (!execution) return void 0;
184
+ const { metadata, input, agent, req, res } = execution;
185
+ return new SkillContext({
186
+ input,
187
+ executionId: metadata.executionId,
188
+ sessionId: metadata.sessionId,
189
+ workflowId: metadata.workflowId,
190
+ callerDid: metadata.callerDid,
191
+ agentNodeDid: metadata.agentNodeDid,
192
+ req,
193
+ res,
194
+ agent,
195
+ memory: agent.getMemoryInterface(metadata),
196
+ workflow: agent.getWorkflowReporter(metadata),
197
+ did: agent.getDidInterface(metadata, input)
198
+ });
199
+ }
200
+ var RateLimitError = class extends Error {
201
+ retryAfter;
202
+ constructor(message, retryAfter) {
203
+ super(message);
204
+ this.name = "RateLimitError";
205
+ this.retryAfter = retryAfter;
206
+ }
207
+ };
208
+ var StatelessRateLimiter = class {
209
+ maxRetries;
210
+ baseDelay;
211
+ maxDelay;
212
+ jitterFactor;
213
+ circuitBreakerThreshold;
214
+ circuitBreakerTimeout;
215
+ _containerSeed;
216
+ _consecutiveFailures = 0;
217
+ _circuitOpenTime;
218
+ constructor(options = {}) {
219
+ this.maxRetries = options.maxRetries ?? 20;
220
+ this.baseDelay = options.baseDelay ?? 1;
221
+ this.maxDelay = options.maxDelay ?? 300;
222
+ this.jitterFactor = options.jitterFactor ?? 0.25;
223
+ this.circuitBreakerThreshold = options.circuitBreakerThreshold ?? 10;
224
+ this.circuitBreakerTimeout = options.circuitBreakerTimeout ?? 300;
225
+ this._containerSeed = this._getContainerSeed();
226
+ }
227
+ _getContainerSeed() {
228
+ const identifier = `${os.hostname()}-${process.pid}`;
229
+ const hash = crypto.createHash("md5").update(identifier).digest("hex");
230
+ return parseInt(hash.slice(0, 8), 16);
231
+ }
232
+ _isRateLimitError(error) {
233
+ if (!error) return false;
234
+ const err = error;
235
+ const className = err?.constructor?.name;
236
+ if (className && className.includes("RateLimitError")) {
237
+ return true;
238
+ }
239
+ const response = err?.response;
240
+ const statusCandidates = [
241
+ err?.status,
242
+ err?.statusCode,
243
+ response?.status,
244
+ response?.statusCode,
245
+ response?.status_code
246
+ ];
247
+ if (statusCandidates.some((code) => code === 429 || code === 503)) {
248
+ return true;
249
+ }
250
+ const message = String(err?.message ?? err ?? "").toLowerCase();
251
+ const rateLimitKeywords = [
252
+ "rate limit",
253
+ "rate-limit",
254
+ "rate_limit",
255
+ "too many requests",
256
+ "quota exceeded",
257
+ "temporarily rate-limited",
258
+ "rate limited",
259
+ "requests per",
260
+ "rpm exceeded",
261
+ "tpm exceeded",
262
+ "usage limit",
263
+ "throttled",
264
+ "throttling"
265
+ ];
266
+ return rateLimitKeywords.some((keyword) => message.includes(keyword));
267
+ }
268
+ _extractRetryAfter(error) {
269
+ if (!error) return void 0;
270
+ const err = error;
271
+ const headers = err?.response?.headers ?? err?.response?.Headers ?? err?.response?.header;
272
+ if (headers && typeof headers === "object") {
273
+ const retryAfterKey = Object.keys(headers).find((k) => k.toLowerCase() === "retry-after");
274
+ if (retryAfterKey) {
275
+ const value = Array.isArray(headers[retryAfterKey]) ? headers[retryAfterKey][0] : headers[retryAfterKey];
276
+ const parsed2 = parseFloat(value);
277
+ if (!Number.isNaN(parsed2)) {
278
+ return parsed2;
279
+ }
280
+ }
281
+ }
282
+ const retryAfter = err?.retryAfter ?? err?.retry_after;
283
+ const parsed = parseFloat(retryAfter);
284
+ if (!Number.isNaN(parsed)) {
285
+ return parsed;
286
+ }
287
+ return void 0;
288
+ }
289
+ _createJitterRng(seed) {
290
+ let x = seed >>> 0;
291
+ return () => {
292
+ x = (1664525 * x + 1013904223) % 4294967296;
293
+ return x / 4294967296;
294
+ };
295
+ }
296
+ _calculateBackoffDelay(attempt, retryAfter) {
297
+ let baseDelay;
298
+ if (retryAfter && retryAfter <= this.maxDelay) {
299
+ baseDelay = retryAfter;
300
+ } else {
301
+ baseDelay = Math.min(this.baseDelay * 2 ** attempt, this.maxDelay);
302
+ }
303
+ const jitterRange = baseDelay * this.jitterFactor;
304
+ const rng = this._createJitterRng(this._containerSeed + attempt);
305
+ const jitter = (rng() * 2 - 1) * jitterRange;
306
+ const delay = Math.max(0.1, baseDelay + jitter);
307
+ return delay;
308
+ }
309
+ _checkCircuitBreaker() {
310
+ if (this._circuitOpenTime === void 0) {
311
+ return false;
312
+ }
313
+ if (this._now() - this._circuitOpenTime > this.circuitBreakerTimeout) {
314
+ this._circuitOpenTime = void 0;
315
+ this._consecutiveFailures = 0;
316
+ return false;
317
+ }
318
+ return true;
319
+ }
320
+ _updateCircuitBreaker(success) {
321
+ if (success) {
322
+ this._consecutiveFailures = 0;
323
+ this._circuitOpenTime = void 0;
324
+ return;
325
+ }
326
+ this._consecutiveFailures += 1;
327
+ if (this._consecutiveFailures >= this.circuitBreakerThreshold && this._circuitOpenTime === void 0) {
328
+ this._circuitOpenTime = this._now();
329
+ }
330
+ }
331
+ async _sleep(delaySeconds) {
332
+ await new Promise((resolve) => setTimeout(resolve, delaySeconds * 1e3));
333
+ }
334
+ _now() {
335
+ return Date.now() / 1e3;
336
+ }
337
+ async executeWithRetry(fn) {
338
+ if (this._checkCircuitBreaker()) {
339
+ throw new RateLimitError(
340
+ `Circuit breaker is open. Too many consecutive rate limit failures. Will retry after ${this.circuitBreakerTimeout} seconds.`
341
+ );
342
+ }
343
+ let lastError;
344
+ for (let attempt = 0; attempt <= this.maxRetries; attempt += 1) {
345
+ try {
346
+ const result = await fn();
347
+ this._updateCircuitBreaker(true);
348
+ return result;
349
+ } catch (error) {
350
+ lastError = error;
351
+ if (!this._isRateLimitError(error)) {
352
+ throw error;
353
+ }
354
+ this._updateCircuitBreaker(false);
355
+ if (attempt >= this.maxRetries) {
356
+ break;
357
+ }
358
+ const retryAfter = this._extractRetryAfter(error);
359
+ const delay = this._calculateBackoffDelay(attempt, retryAfter);
360
+ await this._sleep(delay);
361
+ }
362
+ }
363
+ throw new RateLimitError(
364
+ `Rate limit retries exhausted after ${this.maxRetries} attempts. Last error: ${String(lastError)}`,
365
+ this._extractRetryAfter(lastError)
366
+ );
367
+ }
368
+ };
369
+
370
+ // src/ai/AIClient.ts
371
+ var AIClient = class {
372
+ config;
373
+ rateLimiter;
374
+ constructor(config = {}) {
375
+ this.config = {
376
+ enableRateLimitRetry: true,
377
+ rateLimitMaxRetries: 20,
378
+ rateLimitBaseDelay: 1,
379
+ rateLimitMaxDelay: 300,
380
+ rateLimitJitterFactor: 0.25,
381
+ rateLimitCircuitBreakerThreshold: 10,
382
+ rateLimitCircuitBreakerTimeout: 300,
383
+ ...config
384
+ };
385
+ }
386
+ async generate(prompt, options = {}) {
387
+ const model = this.buildModel(options);
388
+ const call = async () => generateText({
389
+ // type cast to avoid provider-model signature drift
390
+ model,
391
+ prompt,
392
+ system: options.system,
393
+ temperature: options.temperature ?? this.config.temperature,
394
+ maxTokens: options.maxTokens ?? this.config.maxTokens,
395
+ schema: options.schema
396
+ });
397
+ const response = await this.withRateLimitRetry(call);
398
+ if (options.schema && response.object !== void 0) {
399
+ return response.object;
400
+ }
401
+ return response.text;
402
+ }
403
+ async stream(prompt, options = {}) {
404
+ const model = this.buildModel(options);
405
+ const streamResult = await this.withRateLimitRetry(
406
+ () => streamText({
407
+ model,
408
+ prompt,
409
+ system: options.system,
410
+ temperature: options.temperature ?? this.config.temperature,
411
+ maxTokens: options.maxTokens ?? this.config.maxTokens
412
+ })
413
+ );
414
+ return streamResult.textStream;
415
+ }
416
+ async embed(value, options = {}) {
417
+ const model = this.buildEmbeddingModel(options);
418
+ const result = await this.withRateLimitRetry(
419
+ () => embed({
420
+ model,
421
+ value
422
+ })
423
+ );
424
+ return result.embedding;
425
+ }
426
+ async embedMany(values, options = {}) {
427
+ const model = this.buildEmbeddingModel(options);
428
+ const result = await this.withRateLimitRetry(
429
+ () => embedMany({
430
+ model,
431
+ values
432
+ })
433
+ );
434
+ return result.embeddings;
435
+ }
436
+ buildModel(options) {
437
+ const provider = options.provider ?? this.config.provider ?? "openai";
438
+ const modelName = options.model ?? this.config.model ?? "gpt-4o";
439
+ if (provider === "anthropic") {
440
+ const anthropic = createAnthropic({
441
+ apiKey: this.config.apiKey,
442
+ baseURL: this.config.baseUrl
443
+ });
444
+ return anthropic(modelName);
445
+ }
446
+ const openai = createOpenAI({
447
+ apiKey: this.config.apiKey,
448
+ baseURL: this.config.baseUrl
449
+ });
450
+ return openai(modelName);
451
+ }
452
+ buildEmbeddingModel(options) {
453
+ const provider = options.provider ?? this.config.provider ?? "openai";
454
+ const modelName = options.model ?? this.config.embeddingModel ?? "text-embedding-3-small";
455
+ if (provider === "anthropic") {
456
+ throw new Error("Embedding generation is not supported for Anthropic provider");
457
+ }
458
+ const openai = createOpenAI({
459
+ apiKey: this.config.apiKey,
460
+ baseURL: this.config.baseUrl
461
+ });
462
+ if (typeof openai.embedding !== "function") {
463
+ throw new Error("Embedding model is not available for the configured provider");
464
+ }
465
+ return openai.embedding(modelName);
466
+ }
467
+ getRateLimiter() {
468
+ if (!this.rateLimiter) {
469
+ this.rateLimiter = new StatelessRateLimiter({
470
+ maxRetries: this.config.rateLimitMaxRetries,
471
+ baseDelay: this.config.rateLimitBaseDelay,
472
+ maxDelay: this.config.rateLimitMaxDelay,
473
+ jitterFactor: this.config.rateLimitJitterFactor,
474
+ circuitBreakerThreshold: this.config.rateLimitCircuitBreakerThreshold,
475
+ circuitBreakerTimeout: this.config.rateLimitCircuitBreakerTimeout
476
+ });
477
+ }
478
+ return this.rateLimiter;
479
+ }
480
+ withRateLimitRetry(fn) {
481
+ if (this.config.enableRateLimitRetry === false) {
482
+ return fn();
483
+ }
484
+ return this.getRateLimiter().executeWithRetry(fn);
485
+ }
486
+ };
487
+ var AgentFieldClient = class {
488
+ http;
489
+ config;
490
+ defaultHeaders;
491
+ constructor(config) {
492
+ const baseURL = (config.agentFieldUrl ?? "http://localhost:8080").replace(/\/$/, "");
493
+ this.http = axios.create({ baseURL });
494
+ this.config = config;
495
+ this.defaultHeaders = this.sanitizeHeaders(config.defaultHeaders ?? {});
496
+ }
497
+ async register(payload) {
498
+ await this.http.post("/api/v1/nodes/register", payload, { headers: this.mergeHeaders() });
499
+ }
500
+ async heartbeat(status = "ready") {
501
+ const nodeId = this.config.nodeId;
502
+ const res = await this.http.post(
503
+ `/api/v1/nodes/${nodeId}/heartbeat`,
504
+ {
505
+ status,
506
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
507
+ },
508
+ { headers: this.mergeHeaders() }
509
+ );
510
+ return res.data;
511
+ }
512
+ async execute(target, input, metadata) {
513
+ const headers = {};
514
+ if (metadata?.runId) headers["X-Run-ID"] = metadata.runId;
515
+ if (metadata?.workflowId) headers["X-Workflow-ID"] = metadata.workflowId;
516
+ if (metadata?.parentExecutionId) headers["X-Parent-Execution-ID"] = metadata.parentExecutionId;
517
+ if (metadata?.sessionId) headers["X-Session-ID"] = metadata.sessionId;
518
+ if (metadata?.actorId) headers["X-Actor-ID"] = metadata.actorId;
519
+ if (metadata?.callerDid) headers["X-Caller-DID"] = metadata.callerDid;
520
+ if (metadata?.targetDid) headers["X-Target-DID"] = metadata.targetDid;
521
+ if (metadata?.agentNodeDid) headers["X-Agent-Node-DID"] = metadata.agentNodeDid;
522
+ if (metadata?.agentNodeId) headers["X-Agent-Node-ID"] = metadata.agentNodeId;
523
+ const res = await this.http.post(
524
+ `/api/v1/execute/${target}`,
525
+ {
526
+ input
527
+ },
528
+ { headers: this.mergeHeaders(headers) }
529
+ );
530
+ return res.data?.result ?? res.data;
531
+ }
532
+ async publishWorkflowEvent(event) {
533
+ const payload = {
534
+ execution_id: event.executionId,
535
+ workflow_id: event.workflowId ?? event.runId,
536
+ run_id: event.runId,
537
+ reasoner_id: event.reasonerId,
538
+ type: event.reasonerId,
539
+ agent_node_id: event.agentNodeId,
540
+ status: event.status,
541
+ parent_execution_id: event.parentExecutionId,
542
+ parent_workflow_id: event.parentWorkflowId ?? event.workflowId ?? event.runId,
543
+ input_data: event.inputData ?? {},
544
+ result: event.result,
545
+ error: event.error,
546
+ duration_ms: event.durationMs
547
+ };
548
+ this.http.post("/api/v1/workflow/executions/events", payload, {
549
+ headers: this.mergeHeaders(),
550
+ timeout: this.config.devMode ? 1e3 : void 0
551
+ }).catch(() => {
552
+ });
553
+ }
554
+ async updateExecutionStatus(executionId, update) {
555
+ if (!executionId) {
556
+ throw new Error("executionId is required to update workflow status");
557
+ }
558
+ const payload = {
559
+ status: update.status ?? "running",
560
+ result: update.result,
561
+ error: update.error,
562
+ duration_ms: update.durationMs,
563
+ progress: update.progress !== void 0 ? Math.round(update.progress) : void 0
564
+ };
565
+ await this.http.post(`/api/v1/executions/${executionId}/status`, payload, { headers: this.mergeHeaders() });
566
+ }
567
+ async discoverCapabilities(options = {}) {
568
+ const format = (options.format ?? "json").toLowerCase();
569
+ const params = { format };
570
+ const dedupe = (values) => Array.from(new Set((values ?? []).filter(Boolean))).map((v) => v);
571
+ const combinedAgents = dedupe([
572
+ ...options.agent ? [options.agent] : [],
573
+ ...options.nodeId ? [options.nodeId] : [],
574
+ ...options.agentIds ?? [],
575
+ ...options.nodeIds ?? []
576
+ ]);
577
+ if (combinedAgents.length === 1) {
578
+ params.agent = combinedAgents[0];
579
+ } else if (combinedAgents.length > 1) {
580
+ params.agent_ids = combinedAgents.join(",");
581
+ }
582
+ if (options.reasoner) params.reasoner = options.reasoner;
583
+ if (options.skill) params.skill = options.skill;
584
+ if (options.tags?.length) params.tags = dedupe(options.tags).join(",");
585
+ if (options.includeInputSchema !== void 0) {
586
+ params.include_input_schema = String(Boolean(options.includeInputSchema));
587
+ }
588
+ if (options.includeOutputSchema !== void 0) {
589
+ params.include_output_schema = String(Boolean(options.includeOutputSchema));
590
+ }
591
+ if (options.includeDescriptions !== void 0) {
592
+ params.include_descriptions = String(Boolean(options.includeDescriptions));
593
+ }
594
+ if (options.includeExamples !== void 0) {
595
+ params.include_examples = String(Boolean(options.includeExamples));
596
+ }
597
+ if (options.healthStatus) params.health_status = options.healthStatus.toLowerCase();
598
+ if (options.limit !== void 0) params.limit = String(options.limit);
599
+ if (options.offset !== void 0) params.offset = String(options.offset);
600
+ const res = await this.http.get("/api/v1/discovery/capabilities", {
601
+ params,
602
+ headers: this.mergeHeaders({
603
+ ...options.headers ?? {},
604
+ Accept: format === "xml" ? "application/xml" : "application/json"
605
+ }),
606
+ responseType: format === "xml" ? "text" : "json",
607
+ transformResponse: (data) => data
608
+ // preserve raw body for xml
609
+ });
610
+ const raw = typeof res.data === "string" ? res.data : JSON.stringify(res.data);
611
+ if (format === "xml") {
612
+ return { format: "xml", raw, xml: raw };
613
+ }
614
+ const parsed = typeof res.data === "string" ? JSON.parse(res.data) : res.data;
615
+ if (format === "compact") {
616
+ return {
617
+ format: "compact",
618
+ raw,
619
+ compact: this.mapCompactDiscovery(parsed)
620
+ };
621
+ }
622
+ return {
623
+ format: "json",
624
+ raw,
625
+ json: this.mapDiscoveryResponse(parsed)
626
+ };
627
+ }
628
+ mapDiscoveryResponse(payload) {
629
+ return {
630
+ discoveredAt: String(payload?.discovered_at ?? ""),
631
+ totalAgents: Number(payload?.total_agents ?? 0),
632
+ totalReasoners: Number(payload?.total_reasoners ?? 0),
633
+ totalSkills: Number(payload?.total_skills ?? 0),
634
+ pagination: {
635
+ limit: Number(payload?.pagination?.limit ?? 0),
636
+ offset: Number(payload?.pagination?.offset ?? 0),
637
+ hasMore: Boolean(payload?.pagination?.has_more)
638
+ },
639
+ capabilities: (payload?.capabilities ?? []).map((cap) => ({
640
+ agentId: cap?.agent_id ?? "",
641
+ baseUrl: cap?.base_url ?? "",
642
+ version: cap?.version ?? "",
643
+ healthStatus: cap?.health_status ?? "",
644
+ deploymentType: cap?.deployment_type,
645
+ lastHeartbeat: cap?.last_heartbeat,
646
+ reasoners: (cap?.reasoners ?? []).map((r) => ({
647
+ id: r?.id ?? "",
648
+ description: r?.description,
649
+ tags: r?.tags ?? [],
650
+ inputSchema: r?.input_schema,
651
+ outputSchema: r?.output_schema,
652
+ examples: r?.examples,
653
+ invocationTarget: r?.invocation_target ?? ""
654
+ })),
655
+ skills: (cap?.skills ?? []).map((s) => ({
656
+ id: s?.id ?? "",
657
+ description: s?.description,
658
+ tags: s?.tags ?? [],
659
+ inputSchema: s?.input_schema,
660
+ invocationTarget: s?.invocation_target ?? ""
661
+ }))
662
+ }))
663
+ };
664
+ }
665
+ mapCompactDiscovery(payload) {
666
+ const toCap = (cap) => ({
667
+ id: cap?.id ?? "",
668
+ agentId: cap?.agent_id ?? "",
669
+ target: cap?.target ?? "",
670
+ tags: cap?.tags ?? []
671
+ });
672
+ return {
673
+ discoveredAt: String(payload?.discovered_at ?? ""),
674
+ reasoners: (payload?.reasoners ?? []).map(toCap),
675
+ skills: (payload?.skills ?? []).map(toCap)
676
+ };
677
+ }
678
+ sanitizeHeaders(headers) {
679
+ const sanitized = {};
680
+ Object.entries(headers).forEach(([key, value]) => {
681
+ if (value === void 0 || value === null) return;
682
+ sanitized[key] = typeof value === "string" ? value : String(value);
683
+ });
684
+ return sanitized;
685
+ }
686
+ mergeHeaders(headers) {
687
+ return {
688
+ ...this.defaultHeaders,
689
+ ...this.sanitizeHeaders(headers ?? {})
690
+ };
691
+ }
692
+ };
693
+ var MemoryClient = class {
694
+ http;
695
+ defaultHeaders;
696
+ constructor(baseUrl, defaultHeaders) {
697
+ this.http = axios.create({
698
+ baseURL: baseUrl.replace(/\/$/, "")
699
+ });
700
+ this.defaultHeaders = this.sanitizeHeaders(defaultHeaders ?? {});
701
+ }
702
+ async set(key, data, options = {}) {
703
+ const payload = { key, data };
704
+ if (options.scope) payload.scope = options.scope;
705
+ await this.http.post("/api/v1/memory/set", payload, {
706
+ headers: this.buildHeaders(options)
707
+ });
708
+ }
709
+ async get(key, options = {}) {
710
+ try {
711
+ const payload = { key };
712
+ if (options.scope) payload.scope = options.scope;
713
+ const res = await this.http.post("/api/v1/memory/get", payload, {
714
+ headers: this.buildHeaders(options)
715
+ });
716
+ return res.data?.data;
717
+ } catch (err) {
718
+ if (isAxiosError(err) && err.response?.status === 404) {
719
+ return void 0;
720
+ }
721
+ throw err;
722
+ }
723
+ }
724
+ async delete(key, options = {}) {
725
+ const payload = { key };
726
+ if (options.scope) payload.scope = options.scope;
727
+ await this.http.post("/api/v1/memory/delete", payload, {
728
+ headers: this.buildHeaders(options)
729
+ });
730
+ }
731
+ async listKeys(scope, options = {}) {
732
+ const res = await this.http.get("/api/v1/memory/list", {
733
+ params: { scope },
734
+ headers: this.buildHeaders({ ...options, scope })
735
+ });
736
+ return (res.data ?? []).map((item) => item?.key).filter(Boolean);
737
+ }
738
+ async exists(key, options = {}) {
739
+ const value = await this.get(key, options);
740
+ return value !== void 0;
741
+ }
742
+ async setVector(key, embedding, metadata, options = {}) {
743
+ const payload = {
744
+ key,
745
+ embedding
746
+ };
747
+ if (metadata !== void 0) payload.metadata = metadata;
748
+ if (options.scope) payload.scope = options.scope;
749
+ await this.http.post("/api/v1/memory/vector/set", payload, {
750
+ headers: this.buildHeaders(options)
751
+ });
752
+ }
753
+ async deleteVector(key, options = {}) {
754
+ const payload = { key };
755
+ if (options.scope) payload.scope = options.scope;
756
+ await this.http.post("/api/v1/memory/vector/delete", payload, {
757
+ headers: this.buildHeaders(options)
758
+ });
759
+ }
760
+ async searchVector(queryEmbedding, options = {}) {
761
+ const payload = {
762
+ query_embedding: queryEmbedding,
763
+ top_k: options.topK ?? 10
764
+ };
765
+ if (options.filters) payload.filters = options.filters;
766
+ if (options.scope) payload.scope = options.scope;
767
+ const res = await this.http.post("/api/v1/memory/vector/search", payload, {
768
+ headers: this.buildHeaders(options)
769
+ });
770
+ return res.data ?? [];
771
+ }
772
+ buildHeaders(options = {}) {
773
+ const { scope, scopeId, metadata } = options;
774
+ const headers = { ...this.defaultHeaders };
775
+ const workflowId = metadata?.workflowId ?? metadata?.runId;
776
+ if (workflowId) headers["X-Workflow-ID"] = workflowId;
777
+ if (metadata?.sessionId) headers["X-Session-ID"] = metadata.sessionId;
778
+ if (metadata?.actorId) headers["X-Actor-ID"] = metadata.actorId;
779
+ if (metadata?.runId) headers["X-Run-ID"] = metadata.runId;
780
+ if (metadata?.executionId) headers["X-Execution-ID"] = metadata.executionId;
781
+ if (metadata?.parentExecutionId) headers["X-Parent-Execution-ID"] = metadata.parentExecutionId;
782
+ if (metadata?.callerDid) headers["X-Caller-DID"] = metadata.callerDid;
783
+ if (metadata?.targetDid) headers["X-Target-DID"] = metadata.targetDid;
784
+ if (metadata?.agentNodeDid) headers["X-Agent-Node-DID"] = metadata.agentNodeDid;
785
+ if (metadata?.agentNodeId) headers["X-Agent-Node-ID"] = metadata.agentNodeId;
786
+ const headerName = this.scopeToHeader(scope);
787
+ const resolvedScopeId = this.resolveScopeId(scope, scopeId, metadata);
788
+ if (headerName && resolvedScopeId) {
789
+ headers[headerName] = resolvedScopeId;
790
+ }
791
+ return { ...headers, ...this.sanitizeHeaders(options.headers ?? {}) };
792
+ }
793
+ scopeToHeader(scope) {
794
+ switch (scope) {
795
+ case "workflow":
796
+ return "X-Workflow-ID";
797
+ case "session":
798
+ return "X-Session-ID";
799
+ case "actor":
800
+ return "X-Actor-ID";
801
+ default:
802
+ return void 0;
803
+ }
804
+ }
805
+ resolveScopeId(scope, scopeId, metadata) {
806
+ if (scopeId) return scopeId;
807
+ switch (scope) {
808
+ case "workflow":
809
+ return metadata?.workflowId ?? metadata?.runId;
810
+ case "session":
811
+ return metadata?.sessionId;
812
+ case "actor":
813
+ return metadata?.actorId;
814
+ case "global":
815
+ return "global";
816
+ default:
817
+ return void 0;
818
+ }
819
+ }
820
+ sanitizeHeaders(headers) {
821
+ const sanitized = {};
822
+ Object.entries(headers).forEach(([key, value]) => {
823
+ if (value === void 0 || value === null) return;
824
+ sanitized[key] = typeof value === "string" ? value : String(value);
825
+ });
826
+ return sanitized;
827
+ }
828
+ };
829
+ var MemoryEventClient = class {
830
+ url;
831
+ ws;
832
+ handlers = [];
833
+ reconnectDelay = 1e3;
834
+ closed = false;
835
+ headers;
836
+ constructor(baseUrl, headers) {
837
+ this.url = `${baseUrl.replace(/^http/, "ws")}/api/v1/memory/events/ws`;
838
+ this.headers = this.buildForwardHeaders(headers ?? {});
839
+ }
840
+ start() {
841
+ if (this.ws) return;
842
+ this.connect();
843
+ }
844
+ onEvent(handler) {
845
+ this.handlers.push(handler);
846
+ }
847
+ stop() {
848
+ this.closed = true;
849
+ this.ws?.close();
850
+ }
851
+ connect() {
852
+ this.ws = new WebSocket(this.url, { headers: this.headers });
853
+ this.ws.on("open", () => {
854
+ this.reconnectDelay = 1e3;
855
+ });
856
+ this.ws.on("message", async (raw) => {
857
+ try {
858
+ const parsed = JSON.parse(raw.toString());
859
+ for (const handler of this.handlers) {
860
+ await handler(parsed);
861
+ }
862
+ } catch (err) {
863
+ console.error("Failed to handle memory event", err);
864
+ }
865
+ });
866
+ this.ws.on("close", () => this.scheduleReconnect());
867
+ this.ws.on("error", () => this.scheduleReconnect());
868
+ }
869
+ scheduleReconnect() {
870
+ if (this.closed) return;
871
+ setTimeout(() => {
872
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, 3e4);
873
+ this.connect();
874
+ }, this.reconnectDelay);
875
+ }
876
+ buildForwardHeaders(headers) {
877
+ const allowed = /* @__PURE__ */ new Set(["authorization", "cookie"]);
878
+ const sanitized = {};
879
+ Object.entries(headers).forEach(([key, value]) => {
880
+ if (value === void 0 || value === null) return;
881
+ const lower = key.toLowerCase();
882
+ if (lower.startsWith("x-") || allowed.has(lower)) {
883
+ sanitized[key] = typeof value === "string" ? value : String(value);
884
+ }
885
+ });
886
+ return sanitized;
887
+ }
888
+ };
889
+
890
+ // src/memory/MemoryInterface.ts
891
+ var MemoryInterface = class _MemoryInterface {
892
+ client;
893
+ eventClient;
894
+ aiClient;
895
+ defaultScope;
896
+ defaultScopeId;
897
+ metadata;
898
+ constructor(params) {
899
+ this.client = params.client;
900
+ this.eventClient = params.eventClient;
901
+ this.aiClient = params.aiClient;
902
+ this.defaultScope = params.defaultScope ?? "workflow";
903
+ this.defaultScopeId = params.defaultScopeId;
904
+ this.metadata = params.metadata;
905
+ }
906
+ async set(key, data, scope = this.defaultScope, scopeId = this.defaultScopeId) {
907
+ await this.client.set(key, data, {
908
+ scope,
909
+ scopeId,
910
+ metadata: this.metadata
911
+ });
912
+ }
913
+ get(key, scope = this.defaultScope, scopeId = this.defaultScopeId) {
914
+ if (scope === this.defaultScope && scopeId === this.defaultScopeId) {
915
+ return this.getWithFallback(key);
916
+ }
917
+ return this.client.get(key, {
918
+ scope,
919
+ scopeId,
920
+ metadata: this.metadata
921
+ });
922
+ }
923
+ async getWithFallback(key) {
924
+ for (const candidate of this.getScopeOrder()) {
925
+ const value = await this.client.get(key, {
926
+ scope: candidate.scope,
927
+ scopeId: candidate.scopeId,
928
+ metadata: this.metadata
929
+ });
930
+ if (value !== void 0) return value;
931
+ }
932
+ return void 0;
933
+ }
934
+ async setVector(key, embedding, metadata, scope = this.defaultScope, scopeId = this.defaultScopeId) {
935
+ await this.client.setVector(key, embedding, metadata, {
936
+ scope,
937
+ scopeId,
938
+ metadata: this.metadata
939
+ });
940
+ }
941
+ async deleteVector(key, scope = this.defaultScope, scopeId = this.defaultScopeId) {
942
+ await this.client.deleteVector(key, {
943
+ scope,
944
+ scopeId,
945
+ metadata: this.metadata
946
+ });
947
+ }
948
+ searchVector(queryEmbedding, options = {}) {
949
+ return this.client.searchVector(queryEmbedding, {
950
+ ...options,
951
+ metadata: this.metadata
952
+ });
953
+ }
954
+ delete(key, scope = this.defaultScope, scopeId = this.defaultScopeId) {
955
+ return this.client.delete(key, {
956
+ scope,
957
+ scopeId,
958
+ metadata: this.metadata
959
+ });
960
+ }
961
+ exists(key, scope = this.defaultScope, scopeId = this.defaultScopeId) {
962
+ return this.client.exists(key, {
963
+ scope,
964
+ scopeId,
965
+ metadata: this.metadata
966
+ });
967
+ }
968
+ listKeys(scope = this.defaultScope, scopeId = this.defaultScopeId) {
969
+ return this.client.listKeys(scope, {
970
+ scope,
971
+ scopeId,
972
+ metadata: this.metadata
973
+ });
974
+ }
975
+ async embedText(text, options) {
976
+ if (!this.aiClient) {
977
+ throw new Error("AI client not configured for embeddings");
978
+ }
979
+ return this.aiClient.embed(text, options);
980
+ }
981
+ async embedTexts(texts, options) {
982
+ if (!this.aiClient) {
983
+ throw new Error("AI client not configured for embeddings");
984
+ }
985
+ return this.aiClient.embedMany(texts, options);
986
+ }
987
+ async embedAndSet(key, text, metadata, scope = this.defaultScope, scopeId = this.defaultScopeId, embeddingOptions) {
988
+ const embedding = await this.embedText(text, embeddingOptions);
989
+ await this.setVector(key, embedding, metadata, scope, scopeId);
990
+ return embedding;
991
+ }
992
+ async deleteVectors(keys, scope = this.defaultScope, scopeId = this.defaultScopeId) {
993
+ for (const key of keys) {
994
+ await this.deleteVector(key, scope, scopeId);
995
+ }
996
+ }
997
+ workflow(scopeId) {
998
+ return this.cloneWithScope("workflow", scopeId);
999
+ }
1000
+ session(scopeId) {
1001
+ return this.cloneWithScope("session", scopeId);
1002
+ }
1003
+ actor(scopeId) {
1004
+ return this.cloneWithScope("actor", scopeId);
1005
+ }
1006
+ get globalScope() {
1007
+ return this.cloneWithScope("global", "global");
1008
+ }
1009
+ onEvent(handler) {
1010
+ this.eventClient?.onEvent(handler);
1011
+ }
1012
+ cloneWithScope(scope, scopeId) {
1013
+ return new _MemoryInterface({
1014
+ client: this.client,
1015
+ eventClient: this.eventClient,
1016
+ aiClient: this.aiClient,
1017
+ defaultScope: scope,
1018
+ defaultScopeId: scopeId ?? this.resolveScopeId(scope, this.metadata),
1019
+ metadata: this.metadata
1020
+ });
1021
+ }
1022
+ getScopeOrder() {
1023
+ const metadata = this.metadata ?? {};
1024
+ const order = [];
1025
+ const pushUnique = (scope, scopeId) => {
1026
+ const key = `${scope}:${scopeId ?? ""}`;
1027
+ if (!order.some((c) => `${c.scope}:${c.scopeId ?? ""}` === key)) {
1028
+ order.push({ scope, scopeId });
1029
+ }
1030
+ };
1031
+ pushUnique(this.defaultScope, this.defaultScopeId ?? this.resolveScopeId(this.defaultScope, metadata));
1032
+ const defaultSequence = ["workflow", "session", "actor", "global"];
1033
+ defaultSequence.forEach((scope) => {
1034
+ pushUnique(scope, this.resolveScopeId(scope, metadata));
1035
+ });
1036
+ return order;
1037
+ }
1038
+ resolveScopeId(scope, metadata) {
1039
+ switch (scope) {
1040
+ case "workflow":
1041
+ return metadata?.workflowId ?? metadata?.runId;
1042
+ case "session":
1043
+ return metadata?.sessionId;
1044
+ case "actor":
1045
+ return metadata?.actorId;
1046
+ case "global":
1047
+ return "global";
1048
+ default:
1049
+ return void 0;
1050
+ }
1051
+ }
1052
+ };
1053
+ var DidClient = class {
1054
+ http;
1055
+ defaultHeaders;
1056
+ constructor(baseUrl, defaultHeaders) {
1057
+ this.http = axios.create({ baseURL: baseUrl.replace(/\/$/, "") });
1058
+ this.defaultHeaders = this.sanitizeHeaders(defaultHeaders ?? {});
1059
+ }
1060
+ async generateCredential(params) {
1061
+ const ctx = params.executionContext;
1062
+ const timestamp = ctx.timestamp instanceof Date ? ctx.timestamp.toISOString() : ctx.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
1063
+ const payload = {
1064
+ execution_context: {
1065
+ execution_id: ctx.executionId,
1066
+ workflow_id: ctx.workflowId,
1067
+ session_id: ctx.sessionId,
1068
+ caller_did: ctx.callerDid,
1069
+ target_did: ctx.targetDid,
1070
+ agent_node_did: ctx.agentNodeDid,
1071
+ timestamp
1072
+ },
1073
+ input_data: this.serializeDataForJson(params.inputData),
1074
+ output_data: this.serializeDataForJson(params.outputData),
1075
+ status: params.status ?? "succeeded",
1076
+ error_message: params.errorMessage,
1077
+ duration_ms: params.durationMs ?? 0
1078
+ };
1079
+ const res = await this.http.post("/api/v1/execution/vc", payload, {
1080
+ headers: this.mergeHeaders(params.headers)
1081
+ });
1082
+ return this.mapExecutionCredential(res.data);
1083
+ }
1084
+ async exportAuditTrail(filters = {}) {
1085
+ const res = await this.http.get("/api/v1/did/export/vcs", {
1086
+ params: this.cleanFilters(filters),
1087
+ headers: this.mergeHeaders()
1088
+ });
1089
+ const data = res.data ?? {};
1090
+ return {
1091
+ agentDids: data.agent_dids ?? [],
1092
+ executionVcs: (data.execution_vcs ?? []).map((vc) => ({
1093
+ vcId: vc.vc_id,
1094
+ executionId: vc.execution_id,
1095
+ workflowId: vc.workflow_id,
1096
+ sessionId: vc.session_id,
1097
+ issuerDid: vc.issuer_did,
1098
+ targetDid: vc.target_did,
1099
+ callerDid: vc.caller_did,
1100
+ status: vc.status,
1101
+ createdAt: vc.created_at
1102
+ })),
1103
+ workflowVcs: (data.workflow_vcs ?? []).map((vc) => ({
1104
+ workflowId: vc.workflow_id,
1105
+ sessionId: vc.session_id,
1106
+ componentVcs: vc.component_vcs ?? [],
1107
+ workflowVcId: vc.workflow_vc_id ?? vc.workflowVcId ?? vc.workflow_id,
1108
+ status: vc.status,
1109
+ startTime: vc.start_time,
1110
+ endTime: vc.end_time,
1111
+ totalSteps: vc.total_steps ?? 0,
1112
+ completedSteps: vc.completed_steps ?? 0
1113
+ })),
1114
+ totalCount: data.total_count ?? 0,
1115
+ filtersApplied: data.filters_applied
1116
+ };
1117
+ }
1118
+ serializeDataForJson(data) {
1119
+ if (data === void 0 || data === null) return "";
1120
+ let value;
1121
+ if (typeof data === "string") {
1122
+ value = data;
1123
+ } else if (data instanceof Uint8Array) {
1124
+ value = Buffer.from(data).toString("utf-8");
1125
+ } else if (typeof data === "object") {
1126
+ try {
1127
+ value = JSON.stringify(data, Object.keys(data).sort());
1128
+ } catch {
1129
+ value = String(data);
1130
+ }
1131
+ } else {
1132
+ value = String(data);
1133
+ }
1134
+ return Buffer.from(value, "utf-8").toString("base64");
1135
+ }
1136
+ mapExecutionCredential(data) {
1137
+ return {
1138
+ vcId: data?.vc_id ?? "",
1139
+ executionId: data?.execution_id ?? "",
1140
+ workflowId: data?.workflow_id ?? "",
1141
+ sessionId: data?.session_id,
1142
+ issuerDid: data?.issuer_did,
1143
+ targetDid: data?.target_did,
1144
+ callerDid: data?.caller_did,
1145
+ vcDocument: data?.vc_document,
1146
+ signature: data?.signature,
1147
+ inputHash: data?.input_hash,
1148
+ outputHash: data?.output_hash,
1149
+ status: data?.status ?? "",
1150
+ createdAt: data?.created_at ?? ""
1151
+ };
1152
+ }
1153
+ cleanFilters(filters) {
1154
+ const cleaned = {};
1155
+ if (filters.workflowId) cleaned.workflow_id = filters.workflowId;
1156
+ if (filters.sessionId) cleaned.session_id = filters.sessionId;
1157
+ if (filters.issuerDid) cleaned.issuer_did = filters.issuerDid;
1158
+ if (filters.status) cleaned.status = filters.status;
1159
+ if (filters.limit !== void 0) cleaned.limit = filters.limit;
1160
+ return cleaned;
1161
+ }
1162
+ mergeHeaders(headers) {
1163
+ return {
1164
+ ...this.defaultHeaders,
1165
+ ...this.sanitizeHeaders(headers ?? {})
1166
+ };
1167
+ }
1168
+ sanitizeHeaders(headers) {
1169
+ const sanitized = {};
1170
+ Object.entries(headers).forEach(([key, value]) => {
1171
+ if (value === void 0 || value === null) return;
1172
+ sanitized[key] = typeof value === "string" ? value : String(value);
1173
+ });
1174
+ return sanitized;
1175
+ }
1176
+ };
1177
+
1178
+ // src/did/DidInterface.ts
1179
+ var DidInterface = class {
1180
+ client;
1181
+ metadata;
1182
+ enabled;
1183
+ defaultInput;
1184
+ constructor(params) {
1185
+ this.client = params.client;
1186
+ this.metadata = params.metadata;
1187
+ this.enabled = params.enabled;
1188
+ this.defaultInput = params.defaultInput;
1189
+ }
1190
+ async generateCredential(options = {}) {
1191
+ if (!this.enabled) {
1192
+ throw new Error("DID/VC features are disabled. Enable didEnabled in AgentConfig to use ctx.did.");
1193
+ }
1194
+ const executionContext = {
1195
+ executionId: options.executionId ?? this.metadata.executionId,
1196
+ workflowId: options.workflowId ?? this.metadata.workflowId ?? this.metadata.runId,
1197
+ sessionId: options.sessionId ?? this.metadata.sessionId,
1198
+ callerDid: options.callerDid ?? this.metadata.callerDid,
1199
+ targetDid: options.targetDid ?? this.metadata.targetDid,
1200
+ agentNodeDid: options.agentNodeDid ?? this.metadata.agentNodeDid,
1201
+ timestamp: options.timestamp
1202
+ };
1203
+ return this.client.generateCredential({
1204
+ executionContext,
1205
+ inputData: options.inputData ?? this.defaultInput,
1206
+ outputData: options.outputData,
1207
+ status: options.status,
1208
+ errorMessage: options.errorMessage,
1209
+ durationMs: options.durationMs,
1210
+ headers: options.headers
1211
+ });
1212
+ }
1213
+ exportAuditTrail(filters) {
1214
+ if (!this.enabled) {
1215
+ throw new Error("DID/VC features are disabled. Enable didEnabled in AgentConfig to use ctx.did.");
1216
+ }
1217
+ return this.client.exportAuditTrail(filters);
1218
+ }
1219
+ };
1220
+
1221
+ // src/utils/pattern.ts
1222
+ function matchesPattern(pattern, value) {
1223
+ const escaped = pattern.replace(/[-/\\^$+?.()|[\]{}]/g, "\\$&").replace(/\*/g, ".*");
1224
+ const regex = new RegExp(`^${escaped}$`);
1225
+ return regex.test(value);
1226
+ }
1227
+
1228
+ // src/workflow/WorkflowReporter.ts
1229
+ var WorkflowReporter = class {
1230
+ client;
1231
+ metadata;
1232
+ constructor(client, metadata) {
1233
+ if (!metadata.executionId) {
1234
+ throw new Error("WorkflowReporter requires an executionId");
1235
+ }
1236
+ this.client = client;
1237
+ this.metadata = metadata;
1238
+ }
1239
+ async progress(progress, options) {
1240
+ const normalized = Math.min(100, Math.max(0, Math.round(progress)));
1241
+ return this.client.updateExecutionStatus(this.metadata.executionId, {
1242
+ status: options?.status ?? "running",
1243
+ progress: normalized,
1244
+ result: options?.result,
1245
+ error: options?.error,
1246
+ durationMs: options?.durationMs
1247
+ });
1248
+ }
1249
+ };
1250
+ var MCPClient = class {
1251
+ alias;
1252
+ baseUrl;
1253
+ transport;
1254
+ http;
1255
+ devMode;
1256
+ lastHealthy = false;
1257
+ constructor(config, devMode) {
1258
+ if (!config.alias) {
1259
+ throw new Error("MCP server alias is required");
1260
+ }
1261
+ if (!config.url && !config.port) {
1262
+ throw new Error(`MCP server "${config.alias}" requires a url or port`);
1263
+ }
1264
+ this.alias = config.alias;
1265
+ this.transport = config.transport ?? "http";
1266
+ this.baseUrl = (config.url ?? `http://localhost:${config.port}`).replace(/\/$/, "");
1267
+ this.http = axios.create({
1268
+ baseURL: this.baseUrl,
1269
+ headers: config.headers
1270
+ });
1271
+ this.devMode = Boolean(devMode);
1272
+ }
1273
+ async healthCheck() {
1274
+ try {
1275
+ await this.http.get("/health");
1276
+ this.lastHealthy = true;
1277
+ return true;
1278
+ } catch (err) {
1279
+ this.lastHealthy = false;
1280
+ if (this.devMode) {
1281
+ console.warn(`MCP health check failed for ${this.alias}:`, err instanceof Error ? err.message : err);
1282
+ }
1283
+ return false;
1284
+ }
1285
+ }
1286
+ async listTools() {
1287
+ try {
1288
+ if (this.transport === "bridge") {
1289
+ const res2 = await this.http.post("/mcp/tools/list");
1290
+ const tools2 = res2.data?.tools ?? [];
1291
+ return this.normalizeTools(tools2);
1292
+ }
1293
+ const res = await this.http.post("/mcp/v1", {
1294
+ jsonrpc: "2.0",
1295
+ id: Date.now(),
1296
+ method: "tools/list",
1297
+ params: {}
1298
+ });
1299
+ const tools = res.data?.result?.tools ?? [];
1300
+ return this.normalizeTools(tools);
1301
+ } catch (err) {
1302
+ if (this.devMode) {
1303
+ console.warn(`MCP listTools failed for ${this.alias}:`, err instanceof Error ? err.message : err);
1304
+ }
1305
+ return [];
1306
+ }
1307
+ }
1308
+ async callTool(toolName, arguments_ = {}) {
1309
+ if (!toolName) {
1310
+ throw new Error("toolName is required");
1311
+ }
1312
+ try {
1313
+ if (this.transport === "bridge") {
1314
+ const res2 = await this.http.post("/mcp/tools/call", {
1315
+ tool_name: toolName,
1316
+ arguments: arguments_
1317
+ });
1318
+ return res2.data?.result ?? res2.data;
1319
+ }
1320
+ const res = await this.http.post("/mcp/v1", {
1321
+ jsonrpc: "2.0",
1322
+ id: Date.now(),
1323
+ method: "tools/call",
1324
+ params: { name: toolName, arguments: arguments_ }
1325
+ });
1326
+ if (res.data?.error) {
1327
+ throw new Error(String(res.data.error?.message ?? res.data.error));
1328
+ }
1329
+ if (res.data?.result !== void 0) {
1330
+ return res.data.result;
1331
+ }
1332
+ return res.data;
1333
+ } catch (err) {
1334
+ if (this.devMode) {
1335
+ console.warn(`MCP callTool failed for ${this.alias}.${toolName}:`, err instanceof Error ? err.message : err);
1336
+ }
1337
+ throw err;
1338
+ }
1339
+ }
1340
+ get lastHealthStatus() {
1341
+ return this.lastHealthy;
1342
+ }
1343
+ normalizeTools(tools) {
1344
+ return (tools ?? []).map((tool) => ({
1345
+ name: tool?.name ?? "unknown",
1346
+ description: tool?.description,
1347
+ inputSchema: tool?.inputSchema ?? tool?.input_schema,
1348
+ input_schema: tool?.input_schema
1349
+ }));
1350
+ }
1351
+ };
1352
+
1353
+ // src/mcp/MCPClientRegistry.ts
1354
+ var MCPClientRegistry = class {
1355
+ clients = /* @__PURE__ */ new Map();
1356
+ devMode;
1357
+ constructor(devMode) {
1358
+ this.devMode = Boolean(devMode);
1359
+ }
1360
+ register(config) {
1361
+ const client = new MCPClient(config, this.devMode);
1362
+ this.clients.set(config.alias, client);
1363
+ return client;
1364
+ }
1365
+ get(alias) {
1366
+ return this.clients.get(alias);
1367
+ }
1368
+ list() {
1369
+ return Array.from(this.clients.values());
1370
+ }
1371
+ async healthSummary() {
1372
+ if (!this.clients.size) {
1373
+ return {
1374
+ status: "disabled",
1375
+ totalServers: 0,
1376
+ healthyServers: 0,
1377
+ servers: []
1378
+ };
1379
+ }
1380
+ const results = await Promise.all(
1381
+ Array.from(this.clients.values()).map(async (client) => {
1382
+ const healthy = await client.healthCheck();
1383
+ return {
1384
+ alias: client.alias,
1385
+ baseUrl: client.baseUrl,
1386
+ transport: client.transport,
1387
+ healthy
1388
+ };
1389
+ })
1390
+ );
1391
+ const healthyCount = results.filter((r) => r.healthy).length;
1392
+ const status = healthyCount === 0 ? "degraded" : healthyCount === results.length ? "ok" : "degraded";
1393
+ return {
1394
+ status,
1395
+ totalServers: results.length,
1396
+ healthyServers: healthyCount,
1397
+ servers: results
1398
+ };
1399
+ }
1400
+ };
1401
+
1402
+ // src/mcp/MCPToolRegistrar.ts
1403
+ var MCPToolRegistrar = class {
1404
+ constructor(agent, registry, options = {}) {
1405
+ this.agent = agent;
1406
+ this.registry = registry;
1407
+ this.options = options;
1408
+ this.devMode = Boolean(options.devMode);
1409
+ }
1410
+ registered = /* @__PURE__ */ new Set();
1411
+ devMode;
1412
+ registerServers(servers) {
1413
+ servers.forEach((server) => this.registry.register(server));
1414
+ }
1415
+ async registerAll() {
1416
+ const registrations = [];
1417
+ const clients = this.registry.list();
1418
+ for (const client of clients) {
1419
+ const healthy = await client.healthCheck();
1420
+ if (!healthy) {
1421
+ if (this.devMode) {
1422
+ console.warn(`Skipping MCP server ${client.alias} (health check failed)`);
1423
+ }
1424
+ continue;
1425
+ }
1426
+ const tools = await client.listTools();
1427
+ for (const tool of tools) {
1428
+ if (!tool?.name) continue;
1429
+ const skillName = this.buildSkillName(client.alias, tool.name);
1430
+ if (this.registered.has(skillName) || this.agent.skills.get(skillName)) {
1431
+ continue;
1432
+ }
1433
+ this.agent.skill(
1434
+ skillName,
1435
+ async (ctx) => {
1436
+ const args = ctx.input && typeof ctx.input === "object" ? ctx.input : {};
1437
+ const result = await client.callTool(tool.name, args);
1438
+ return {
1439
+ status: "success",
1440
+ result,
1441
+ server: client.alias,
1442
+ tool: tool.name
1443
+ };
1444
+ },
1445
+ {
1446
+ description: tool.description ?? `MCP tool ${tool.name} from ${client.alias}`,
1447
+ inputSchema: tool.inputSchema ?? tool.input_schema ?? {},
1448
+ tags: this.buildTags(client.alias)
1449
+ }
1450
+ );
1451
+ this.registered.add(skillName);
1452
+ registrations.push({ server: client.alias, skillName, tool });
1453
+ if (this.devMode) {
1454
+ console.info(`Registered MCP skill ${skillName}`);
1455
+ }
1456
+ }
1457
+ }
1458
+ return { registered: registrations };
1459
+ }
1460
+ buildTags(alias) {
1461
+ return Array.from(/* @__PURE__ */ new Set(["mcp", alias, ...this.options.tags ?? []]));
1462
+ }
1463
+ buildSkillName(serverAlias, toolName) {
1464
+ const base = [this.options.namespace, serverAlias, toolName].filter(Boolean).join("_");
1465
+ return this.sanitize(base);
1466
+ }
1467
+ sanitize(value) {
1468
+ const collapsed = value.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
1469
+ if (/^[0-9]/.test(collapsed)) {
1470
+ return `mcp_${collapsed}`;
1471
+ }
1472
+ return collapsed || "mcp_tool";
1473
+ }
1474
+ };
1475
+
1476
+ // src/agent/Agent.ts
1477
+ var TargetNotFoundError = class extends Error {
1478
+ };
1479
+ var Agent = class {
1480
+ config;
1481
+ app;
1482
+ reasoners = new ReasonerRegistry();
1483
+ skills = new SkillRegistry();
1484
+ server;
1485
+ heartbeatTimer;
1486
+ aiClient;
1487
+ agentFieldClient;
1488
+ memoryClient;
1489
+ memoryEventClient;
1490
+ didClient;
1491
+ memoryWatchers = [];
1492
+ mcpClientRegistry;
1493
+ mcpToolRegistrar;
1494
+ constructor(config) {
1495
+ const mcp = config.mcp ? {
1496
+ autoRegisterTools: config.mcp.autoRegisterTools ?? true,
1497
+ ...config.mcp
1498
+ } : void 0;
1499
+ this.config = {
1500
+ port: 8001,
1501
+ agentFieldUrl: "http://localhost:8080",
1502
+ host: "0.0.0.0",
1503
+ ...config,
1504
+ didEnabled: config.didEnabled ?? true,
1505
+ deploymentType: config.deploymentType ?? "long_running",
1506
+ mcp
1507
+ };
1508
+ this.app = express();
1509
+ this.app.use(express.json());
1510
+ this.aiClient = new AIClient(this.config.aiConfig);
1511
+ this.agentFieldClient = new AgentFieldClient(this.config);
1512
+ this.memoryClient = new MemoryClient(this.config.agentFieldUrl, this.config.defaultHeaders);
1513
+ this.memoryEventClient = new MemoryEventClient(this.config.agentFieldUrl, this.config.defaultHeaders);
1514
+ this.didClient = new DidClient(this.config.agentFieldUrl, this.config.defaultHeaders);
1515
+ this.memoryEventClient.onEvent((event) => this.dispatchMemoryEvent(event));
1516
+ if (this.config.mcp?.servers?.length) {
1517
+ this.mcpClientRegistry = new MCPClientRegistry(this.config.devMode);
1518
+ this.mcpToolRegistrar = new MCPToolRegistrar(this, this.mcpClientRegistry, {
1519
+ namespace: this.config.mcp.namespace,
1520
+ tags: this.config.mcp.tags,
1521
+ devMode: this.config.devMode
1522
+ });
1523
+ this.mcpToolRegistrar.registerServers(this.config.mcp.servers);
1524
+ }
1525
+ this.registerDefaultRoutes();
1526
+ }
1527
+ reasoner(name, handler, options) {
1528
+ this.reasoners.register(name, handler, options);
1529
+ return this;
1530
+ }
1531
+ skill(name, handler, options) {
1532
+ this.skills.register(name, handler, options);
1533
+ return this;
1534
+ }
1535
+ includeRouter(router) {
1536
+ this.reasoners.includeRouter(router);
1537
+ this.skills.includeRouter(router);
1538
+ }
1539
+ handler() {
1540
+ return async (event, res) => {
1541
+ if (res && typeof res === "object" && typeof res.setHeader === "function") {
1542
+ return this.handleHttpRequest(event, res);
1543
+ }
1544
+ return this.handleServerlessEvent(event);
1545
+ };
1546
+ }
1547
+ watchMemory(pattern, handler, options) {
1548
+ const patterns = Array.isArray(pattern) ? pattern : [pattern];
1549
+ patterns.forEach(
1550
+ (p) => this.memoryWatchers.push({ pattern: p, handler, scope: options?.scope, scopeId: options?.scopeId })
1551
+ );
1552
+ this.memoryEventClient.start();
1553
+ }
1554
+ discover(options) {
1555
+ return this.agentFieldClient.discoverCapabilities(options);
1556
+ }
1557
+ async registerMcpTools() {
1558
+ if (!this.mcpToolRegistrar) return { registered: [] };
1559
+ return this.mcpToolRegistrar.registerAll();
1560
+ }
1561
+ getAIClient() {
1562
+ return this.aiClient;
1563
+ }
1564
+ getMemoryInterface(metadata) {
1565
+ const defaultScope = this.config.memoryConfig?.defaultScope ?? "workflow";
1566
+ const defaultScopeId = defaultScope === "session" ? metadata?.sessionId : defaultScope === "actor" ? metadata?.actorId : metadata?.workflowId ?? metadata?.runId ?? metadata?.sessionId ?? metadata?.actorId;
1567
+ return new MemoryInterface({
1568
+ client: this.memoryClient,
1569
+ eventClient: this.memoryEventClient,
1570
+ aiClient: this.aiClient,
1571
+ defaultScope,
1572
+ defaultScopeId,
1573
+ metadata: {
1574
+ workflowId: metadata?.workflowId ?? metadata?.runId,
1575
+ sessionId: metadata?.sessionId,
1576
+ actorId: metadata?.actorId,
1577
+ runId: metadata?.runId,
1578
+ executionId: metadata?.executionId,
1579
+ parentExecutionId: metadata?.parentExecutionId,
1580
+ callerDid: metadata?.callerDid,
1581
+ targetDid: metadata?.targetDid,
1582
+ agentNodeDid: metadata?.agentNodeDid,
1583
+ agentNodeId: this.config.nodeId
1584
+ }
1585
+ });
1586
+ }
1587
+ getWorkflowReporter(metadata) {
1588
+ return new WorkflowReporter(this.agentFieldClient, {
1589
+ executionId: metadata.executionId,
1590
+ runId: metadata.runId,
1591
+ workflowId: metadata.workflowId,
1592
+ agentNodeId: this.config.nodeId
1593
+ });
1594
+ }
1595
+ getDidInterface(metadata, defaultInput) {
1596
+ return new DidInterface({
1597
+ client: this.didClient,
1598
+ metadata: {
1599
+ ...metadata,
1600
+ agentNodeDid: metadata.agentNodeDid ?? this.config.defaultHeaders?.["X-Agent-Node-DID"]?.toString()
1601
+ },
1602
+ enabled: Boolean(this.config.didEnabled),
1603
+ defaultInput
1604
+ });
1605
+ }
1606
+ async serve() {
1607
+ if (this.config.mcp?.autoRegisterTools !== false) {
1608
+ try {
1609
+ await this.registerMcpTools();
1610
+ } catch (err) {
1611
+ if (this.config.devMode) {
1612
+ console.warn("MCP tool registration failed", err);
1613
+ }
1614
+ }
1615
+ }
1616
+ await this.registerWithControlPlane();
1617
+ const port = this.config.port ?? 8001;
1618
+ const host = this.config.host ?? "0.0.0.0";
1619
+ await this.agentFieldClient.heartbeat("starting");
1620
+ await new Promise((resolve, reject) => {
1621
+ this.server = this.app.listen(port, host, () => resolve()).on("error", reject);
1622
+ });
1623
+ this.memoryEventClient.start();
1624
+ this.startHeartbeat();
1625
+ }
1626
+ async shutdown() {
1627
+ if (this.heartbeatTimer) {
1628
+ clearInterval(this.heartbeatTimer);
1629
+ }
1630
+ await new Promise((resolve, reject) => {
1631
+ this.server?.close((err) => {
1632
+ if (err) reject(err);
1633
+ else resolve();
1634
+ });
1635
+ });
1636
+ this.memoryEventClient.stop();
1637
+ }
1638
+ async call(target, input) {
1639
+ const { agentId, name } = this.parseTarget(target);
1640
+ if (!agentId || agentId === this.config.nodeId) {
1641
+ const local = this.reasoners.get(name);
1642
+ if (!local) throw new Error(`Reasoner not found: ${name}`);
1643
+ const parentMetadata = ExecutionContext.getCurrent()?.metadata;
1644
+ const runId = parentMetadata?.runId ?? parentMetadata?.executionId ?? randomUUID();
1645
+ const metadata2 = {
1646
+ ...parentMetadata,
1647
+ executionId: randomUUID(),
1648
+ parentExecutionId: parentMetadata?.executionId,
1649
+ runId,
1650
+ workflowId: parentMetadata?.workflowId ?? runId
1651
+ };
1652
+ const dummyReq = {};
1653
+ const dummyRes = {};
1654
+ const execCtx = new ExecutionContext({
1655
+ input,
1656
+ metadata: {
1657
+ ...metadata2,
1658
+ executionId: metadata2.executionId ?? randomUUID()
1659
+ },
1660
+ req: dummyReq,
1661
+ res: dummyRes,
1662
+ agent: this
1663
+ });
1664
+ const startTime = Date.now();
1665
+ const emitEvent = async (status, payload) => {
1666
+ await this.agentFieldClient.publishWorkflowEvent({
1667
+ executionId: execCtx.metadata.executionId,
1668
+ runId: execCtx.metadata.runId ?? execCtx.metadata.executionId,
1669
+ workflowId: execCtx.metadata.workflowId,
1670
+ reasonerId: name,
1671
+ agentNodeId: this.config.nodeId,
1672
+ status,
1673
+ parentExecutionId: execCtx.metadata.parentExecutionId,
1674
+ parentWorkflowId: execCtx.metadata.workflowId,
1675
+ inputData: status === "running" ? input : void 0,
1676
+ result: status === "succeeded" ? payload : void 0,
1677
+ error: status === "failed" ? payload?.message ?? String(payload) : void 0,
1678
+ durationMs: status === "running" ? void 0 : Date.now() - startTime
1679
+ });
1680
+ };
1681
+ await emitEvent("running", null);
1682
+ return ExecutionContext.run(execCtx, async () => {
1683
+ try {
1684
+ const result = await local.handler(
1685
+ new ReasonerContext({
1686
+ input,
1687
+ executionId: execCtx.metadata.executionId,
1688
+ runId: execCtx.metadata.runId,
1689
+ sessionId: execCtx.metadata.sessionId,
1690
+ actorId: execCtx.metadata.actorId,
1691
+ workflowId: execCtx.metadata.workflowId,
1692
+ parentExecutionId: execCtx.metadata.parentExecutionId,
1693
+ callerDid: execCtx.metadata.callerDid,
1694
+ targetDid: execCtx.metadata.targetDid,
1695
+ agentNodeDid: execCtx.metadata.agentNodeDid,
1696
+ req: dummyReq,
1697
+ res: dummyRes,
1698
+ agent: this,
1699
+ aiClient: this.aiClient,
1700
+ memory: this.getMemoryInterface(execCtx.metadata),
1701
+ workflow: this.getWorkflowReporter(execCtx.metadata),
1702
+ did: this.getDidInterface(execCtx.metadata, input)
1703
+ })
1704
+ );
1705
+ await emitEvent("succeeded", result);
1706
+ return result;
1707
+ } catch (err) {
1708
+ await emitEvent("failed", err);
1709
+ throw err;
1710
+ }
1711
+ });
1712
+ }
1713
+ const metadata = ExecutionContext.getCurrent()?.metadata;
1714
+ return this.agentFieldClient.execute(target, input, {
1715
+ runId: metadata?.runId ?? metadata?.executionId,
1716
+ workflowId: metadata?.workflowId ?? metadata?.runId,
1717
+ parentExecutionId: metadata?.executionId,
1718
+ sessionId: metadata?.sessionId,
1719
+ actorId: metadata?.actorId,
1720
+ callerDid: metadata?.callerDid,
1721
+ targetDid: metadata?.targetDid,
1722
+ agentNodeDid: metadata?.agentNodeDid,
1723
+ agentNodeId: this.config.nodeId
1724
+ });
1725
+ }
1726
+ registerDefaultRoutes() {
1727
+ this.app.get("/health", (_req, res) => {
1728
+ res.json(this.health());
1729
+ });
1730
+ this.app.get("/discover", (_req, res) => {
1731
+ res.json(this.discoveryPayload(this.config.deploymentType ?? "long_running"));
1732
+ });
1733
+ this.app.get("/health/mcp", async (_req, res) => {
1734
+ if (!this.mcpClientRegistry) {
1735
+ res.json({ status: "disabled", totalServers: 0, healthyServers: 0, servers: [] });
1736
+ return;
1737
+ }
1738
+ try {
1739
+ const summary = await this.mcpClientRegistry.healthSummary();
1740
+ res.json(summary);
1741
+ } catch (err) {
1742
+ res.status(500).json({ status: "error", error: err?.message ?? "MCP health check failed" });
1743
+ }
1744
+ });
1745
+ this.app.get("/mcp/status", (_req, res) => {
1746
+ res.json(this.mcpStatus());
1747
+ });
1748
+ this.app.get("/status", (_req, res) => {
1749
+ res.json({
1750
+ ...this.health(),
1751
+ reasoners: this.reasoners.all().map((r) => r.name),
1752
+ skills: this.skills.all().map((s) => s.name)
1753
+ });
1754
+ });
1755
+ this.app.get("/reasoners", (_req, res) => {
1756
+ res.json(this.reasoners.all().map((r) => r.name));
1757
+ });
1758
+ this.app.get("/skills", (_req, res) => {
1759
+ res.json(this.skills.all().map((s) => s.name));
1760
+ });
1761
+ this.app.post("/api/v1/reasoners/*", (req, res) => this.executeReasoner(req, res, req.params[0]));
1762
+ this.app.post("/reasoners/:name", (req, res) => this.executeReasoner(req, res, req.params.name));
1763
+ this.app.post("/api/v1/skills/*", (req, res) => this.executeSkill(req, res, req.params[0]));
1764
+ this.app.post("/skills/:name", (req, res) => this.executeSkill(req, res, req.params.name));
1765
+ this.app.post("/execute", (req, res) => this.executeServerlessHttp(req, res));
1766
+ this.app.post("/execute/:name", (req, res) => this.executeServerlessHttp(req, res, req.params.name));
1767
+ }
1768
+ async executeReasoner(req, res, name) {
1769
+ try {
1770
+ await this.executeInvocation({
1771
+ targetName: name,
1772
+ targetType: "reasoner",
1773
+ input: req.body,
1774
+ metadata: this.buildMetadata(req),
1775
+ req,
1776
+ res,
1777
+ respond: true
1778
+ });
1779
+ } catch (err) {
1780
+ if (err instanceof TargetNotFoundError) {
1781
+ res.status(404).json({ error: err.message });
1782
+ } else {
1783
+ res.status(500).json({ error: err?.message ?? "Execution failed" });
1784
+ }
1785
+ }
1786
+ }
1787
+ async executeSkill(req, res, name) {
1788
+ try {
1789
+ await this.executeInvocation({
1790
+ targetName: name,
1791
+ targetType: "skill",
1792
+ input: req.body,
1793
+ metadata: this.buildMetadata(req),
1794
+ req,
1795
+ res,
1796
+ respond: true
1797
+ });
1798
+ } catch (err) {
1799
+ if (err instanceof TargetNotFoundError) {
1800
+ res.status(404).json({ error: err.message });
1801
+ } else {
1802
+ res.status(500).json({ error: err?.message ?? "Execution failed" });
1803
+ }
1804
+ }
1805
+ }
1806
+ buildMetadata(req) {
1807
+ return this.buildMetadataFromHeaders(req.headers);
1808
+ }
1809
+ async executeServerlessHttp(req, res, explicitName) {
1810
+ const invocation = this.extractInvocationDetails({
1811
+ path: req.path,
1812
+ explicitTarget: explicitName,
1813
+ query: req.query,
1814
+ body: req.body
1815
+ });
1816
+ if (!invocation.name) {
1817
+ res.status(400).json({ error: "Missing 'target' or 'reasoner' in request" });
1818
+ return;
1819
+ }
1820
+ try {
1821
+ const result = await this.executeInvocation({
1822
+ targetName: invocation.name,
1823
+ targetType: invocation.targetType,
1824
+ input: invocation.input,
1825
+ metadata: this.buildMetadata(req),
1826
+ req,
1827
+ res,
1828
+ respond: true
1829
+ });
1830
+ if (result !== void 0 && !res.headersSent) {
1831
+ res.json(result);
1832
+ }
1833
+ } catch (err) {
1834
+ if (err instanceof TargetNotFoundError) {
1835
+ res.status(404).json({ error: err.message });
1836
+ } else {
1837
+ res.status(500).json({ error: err?.message ?? "Execution failed" });
1838
+ }
1839
+ }
1840
+ }
1841
+ buildMetadataFromHeaders(headers, overrides) {
1842
+ const normalized = {};
1843
+ Object.entries(headers ?? {}).forEach(([key, value]) => {
1844
+ normalized[key.toLowerCase()] = Array.isArray(value) ? value[0] : value;
1845
+ });
1846
+ const executionId = overrides?.executionId ?? normalized["x-execution-id"] ?? randomUUID();
1847
+ const runId = overrides?.runId ?? normalized["x-run-id"] ?? executionId;
1848
+ const workflowId = overrides?.workflowId ?? normalized["x-workflow-id"] ?? runId;
1849
+ return {
1850
+ executionId,
1851
+ runId,
1852
+ workflowId,
1853
+ sessionId: overrides?.sessionId ?? normalized["x-session-id"],
1854
+ actorId: overrides?.actorId ?? normalized["x-actor-id"],
1855
+ parentExecutionId: overrides?.parentExecutionId ?? normalized["x-parent-execution-id"],
1856
+ callerDid: overrides?.callerDid ?? normalized["x-caller-did"],
1857
+ targetDid: overrides?.targetDid ?? normalized["x-target-did"],
1858
+ agentNodeDid: overrides?.agentNodeDid ?? normalized["x-agent-node-did"] ?? normalized["x-agent-did"]
1859
+ };
1860
+ }
1861
+ handleHttpRequest(req, res) {
1862
+ const handler = this.app;
1863
+ return handler(req, res);
1864
+ }
1865
+ async handleServerlessEvent(event) {
1866
+ const path = event?.path ?? event?.rawPath ?? "";
1867
+ const action = event?.action ?? "";
1868
+ if (path === "/discover" || action === "discover") {
1869
+ return {
1870
+ statusCode: 200,
1871
+ headers: { "content-type": "application/json" },
1872
+ body: this.discoveryPayload(this.config.deploymentType ?? "serverless")
1873
+ };
1874
+ }
1875
+ const body = this.normalizeEventBody(event);
1876
+ const invocation = this.extractInvocationDetails({
1877
+ path,
1878
+ query: event?.queryStringParameters,
1879
+ body,
1880
+ reasoner: event?.reasoner,
1881
+ target: event?.target,
1882
+ skill: event?.skill,
1883
+ type: event?.type
1884
+ });
1885
+ if (!invocation.name) {
1886
+ return {
1887
+ statusCode: 400,
1888
+ headers: { "content-type": "application/json" },
1889
+ body: { error: "Missing 'target' or 'reasoner' in request" }
1890
+ };
1891
+ }
1892
+ const metadata = this.buildMetadataFromHeaders(event?.headers ?? {}, this.mergeExecutionContext(event));
1893
+ try {
1894
+ const result = await this.executeInvocation({
1895
+ targetName: invocation.name,
1896
+ targetType: invocation.targetType,
1897
+ input: invocation.input,
1898
+ metadata
1899
+ });
1900
+ return { statusCode: 200, headers: { "content-type": "application/json" }, body: result };
1901
+ } catch (err) {
1902
+ if (err instanceof TargetNotFoundError) {
1903
+ return {
1904
+ statusCode: 404,
1905
+ headers: { "content-type": "application/json" },
1906
+ body: { error: err.message }
1907
+ };
1908
+ }
1909
+ return {
1910
+ statusCode: 500,
1911
+ headers: { "content-type": "application/json" },
1912
+ body: { error: err?.message ?? "Execution failed" }
1913
+ };
1914
+ }
1915
+ }
1916
+ normalizeEventBody(event) {
1917
+ const parsed = this.parseBody(event?.body);
1918
+ if (parsed && typeof parsed === "object" && event?.input !== void 0 && parsed.input === void 0) {
1919
+ return { ...parsed, input: event.input };
1920
+ }
1921
+ if ((parsed === void 0 || parsed === null) && event?.input !== void 0) {
1922
+ return { input: event.input };
1923
+ }
1924
+ return parsed;
1925
+ }
1926
+ mergeExecutionContext(event) {
1927
+ const ctx = event?.executionContext ?? event?.execution_context;
1928
+ if (!ctx) return {};
1929
+ return {
1930
+ executionId: ctx.executionId ?? ctx.execution_id ?? ctx.executionId,
1931
+ runId: ctx.runId ?? ctx.run_id,
1932
+ workflowId: ctx.workflowId ?? ctx.workflow_id,
1933
+ parentExecutionId: ctx.parentExecutionId ?? ctx.parent_execution_id,
1934
+ sessionId: ctx.sessionId ?? ctx.session_id,
1935
+ actorId: ctx.actorId ?? ctx.actor_id,
1936
+ callerDid: ctx.callerDid ?? ctx.caller_did,
1937
+ targetDid: ctx.targetDid ?? ctx.target_did,
1938
+ agentNodeDid: ctx.agentNodeDid ?? ctx.agent_node_did
1939
+ };
1940
+ }
1941
+ extractInvocationDetails(params) {
1942
+ const pathTarget = this.parsePathTarget(params.path);
1943
+ const name = this.firstDefined(
1944
+ params.explicitTarget,
1945
+ pathTarget.name,
1946
+ params.query?.target,
1947
+ params.query?.reasoner,
1948
+ params.query?.skill,
1949
+ params.target,
1950
+ params.reasoner,
1951
+ params.skill,
1952
+ params.body?.target,
1953
+ params.body?.reasoner,
1954
+ params.body?.skill
1955
+ ) ?? pathTarget.name;
1956
+ const typeValue = this.firstDefined(
1957
+ pathTarget.targetType,
1958
+ params.type,
1959
+ params.query?.type,
1960
+ params.query?.targetType,
1961
+ params.body?.type,
1962
+ params.body?.targetType
1963
+ ) ?? void 0;
1964
+ const input = this.normalizeInputPayload(params.body);
1965
+ return { name: name ?? void 0, targetType: typeValue, input };
1966
+ }
1967
+ parsePathTarget(path) {
1968
+ if (!path) return {};
1969
+ const normalized = path.split("?")[0];
1970
+ const reasonerMatch = normalized.match(/\/reasoners\/([^/]+)/);
1971
+ if (reasonerMatch?.[1]) {
1972
+ return { name: reasonerMatch[1], targetType: "reasoner" };
1973
+ }
1974
+ const skillMatch = normalized.match(/\/skills\/([^/]+)/);
1975
+ if (skillMatch?.[1]) {
1976
+ return { name: skillMatch[1], targetType: "skill" };
1977
+ }
1978
+ const executeMatch = normalized.match(/\/execute\/([^/]+)/);
1979
+ if (executeMatch?.[1]) {
1980
+ return { name: executeMatch[1] };
1981
+ }
1982
+ return {};
1983
+ }
1984
+ parseBody(body) {
1985
+ if (body === void 0 || body === null) return body;
1986
+ if (typeof body === "string") {
1987
+ try {
1988
+ return JSON.parse(body);
1989
+ } catch {
1990
+ return body;
1991
+ }
1992
+ }
1993
+ return body;
1994
+ }
1995
+ normalizeInputPayload(body) {
1996
+ if (body === void 0 || body === null) return {};
1997
+ const parsed = this.parseBody(body);
1998
+ if (parsed && typeof parsed === "object") {
1999
+ const { target, reasoner, skill, type, targetType, ...rest } = parsed;
2000
+ if (parsed.input !== void 0) {
2001
+ return parsed.input;
2002
+ }
2003
+ if (parsed.data !== void 0) {
2004
+ return parsed.data;
2005
+ }
2006
+ if (Object.keys(rest).length === 0) {
2007
+ return {};
2008
+ }
2009
+ return rest;
2010
+ }
2011
+ return parsed;
2012
+ }
2013
+ firstDefined(...values) {
2014
+ for (const value of values) {
2015
+ if (value !== void 0 && value !== null) {
2016
+ return value;
2017
+ }
2018
+ }
2019
+ return void 0;
2020
+ }
2021
+ reasonerDefinitions() {
2022
+ return this.reasoners.all().map((r) => ({
2023
+ id: r.name,
2024
+ input_schema: r.options?.inputSchema ?? {},
2025
+ output_schema: r.options?.outputSchema ?? {},
2026
+ memory_config: r.options?.memoryConfig ?? {
2027
+ auto_inject: [],
2028
+ memory_retention: "",
2029
+ cache_results: false
2030
+ },
2031
+ tags: r.options?.tags ?? []
2032
+ }));
2033
+ }
2034
+ skillDefinitions() {
2035
+ return this.skills.all().map((s) => ({
2036
+ id: s.name,
2037
+ input_schema: s.options?.inputSchema ?? {},
2038
+ tags: s.options?.tags ?? []
2039
+ }));
2040
+ }
2041
+ discoveryPayload(deploymentType) {
2042
+ return {
2043
+ node_id: this.config.nodeId,
2044
+ version: this.config.version,
2045
+ deployment_type: deploymentType,
2046
+ reasoners: this.reasonerDefinitions(),
2047
+ skills: this.skillDefinitions()
2048
+ };
2049
+ }
2050
+ async executeInvocation(params) {
2051
+ const targetType = params.targetType;
2052
+ if (targetType === "skill") {
2053
+ const skill = this.skills.get(params.targetName);
2054
+ if (!skill) {
2055
+ throw new TargetNotFoundError(`Skill not found: ${params.targetName}`);
2056
+ }
2057
+ return this.runSkill(skill, params);
2058
+ }
2059
+ const reasoner = this.reasoners.get(params.targetName);
2060
+ if (reasoner) {
2061
+ return this.runReasoner(reasoner, params);
2062
+ }
2063
+ const fallbackSkill = this.skills.get(params.targetName);
2064
+ if (fallbackSkill) {
2065
+ return this.runSkill(fallbackSkill, params);
2066
+ }
2067
+ throw new TargetNotFoundError(`Reasoner not found: ${params.targetName}`);
2068
+ }
2069
+ async runReasoner(reasoner, params) {
2070
+ const req = params.req ?? {};
2071
+ const res = params.res ?? {};
2072
+ const execCtx = new ExecutionContext({
2073
+ input: params.input,
2074
+ metadata: params.metadata,
2075
+ req,
2076
+ res,
2077
+ agent: this
2078
+ });
2079
+ return ExecutionContext.run(execCtx, async () => {
2080
+ try {
2081
+ const ctx = new ReasonerContext({
2082
+ input: params.input,
2083
+ executionId: params.metadata.executionId,
2084
+ runId: params.metadata.runId,
2085
+ sessionId: params.metadata.sessionId,
2086
+ actorId: params.metadata.actorId,
2087
+ workflowId: params.metadata.workflowId,
2088
+ parentExecutionId: params.metadata.parentExecutionId,
2089
+ callerDid: params.metadata.callerDid,
2090
+ targetDid: params.metadata.targetDid,
2091
+ agentNodeDid: params.metadata.agentNodeDid,
2092
+ req,
2093
+ res,
2094
+ agent: this,
2095
+ aiClient: this.aiClient,
2096
+ memory: this.getMemoryInterface(params.metadata),
2097
+ workflow: this.getWorkflowReporter(params.metadata),
2098
+ did: this.getDidInterface(params.metadata, params.input)
2099
+ });
2100
+ const result = await reasoner.handler(ctx);
2101
+ if (params.respond && params.res) {
2102
+ params.res.json(result);
2103
+ return;
2104
+ }
2105
+ return result;
2106
+ } catch (err) {
2107
+ if (params.respond && params.res) {
2108
+ params.res.status(500).json({ error: err?.message ?? "Execution failed" });
2109
+ return;
2110
+ }
2111
+ throw err;
2112
+ }
2113
+ });
2114
+ }
2115
+ async runSkill(skill, params) {
2116
+ const req = params.req ?? {};
2117
+ const res = params.res ?? {};
2118
+ const execCtx = new ExecutionContext({
2119
+ input: params.input,
2120
+ metadata: params.metadata,
2121
+ req,
2122
+ res,
2123
+ agent: this
2124
+ });
2125
+ return ExecutionContext.run(execCtx, async () => {
2126
+ try {
2127
+ const ctx = new SkillContext({
2128
+ input: params.input,
2129
+ executionId: params.metadata.executionId,
2130
+ sessionId: params.metadata.sessionId,
2131
+ workflowId: params.metadata.workflowId,
2132
+ req,
2133
+ res,
2134
+ agent: this,
2135
+ memory: this.getMemoryInterface(params.metadata),
2136
+ workflow: this.getWorkflowReporter(params.metadata),
2137
+ did: this.getDidInterface(params.metadata, params.input)
2138
+ });
2139
+ const result = await skill.handler(ctx);
2140
+ if (params.respond && params.res) {
2141
+ params.res.json(result);
2142
+ return;
2143
+ }
2144
+ return result;
2145
+ } catch (err) {
2146
+ if (params.respond && params.res) {
2147
+ params.res.status(500).json({ error: err?.message ?? "Execution failed" });
2148
+ return;
2149
+ }
2150
+ throw err;
2151
+ }
2152
+ });
2153
+ }
2154
+ async registerWithControlPlane() {
2155
+ try {
2156
+ const reasoners = this.reasonerDefinitions();
2157
+ const skills = this.skillDefinitions();
2158
+ const port = this.config.port ?? 8001;
2159
+ const hostForUrl = this.config.publicUrl ? void 0 : this.config.host && this.config.host !== "0.0.0.0" ? this.config.host : "127.0.0.1";
2160
+ const publicUrl = this.config.publicUrl ?? `http://${hostForUrl ?? "127.0.0.1"}:${port}`;
2161
+ await this.agentFieldClient.register({
2162
+ id: this.config.nodeId,
2163
+ version: this.config.version,
2164
+ base_url: publicUrl,
2165
+ public_url: publicUrl,
2166
+ deployment_type: this.config.deploymentType ?? "long_running",
2167
+ reasoners,
2168
+ skills
2169
+ });
2170
+ } catch (err) {
2171
+ if (!this.config.devMode) {
2172
+ throw err;
2173
+ }
2174
+ console.warn("Control plane registration failed (devMode=true), continuing locally", err);
2175
+ }
2176
+ }
2177
+ startHeartbeat() {
2178
+ const interval = this.config.heartbeatIntervalMs ?? 3e4;
2179
+ if (interval <= 0) return;
2180
+ const tick = async () => {
2181
+ try {
2182
+ await this.agentFieldClient.heartbeat("ready");
2183
+ } catch (err) {
2184
+ if (!this.config.devMode) {
2185
+ console.warn("Heartbeat failed", err);
2186
+ }
2187
+ }
2188
+ };
2189
+ this.heartbeatTimer = setInterval(tick, interval);
2190
+ tick();
2191
+ }
2192
+ health() {
2193
+ return {
2194
+ status: "running",
2195
+ nodeId: this.config.nodeId,
2196
+ version: this.config.version
2197
+ };
2198
+ }
2199
+ mcpStatus() {
2200
+ const servers = this.mcpClientRegistry ? this.mcpClientRegistry.list().map((client) => ({
2201
+ alias: client.alias,
2202
+ baseUrl: client.baseUrl,
2203
+ transport: client.transport
2204
+ })) : [];
2205
+ const skills = this.skills.all().filter((skill) => skill.options?.tags?.includes("mcp")).map((skill) => skill.name);
2206
+ return {
2207
+ status: servers.length ? "configured" : "disabled",
2208
+ servers,
2209
+ skills
2210
+ };
2211
+ }
2212
+ dispatchMemoryEvent(event) {
2213
+ this.memoryWatchers.forEach(({ pattern, handler, scope, scopeId }) => {
2214
+ const scopeMatch = (!scope || scope === event.scope) && (!scopeId || scopeId === event.scopeId);
2215
+ if (scopeMatch && matchesPattern(pattern, event.key)) {
2216
+ handler(event);
2217
+ }
2218
+ });
2219
+ }
2220
+ parseTarget(target) {
2221
+ if (!target.includes(".")) {
2222
+ return { name: target };
2223
+ }
2224
+ const [agentId, remainder] = target.split(".", 2);
2225
+ const name = remainder.replace(":", "/");
2226
+ return { agentId, name };
2227
+ }
2228
+ };
2229
+
2230
+ // src/router/AgentRouter.ts
2231
+ var AgentRouter = class {
2232
+ prefix;
2233
+ tags;
2234
+ reasoners = [];
2235
+ skills = [];
2236
+ constructor(options = {}) {
2237
+ this.prefix = options.prefix;
2238
+ this.tags = options.tags;
2239
+ }
2240
+ reasoner(name, handler, options) {
2241
+ const fullName = this.prefix ? `${sanitize(this.prefix)}_${name}` : name;
2242
+ this.reasoners.push({ name: fullName, handler, options });
2243
+ return this;
2244
+ }
2245
+ skill(name, handler, options) {
2246
+ const fullName = this.prefix ? `${sanitize(this.prefix)}_${name}` : name;
2247
+ this.skills.push({ name: fullName, handler, options });
2248
+ return this;
2249
+ }
2250
+ };
2251
+ function sanitize(value) {
2252
+ return value.replace(/[^0-9a-zA-Z]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
2253
+ }
2254
+
2255
+ export { AIClient, Agent, AgentRouter, DidClient, DidInterface, ExecutionContext, MCPClient, MCPClientRegistry, MCPToolRegistrar, MemoryClient, MemoryEventClient, MemoryInterface, RateLimitError, ReasonerContext, SkillContext, StatelessRateLimiter, WorkflowReporter, getCurrentContext, getCurrentSkillContext };
2256
+ //# sourceMappingURL=index.js.map
2257
+ //# sourceMappingURL=index.js.map