@hol-org/hashnet-mcp 1.0.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,1946 @@
1
+ // src/transports/index.ts
2
+ import http from "http";
3
+ import { randomUUID as randomUUID2 } from "crypto";
4
+ import { PassThrough } from "stream";
5
+
6
+ // src/mcp.ts
7
+ import { randomUUID } from "crypto";
8
+ import {
9
+ RegistryBrokerError as RegistryBrokerError2
10
+ } from "@hashgraphonline/standards-sdk";
11
+ import { FastMCP } from "fastmcp";
12
+ import { z as z3 } from "zod";
13
+
14
+ // src/broker.ts
15
+ import { RegistryBrokerClient } from "@hashgraphonline/standards-sdk";
16
+ import Bottleneck from "bottleneck";
17
+ import IORedis from "ioredis";
18
+ import { fetch as undiciFetch } from "undici";
19
+
20
+ // src/config.ts
21
+ import { config as loadEnv } from "dotenv";
22
+ import { z } from "zod";
23
+ if (process.env.NODE_ENV !== "test") {
24
+ loadEnv();
25
+ }
26
+ var LOG_LEVELS = ["fatal", "error", "warn", "info", "debug", "trace"];
27
+ var envSchema = z.object({
28
+ REGISTRY_BROKER_API_URL: z.string().url().default("https://registry.hashgraphonline.com/api/v1"),
29
+ REGISTRY_BROKER_API_KEY: z.string().min(1).optional(),
30
+ HEDERA_ACCOUNT_ID: z.string().min(1).optional(),
31
+ HEDERA_PRIVATE_KEY: z.string().min(1).optional(),
32
+ PORT: z.coerce.number().int().positive().default(3333),
33
+ BROKER_MAX_CONCURRENT: z.coerce.number().int().positive().optional(),
34
+ BROKER_MIN_TIME_MS: z.coerce.number().int().nonnegative().optional(),
35
+ BROKER_RESERVOIR: z.coerce.number().int().positive().optional(),
36
+ BROKER_RESERVOIR_REFRESH_INTERVAL_MS: z.coerce.number().int().positive().optional(),
37
+ BROKER_RESERVOIR_REFRESH_AMOUNT: z.coerce.number().int().positive().optional(),
38
+ BROKER_RATE_LIMIT_REDIS_URL: z.string().url().optional(),
39
+ LOG_LEVEL: z.enum(LOG_LEVELS).default("info"),
40
+ WORKFLOW_DRY_RUN: z.enum(["0", "1"]).optional().transform((value) => value === "1"),
41
+ BROKER_AUTO_TOP_UP: z.enum(["0", "1"]).optional().transform((value) => value === "1")
42
+ }).superRefine((val, ctx) => {
43
+ const hasAccount = Boolean(val.HEDERA_ACCOUNT_ID);
44
+ const hasKey = Boolean(val.HEDERA_PRIVATE_KEY);
45
+ if (hasAccount !== hasKey) {
46
+ ctx.addIssue({
47
+ code: z.ZodIssueCode.custom,
48
+ message: "HEDERA_ACCOUNT_ID and HEDERA_PRIVATE_KEY must both be set to enable registrationAutoTopUp."
49
+ });
50
+ }
51
+ });
52
+ var normalized = (value) => {
53
+ if (value === void 0) return void 0;
54
+ const trimmed = value.trim();
55
+ return trimmed.length === 0 ? void 0 : trimmed;
56
+ };
57
+ var parsed = envSchema.safeParse({
58
+ REGISTRY_BROKER_API_URL: normalized(process.env.REGISTRY_BROKER_API_URL),
59
+ REGISTRY_BROKER_API_KEY: normalized(process.env.REGISTRY_BROKER_API_KEY),
60
+ HEDERA_ACCOUNT_ID: normalized(process.env.HEDERA_ACCOUNT_ID),
61
+ HEDERA_PRIVATE_KEY: normalized(process.env.HEDERA_PRIVATE_KEY),
62
+ PORT: normalized(process.env.PORT),
63
+ BROKER_MAX_CONCURRENT: normalized(process.env.BROKER_MAX_CONCURRENT),
64
+ BROKER_MIN_TIME_MS: normalized(process.env.BROKER_MIN_TIME_MS),
65
+ BROKER_RESERVOIR: normalized(process.env.BROKER_RESERVOIR),
66
+ BROKER_RESERVOIR_REFRESH_INTERVAL_MS: normalized(process.env.BROKER_RESERVOIR_REFRESH_INTERVAL_MS),
67
+ BROKER_RESERVOIR_REFRESH_AMOUNT: normalized(process.env.BROKER_RESERVOIR_REFRESH_AMOUNT),
68
+ BROKER_RATE_LIMIT_REDIS_URL: normalized(process.env.BROKER_RATE_LIMIT_REDIS_URL),
69
+ LOG_LEVEL: normalized(process.env.LOG_LEVEL),
70
+ WORKFLOW_DRY_RUN: normalized(process.env.WORKFLOW_DRY_RUN),
71
+ BROKER_AUTO_TOP_UP: normalized(process.env.BROKER_AUTO_TOP_UP)
72
+ });
73
+ if (!parsed.success) {
74
+ throw new Error(`Invalid environment configuration:
75
+ ${parsed.error.toString()}`);
76
+ }
77
+ var config = {
78
+ registryBrokerUrl: parsed.data.REGISTRY_BROKER_API_URL,
79
+ registryBrokerApiKey: parsed.data.REGISTRY_BROKER_API_KEY,
80
+ hederaAccountId: parsed.data.HEDERA_ACCOUNT_ID,
81
+ hederaPrivateKey: parsed.data.HEDERA_PRIVATE_KEY,
82
+ port: parsed.data.PORT,
83
+ autoTopUpEnabled: Boolean(parsed.data.BROKER_AUTO_TOP_UP) && Boolean(parsed.data.HEDERA_ACCOUNT_ID && parsed.data.HEDERA_PRIVATE_KEY),
84
+ rateLimit: (() => {
85
+ const {
86
+ BROKER_MAX_CONCURRENT,
87
+ BROKER_MIN_TIME_MS,
88
+ BROKER_RESERVOIR,
89
+ BROKER_RESERVOIR_REFRESH_AMOUNT,
90
+ BROKER_RESERVOIR_REFRESH_INTERVAL_MS,
91
+ BROKER_RATE_LIMIT_REDIS_URL
92
+ } = parsed.data;
93
+ const hasLimiter = BROKER_MAX_CONCURRENT || BROKER_MIN_TIME_MS || BROKER_RESERVOIR || BROKER_RATE_LIMIT_REDIS_URL;
94
+ if (!hasLimiter) return void 0;
95
+ return {
96
+ maxConcurrent: BROKER_MAX_CONCURRENT,
97
+ minTimeMs: BROKER_MIN_TIME_MS,
98
+ reservoir: BROKER_RESERVOIR,
99
+ reservoirRefreshAmount: BROKER_RESERVOIR_REFRESH_AMOUNT,
100
+ reservoirRefreshIntervalMs: BROKER_RESERVOIR_REFRESH_INTERVAL_MS,
101
+ redis: BROKER_RATE_LIMIT_REDIS_URL ? {
102
+ url: BROKER_RATE_LIMIT_REDIS_URL
103
+ } : void 0
104
+ };
105
+ })(),
106
+ workflowDryRun: parsed.data.WORKFLOW_DRY_RUN ?? false,
107
+ httpStreamPort: parsed.data.HTTP_STREAM_PORT,
108
+ logLevel: parsed.data.LOG_LEVEL
109
+ };
110
+
111
+ // src/broker.ts
112
+ var broker = new RegistryBrokerClient({
113
+ baseUrl: config.registryBrokerUrl,
114
+ apiKey: config.registryBrokerApiKey,
115
+ registrationAutoTopUp: config.autoTopUpEnabled ? {
116
+ accountId: config.hederaAccountId,
117
+ privateKey: config.hederaPrivateKey,
118
+ memo: "mcp-autotopup"
119
+ } : void 0
120
+ });
121
+ var brokerLimiter = createLimiter();
122
+ function createLimiter() {
123
+ if (!config.rateLimit) return void 0;
124
+ const limiterOptions = {};
125
+ if (config.rateLimit.maxConcurrent !== void 0) {
126
+ limiterOptions.maxConcurrent = config.rateLimit.maxConcurrent;
127
+ }
128
+ if (config.rateLimit.minTimeMs !== void 0) {
129
+ limiterOptions.minTime = config.rateLimit.minTimeMs;
130
+ }
131
+ if (config.rateLimit.reservoir !== void 0) {
132
+ limiterOptions.reservoir = config.rateLimit.reservoir;
133
+ }
134
+ if (config.rateLimit.reservoirRefreshAmount !== void 0) {
135
+ limiterOptions.reservoirRefreshAmount = config.rateLimit.reservoirRefreshAmount;
136
+ }
137
+ if (config.rateLimit.reservoirRefreshIntervalMs !== void 0) {
138
+ limiterOptions.reservoirRefreshInterval = config.rateLimit.reservoirRefreshIntervalMs;
139
+ }
140
+ if (config.rateLimit.redis?.url) {
141
+ limiterOptions.datastore = "ioredis";
142
+ limiterOptions.connection = new IORedis(config.rateLimit.redis.url);
143
+ }
144
+ if (!limiterOptions.maxConcurrent && !limiterOptions.minTime && !limiterOptions.reservoir && !limiterOptions.datastore) {
145
+ return void 0;
146
+ }
147
+ return new Bottleneck(limiterOptions);
148
+ }
149
+ async function withBroker(task) {
150
+ if (brokerLimiter) {
151
+ return brokerLimiter.schedule(() => task(broker));
152
+ }
153
+ return task(broker);
154
+ }
155
+ async function getCreditBalance(accountId) {
156
+ if (!config.registryBrokerApiKey) {
157
+ throw new Error("REGISTRY_BROKER_API_KEY is required to fetch credit balances.");
158
+ }
159
+ const base = config.registryBrokerUrl.endsWith("/") ? config.registryBrokerUrl : `${config.registryBrokerUrl}/`;
160
+ const url = new URL("credits/balance", base);
161
+ if (accountId) {
162
+ url.searchParams.set("accountId", accountId);
163
+ }
164
+ const headers = {
165
+ accept: "application/json",
166
+ "x-api-key": config.registryBrokerApiKey
167
+ };
168
+ const request = async () => {
169
+ const response = await undiciFetch(url, { method: "GET", headers });
170
+ if (!response.ok) {
171
+ const hint = await safeReadBody(response);
172
+ throw new Error(`Failed to fetch credit balance (${response.status}): ${hint ?? response.statusText}`);
173
+ }
174
+ return await response.json();
175
+ };
176
+ if (brokerLimiter) {
177
+ return brokerLimiter.schedule(request);
178
+ }
179
+ return request();
180
+ }
181
+ async function safeReadBody(response) {
182
+ try {
183
+ const text = await response.text();
184
+ return text || void 0;
185
+ } catch {
186
+ return void 0;
187
+ }
188
+ }
189
+
190
+ // src/logger.ts
191
+ import pino from "pino";
192
+ var logger = pino({
193
+ level: config.logLevel,
194
+ base: void 0
195
+ });
196
+
197
+ // src/schemas/agent.ts
198
+ import { z as z2 } from "zod";
199
+ var socialLinkSchema = z2.object({
200
+ platform: z2.string(),
201
+ handle: z2.string()
202
+ });
203
+ var aiAgentSchema = z2.object({
204
+ type: z2.union([z2.literal(0), z2.literal(1)]),
205
+ capabilities: z2.array(z2.number().int().nonnegative()),
206
+ model: z2.string(),
207
+ creator: z2.string().optional()
208
+ });
209
+ var mcpServerSchema = z2.object({
210
+ version: z2.string(),
211
+ connectionInfo: z2.object({
212
+ url: z2.string().url(),
213
+ transport: z2.enum(["stdio", "sse"])
214
+ }),
215
+ services: z2.array(z2.number().int().nonnegative()),
216
+ description: z2.string(),
217
+ capabilities: z2.array(z2.string()).optional(),
218
+ resources: z2.array(
219
+ z2.object({
220
+ name: z2.string(),
221
+ description: z2.string()
222
+ })
223
+ ).optional(),
224
+ tools: z2.array(
225
+ z2.object({
226
+ name: z2.string(),
227
+ description: z2.string()
228
+ })
229
+ ).optional(),
230
+ maintainer: z2.string().optional(),
231
+ repository: z2.string().optional(),
232
+ docs: z2.string().optional()
233
+ });
234
+ var baseProfileSchema = z2.object({
235
+ version: z2.string(),
236
+ type: z2.number().int(),
237
+ display_name: z2.string(),
238
+ alias: z2.string().optional(),
239
+ bio: z2.string().optional(),
240
+ socials: z2.array(socialLinkSchema).optional(),
241
+ profileImage: z2.string().optional(),
242
+ uaid: z2.string().optional(),
243
+ properties: z2.record(z2.string(), z2.any()).optional(),
244
+ inboundTopicId: z2.string().optional(),
245
+ outboundTopicId: z2.string().optional(),
246
+ base_account: z2.string().optional()
247
+ });
248
+ var agentProfileSchema = baseProfileSchema.extend({
249
+ aiAgent: aiAgentSchema.optional(),
250
+ mcpServer: mcpServerSchema.optional()
251
+ });
252
+ var metadataSchema = z2.object({
253
+ trustScore: z2.number().min(0).max(100).optional(),
254
+ verified: z2.boolean().optional(),
255
+ avgLatency: z2.number().nonnegative().optional(),
256
+ uptime: z2.number().min(0).max(100).optional(),
257
+ provider: z2.string().optional(),
258
+ category: z2.string().optional(),
259
+ adapter: z2.string().optional(),
260
+ openConvAICompatible: z2.boolean().optional(),
261
+ customFields: z2.record(z2.string(), z2.union([z2.string(), z2.number(), z2.boolean()])).optional()
262
+ });
263
+ var agentRegistrationSchema = z2.object({
264
+ profile: agentProfileSchema,
265
+ endpoint: z2.string().url().optional(),
266
+ protocol: z2.string().optional(),
267
+ communicationProtocol: z2.string().optional(),
268
+ registry: z2.string().optional(),
269
+ additionalRegistries: z2.array(z2.string()).optional(),
270
+ metadata: metadataSchema.optional()
271
+ });
272
+
273
+ // src/workflows/env.ts
274
+ function ensureRequiredEnv(requiredEnv, options) {
275
+ if (!requiredEnv?.length) return;
276
+ const missing = getMissingEnvVars(requiredEnv);
277
+ if (missing.length > 0) {
278
+ options?.logger?.error?.({ missingEnv: missing }, "workflow.env.missing");
279
+ const label = options?.context ?? "workflow";
280
+ throw new Error(`Missing required environment variables for ${label}: ${missing.join(", ")}`);
281
+ }
282
+ }
283
+ function getMissingEnvVars(requiredEnv) {
284
+ return requiredEnv.filter((variable) => {
285
+ const value = process.env[variable];
286
+ return value === void 0 || value.length === 0;
287
+ });
288
+ }
289
+
290
+ // src/workflows/pipeline.ts
291
+ function createPipeline(definition) {
292
+ async function run(input, options) {
293
+ const pipelineLogger = logger.child({ pipeline: definition.name });
294
+ const dryRun = options?.dryRun ?? config.workflowDryRun;
295
+ ensureRequiredEnv(definition.requiredEnv, { logger: pipelineLogger, context: definition.name });
296
+ const context = await definition.createContext(input);
297
+ const stepsResults = [];
298
+ for (let index = 0; index < definition.steps.length; index += 1) {
299
+ const step = definition.steps[index];
300
+ const stepLogger = pipelineLogger.child({ step: step.name, index });
301
+ const stepArgs = {
302
+ input,
303
+ context,
304
+ dryRun,
305
+ logger: stepLogger
306
+ };
307
+ const shouldSkip = await shouldSkipStep(step, stepArgs, dryRun);
308
+ const startedAt = Date.now();
309
+ if (shouldSkip) {
310
+ stepLogger.info({ dryRun }, "pipeline.step.skipped");
311
+ stepsResults.push({ name: step.name, durationMs: 0, skipped: true });
312
+ await options?.hooks?.onStepStart?.({ pipeline: definition.name, step: step.name, index, context });
313
+ await options?.hooks?.onStepSuccess?.({ pipeline: definition.name, step: step.name, index, context, output: void 0 });
314
+ continue;
315
+ }
316
+ pipelineLogger.info({ step: step.name }, "pipeline.step.start");
317
+ await options?.hooks?.onStepStart?.({ pipeline: definition.name, step: step.name, index, context });
318
+ try {
319
+ const output = await step.run(stepArgs);
320
+ const durationMs = Date.now() - startedAt;
321
+ stepLogger.info({ durationMs }, "pipeline.step.success");
322
+ stepsResults.push({ name: step.name, durationMs, skipped: false, output });
323
+ await options?.hooks?.onStepSuccess?.({ pipeline: definition.name, step: step.name, index, context, output });
324
+ } catch (error) {
325
+ const durationMs = Date.now() - startedAt;
326
+ const message = error instanceof Error ? error.message : String(error);
327
+ stepLogger.error({ durationMs, error: message }, "pipeline.step.error");
328
+ stepsResults.push({ name: step.name, durationMs, skipped: false, error: message });
329
+ await options?.hooks?.onStepError?.({ pipeline: definition.name, step: step.name, index, context, error });
330
+ throw error;
331
+ }
332
+ }
333
+ return {
334
+ pipeline: definition.name,
335
+ context,
336
+ steps: stepsResults,
337
+ dryRun
338
+ };
339
+ }
340
+ return { definition, run };
341
+ }
342
+ async function shouldSkipStep(step, args, dryRun) {
343
+ if (dryRun && step.allowDuringDryRun !== true) {
344
+ return true;
345
+ }
346
+ if (step.skip) {
347
+ return Boolean(await step.skip(args));
348
+ }
349
+ return false;
350
+ }
351
+
352
+ // src/workflows/registry.ts
353
+ var pipelines = /* @__PURE__ */ new Map();
354
+ function registerPipeline(definition) {
355
+ const pipeline = createPipeline(definition);
356
+ pipelines.set(definition.name, pipeline);
357
+ return pipeline;
358
+ }
359
+
360
+ // src/workflows/discovery.ts
361
+ var discoveryDefinition = {
362
+ name: "workflow.discovery",
363
+ description: "Run hol.search and hol.vectorSearch to explore agents.",
364
+ version: "1.0.0",
365
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
366
+ createContext: () => ({ results: {} }),
367
+ steps: [
368
+ {
369
+ name: "hol.search",
370
+ description: "Keyword search",
371
+ allowDuringDryRun: true,
372
+ run: async ({ input, context }) => {
373
+ const payload = { q: input.query, limit: input.limit ?? 5 };
374
+ const response = await withBroker((client) => client.search(payload));
375
+ context.results.search = response;
376
+ return response;
377
+ }
378
+ },
379
+ {
380
+ name: "hol.vectorSearch",
381
+ description: "Vector similarity search",
382
+ allowDuringDryRun: true,
383
+ run: async ({ input, context }) => {
384
+ if (!input.query) {
385
+ return void 0;
386
+ }
387
+ const response = await withBroker((client) => client.vectorSearch({ query: input.query, limit: input.limit ?? 5 }));
388
+ context.results.vector = response;
389
+ return response;
390
+ }
391
+ }
392
+ ]
393
+ };
394
+ var discoveryPipeline = registerPipeline(discoveryDefinition);
395
+
396
+ // src/workflows/utils/credits.ts
397
+ import { RegistryBrokerError } from "@hashgraphonline/standards-sdk";
398
+
399
+ // src/workflows/errors.ts
400
+ var InsufficientCreditsError = class extends Error {
401
+ code = "INSUFFICIENT_CREDITS";
402
+ summary;
403
+ constructor(quote, hint) {
404
+ const shortfall = Math.max(0, quote.shortfallCredits ?? 0);
405
+ const message = hint ?? `Insufficient registry credits (shortfall: ${shortfall})`;
406
+ super(message);
407
+ this.name = "InsufficientCreditsError";
408
+ this.summary = {
409
+ requiredCredits: quote.requiredCredits,
410
+ availableCredits: quote.availableCredits ?? 0,
411
+ shortfallCredits: shortfall,
412
+ estimatedHbar: quote.estimatedHbar,
413
+ creditsPerHbar: quote.creditsPerHbar,
414
+ registry: quote.registry,
415
+ protocol: quote.protocol,
416
+ accountId: quote.accountId
417
+ };
418
+ }
419
+ };
420
+
421
+ // src/workflows/utils/credits.ts
422
+ async function runCreditAwareRegistration({ payload, onShortfall }) {
423
+ while (true) {
424
+ try {
425
+ const response = await withBroker((client) => client.registerAgent(payload));
426
+ return response;
427
+ } catch (error) {
428
+ const converted = await translateCreditError(error, payload);
429
+ if (converted) {
430
+ const action = await onShortfall?.(converted) ?? "abort";
431
+ if (action === "retry") {
432
+ continue;
433
+ }
434
+ throw converted;
435
+ }
436
+ throw error;
437
+ }
438
+ }
439
+ }
440
+ async function translateCreditError(error, payload) {
441
+ if (!(error instanceof RegistryBrokerError) || error.status !== 402) {
442
+ return null;
443
+ }
444
+ const quote = await withBroker((client) => client.getRegistrationQuote(payload));
445
+ return new InsufficientCreditsError(quote);
446
+ }
447
+ async function waitForRegistrationCompletion(attemptId) {
448
+ return withBroker(
449
+ (client) => client.waitForRegistrationCompletion(attemptId, {
450
+ intervalMs: 2e3,
451
+ timeoutMs: 5 * 6e4
452
+ })
453
+ );
454
+ }
455
+
456
+ // src/workflows/registration.ts
457
+ var registrationDefinition = {
458
+ name: "workflow.registerMcp",
459
+ description: "Quote, register, and wait for completion.",
460
+ version: "1.0.0",
461
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
462
+ createContext: ({ payload }) => ({ payload }),
463
+ steps: [
464
+ {
465
+ name: "hol.getRegistrationQuote",
466
+ allowDuringDryRun: true,
467
+ run: async ({ context }) => {
468
+ const quote = await withBroker((client) => client.getRegistrationQuote(context.payload));
469
+ context.quote = quote;
470
+ return quote;
471
+ }
472
+ },
473
+ {
474
+ name: "hol.registerAgent",
475
+ run: async ({ context }) => {
476
+ const response = await runCreditAwareRegistration({
477
+ payload: context.payload,
478
+ onShortfall: async (err) => {
479
+ context.quote = err.summary;
480
+ return "abort";
481
+ }
482
+ });
483
+ if ("attemptId" in response && typeof response.attemptId === "string") {
484
+ context.attemptId = response.attemptId;
485
+ }
486
+ context.result = response;
487
+ return response;
488
+ }
489
+ },
490
+ {
491
+ name: "hol.waitForRegistrationCompletion",
492
+ run: async ({ context }) => {
493
+ if (!context.attemptId) {
494
+ throw new Error("Registration attemptId missing.");
495
+ }
496
+ const result = await withBroker(
497
+ (client) => client.waitForRegistrationCompletion(context.attemptId, {
498
+ intervalMs: 2e3,
499
+ timeoutMs: 5 * 6e4
500
+ })
501
+ );
502
+ if (result?.result?.uaid) {
503
+ context.uaid = result.result.uaid;
504
+ }
505
+ return result;
506
+ }
507
+ }
508
+ ]
509
+ };
510
+ var registrationPipeline = registerPipeline(registrationDefinition);
511
+
512
+ // src/workflows/chat.ts
513
+ var chatDefinition = {
514
+ name: "workflow.chatSmoke",
515
+ description: "Create a chat session, send a message, read history, compact, and close.",
516
+ version: "1.0.0",
517
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
518
+ createContext: ({ uaid, auth }) => ({ uaid, auth, transcript: void 0 }),
519
+ steps: [
520
+ {
521
+ name: "hol.chat.createSession",
522
+ run: async ({ context }) => {
523
+ const response = await withBroker(
524
+ (client) => client.chat.createSession({ uaid: context.uaid, historyTtlSeconds: 60, auth: context.auth })
525
+ );
526
+ if (response?.sessionId) {
527
+ context.sessionId = response.sessionId;
528
+ }
529
+ return response;
530
+ }
531
+ },
532
+ {
533
+ name: "hol.chat.sendMessage",
534
+ run: async ({ input, context }) => {
535
+ if (!context.sessionId) throw new Error("Missing chat session");
536
+ return withBroker(
537
+ (client) => client.chat.sendMessage({
538
+ sessionId: context.sessionId,
539
+ message: input.message ?? "Hello from workflow.chatSmoke",
540
+ auth: input.auth ?? context.auth
541
+ })
542
+ );
543
+ }
544
+ },
545
+ {
546
+ name: "hol.chat.history",
547
+ run: async ({ context }) => {
548
+ if (!context.sessionId) throw new Error("Missing chat session");
549
+ const history = await withBroker((client) => client.chat.getHistory(context.sessionId));
550
+ context.transcript = history;
551
+ return history;
552
+ }
553
+ },
554
+ {
555
+ name: "hol.chat.compact",
556
+ allowDuringDryRun: true,
557
+ run: async ({ context }) => {
558
+ if (!context.sessionId) throw new Error("Missing chat session");
559
+ return withBroker((client) => client.chat.compactHistory({ sessionId: context.sessionId, preserveEntries: 2 }));
560
+ }
561
+ },
562
+ {
563
+ name: "hol.chat.end",
564
+ allowDuringDryRun: true,
565
+ run: async ({ context }) => {
566
+ if (!context.sessionId) throw new Error("Missing chat session");
567
+ return withBroker((client) => client.chat.endSession(context.sessionId));
568
+ }
569
+ }
570
+ ]
571
+ };
572
+ var chatPipeline = registerPipeline(chatDefinition);
573
+
574
+ // src/workflows/ops.ts
575
+ var opsDefinition = {
576
+ name: "workflow.opsCheck",
577
+ description: "Run stats, metrics, dashboard, listProtocols, detectProtocol.",
578
+ version: "1.0.0",
579
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
580
+ createContext: () => ({}),
581
+ steps: [
582
+ {
583
+ name: "hol.stats",
584
+ allowDuringDryRun: true,
585
+ run: async ({ context }) => {
586
+ const response = await withBroker((client) => client.stats());
587
+ context.stats = response;
588
+ return response;
589
+ }
590
+ },
591
+ {
592
+ name: "hol.metricsSummary",
593
+ allowDuringDryRun: true,
594
+ run: async ({ context }) => {
595
+ const response = await withBroker((client) => client.metricsSummary());
596
+ context.metrics = response;
597
+ return response;
598
+ }
599
+ },
600
+ {
601
+ name: "hol.dashboardStats",
602
+ allowDuringDryRun: true,
603
+ run: async ({ context }) => {
604
+ const response = await withBroker((client) => client.dashboardStats());
605
+ context.dashboard = response;
606
+ return response;
607
+ }
608
+ },
609
+ {
610
+ name: "hol.listProtocols",
611
+ allowDuringDryRun: true,
612
+ run: async () => withBroker((client) => client.listProtocols())
613
+ },
614
+ {
615
+ name: "hol.detectProtocol",
616
+ allowDuringDryRun: true,
617
+ run: async () => withBroker(
618
+ (client) => client.detectProtocol({
619
+ headers: { "content-type": "application/json" },
620
+ body: "{}"
621
+ })
622
+ )
623
+ }
624
+ ]
625
+ };
626
+ var opsPipeline = registerPipeline(opsDefinition);
627
+
628
+ // src/workflows/combined.ts
629
+ var fullDefinition = {
630
+ name: "workflow.fullRegistration",
631
+ description: "Discovery \u2192 Registration \u2192 Chat \u2192 Ops health check",
632
+ version: "1.0.0",
633
+ requiredEnv: ["REGISTRY_BROKER_API_KEY", "HEDERA_ACCOUNT_ID", "HEDERA_PRIVATE_KEY"],
634
+ createContext: () => ({}),
635
+ steps: [
636
+ {
637
+ name: "workflow.discovery",
638
+ allowDuringDryRun: true,
639
+ run: async ({ input, context }) => {
640
+ const result = await discoveryPipeline.run({ query: input.discoveryQuery, limit: 5 });
641
+ context.discovery = result;
642
+ return result;
643
+ }
644
+ },
645
+ {
646
+ name: "workflow.registerMcp",
647
+ run: async ({ input, context, dryRun }) => {
648
+ const payload = { payload: input.registrationPayload };
649
+ const result = await registrationPipeline.run(payload, { dryRun });
650
+ context.registration = result;
651
+ context.uaid = result.context.uaid;
652
+ return result;
653
+ }
654
+ },
655
+ {
656
+ name: "workflow.chatSmoke",
657
+ run: async ({ input, context, dryRun }) => {
658
+ if (!context.uaid) throw new Error("UAID missing from registration context");
659
+ const result = await chatPipeline.run({ uaid: context.uaid, message: input.chatMessage }, { dryRun });
660
+ context.chat = result;
661
+ return result;
662
+ }
663
+ },
664
+ {
665
+ name: "workflow.opsCheck",
666
+ allowDuringDryRun: true,
667
+ run: async ({ context, dryRun }) => {
668
+ const result = await opsPipeline.run({}, { dryRun });
669
+ context.ops = result;
670
+ return result;
671
+ }
672
+ }
673
+ ]
674
+ };
675
+ var fullWorkflowPipeline = registerPipeline(fullDefinition);
676
+
677
+ // src/workflows/scaffold.ts
678
+ function scaffoldWorkflow(definition) {
679
+ if (!definition.version) {
680
+ definition.version = "1.0.0";
681
+ }
682
+ if (!definition.requiredEnv) {
683
+ definition.requiredEnv = ["REGISTRY_BROKER_API_KEY"];
684
+ }
685
+ return registerPipeline(definition);
686
+ }
687
+
688
+ // src/workflows/openrouter-chat.ts
689
+ var openRouterChatDefinition = {
690
+ name: "workflow.openrouterChat",
691
+ description: "Discover an OpenRouter model and run a chat message against it.",
692
+ version: "1.0.0",
693
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
694
+ createContext: () => ({}),
695
+ steps: [
696
+ {
697
+ name: "hol.search",
698
+ run: async ({ input, context }) => {
699
+ const result = await withBroker(
700
+ (client) => client.search({ q: input.modelId, registries: input.registry ? [input.registry] : ["openrouter"], limit: 1 })
701
+ );
702
+ if (!result.hits?.length) {
703
+ throw new Error(`Model ${input.modelId} not found in registry ${input.registry ?? "openrouter"}`);
704
+ }
705
+ context.uaid = result.hits[0].uaid;
706
+ return result.hits[0];
707
+ }
708
+ },
709
+ {
710
+ name: "hol.chat.createSession",
711
+ run: async ({ input, context }) => {
712
+ if (!context.uaid) throw new Error("UAID missing from discovery step");
713
+ const auth = input.authToken ? { type: "bearer", token: input.authToken } : void 0;
714
+ const response = await withBroker(
715
+ (client) => client.chat.createSession({ uaid: context.uaid, historyTtlSeconds: input.historyTtlSeconds ?? 900, auth })
716
+ );
717
+ context.sessionId = response.sessionId;
718
+ return response;
719
+ }
720
+ },
721
+ {
722
+ name: "hol.chat.sendMessage",
723
+ run: async ({ input, context }) => {
724
+ if (!context.sessionId) throw new Error("Missing chat session");
725
+ const auth = input.authToken ? { type: "bearer", token: input.authToken } : void 0;
726
+ return withBroker(
727
+ (client) => client.chat.sendMessage({ sessionId: context.sessionId, auth, message: input.message })
728
+ );
729
+ }
730
+ },
731
+ {
732
+ name: "hol.chat.history",
733
+ allowDuringDryRun: true,
734
+ run: async ({ context }) => {
735
+ if (!context.sessionId) throw new Error("Missing chat session");
736
+ const history = await withBroker((client) => client.chat.getHistory(context.sessionId));
737
+ context.transcript = history;
738
+ return history;
739
+ }
740
+ },
741
+ {
742
+ name: "hol.chat.end",
743
+ allowDuringDryRun: true,
744
+ run: async ({ context }) => {
745
+ if (!context.sessionId) throw new Error("Missing chat session");
746
+ return withBroker((client) => client.chat.endSession(context.sessionId));
747
+ }
748
+ }
749
+ ]
750
+ };
751
+ var openRouterChatWorkflow = scaffoldWorkflow(openRouterChatDefinition);
752
+
753
+ // src/workflows/registry-showcase.ts
754
+ var registryShowcaseDefinition = {
755
+ name: "workflow.registryBrokerShowcase",
756
+ description: "Discovery + analytics + chat showcase workflow inspired by registry-broker-demo.ts.",
757
+ version: "1.0.0",
758
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
759
+ createContext: () => ({}),
760
+ steps: [
761
+ {
762
+ name: "workflow.discovery",
763
+ allowDuringDryRun: true,
764
+ run: async ({ input, context, dryRun }) => {
765
+ const result = await discoveryPipeline.run({ query: input.query }, { dryRun });
766
+ context.discovery = result;
767
+ context.uaid = input.uaid ?? result.steps[0]?.output?.hits?.[0]?.uaid;
768
+ return result;
769
+ }
770
+ },
771
+ {
772
+ name: "hol.listProtocols",
773
+ allowDuringDryRun: true,
774
+ run: async ({ context }) => {
775
+ const response = await withBroker((client) => client.listProtocols());
776
+ context.listProtocols = response;
777
+ return response;
778
+ }
779
+ },
780
+ {
781
+ name: "hol.detectProtocol",
782
+ allowDuringDryRun: true,
783
+ run: async ({ context }) => {
784
+ const response = await withBroker((client) => client.detectProtocol({ headers: { "content-type": "application/json" }, body: "{}" }));
785
+ context.detectProtocol = response;
786
+ return response;
787
+ }
788
+ },
789
+ {
790
+ name: "hol.stats",
791
+ allowDuringDryRun: true,
792
+ run: async ({ context }) => {
793
+ const response = await withBroker((client) => client.stats());
794
+ context.stats = response;
795
+ return response;
796
+ }
797
+ },
798
+ {
799
+ name: "hol.metricsSummary",
800
+ allowDuringDryRun: true,
801
+ run: async ({ context }) => {
802
+ const response = await withBroker((client) => client.metricsSummary());
803
+ context.metrics = response;
804
+ return response;
805
+ }
806
+ },
807
+ {
808
+ name: "hol.dashboardStats",
809
+ allowDuringDryRun: true,
810
+ run: async ({ context }) => {
811
+ const response = await withBroker((client) => client.dashboardStats());
812
+ context.dashboard = response;
813
+ return response;
814
+ }
815
+ },
816
+ {
817
+ name: "hol.websocketStats",
818
+ allowDuringDryRun: true,
819
+ run: async ({ context }) => {
820
+ const response = await withBroker((client) => client.websocketStats());
821
+ context.websocket = response;
822
+ return response;
823
+ }
824
+ },
825
+ {
826
+ name: "workflow.registryBrokerShowcase.chat",
827
+ skip: ({ input, context }) => !(input.message && context.uaid),
828
+ run: async ({ input, context, dryRun }) => {
829
+ if (!context.uaid) throw new Error("No UAID discovered for chat");
830
+ const result = await chatPipeline.run({ uaid: context.uaid, message: input.message }, { dryRun });
831
+ context.chat = result;
832
+ return result;
833
+ }
834
+ },
835
+ {
836
+ name: "hol.getRegistrationQuote",
837
+ skip: ({ input }) => !input.performCreditCheck,
838
+ run: async ({ context }) => {
839
+ const response = await withBroker((client) => client.getRegistrationQuote(context.discovery?.context?.registrationPayload || context.discovery));
840
+ context.creditQuote = response;
841
+ return response;
842
+ }
843
+ }
844
+ ]
845
+ };
846
+ var registryBrokerShowcaseWorkflow = scaffoldWorkflow(registryShowcaseDefinition);
847
+
848
+ // src/workflows/agentverse-bridge.ts
849
+ var agentverseBridgeDefinition = {
850
+ name: "workflow.agentverseBridge",
851
+ description: "Relay messages between a local UAID session and an Agentverse UAID.",
852
+ version: "1.0.0",
853
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
854
+ createContext: () => ({ transcripts: [] }),
855
+ steps: [
856
+ {
857
+ name: "workflow.agentverseBridge.createSessions",
858
+ run: async ({ input, context }) => {
859
+ const local = await withBroker(
860
+ (client) => client.chat.createSession({ uaid: input.uaid, auth: input.localAuth, historyTtlSeconds: 300 })
861
+ );
862
+ const agentverse = await withBroker(
863
+ (client) => client.chat.createSession({ uaid: input.agentverseUaid, auth: input.agentverseAuth, historyTtlSeconds: 300 })
864
+ );
865
+ context.localSession = local.sessionId;
866
+ context.agentverseSession = agentverse.sessionId;
867
+ return { local, agentverse };
868
+ }
869
+ },
870
+ {
871
+ name: "workflow.agentverseBridge.relay",
872
+ run: async ({ input, context }) => {
873
+ if (!context.localSession || !context.agentverseSession) {
874
+ throw new Error("Sessions missing");
875
+ }
876
+ const iterations = input.iterations ?? 1;
877
+ for (let i = 0; i < iterations; i += 1) {
878
+ const localResponse = await withBroker(
879
+ (client) => client.chat.sendMessage({ sessionId: context.localSession, auth: input.localAuth, message: input.localMessage })
880
+ );
881
+ context.transcripts.push({ target: "local", response: localResponse });
882
+ const agentverseResponse = await withBroker(
883
+ (client) => client.chat.sendMessage({ sessionId: context.agentverseSession, auth: input.agentverseAuth, message: input.agentverseMessage })
884
+ );
885
+ context.transcripts.push({ target: "agentverse", response: agentverseResponse });
886
+ }
887
+ return context.transcripts;
888
+ }
889
+ },
890
+ {
891
+ name: "workflow.agentverseBridge.history",
892
+ allowDuringDryRun: true,
893
+ run: async ({ context }) => {
894
+ const localHistory = await withBroker((client) => client.chat.getHistory(context.localSession));
895
+ const agentverseHistory = await withBroker((client) => client.chat.getHistory(context.agentverseSession));
896
+ return { localHistory, agentverseHistory };
897
+ }
898
+ },
899
+ {
900
+ name: "workflow.agentverseBridge.cleanup",
901
+ allowDuringDryRun: true,
902
+ run: async ({ context }) => {
903
+ await Promise.all([
904
+ withBroker((client) => client.chat.endSession(context.localSession)),
905
+ withBroker((client) => client.chat.endSession(context.agentverseSession))
906
+ ]);
907
+ return { ended: true };
908
+ }
909
+ }
910
+ ]
911
+ };
912
+ var agentverseBridgeWorkflow = scaffoldWorkflow(agentverseBridgeDefinition);
913
+
914
+ // src/workflows/erc8004-discovery.ts
915
+ var erc8004DiscoveryDefinition = {
916
+ name: "workflow.erc8004Discovery",
917
+ description: "Filter search/vector/namespace lookups for ERC-8004 registries.",
918
+ version: "1.0.0",
919
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
920
+ createContext: () => ({}),
921
+ steps: [
922
+ {
923
+ name: "hol.search",
924
+ allowDuringDryRun: true,
925
+ run: async ({ input, context }) => {
926
+ const response = await withBroker(
927
+ (client) => client.search({ q: input.query, registries: ["erc-8004"], limit: input.limit ?? 10 })
928
+ );
929
+ context.hits = response.hits;
930
+ return response;
931
+ }
932
+ },
933
+ {
934
+ name: "hol.registrySearchByNamespace",
935
+ allowDuringDryRun: true,
936
+ run: async ({ input }) => withBroker((client) => client.registrySearchByNamespace("erc-8004", input.query))
937
+ }
938
+ ]
939
+ };
940
+ var erc8004DiscoveryWorkflow = scaffoldWorkflow(erc8004DiscoveryDefinition);
941
+
942
+ // src/workflows/register-advanced.ts
943
+ var registerAgentAdvancedDefinition = {
944
+ name: "workflow.registerAgentAdvanced",
945
+ description: "Extended registration workflow with additional registries and optional updates.",
946
+ version: "1.0.0",
947
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
948
+ createContext: ({ payload }) => ({ payload, resolvedRegistries: [], missingRegistries: [] }),
949
+ steps: [
950
+ {
951
+ name: "hol.getAdditionalRegistries",
952
+ allowDuringDryRun: true,
953
+ skip: ({ input }) => !input.additionalRegistrySelections?.length && !input.updateAdditionalRegistries?.length,
954
+ run: async () => withBroker((client) => client.getAdditionalRegistries())
955
+ },
956
+ {
957
+ name: "workflow.resolveAdditionalRegistries",
958
+ allowDuringDryRun: true,
959
+ run: async ({ input, context }, resultFromCatalog) => {
960
+ if (!resultFromCatalog) return null;
961
+ const catalog = resultFromCatalog;
962
+ const selections = input.additionalRegistrySelections ?? [];
963
+ const { resolved, missing } = resolveAdditionalSelections(selections, catalog);
964
+ context.resolvedRegistries = resolved;
965
+ context.missingRegistries = missing;
966
+ if (resolved.length > 0) {
967
+ context.payload = {
968
+ ...context.payload,
969
+ additionalRegistries: resolved
970
+ };
971
+ }
972
+ return { resolved, missing };
973
+ }
974
+ },
975
+ {
976
+ name: "hol.getRegistrationQuote",
977
+ allowDuringDryRun: true,
978
+ run: async ({ context }) => withBroker((client) => client.getRegistrationQuote(context.payload))
979
+ },
980
+ {
981
+ name: "workflow.registerAgentAdvanced.register",
982
+ run: async ({ input, context }) => {
983
+ const response = await runCreditAwareRegistration({
984
+ payload: context.payload,
985
+ onShortfall: async (summary) => {
986
+ context.lastQuote = summary;
987
+ if (!input.creditTopUp) {
988
+ return "abort";
989
+ }
990
+ await purchaseCreditsWithHbar(input.creditTopUp, summary);
991
+ return "retry";
992
+ }
993
+ });
994
+ context.registrationResult = response;
995
+ if ("attemptId" in response && typeof response.attemptId === "string") {
996
+ context.attemptId = response.attemptId;
997
+ }
998
+ if ("uaid" in response && typeof response.uaid === "string") {
999
+ context.uaid = response.uaid;
1000
+ }
1001
+ return response;
1002
+ }
1003
+ },
1004
+ {
1005
+ name: "hol.waitForRegistrationCompletion",
1006
+ run: async ({ context }) => {
1007
+ if (!context.attemptId) throw new Error("Registration attemptId missing.");
1008
+ const result = await waitForRegistrationCompletion(context.attemptId);
1009
+ context.progress = result;
1010
+ if (result?.result?.uaid) {
1011
+ context.uaid = result.result.uaid;
1012
+ }
1013
+ return result;
1014
+ }
1015
+ },
1016
+ {
1017
+ name: "workflow.registerAgentAdvanced.update",
1018
+ skip: ({ input }) => input.skipUpdate || !input.updateAdditionalRegistries?.length,
1019
+ run: async ({ input, context }) => {
1020
+ if (!context.uaid) throw new Error("UAID missing for update.");
1021
+ const resolved = input.updateAdditionalRegistries ?? [];
1022
+ const updatePayload = {
1023
+ ...context.payload,
1024
+ additionalRegistries: resolved
1025
+ };
1026
+ const response = await withBroker((client) => client.updateAgent(context.uaid, updatePayload));
1027
+ context.updateResult = response;
1028
+ return response;
1029
+ }
1030
+ }
1031
+ ]
1032
+ };
1033
+ var registerAgentAdvancedPipeline = scaffoldWorkflow(registerAgentAdvancedDefinition);
1034
+ function resolveAdditionalSelections(selections, catalog) {
1035
+ const resolved = /* @__PURE__ */ new Set();
1036
+ const missing = [];
1037
+ for (const selection of selections) {
1038
+ const matches = collectMatches(selection, catalog);
1039
+ if (matches.length === 0) {
1040
+ missing.push(selection);
1041
+ } else {
1042
+ matches.forEach((key) => resolved.add(key));
1043
+ }
1044
+ }
1045
+ return { resolved: Array.from(resolved), missing };
1046
+ }
1047
+ function collectMatches(selection, catalog) {
1048
+ const target = selection.trim().toLowerCase();
1049
+ if (!target) return [];
1050
+ const matches = [];
1051
+ for (const registry of catalog.registries) {
1052
+ const registryId = registry.id.toLowerCase();
1053
+ if (registryId === target) {
1054
+ registry.networks.forEach((network) => matches.push(network.key));
1055
+ continue;
1056
+ }
1057
+ for (const network of registry.networks) {
1058
+ const keyLower = network.key.toLowerCase();
1059
+ const networkIdLower = network.networkId?.toLowerCase();
1060
+ const labelLower = network.label?.toLowerCase();
1061
+ const nameLower = network.name?.toLowerCase();
1062
+ if (target === keyLower || networkIdLower && target === networkIdLower || labelLower && target === labelLower || nameLower && target === nameLower || target === `${registryId}:${networkIdLower}`) {
1063
+ matches.push(network.key);
1064
+ }
1065
+ }
1066
+ }
1067
+ return matches;
1068
+ }
1069
+ async function purchaseCreditsWithHbar(config2, summary) {
1070
+ const hbarAmount = config2.hbarAmount ?? Math.max(0.25, (summary.shortfallCredits ?? 1) / 100);
1071
+ await withBroker(
1072
+ (client) => client.purchaseCreditsWithHbar({
1073
+ accountId: config2.accountId,
1074
+ privateKey: config2.privateKey,
1075
+ hbarAmount,
1076
+ memo: config2.memo ?? "workflow.registerAgentAdvanced:topup",
1077
+ metadata: {
1078
+ shortfall: summary.shortfallCredits,
1079
+ requiredCredits: summary.requiredCredits
1080
+ }
1081
+ })
1082
+ );
1083
+ }
1084
+
1085
+ // src/workflows/register-erc8004.ts
1086
+ var registerAgentErc8004Definition = {
1087
+ name: "workflow.registerAgentErc8004",
1088
+ description: "ERC-8004-specific registration workflow with optional ledger verification.",
1089
+ version: "1.0.0",
1090
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
1091
+ createContext: () => ({ resolvedNetworks: [], missingNetworks: [] }),
1092
+ steps: [
1093
+ {
1094
+ name: "hol.getAdditionalRegistries",
1095
+ allowDuringDryRun: true,
1096
+ run: async () => withBroker((client) => client.getAdditionalRegistries())
1097
+ },
1098
+ {
1099
+ name: "workflow.erc8004.resolveNetworks",
1100
+ allowDuringDryRun: true,
1101
+ run: async ({ input, context }, catalog) => {
1102
+ const response = catalog;
1103
+ const selections = input.erc8004Networks?.length ? input.erc8004Networks : defaultErc8004Selections(response);
1104
+ const { resolved, missing } = resolveErc8004Selections(selections, response);
1105
+ context.resolvedNetworks = resolved;
1106
+ context.missingNetworks = missing;
1107
+ return { resolved, missing };
1108
+ }
1109
+ },
1110
+ {
1111
+ name: "hol.ledger.authenticate",
1112
+ skip: ({ input }) => !input.ledgerVerification,
1113
+ run: async ({ input }) => withBroker((client) => client.verifyLedgerChallenge(input.ledgerVerification))
1114
+ },
1115
+ {
1116
+ name: "workflow.registerAgentAdvanced",
1117
+ run: async ({ input, context, dryRun }) => {
1118
+ const advancedInput = {
1119
+ payload: withAdditionalRegistries(input.payload, context.resolvedNetworks),
1120
+ additionalRegistrySelections: context.resolvedNetworks,
1121
+ updateAdditionalRegistries: input.updateAdditionalRegistries,
1122
+ skipUpdate: input.skipUpdate,
1123
+ creditTopUp: input.creditTopUp
1124
+ };
1125
+ const result = await registerAgentAdvancedPipeline.run(advancedInput, { dryRun });
1126
+ context.advancedResult = result;
1127
+ return result;
1128
+ }
1129
+ }
1130
+ ]
1131
+ };
1132
+ var registerAgentErc8004Pipeline = scaffoldWorkflow(registerAgentErc8004Definition);
1133
+ function resolveErc8004Selections(selections, catalog) {
1134
+ const resolved = /* @__PURE__ */ new Set();
1135
+ const missing = [];
1136
+ selections.forEach((entry) => {
1137
+ const normalized2 = entry.trim().toLowerCase();
1138
+ if (!normalized2) return;
1139
+ let matched = false;
1140
+ for (const descriptor of catalog.registries) {
1141
+ if (!descriptor.id.toLowerCase().startsWith("erc-8004")) continue;
1142
+ for (const network of descriptor.networks) {
1143
+ const candidates = [network.key, network.networkId, network.label, network.name].map((value) => value?.toLowerCase().trim()).filter(Boolean);
1144
+ if (candidates.includes(normalized2) || `${descriptor.id.toLowerCase()}:${network.networkId?.toLowerCase()}` === normalized2) {
1145
+ resolved.add(network.key);
1146
+ matched = true;
1147
+ }
1148
+ }
1149
+ }
1150
+ if (!matched) {
1151
+ missing.push(entry);
1152
+ }
1153
+ });
1154
+ return { resolved: Array.from(resolved), missing };
1155
+ }
1156
+ function defaultErc8004Selections(catalog) {
1157
+ const defaults = catalog.registries.find((entry) => entry.id.toLowerCase() === "erc-8004");
1158
+ if (!defaults) return [];
1159
+ return defaults.networks.map((network) => network.key);
1160
+ }
1161
+ function withAdditionalRegistries(payload, networks) {
1162
+ if (networks.length === 0) return payload;
1163
+ return { ...payload, additionalRegistries: networks };
1164
+ }
1165
+
1166
+ // src/workflows/x402-topup.ts
1167
+ var x402TopUpDefinition = {
1168
+ name: "workflow.x402TopUp",
1169
+ description: "Buy registry credits via X402 using an EVM wallet.",
1170
+ version: "1.0.0",
1171
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
1172
+ createContext: () => ({}),
1173
+ steps: [
1174
+ {
1175
+ name: "hol.ledger.authenticate",
1176
+ skip: ({ input }) => !input.ledgerVerification,
1177
+ run: async ({ input, context }) => {
1178
+ const verification = await withBroker((client) => client.verifyLedgerChallenge(input.ledgerVerification));
1179
+ context.ledgerVerification = verification;
1180
+ return verification;
1181
+ }
1182
+ },
1183
+ {
1184
+ name: "hol.x402.minimums",
1185
+ allowDuringDryRun: true,
1186
+ run: async ({ context }) => {
1187
+ const minimums = await withBroker((client) => client.getX402Minimums());
1188
+ context.minimums = minimums;
1189
+ return minimums;
1190
+ }
1191
+ },
1192
+ {
1193
+ name: "hol.x402.buyCredits",
1194
+ run: async ({ input, context }) => {
1195
+ const payload = {
1196
+ accountId: input.accountId,
1197
+ credits: input.credits,
1198
+ usdAmount: input.usdAmount,
1199
+ description: input.description,
1200
+ metadata: input.metadata,
1201
+ evmPrivateKey: input.evmPrivateKey,
1202
+ network: input.network,
1203
+ rpcUrl: input.rpcUrl
1204
+ };
1205
+ const purchase = await withBroker((client) => client.buyCreditsWithX402(payload));
1206
+ context.purchase = purchase;
1207
+ return purchase;
1208
+ }
1209
+ }
1210
+ ]
1211
+ };
1212
+ var x402TopUpWorkflow = scaffoldWorkflow(x402TopUpDefinition);
1213
+
1214
+ // src/workflows/erc8004-x402.ts
1215
+ var erc8004X402Definition = {
1216
+ name: "workflow.erc8004X402",
1217
+ description: "Register on ERC-8004 networks with X402 credit purchases and chat smoke.",
1218
+ version: "1.0.0",
1219
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
1220
+ createContext: () => ({}),
1221
+ steps: [
1222
+ {
1223
+ name: "workflow.x402TopUp",
1224
+ skip: ({ input }) => !input.creditPurchase,
1225
+ run: async ({ input, dryRun }) => x402TopUpWorkflow.run(
1226
+ {
1227
+ accountId: input.creditPurchase.accountId,
1228
+ credits: input.creditPurchase.credits,
1229
+ evmPrivateKey: input.creditPurchase.evmPrivateKey,
1230
+ network: input.creditPurchase.network,
1231
+ ledgerVerification: input.creditPurchase.ledgerVerification
1232
+ },
1233
+ { dryRun }
1234
+ )
1235
+ },
1236
+ {
1237
+ name: "workflow.registerAgentErc8004",
1238
+ run: async ({ input, dryRun }) => registerAgentErc8004Pipeline.run(
1239
+ {
1240
+ payload: input.payload,
1241
+ erc8004Networks: input.erc8004Networks,
1242
+ creditTopUp: void 0
1243
+ },
1244
+ { dryRun }
1245
+ )
1246
+ },
1247
+ {
1248
+ name: "workflow.erc8004X402.chat",
1249
+ skip: ({ input }) => !input.chatMessage,
1250
+ run: async ({ input, context, dryRun }) => {
1251
+ const uaid = context?.context?.registrationResult?.context?.uaid;
1252
+ if (!uaid) throw new Error("UAID missing after registration");
1253
+ return chatPipeline.run({ uaid, message: input.chatMessage }, { dryRun });
1254
+ }
1255
+ }
1256
+ ]
1257
+ };
1258
+ var erc8004X402Workflow = scaffoldWorkflow(erc8004X402Definition);
1259
+
1260
+ // src/workflows/x402-registration.ts
1261
+ var x402RegistrationDefinition = {
1262
+ name: "workflow.x402Registration",
1263
+ description: "Full agent registration funded via X402 credits with chat validation.",
1264
+ version: "1.0.0",
1265
+ requiredEnv: ["REGISTRY_BROKER_API_KEY"],
1266
+ createContext: () => ({}),
1267
+ steps: [
1268
+ {
1269
+ name: "workflow.x402TopUp",
1270
+ run: async ({ input, dryRun }) => x402TopUpWorkflow.run(
1271
+ {
1272
+ accountId: input.x402.accountId,
1273
+ credits: input.x402.credits,
1274
+ evmPrivateKey: input.x402.evmPrivateKey,
1275
+ ledgerVerification: input.x402.ledgerVerification
1276
+ },
1277
+ { dryRun }
1278
+ )
1279
+ },
1280
+ {
1281
+ name: "workflow.registerAgentAdvanced",
1282
+ run: async ({ input, dryRun }) => registerAgentAdvancedPipeline.run({ payload: input.payload }, { dryRun })
1283
+ },
1284
+ {
1285
+ name: "workflow.x402Registration.chat",
1286
+ skip: ({ input }) => !input.chatMessage,
1287
+ run: async ({ input, context, dryRun }) => {
1288
+ const uaid = context.context?.registrationResult?.context?.uaid;
1289
+ if (!uaid) throw new Error("UAID missing after registration");
1290
+ return chatPipeline.run({ uaid, message: input.chatMessage }, { dryRun });
1291
+ }
1292
+ }
1293
+ ]
1294
+ };
1295
+ var x402RegistrationWorkflow = scaffoldWorkflow(x402RegistrationDefinition);
1296
+
1297
+ // src/mcp.ts
1298
+ var agentAuthSchema = z3.object({
1299
+ type: z3.enum(["bearer", "basic", "header", "apiKey"]).optional(),
1300
+ token: z3.string().optional(),
1301
+ username: z3.string().optional(),
1302
+ password: z3.string().optional(),
1303
+ headerName: z3.string().optional(),
1304
+ headerValue: z3.string().optional(),
1305
+ headers: z3.record(z3.string(), z3.string()).optional()
1306
+ }).partial();
1307
+ var chatSessionSchema = z3.object({
1308
+ uaid: z3.string().min(1),
1309
+ historyTtlSeconds: z3.number().int().positive().optional(),
1310
+ auth: agentAuthSchema.optional()
1311
+ });
1312
+ var chatMessageSchema = z3.object({
1313
+ sessionId: z3.string().min(1),
1314
+ message: z3.string().min(1),
1315
+ auth: agentAuthSchema.optional()
1316
+ });
1317
+ var chatCompactSchema = z3.object({
1318
+ sessionId: z3.string().min(1),
1319
+ preserveEntries: z3.number().int().min(0).default(4),
1320
+ auth: agentAuthSchema.optional()
1321
+ });
1322
+ var searchInput = z3.object({
1323
+ q: z3.string().optional(),
1324
+ limit: z3.number().int().min(1).max(50).default(10),
1325
+ capabilities: z3.array(z3.string()).optional(),
1326
+ registries: z3.array(z3.string()).optional(),
1327
+ minTrust: z3.number().int().min(0).max(100).optional(),
1328
+ verified: z3.boolean().optional(),
1329
+ online: z3.boolean().optional(),
1330
+ sortBy: z3.enum(["trust", "latency", "most-recent"]).optional(),
1331
+ sortOrder: z3.enum(["asc", "desc"]).optional(),
1332
+ metadata: z3.record(z3.string(), z3.array(z3.string())).optional(),
1333
+ type: z3.enum(["ai-agents", "mcp-servers"]).optional()
1334
+ });
1335
+ var vectorSearchInput = z3.object({
1336
+ query: z3.string().min(1),
1337
+ limit: z3.number().int().min(1).max(20).default(5)
1338
+ });
1339
+ var uaidInput = z3.object({ uaid: z3.string().min(1) });
1340
+ var registrationPayload = z3.object({
1341
+ payload: agentRegistrationSchema
1342
+ });
1343
+ var workflowDiscoveryInput = z3.object({
1344
+ query: z3.string().optional(),
1345
+ limit: z3.number().int().min(1).max(50).optional()
1346
+ });
1347
+ var workflowRegistrationInput = z3.object({
1348
+ payload: agentRegistrationSchema
1349
+ });
1350
+ var workflowChatInput = z3.object({
1351
+ uaid: z3.string().min(1),
1352
+ message: z3.string().optional()
1353
+ });
1354
+ var workflowOpsInput = z3.object({});
1355
+ var workflowFullInput = z3.object({
1356
+ registrationPayload: agentRegistrationSchema,
1357
+ discoveryQuery: z3.string().optional(),
1358
+ chatMessage: z3.string().optional()
1359
+ });
1360
+ var waitForRegistrationInput = z3.object({
1361
+ attemptId: z3.string(),
1362
+ intervalMs: z3.number().int().positive().default(2e3),
1363
+ timeoutMs: z3.number().int().positive().default(5 * 60 * 1e3)
1364
+ });
1365
+ var detectProtocolInput = z3.object({
1366
+ headers: z3.record(z3.string(), z3.string()),
1367
+ body: z3.string().optional()
1368
+ });
1369
+ var sessionIdInput = z3.object({ sessionId: z3.string().min(1) });
1370
+ var emptyObject = z3.object({});
1371
+ var updateAgentInput = z3.object({
1372
+ uaid: z3.string().min(1),
1373
+ payload: agentRegistrationSchema
1374
+ });
1375
+ var registryNamespaceInput = z3.object({
1376
+ registry: z3.string().min(1),
1377
+ query: z3.string().optional()
1378
+ });
1379
+ var creditBalanceInput = z3.object({
1380
+ hederaAccountId: z3.string().min(1).optional(),
1381
+ x402AccountId: z3.string().min(1).optional()
1382
+ });
1383
+ var ledgerNetworkEnum = z3.enum(["mainnet", "testnet"]);
1384
+ var ledgerChallengeInput = z3.object({
1385
+ accountId: z3.string().min(1),
1386
+ network: ledgerNetworkEnum
1387
+ });
1388
+ var ledgerVerifyInput = z3.object({
1389
+ challengeId: z3.string().min(1),
1390
+ accountId: z3.string().min(1),
1391
+ network: ledgerNetworkEnum,
1392
+ signature: z3.string().min(1),
1393
+ signatureKind: z3.enum(["raw", "map"]).optional(),
1394
+ publicKey: z3.string().optional(),
1395
+ expiresInMinutes: z3.number().int().positive().optional()
1396
+ });
1397
+ var purchaseHbarInput = z3.object({
1398
+ accountId: z3.string().min(1),
1399
+ privateKey: z3.string().min(1),
1400
+ hbarAmount: z3.number().positive(),
1401
+ memo: z3.string().optional(),
1402
+ metadata: z3.record(z3.string(), z3.any()).optional()
1403
+ });
1404
+ var buyX402Input = z3.object({
1405
+ accountId: z3.string().min(1),
1406
+ credits: z3.number().positive(),
1407
+ usdAmount: z3.number().positive().optional(),
1408
+ description: z3.string().optional(),
1409
+ metadata: z3.record(z3.string(), z3.any()).optional(),
1410
+ evmPrivateKey: z3.string().min(1),
1411
+ network: z3.enum(["base", "base-sepolia"]).optional(),
1412
+ rpcUrl: z3.string().url().optional()
1413
+ });
1414
+ var mcp = new FastMCP({
1415
+ name: "hashgraph-standards",
1416
+ version: "1.0.0",
1417
+ description: "MCP tools exposing Hashgraph Online Registry Broker via standards-sdk"
1418
+ });
1419
+ var toolDefinitions = [
1420
+ {
1421
+ name: "hol.search",
1422
+ description: "Keyword search for agents or MCP servers with filtering controls.",
1423
+ schema: searchInput,
1424
+ handler: (input) => withBroker((client) => client.search(input))
1425
+ },
1426
+ {
1427
+ name: "hol.vectorSearch",
1428
+ description: "Vector similarity search across registered agents.",
1429
+ schema: vectorSearchInput,
1430
+ handler: (input) => withBroker((client) => client.vectorSearch(input))
1431
+ },
1432
+ {
1433
+ name: "hol.resolveUaid",
1434
+ description: "Resolve, validate, and check the status of a UAID in one call.",
1435
+ schema: uaidInput,
1436
+ handler: ({ uaid }) => withBroker(async (client) => {
1437
+ const [resolved, validation, status] = await Promise.all([
1438
+ client.resolveUaid(uaid),
1439
+ client.validateUaid(uaid),
1440
+ client.getUaidConnectionStatus(uaid)
1441
+ ]);
1442
+ return { resolved, validation, status };
1443
+ })
1444
+ },
1445
+ {
1446
+ name: "hol.closeUaidConnection",
1447
+ description: "Force-close any open UAID connection.",
1448
+ schema: uaidInput,
1449
+ handler: ({ uaid }) => withBroker((client) => client.closeUaidConnection(uaid))
1450
+ },
1451
+ {
1452
+ name: "hol.getRegistrationQuote",
1453
+ description: "Estimate fees for a given agent registration payload.",
1454
+ schema: registrationPayload,
1455
+ handler: ({ payload }) => withBroker((client) => client.getRegistrationQuote(payload))
1456
+ },
1457
+ {
1458
+ name: "hol.registerAgent",
1459
+ description: "Submit an HCS-11-compatible agent registration.",
1460
+ schema: registrationPayload,
1461
+ handler: ({ payload }) => withBroker((client) => client.registerAgent(payload))
1462
+ },
1463
+ {
1464
+ name: "hol.waitForRegistrationCompletion",
1465
+ description: "Poll the registry broker until a registration attempt resolves.",
1466
+ schema: waitForRegistrationInput,
1467
+ handler: ({ attemptId, intervalMs, timeoutMs }) => withBroker(
1468
+ (client) => client.waitForRegistrationCompletion(attemptId, {
1469
+ intervalMs,
1470
+ timeoutMs
1471
+ })
1472
+ )
1473
+ },
1474
+ {
1475
+ name: "hol.updateAgent",
1476
+ description: "Update an existing agent registration payload.",
1477
+ schema: updateAgentInput,
1478
+ handler: ({ uaid, payload }) => withBroker((client) => client.updateAgent(uaid, payload))
1479
+ },
1480
+ {
1481
+ name: "hol.additionalRegistries",
1482
+ description: "Retrieve the catalog of additional registries and networks.",
1483
+ schema: emptyObject,
1484
+ handler: () => withBroker((client) => client.getAdditionalRegistries())
1485
+ },
1486
+ {
1487
+ name: "hol.registrySearchByNamespace",
1488
+ description: "Search within a specific registry namespace.",
1489
+ schema: registryNamespaceInput,
1490
+ handler: ({ registry, query }) => withBroker((client) => client.registrySearchByNamespace(registry, query))
1491
+ },
1492
+ {
1493
+ name: "hol.chat.createSession",
1494
+ description: "Open a chat session linked to a UAID.",
1495
+ schema: chatSessionSchema,
1496
+ handler: (input) => withBroker((client) => client.chat.createSession(input))
1497
+ },
1498
+ {
1499
+ name: "hol.chat.sendMessage",
1500
+ description: "Send a message to an active chat session.",
1501
+ schema: chatMessageSchema,
1502
+ handler: (input) => withBroker((client) => client.chat.sendMessage(input))
1503
+ },
1504
+ {
1505
+ name: "hol.chat.history",
1506
+ description: "Retrieve the message history for a chat session.",
1507
+ schema: sessionIdInput,
1508
+ handler: ({ sessionId }) => withBroker((client) => client.chat.getHistory(sessionId))
1509
+ },
1510
+ {
1511
+ name: "hol.chat.compact",
1512
+ description: "Compact chat history while preserving the latest entries.",
1513
+ schema: chatCompactSchema,
1514
+ handler: (input) => withBroker((client) => client.chat.compactHistory(input))
1515
+ },
1516
+ {
1517
+ name: "hol.chat.end",
1518
+ description: "End a chat session and release broker resources.",
1519
+ schema: sessionIdInput,
1520
+ handler: ({ sessionId }) => withBroker((client) => client.chat.endSession(sessionId))
1521
+ },
1522
+ {
1523
+ name: "hol.listProtocols",
1524
+ description: "List all registered protocols/adapters known to the broker.",
1525
+ schema: emptyObject,
1526
+ handler: () => runBrokerCall("hol.listProtocols", () => withBroker((client) => client.listProtocols()))
1527
+ },
1528
+ {
1529
+ name: "hol.detectProtocol",
1530
+ description: "Detect the expected protocol for an inbound request payload.",
1531
+ schema: detectProtocolInput,
1532
+ handler: (input) => runBrokerCall("hol.detectProtocol", () => withBroker((client) => client.detectProtocol(input)))
1533
+ },
1534
+ {
1535
+ name: "hol.stats",
1536
+ description: "High-level registry statistics and usage metrics.",
1537
+ schema: emptyObject,
1538
+ handler: () => withBroker((client) => client.stats())
1539
+ },
1540
+ {
1541
+ name: "hol.metricsSummary",
1542
+ description: "Aggregated broker metrics suitable for dashboards.",
1543
+ schema: emptyObject,
1544
+ handler: () => withBroker((client) => client.metricsSummary())
1545
+ },
1546
+ {
1547
+ name: "hol.dashboardStats",
1548
+ description: "Detailed dashboard statistics from the broker.",
1549
+ schema: emptyObject,
1550
+ handler: () => withBroker((client) => client.dashboardStats())
1551
+ },
1552
+ {
1553
+ name: "hol.websocketStats",
1554
+ description: "Retrieve websocket connection counts and throughput.",
1555
+ schema: emptyObject,
1556
+ handler: () => withBroker((client) => client.websocketStats())
1557
+ },
1558
+ {
1559
+ name: "hol.ledger.challenge",
1560
+ description: "Create a ledger challenge message for account verification.",
1561
+ schema: ledgerChallengeInput,
1562
+ handler: (input) => withBroker((client) => client.createLedgerChallenge(input))
1563
+ },
1564
+ {
1565
+ name: "hol.ledger.authenticate",
1566
+ description: "Verify a signed ledger challenge (sets ledger API key).",
1567
+ schema: ledgerVerifyInput,
1568
+ handler: (input) => withBroker((client) => client.verifyLedgerChallenge(input))
1569
+ },
1570
+ {
1571
+ name: "hol.purchaseCredits.hbar",
1572
+ description: "Purchase registry credits using HBAR funds.",
1573
+ schema: purchaseHbarInput,
1574
+ handler: (input) => withBroker((client) => client.purchaseCreditsWithHbar(input))
1575
+ },
1576
+ {
1577
+ name: "hol.credits.balance",
1578
+ description: "Fetch credit balances for the current API key and optional Hedera/X402 accounts.",
1579
+ schema: creditBalanceInput,
1580
+ handler: async (input) => {
1581
+ const hederaAccountId = input.hederaAccountId;
1582
+ const [apiKeyBalance, hederaBalance, x402Balance] = await Promise.all([
1583
+ getCreditBalance(),
1584
+ hederaAccountId ? safeBalanceLookup("hedera", hederaAccountId) : Promise.resolve(null),
1585
+ input.x402AccountId ? safeBalanceLookup("x402", input.x402AccountId) : Promise.resolve(null)
1586
+ ]);
1587
+ return {
1588
+ apiKey: apiKeyBalance,
1589
+ hedera: hederaBalance,
1590
+ x402: x402Balance
1591
+ };
1592
+ }
1593
+ },
1594
+ {
1595
+ name: "hol.x402.minimums",
1596
+ description: "Fetch the minimum credit purchase requirements for X402.",
1597
+ schema: emptyObject,
1598
+ handler: () => withBroker((client) => client.getX402Minimums())
1599
+ },
1600
+ {
1601
+ name: "hol.x402.buyCredits",
1602
+ description: "Buy registry credits via X402 using an EVM private key.",
1603
+ schema: buyX402Input,
1604
+ handler: (input) => withBroker((client) => client.buyCreditsWithX402(input))
1605
+ },
1606
+ {
1607
+ name: "workflow.discovery",
1608
+ description: "Pipeline: hol.search + hol.vectorSearch",
1609
+ schema: workflowDiscoveryInput,
1610
+ handler: async (input) => formatPipelineResult(await discoveryPipeline.run(input))
1611
+ },
1612
+ {
1613
+ name: "workflow.registerMcp",
1614
+ description: "Pipeline: get quote, register agent, wait for completion",
1615
+ schema: workflowRegistrationInput,
1616
+ handler: async ({ payload }) => formatPipelineResult(await registrationPipeline.run({ payload }))
1617
+ },
1618
+ {
1619
+ name: "workflow.chatSmoke",
1620
+ description: "Pipeline: chat session smoke test for UAID",
1621
+ schema: workflowChatInput,
1622
+ handler: async (input) => formatPipelineResult(await chatPipeline.run(input))
1623
+ },
1624
+ {
1625
+ name: "workflow.opsCheck",
1626
+ description: "Pipeline: stats, metrics, dashboard, protocols",
1627
+ schema: workflowOpsInput,
1628
+ handler: async () => formatPipelineResult(await opsPipeline.run({}))
1629
+ },
1630
+ {
1631
+ name: "workflow.openrouterChat",
1632
+ description: "Pipeline: discover OpenRouter model and run a chat message",
1633
+ schema: z3.object({ modelId: z3.string().min(1), registry: z3.string().optional(), message: z3.string(), authToken: z3.string().optional() }),
1634
+ handler: async (input) => formatPipelineResult(await openRouterChatWorkflow.run(input))
1635
+ },
1636
+ {
1637
+ name: "workflow.registryBrokerShowcase",
1638
+ description: "Pipeline: discovery, analytics, UAID validation, chat",
1639
+ schema: z3.object({ query: z3.string().optional(), uaid: z3.string().optional(), message: z3.string().optional(), performCreditCheck: z3.boolean().optional() }),
1640
+ handler: async (input) => formatPipelineResult(await registryBrokerShowcaseWorkflow.run(input))
1641
+ },
1642
+ {
1643
+ name: "workflow.agentverseBridge",
1644
+ description: "Pipeline: relay chat between local UAID and Agentverse UAID",
1645
+ schema: z3.object({
1646
+ uaid: z3.string().min(1),
1647
+ agentverseUaid: z3.string().min(1),
1648
+ localMessage: z3.string().min(1),
1649
+ agentverseMessage: z3.string().min(1),
1650
+ iterations: z3.number().int().positive().optional()
1651
+ }),
1652
+ handler: async (input) => formatPipelineResult(await agentverseBridgeWorkflow.run(input))
1653
+ },
1654
+ {
1655
+ name: "workflow.erc8004Discovery",
1656
+ description: "Pipeline: search ERC-8004 registries",
1657
+ schema: z3.object({ query: z3.string().optional(), limit: z3.number().int().positive().optional() }),
1658
+ handler: async (input) => formatPipelineResult(await erc8004DiscoveryWorkflow.run(input))
1659
+ },
1660
+ {
1661
+ name: "workflow.erc8004X402",
1662
+ description: "Pipeline: ERC-8004 registration funded via X402 credits",
1663
+ schema: z3.object({
1664
+ payload: agentRegistrationSchema,
1665
+ erc8004Networks: z3.array(z3.string()).optional(),
1666
+ chatMessage: z3.string().optional()
1667
+ }),
1668
+ handler: async (input) => formatPipelineResult(await erc8004X402Workflow.run(input))
1669
+ },
1670
+ {
1671
+ name: "workflow.x402Registration",
1672
+ description: "Pipeline: register agent using X402 payments + chat smoke test",
1673
+ schema: z3.object({
1674
+ payload: agentRegistrationSchema,
1675
+ chatMessage: z3.string().optional()
1676
+ }),
1677
+ handler: async (input) => formatPipelineResult(await x402RegistrationWorkflow.run(input))
1678
+ },
1679
+ {
1680
+ name: "workflow.fullRegistration",
1681
+ description: "Pipeline: discovery \u2192 register \u2192 chat \u2192 ops",
1682
+ schema: workflowFullInput,
1683
+ handler: async (input) => formatPipelineResult(await fullWorkflowPipeline.run(input))
1684
+ }
1685
+ ];
1686
+ function formatPipelineResult(result) {
1687
+ const summaryLines = [
1688
+ `Workflow: ${result.pipeline}`,
1689
+ result.dryRun ? "(dry-run)" : void 0,
1690
+ result.context?.uaid ? `UAID: ${result.context.uaid}` : void 0,
1691
+ `Steps executed: ${result.steps.length}`
1692
+ ].filter(Boolean);
1693
+ return {
1694
+ content: [
1695
+ { type: "text", text: summaryLines.join("\n") },
1696
+ buildObjectContent("pipeline.result", result)
1697
+ ],
1698
+ structuredContent: result
1699
+ };
1700
+ }
1701
+ function buildLoggedTool(definition) {
1702
+ return {
1703
+ name: definition.name,
1704
+ description: definition.description,
1705
+ parameters: definition.schema,
1706
+ execute: async (args, context) => {
1707
+ const requestId = context?.requestId ?? randomUUID();
1708
+ const started = Date.now();
1709
+ try {
1710
+ const parsedInput = definition.schema.parse(args);
1711
+ logger.debug({ requestId, tool: definition.name }, "tool.invoke");
1712
+ const result = await definition.handler(parsedInput);
1713
+ logger.info(
1714
+ {
1715
+ requestId,
1716
+ tool: definition.name,
1717
+ durationMs: Date.now() - started
1718
+ },
1719
+ "tool.success"
1720
+ );
1721
+ return normalizeResult(result);
1722
+ } catch (error) {
1723
+ logger.error(
1724
+ {
1725
+ requestId,
1726
+ tool: definition.name,
1727
+ durationMs: Date.now() - started,
1728
+ error: error instanceof Error ? error.message : String(error)
1729
+ },
1730
+ "tool.failure"
1731
+ );
1732
+ throw error;
1733
+ }
1734
+ }
1735
+ };
1736
+ }
1737
+ for (const definition of toolDefinitions) {
1738
+ mcp.addTool(buildLoggedTool(definition));
1739
+ }
1740
+ var registeredTools = toolDefinitions;
1741
+ function isContentValue(value) {
1742
+ return Boolean(
1743
+ value && typeof value === "object" && "type" in value && typeof value.type === "string"
1744
+ );
1745
+ }
1746
+ function normalizeResult(value) {
1747
+ if (isResultShape(value)) {
1748
+ const record = value;
1749
+ return {
1750
+ content: normalizeContent(record.content),
1751
+ structuredContent: isPlainObject(record.structuredContent) ? record.structuredContent : void 0,
1752
+ isError: typeof record.isError === "boolean" ? record.isError : void 0
1753
+ };
1754
+ }
1755
+ if (isPlainObject(value)) {
1756
+ return {
1757
+ content: [buildObjectContent("tool.result", value)],
1758
+ structuredContent: value
1759
+ };
1760
+ }
1761
+ return { content: normalizeContent(value) };
1762
+ }
1763
+ function normalizeContent(result) {
1764
+ if (Array.isArray(result) && result.every(isContentValue)) {
1765
+ return result;
1766
+ }
1767
+ if (isContentValue(result)) {
1768
+ return [result];
1769
+ }
1770
+ if (result === void 0 || result === null) {
1771
+ return [{ type: "text", text: "ok" }];
1772
+ }
1773
+ if (typeof result === "string" || typeof result === "number" || typeof result === "boolean") {
1774
+ return [{ type: "text", text: String(result) }];
1775
+ }
1776
+ if (isPlainObject(result)) {
1777
+ return [buildObjectContent("tool.result", result)];
1778
+ }
1779
+ return [{ type: "text", text: JSON.stringify(result) }];
1780
+ }
1781
+ function buildObjectContent(name, value) {
1782
+ return {
1783
+ type: "text",
1784
+ text: `${name}:
1785
+ ${JSON.stringify(value, null, 2)}`
1786
+ };
1787
+ }
1788
+ function isResultShape(value) {
1789
+ return Boolean(value && typeof value === "object" && ("content" in value || "structuredContent" in value));
1790
+ }
1791
+ function isPlainObject(value) {
1792
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
1793
+ }
1794
+ async function runBrokerCall(label, fn) {
1795
+ try {
1796
+ return await fn();
1797
+ } catch (error) {
1798
+ if (error instanceof RegistryBrokerError2) {
1799
+ const body = typeof error.body === "object" ? JSON.stringify(error.body) : String(error.body);
1800
+ throw new Error(`${label} failed (${error.status} ${error.statusText ?? ""}): ${body}`);
1801
+ }
1802
+ throw error;
1803
+ }
1804
+ }
1805
+ async function safeBalanceLookup(label, accountId) {
1806
+ try {
1807
+ return await getCreditBalance(accountId);
1808
+ } catch (error) {
1809
+ const message = error instanceof Error ? error.message : String(error);
1810
+ return { error: `${label} balance unavailable: ${message}`, accountId };
1811
+ }
1812
+ }
1813
+ mcp.addResource({
1814
+ name: "hol.search.help",
1815
+ uri: "help://rb/search",
1816
+ mimeType: "text/markdown",
1817
+ load: async () => [
1818
+ {
1819
+ text: [
1820
+ "# hol.search",
1821
+ "",
1822
+ "Discover registered agents or MCP servers.",
1823
+ "",
1824
+ "- `q`: keyword search",
1825
+ "- `capabilities`: filter by declared skills",
1826
+ '- `metadata`: pass `{ "region": ["na"] }` style filters',
1827
+ "- `type`: limit results to `ai-agents` or `mcp-servers`"
1828
+ ].join("\n")
1829
+ }
1830
+ ]
1831
+ });
1832
+
1833
+ // src/transports/index.ts
1834
+ var LOOPBACK = "127.0.0.1";
1835
+ async function runStdio() {
1836
+ logger.info("Starting stdio transport");
1837
+ await mcp.stdio();
1838
+ logger.info("Stdio transport exited");
1839
+ }
1840
+ async function runSSE() {
1841
+ const upstreamPort = config.httpStreamPort ?? config.port + 1;
1842
+ await startHttpStreamBackend(upstreamPort);
1843
+ const gateway = createGatewayServer(upstreamPort);
1844
+ await new Promise((resolve, reject) => {
1845
+ gateway.once("error", reject);
1846
+ gateway.listen(config.port, () => {
1847
+ logger.info({ port: config.port, upstreamPort }, "Gateway listening");
1848
+ resolve();
1849
+ });
1850
+ });
1851
+ }
1852
+ async function startHttpStreamBackend(port) {
1853
+ await mcp.start({
1854
+ transportType: "httpStream",
1855
+ httpStream: {
1856
+ port,
1857
+ host: LOOPBACK,
1858
+ endpoint: "/mcp/stream",
1859
+ enableJsonResponse: false
1860
+ }
1861
+ });
1862
+ logger.info({ port }, "HTTP stream backend ready");
1863
+ }
1864
+ function createGatewayServer(upstreamPort) {
1865
+ return http.createServer(createGatewayHandler(upstreamPort));
1866
+ }
1867
+ function createGatewayHandler(upstreamPort) {
1868
+ return (req, res) => {
1869
+ if (!req.url) {
1870
+ res.writeHead(400).end("Missing URL");
1871
+ return;
1872
+ }
1873
+ if (req.url.startsWith("/healthz")) {
1874
+ const body = JSON.stringify({
1875
+ status: "ok",
1876
+ uptime: process.uptime(),
1877
+ tools: registeredTools.length,
1878
+ requestId: randomUUID2()
1879
+ });
1880
+ res.writeHead(200, { "content-type": "application/json" });
1881
+ res.end(body);
1882
+ return;
1883
+ }
1884
+ proxyRequest(req, res, upstreamPort);
1885
+ };
1886
+ }
1887
+ function proxyRequest(req, res, upstreamPort) {
1888
+ logger.debug({ method: req.method, url: req.url }, "gateway.forward");
1889
+ const proxyReq = http.request(
1890
+ {
1891
+ hostname: LOOPBACK,
1892
+ port: upstreamPort,
1893
+ method: req.method,
1894
+ path: req.url,
1895
+ headers: {
1896
+ ...req.headers,
1897
+ host: `${LOOPBACK}:${upstreamPort}`
1898
+ }
1899
+ },
1900
+ (proxyRes) => {
1901
+ res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
1902
+ proxyRes.pipe(res);
1903
+ }
1904
+ );
1905
+ proxyReq.on("error", (error) => {
1906
+ logger.error({ error }, "proxy.error");
1907
+ if (!res.headersSent) {
1908
+ res.writeHead(502);
1909
+ }
1910
+ res.end("Upstream error");
1911
+ });
1912
+ if (req.method && ["POST", "PUT", "PATCH"].includes(req.method)) {
1913
+ const tee = new PassThrough();
1914
+ let preview = "";
1915
+ tee.on("data", (chunk) => {
1916
+ if (preview.length < 512) {
1917
+ preview += chunk.toString();
1918
+ }
1919
+ });
1920
+ tee.on("end", () => {
1921
+ if (preview.length) {
1922
+ logger.debug({ preview: preview.slice(0, 512) }, "proxy.preview");
1923
+ }
1924
+ });
1925
+ req.pipe(tee).pipe(proxyReq);
1926
+ } else {
1927
+ req.pipe(proxyReq);
1928
+ }
1929
+ }
1930
+
1931
+ // src/index.ts
1932
+ var transport = (process.env.MCP_TRANSPORT ?? "sse").toLowerCase();
1933
+ if (transport === "stdio") {
1934
+ logger.info({ transport }, "starting MCP server");
1935
+ runStdio().catch((err) => {
1936
+ logger.error({ err }, "Failed to start stdio transport");
1937
+ process.exitCode = 1;
1938
+ });
1939
+ } else {
1940
+ logger.info({ transport }, "starting MCP server");
1941
+ runSSE().catch((err) => {
1942
+ logger.error({ err }, "Failed to start SSE transport");
1943
+ process.exitCode = 1;
1944
+ });
1945
+ }
1946
+ //# sourceMappingURL=index.js.map