@hanzo/playground 0.1.41-rc.101

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