@agentxv2/sdk 0.3.0 → 0.4.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.
Files changed (107) hide show
  1. package/README.md +25 -16
  2. package/dist/core.d.mts +64 -0
  3. package/dist/core.d.ts +64 -0
  4. package/dist/core.js +275 -0
  5. package/dist/core.js.map +1 -0
  6. package/dist/core.mjs +240 -0
  7. package/dist/core.mjs.map +1 -0
  8. package/dist/{agent/agent-runner.d.ts → index-DhXVi_ub.d.ts} +94 -10
  9. package/dist/index-eQO4iaOr.d.mts +208 -0
  10. package/dist/index.d.mts +269 -0
  11. package/dist/index.d.ts +269 -10
  12. package/dist/index.js +2416 -31
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +2363 -0
  15. package/dist/index.mjs.map +1 -0
  16. package/dist/react.d.mts +3 -0
  17. package/dist/react.d.ts +3 -0
  18. package/dist/react.js +755 -0
  19. package/dist/react.js.map +1 -0
  20. package/dist/react.mjs +735 -0
  21. package/dist/react.mjs.map +1 -0
  22. package/dist/{core/types.d.ts → types-2aHUvS4M.d.mts} +34 -33
  23. package/dist/types-2aHUvS4M.d.ts +297 -0
  24. package/package.json +12 -11
  25. package/dist/a2a/a2a.d.ts +0 -37
  26. package/dist/a2a/a2a.d.ts.map +0 -1
  27. package/dist/a2a/a2a.js +0 -252
  28. package/dist/a2a/a2a.js.map +0 -1
  29. package/dist/a2a/index.d.ts +0 -4
  30. package/dist/a2a/index.d.ts.map +0 -1
  31. package/dist/a2a/index.js +0 -4
  32. package/dist/a2a/index.js.map +0 -1
  33. package/dist/agent/agent-runner.d.ts.map +0 -1
  34. package/dist/agent/agent-runner.js +0 -249
  35. package/dist/agent/agent-runner.js.map +0 -1
  36. package/dist/agent/index.d.ts +0 -3
  37. package/dist/agent/index.d.ts.map +0 -1
  38. package/dist/agent/index.js +0 -3
  39. package/dist/agent/index.js.map +0 -1
  40. package/dist/config/config.d.ts +0 -31
  41. package/dist/config/config.d.ts.map +0 -1
  42. package/dist/config/config.js +0 -95
  43. package/dist/config/config.js.map +0 -1
  44. package/dist/config/index.d.ts +0 -4
  45. package/dist/config/index.d.ts.map +0 -1
  46. package/dist/config/index.js +0 -4
  47. package/dist/config/index.js.map +0 -1
  48. package/dist/core/crypto.d.ts +0 -62
  49. package/dist/core/crypto.d.ts.map +0 -1
  50. package/dist/core/crypto.js +0 -291
  51. package/dist/core/crypto.js.map +0 -1
  52. package/dist/core/index.d.ts +0 -3
  53. package/dist/core/index.d.ts.map +0 -1
  54. package/dist/core/index.js +0 -4
  55. package/dist/core/index.js.map +0 -1
  56. package/dist/core/types.d.ts.map +0 -1
  57. package/dist/core/types.js +0 -30
  58. package/dist/core/types.js.map +0 -1
  59. package/dist/index.d.ts.map +0 -1
  60. package/dist/mcp/connector.d.ts +0 -43
  61. package/dist/mcp/connector.d.ts.map +0 -1
  62. package/dist/mcp/connector.js +0 -79
  63. package/dist/mcp/connector.js.map +0 -1
  64. package/dist/mcp/index.d.ts +0 -4
  65. package/dist/mcp/index.d.ts.map +0 -1
  66. package/dist/mcp/index.js +0 -4
  67. package/dist/mcp/index.js.map +0 -1
  68. package/dist/react/index.d.ts +0 -4
  69. package/dist/react/index.d.ts.map +0 -1
  70. package/dist/react/index.js +0 -3
  71. package/dist/react/index.js.map +0 -1
  72. package/dist/react/useAgentRunner.d.ts +0 -16
  73. package/dist/react/useAgentRunner.d.ts.map +0 -1
  74. package/dist/react/useAgentRunner.js +0 -204
  75. package/dist/react/useAgentRunner.js.map +0 -1
  76. package/dist/registry/agent-registry.d.ts +0 -52
  77. package/dist/registry/agent-registry.d.ts.map +0 -1
  78. package/dist/registry/agent-registry.js +0 -221
  79. package/dist/registry/agent-registry.js.map +0 -1
  80. package/dist/registry/index.d.ts +0 -7
  81. package/dist/registry/index.d.ts.map +0 -1
  82. package/dist/registry/index.js +0 -6
  83. package/dist/registry/index.js.map +0 -1
  84. package/dist/registry/ipfs-fetcher.d.ts +0 -39
  85. package/dist/registry/ipfs-fetcher.d.ts.map +0 -1
  86. package/dist/registry/ipfs-fetcher.js +0 -139
  87. package/dist/registry/ipfs-fetcher.js.map +0 -1
  88. package/dist/reputation/index.d.ts +0 -4
  89. package/dist/reputation/index.d.ts.map +0 -1
  90. package/dist/reputation/index.js +0 -4
  91. package/dist/reputation/index.js.map +0 -1
  92. package/dist/reputation/reputation.d.ts +0 -26
  93. package/dist/reputation/reputation.d.ts.map +0 -1
  94. package/dist/reputation/reputation.js +0 -113
  95. package/dist/reputation/reputation.js.map +0 -1
  96. package/dist/subscription/agent-x402.d.ts +0 -33
  97. package/dist/subscription/agent-x402.d.ts.map +0 -1
  98. package/dist/subscription/agent-x402.js +0 -144
  99. package/dist/subscription/agent-x402.js.map +0 -1
  100. package/dist/subscription/index.d.ts +0 -6
  101. package/dist/subscription/index.d.ts.map +0 -1
  102. package/dist/subscription/index.js +0 -5
  103. package/dist/subscription/index.js.map +0 -1
  104. package/dist/subscription/subscription.d.ts +0 -67
  105. package/dist/subscription/subscription.d.ts.map +0 -1
  106. package/dist/subscription/subscription.js +0 -346
  107. package/dist/subscription/subscription.js.map +0 -1
package/dist/react.mjs ADDED
@@ -0,0 +1,735 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/react/useAgentRunner.ts
9
+ import { useState, useEffect, useRef } from "react";
10
+ import { usePublicClient, useWalletClient } from "wagmi";
11
+
12
+ // src/core/crypto.ts
13
+ import { gcm } from "@noble/ciphers/aes.js";
14
+ import { secp256k1 } from "@noble/curves/secp256k1.js";
15
+ import { sha256 } from "@noble/hashes/sha2.js";
16
+ import { hkdf } from "@noble/hashes/hkdf.js";
17
+ import { hmac } from "@noble/hashes/hmac.js";
18
+ import { bytesToHex, hexToBytes } from "@noble/ciphers/utils.js";
19
+ function randomBytes(length) {
20
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
21
+ const buf = new Uint8Array(length);
22
+ crypto.getRandomValues(buf);
23
+ return buf;
24
+ }
25
+ const nodeCrypto = __require("crypto");
26
+ return new Uint8Array(nodeCrypto.randomBytes(length));
27
+ }
28
+ var AES_KEY_SIZE = 32;
29
+ var IV_SIZE = 12;
30
+ var TAG_SIZE = 16;
31
+ function fromBase64(b64) {
32
+ if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(b64, "base64"));
33
+ const binary = atob(b64);
34
+ const bytes = new Uint8Array(binary.length);
35
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
36
+ return bytes;
37
+ }
38
+ function aesDecrypt(encryptedBase64, keyHex) {
39
+ const key = hexToBytes(keyHex);
40
+ const combined = fromBase64(encryptedBase64);
41
+ const iv = combined.subarray(0, IV_SIZE);
42
+ const ciphertext = combined.subarray(IV_SIZE, -TAG_SIZE);
43
+ const authTag = combined.subarray(-TAG_SIZE);
44
+ const cipher = gcm(key, iv);
45
+ const ciphertextWithTag = new Uint8Array(ciphertext.length + TAG_SIZE);
46
+ ciphertextWithTag.set(ciphertext, 0);
47
+ ciphertextWithTag.set(authTag, ciphertext.length);
48
+ const decrypted = cipher.decrypt(ciphertextWithTag);
49
+ return new TextDecoder().decode(decrypted);
50
+ }
51
+ function generateAesKey() {
52
+ return bytesToHex(randomBytes(AES_KEY_SIZE));
53
+ }
54
+ function eciesEncode(ephemeralPub, iv, ciphertext, mac) {
55
+ const out = new Uint8Array(33 + 16 + ciphertext.length + 32);
56
+ out.set(ephemeralPub, 0);
57
+ out.set(iv, 33);
58
+ out.set(ciphertext, 33 + 16);
59
+ out.set(mac, 33 + 16 + ciphertext.length);
60
+ return bytesToHex(out);
61
+ }
62
+ function eciesDecode(dataHex) {
63
+ const d = hexToBytes(dataHex);
64
+ return {
65
+ ephemeralPub: d.subarray(0, 33),
66
+ iv: d.subarray(33, 49),
67
+ ciphertext: d.subarray(49, -32),
68
+ mac: d.subarray(-32)
69
+ };
70
+ }
71
+ function aesCtrEncrypt(key, ctrBytes, data) {
72
+ const blockSize = 16;
73
+ const cipher = gcm(key, ctrBytes);
74
+ const result = new Uint8Array(data.length);
75
+ const counter = new Uint8Array(blockSize);
76
+ counter.set(ctrBytes);
77
+ for (let i = 0; i < data.length; i += blockSize) {
78
+ const keystream = gcm(key, counter).encrypt(new Uint8Array(blockSize));
79
+ for (let j = 0; j < blockSize && i + j < data.length; j++) {
80
+ result[i + j] = keystream[j] ^ data[i + j];
81
+ }
82
+ for (let j = blockSize - 1; j >= 0; j--) {
83
+ const val = counter[j];
84
+ if (val !== void 0) {
85
+ counter[j] = val + 1 & 255;
86
+ if (counter[j] !== 0) break;
87
+ }
88
+ }
89
+ }
90
+ return result;
91
+ }
92
+ function eciesEncrypt(dataHex, publicKey) {
93
+ const ephPriv = randomBytes(32);
94
+ const ephPub = secp256k1.getPublicKey(ephPriv, true);
95
+ let recipientPub;
96
+ if (publicKey.startsWith("04") && publicKey.length === 130) {
97
+ recipientPub = hexToBytes(publicKey);
98
+ } else if (publicKey.startsWith("02") || publicKey.startsWith("03")) {
99
+ recipientPub = hexToBytes(publicKey);
100
+ } else {
101
+ throw new Error("Invalid public key format: expected hex with 02/03/04 prefix");
102
+ }
103
+ const shared = secp256k1.getSharedSecret(ephPriv, recipientPub);
104
+ const sharedX = shared.subarray(1, 33);
105
+ const sharedKey = sha256(sharedX);
106
+ const hkdfOut = hkdf(sha256, sharedKey, void 0, void 0, 64);
107
+ const encKey = hkdfOut.subarray(0, 32);
108
+ const macKey = hkdfOut.subarray(32, 64);
109
+ const iv = randomBytes(16);
110
+ const plaintext = hexToBytes(dataHex);
111
+ const ciphertext = aesCtrEncrypt(encKey, iv, plaintext);
112
+ const macInput = new Uint8Array(33 + 16 + ciphertext.length);
113
+ macInput.set(ephPub, 0);
114
+ macInput.set(iv, 33);
115
+ macInput.set(ciphertext, 33 + 16);
116
+ const mac = hmac(sha256, macKey, macInput);
117
+ return eciesEncode(ephPub, iv, ciphertext, mac);
118
+ }
119
+ function eciesDecrypt(dataHex, privateKey) {
120
+ const { ephemeralPub, iv, ciphertext, mac } = eciesDecode(dataHex);
121
+ const privBytes = hexToBytes(privateKey);
122
+ const shared = secp256k1.getSharedSecret(privBytes, ephemeralPub);
123
+ const sharedX = shared.subarray(1, 33);
124
+ const sharedKey = sha256(sharedX);
125
+ const hkdfOut = hkdf(sha256, sharedKey, void 0, void 0, 64);
126
+ const encKey = hkdfOut.subarray(0, 32);
127
+ const macKey = hkdfOut.subarray(32, 64);
128
+ const macInput = new Uint8Array(33 + 16 + ciphertext.length);
129
+ macInput.set(ephemeralPub, 0);
130
+ macInput.set(iv, 33);
131
+ macInput.set(ciphertext, 33 + 16);
132
+ const expectedMac = hmac(sha256, macKey, macInput);
133
+ if (!constantTimeEqual(mac, expectedMac)) {
134
+ throw new Error("ECIES decryption failed: MAC mismatch");
135
+ }
136
+ const plaintext = aesCtrEncrypt(encKey, iv, ciphertext);
137
+ return bytesToHex(plaintext);
138
+ }
139
+ function constantTimeEqual(a, b) {
140
+ if (a.length !== b.length) return false;
141
+ let diff = 0;
142
+ for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
143
+ return diff === 0;
144
+ }
145
+ function decryptPayload(encrypted, keyHex) {
146
+ if (encrypted.algorithm !== "AES-256-GCM") {
147
+ throw new Error(`Unsupported algorithm: ${encrypted.algorithm}`);
148
+ }
149
+ return JSON.parse(aesDecrypt(encrypted.data, keyHex));
150
+ }
151
+ function unpackAgent(encryptedPayload, eciesEncryptedKey, privateKey) {
152
+ const aesKeyHex = eciesDecrypt(eciesEncryptedKey, privateKey);
153
+ return decryptPayload(encryptedPayload, aesKeyHex);
154
+ }
155
+
156
+ // src/registry/ipfs-fetcher.ts
157
+ var IPFSFetcher = class {
158
+ gateway;
159
+ fallbackGateways;
160
+ timeoutMs;
161
+ cache = /* @__PURE__ */ new Map();
162
+ maxCache;
163
+ pending = /* @__PURE__ */ new Map();
164
+ failed = /* @__PURE__ */ new Set();
165
+ constructor(config = {}) {
166
+ this.gateway = config.gateway ?? "ipfs.io";
167
+ this.fallbackGateways = config.fallbackGateways ?? [
168
+ "gateway.pinata.cloud",
169
+ "dweb.link",
170
+ "cf-ipfs.com"
171
+ ];
172
+ this.timeoutMs = config.timeoutMs ?? 1e4;
173
+ this.maxCache = config.maxCache ?? 200;
174
+ }
175
+ // ── Public API ──────────────────────────────────────────────────────────
176
+ /** Fetch JSON from a single IPFS CID. */
177
+ async fetchJSON(cid) {
178
+ const cached = this.cache.get(cid);
179
+ if (cached) return cached.data;
180
+ if (this.failed.has(cid)) throw new Error(`CID ${cid} previously failed`);
181
+ const pending = this.pending.get(cid);
182
+ if (pending) return pending;
183
+ const promise = this._doFetch(cid);
184
+ this.pending.set(cid, promise);
185
+ try {
186
+ const data = await promise;
187
+ this._cacheSet(cid, data);
188
+ return data;
189
+ } catch (e) {
190
+ this.failed.add(cid);
191
+ throw e;
192
+ } finally {
193
+ this.pending.delete(cid);
194
+ }
195
+ }
196
+ /** Fetch encrypted agent payload (validates algorithm). */
197
+ async fetchEncryptedPayload(cid) {
198
+ const raw = await this.fetchJSON(cid);
199
+ if (!raw.encrypted || raw.algorithm !== "AES-256-GCM" || typeof raw.data !== "string") {
200
+ throw new Error(`Invalid EncryptedPayload at CID ${cid}`);
201
+ }
202
+ return raw;
203
+ }
204
+ /** Batch fetch multiple CIDs with concurrency control. */
205
+ async fetchBatch(cids, concurrency = 5) {
206
+ const results = /* @__PURE__ */ new Map();
207
+ const unique = [...new Set(cids)].filter((c) => this.isValidCID(c));
208
+ for (let i = 0; i < unique.length; i += concurrency) {
209
+ const batch = unique.slice(i, i + concurrency);
210
+ const settled = await Promise.allSettled(
211
+ batch.map((cid) => this.fetchJSON(cid))
212
+ );
213
+ settled.forEach((r, j) => {
214
+ if (r.status === "fulfilled") results.set(batch[j], r.value);
215
+ });
216
+ if (i + concurrency < unique.length) {
217
+ await new Promise((r) => setTimeout(r, 200));
218
+ }
219
+ }
220
+ return results;
221
+ }
222
+ /** Check if a string looks like a valid IPFS CID. */
223
+ isValidCID(cid) {
224
+ return /^(Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[a-z2-7]{58,}|[A-Za-z0-9+/]{46,})$/.test(cid);
225
+ }
226
+ /** Clear cache (optionally for a specific CID). */
227
+ clearCache(cid) {
228
+ if (cid) {
229
+ this.cache.delete(cid);
230
+ } else {
231
+ this.cache.clear();
232
+ }
233
+ this.failed.clear();
234
+ }
235
+ /** Number of cached entries. */
236
+ get cacheSize() {
237
+ return this.cache.size;
238
+ }
239
+ // ── Internal ─────────────────────────────────────────────────────────────
240
+ async _doFetch(cid) {
241
+ if (!this.isValidCID(cid)) throw new Error(`Invalid CID: ${cid}`);
242
+ try {
243
+ return await this._fetchFrom(cid, this.gateway, this.timeoutMs);
244
+ } catch {
245
+ }
246
+ for (const gw of this.fallbackGateways) {
247
+ try {
248
+ return await this._fetchFrom(cid, gw, this.timeoutMs);
249
+ } catch {
250
+ }
251
+ }
252
+ throw new Error(`All IPFS gateways failed for CID ${cid}`);
253
+ }
254
+ async _fetchFrom(cid, gateway, timeoutMs) {
255
+ const url = `https://${gateway}/ipfs/${cid}`;
256
+ const res = await fetch(url, {
257
+ headers: { Accept: "application/json" },
258
+ signal: AbortSignal.timeout(timeoutMs)
259
+ });
260
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
261
+ return await res.json();
262
+ }
263
+ _cacheSet(cid, data) {
264
+ this.cache.set(cid, { data, timestamp: Date.now() });
265
+ if (this.cache.size > this.maxCache) {
266
+ const oldest = [...this.cache.entries()].sort(
267
+ (a, b) => a[1].timestamp - b[1].timestamp
268
+ )[0];
269
+ if (oldest) this.cache.delete(oldest[0]);
270
+ }
271
+ }
272
+ };
273
+ var defaultIPFSFetcher = new IPFSFetcher();
274
+
275
+ // src/core/types.ts
276
+ var AgentXError = class extends Error {
277
+ code;
278
+ /** If NOT_SUBSCRIBED, carry enough info for wallet/X402 auto-payment */
279
+ paymentInfo;
280
+ constructor(code, message) {
281
+ super(message);
282
+ this.code = code;
283
+ this.name = "AgentXError";
284
+ }
285
+ };
286
+
287
+ // src/agent/agent-runner.ts
288
+ var AgentRunner = class {
289
+ reader;
290
+ wallet;
291
+ ipfs;
292
+ constructor(config) {
293
+ this.reader = config.reader;
294
+ this.wallet = config.wallet;
295
+ this.ipfs = config.ipfsFetcher ?? new IPFSFetcher({
296
+ fallbackGateways: config.ipfsGateways ?? [
297
+ "gateway.pinata.cloud",
298
+ "dweb.link",
299
+ "cf-ipfs.com"
300
+ ]
301
+ });
302
+ }
303
+ // ── Primary API: useAgent ────────────────────────────────────────────────
304
+ /**
305
+ * Load and decrypt an Agent, returning a run context ready to inject
306
+ * into any LLM conversation.
307
+ *
308
+ * Steps:
309
+ * 1. Verify on-chain subscription (frontend check)
310
+ * 2. Fetch metadata → get encryptedPayloadCid + eciesEncryptedKey
311
+ * 3. IPFS fetch encrypted payload
312
+ * 4. ECIES decrypt AES key (using wallet private key)
313
+ * 5. AES-256-GCM decrypt payload → { prompt, skills, mcp }
314
+ * 6. Build RunnableSkill wrappers (Open: local stub, Closed: MCP remote)
315
+ */
316
+ async useAgent(agentId) {
317
+ const address = await this.wallet.getAddress();
318
+ const isActive = await this.reader.hasActiveSubscription(address, agentId);
319
+ if (!isActive) {
320
+ const err = new AgentXError(
321
+ "NOT_SUBSCRIBED" /* NOT_SUBSCRIBED */,
322
+ `No active subscription for Agent #${agentId}. Check error.paymentInfo for auto-subscribe via wallet/X402.`
323
+ );
324
+ err.paymentInfo = {
325
+ agentId
326
+ };
327
+ throw err;
328
+ }
329
+ const attrs = await this.reader.getAttributes(agentId);
330
+ const encryptedPayloadCid = attrs.encryptedPayloadCid;
331
+ const eciesEncryptedKey = attrs.eciesEncryptedKey;
332
+ if (!encryptedPayloadCid || !eciesEncryptedKey) {
333
+ throw new AgentXError(
334
+ "AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */,
335
+ `Agent #${agentId} metadata incomplete \u2014 missing encryptedPayloadCid or eciesEncryptedKey`
336
+ );
337
+ }
338
+ let encryptedPayload;
339
+ try {
340
+ encryptedPayload = await this.ipfs.fetchEncryptedPayload(encryptedPayloadCid);
341
+ } catch (e) {
342
+ throw new AgentXError(
343
+ "IPFS_FETCH_FAILED" /* IPFS_FETCH_FAILED */,
344
+ `Failed to fetch encrypted payload for agent #${agentId}: ${e}`
345
+ );
346
+ }
347
+ let privatePayload;
348
+ try {
349
+ const privKey = await this._getPrivateKey();
350
+ privatePayload = unpackAgent(encryptedPayload, eciesEncryptedKey, privKey);
351
+ } catch (e) {
352
+ throw new AgentXError(
353
+ "DECRYPTION_FAILED" /* DECRYPTION_FAILED */,
354
+ `Failed to decrypt agent #${agentId}: ${e}`
355
+ );
356
+ }
357
+ const skills = privatePayload.skills.map((s) => this._wrapSkill(s));
358
+ return {
359
+ agentId,
360
+ prompt: privatePayload.prompt,
361
+ skills,
362
+ mcp: {
363
+ type: privatePayload.mcp.type,
364
+ url: privatePayload.mcp.url,
365
+ toolFilter: privatePayload.mcp.toolFilter
366
+ },
367
+ subscriptionExpiry: 0
368
+ };
369
+ }
370
+ // ── Publishing ───────────────────────────────────────────────────────────
371
+ /**
372
+ * Pack an AgentPayload for publishing (encryption only, no IPFS upload).
373
+ * Caller is responsible for IPFS upload and on-chain registration.
374
+ */
375
+ packForPublish(payload, publicKey) {
376
+ const key = generateAesKey();
377
+ return {
378
+ encryptedCid: "",
379
+ publicCid: "",
380
+ aesKeyHex: key,
381
+ eciesEncryptedKeyHex: eciesEncrypt(key, publicKey)
382
+ };
383
+ }
384
+ // ── Internals ────────────────────────────────────────────────────────────
385
+ /** Wrap a SkillDef into a RunnableSkill with execute(). */
386
+ _wrapSkill(skill) {
387
+ let mode = "open";
388
+ let executeFn;
389
+ if (skill.execution) {
390
+ if (skill.execution.type === "mcp") {
391
+ mode = "mcp";
392
+ const endpoint = skill.execution.endpoint ?? "";
393
+ const toolName = skill.execution.toolName ?? skill.name;
394
+ executeFn = async (input) => {
395
+ return this._executeMCPTool(endpoint, toolName, input);
396
+ };
397
+ } else if (skill.execution.type === "a2a") {
398
+ mode = "a2a";
399
+ executeFn = async (input) => {
400
+ return this._executeA2ASkill(skill, input);
401
+ };
402
+ } else {
403
+ throw new AgentXError(
404
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
405
+ `Unknown execution type "${skill.execution.type}" for skill "${skill.name}"`
406
+ );
407
+ }
408
+ } else {
409
+ executeFn = async () => {
410
+ throw new AgentXError(
411
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
412
+ `Open skill "${skill.name}" has no local executor. Implement execute() or switch to execution.type = "mcp" or "a2a".`
413
+ );
414
+ };
415
+ }
416
+ return {
417
+ name: skill.name,
418
+ description: skill.description,
419
+ inputSchema: skill.inputSchema,
420
+ outputSchema: skill.outputSchema,
421
+ mode,
422
+ execute: executeFn,
423
+ /** If A2A, carry delegation metadata so the LLM can see it */
424
+ a2aTargetAgentId: skill.execution?.type === "a2a" ? skill.execution.targetAgentId : void 0
425
+ };
426
+ }
427
+ /** Call a tool on the publisher's MCP server (Closed skill). */
428
+ async _executeMCPTool(endpoint, toolName, params) {
429
+ const address = await this.wallet.getAddress();
430
+ const timestamp = Math.floor(Date.now() / 1e3);
431
+ const message = `agentx:mcp:${toolName}:${timestamp}`;
432
+ const signature = await this.wallet.signMessage(message);
433
+ const res = await fetch(endpoint, {
434
+ method: "POST",
435
+ headers: {
436
+ "Content-Type": "application/json",
437
+ "X-Subscriber-Address": address,
438
+ "X-Signature": signature,
439
+ "X-Timestamp": String(timestamp)
440
+ },
441
+ body: JSON.stringify({
442
+ method: "tools/call",
443
+ params: {
444
+ name: toolName,
445
+ arguments: params
446
+ }
447
+ })
448
+ });
449
+ if (!res.ok) {
450
+ const text = await res.text();
451
+ if (res.status === 403) {
452
+ throw new AgentXError(
453
+ "SUBSCRIPTION_EXPIRED" /* SUBSCRIPTION_EXPIRED */,
454
+ `MCP server rejected request: subscription may have expired. ${text}`
455
+ );
456
+ }
457
+ throw new AgentXError(
458
+ "TX_FAILED" /* TX_FAILED */,
459
+ `MCP tool "${toolName}" failed (HTTP ${res.status}): ${text}`
460
+ );
461
+ }
462
+ const data = await res.json();
463
+ const content = data.content?.[0];
464
+ if (content?.type === "text" && content.text) {
465
+ try {
466
+ return JSON.parse(content.text);
467
+ } catch {
468
+ return content.text;
469
+ }
470
+ }
471
+ return data;
472
+ }
473
+ /**
474
+ * Execute an A2A skill — delegate to another AgentX Agent.
475
+ *
476
+ * Standard Interface:
477
+ * Input: { task, ...taskSpecificParams }
478
+ * Output: { agentId, prompt, skills[] }
479
+ *
480
+ * The caller (LLM) receives the sub-Agent's prompt + skill list.
481
+ * The LLM then decides how to use the sub-Agent — typically by
482
+ * injecting the sub-Agent's system prompt and calling its skills.
483
+ */
484
+ async _executeA2ASkill(skill, input) {
485
+ const exec = skill.execution;
486
+ if (!exec || exec.type !== "a2a") {
487
+ throw new AgentXError(
488
+ "INVALID_SCHEMA" /* INVALID_SCHEMA */,
489
+ `Skill "${skill.name}" is not an A2A delegation skill`
490
+ );
491
+ }
492
+ const targetAgentId = exec.targetAgentId;
493
+ let subContext;
494
+ try {
495
+ subContext = await this.useAgent(targetAgentId);
496
+ } catch (e) {
497
+ throw new AgentXError(
498
+ "AGENT_NOT_FOUND" /* AGENT_NOT_FOUND */,
499
+ `A2A delegation failed: cannot load Agent #${targetAgentId}. ${e}`
500
+ );
501
+ }
502
+ if (exec.skillFilter && exec.skillFilter.length > 0) {
503
+ const filterSet = new Set(exec.skillFilter);
504
+ subContext = {
505
+ ...subContext,
506
+ skills: subContext.skills.filter((s) => filterSet.has(s.name))
507
+ };
508
+ }
509
+ if (exec.promptOverride) {
510
+ subContext = { ...subContext, prompt: exec.promptOverride };
511
+ }
512
+ return {
513
+ agentId: targetAgentId,
514
+ prompt: subContext.prompt,
515
+ skills: subContext.skills.map((s) => ({
516
+ name: s.name,
517
+ description: s.description,
518
+ inputSchema: s.inputSchema
519
+ })),
520
+ // Pass the caller's input to the sub-agent's context
521
+ callerInput: input
522
+ };
523
+ }
524
+ async _getPrivateKey() {
525
+ if (this.wallet.getPrivateKey) return this.wallet.getPrivateKey();
526
+ throw new AgentXError(
527
+ "WALLET_NOT_CONNECTED" /* WALLET_NOT_CONNECTED */,
528
+ "Wallet must support getPrivateKey() for ECIES decryption."
529
+ );
530
+ }
531
+ };
532
+
533
+ // src/config/config.ts
534
+ var KNOWN_CHAINS = {
535
+ // Sepolia Testnet
536
+ // v3 (deployed 2026-07-13): platformFee=250bps(2.5%), ReentrancyGuard, audit fixes
537
+ 11155111: {
538
+ chainId: 11155111,
539
+ contracts: {
540
+ identityRegistry: "0xe94ad380d3F8d08a7590eda0C84f354a93F96e5F",
541
+ subscriptionManager: "0xC15fE80b9d800abb72121F353a6ae6d6E9077E63",
542
+ paymentGateway: "0x0000000000000000000000000000000000000000",
543
+ a2aProtocolRegistry: "0x0000000000000000000000000000000000000000",
544
+ reputationRegistry: "0x0000000000000000000000000000000000000000",
545
+ configurationRegistry: "0x0000000000000000000000000000000000000000"
546
+ },
547
+ ipfsGateways: ["ipfs.io", "gateway.pinata.cloud", "dweb.link", "cf-ipfs.com"]
548
+ },
549
+ // OxaChain L1 Mainnet
550
+ // Chain ID 19505, Clique PoA, Shanghai+Cancun, gas token T0x
551
+ // Deployer: 0x8E869A0624fF9e766Df71b5B08897d00E4d260ba
552
+ // RPC: http://43.156.99.215:18545
553
+ // Explorer: http://43.156.99.215:18400
554
+ 19505: {
555
+ chainId: 19505,
556
+ contracts: {
557
+ identityRegistry: "0x0292af212Ce34bbCd95BbC69F4F8c9f7ae123902",
558
+ subscriptionManager: "0x37BA9DdfE66Aa86f920a34Ae0ae268342151E249",
559
+ paymentGateway: "0x0000000000000000000000000000000000000000",
560
+ a2aProtocolRegistry: "0x0000000000000000000000000000000000000000",
561
+ reputationRegistry: "0x0000000000000000000000000000000000000000",
562
+ configurationRegistry: "0x0000000000000000000000000000000000000000"
563
+ },
564
+ ipfsGateways: ["ipfs.io", "gateway.pinata.cloud", "dweb.link", "cf-ipfs.com"],
565
+ rpcUrl: "http://43.156.99.215:18545"
566
+ }
567
+ };
568
+
569
+ // src/react/useAgentRunner.ts
570
+ var IDENTITY_REGISTRY_ABI = [
571
+ // getAgentMetadata returns MetadataEntry[] with key+value strings
572
+ {
573
+ name: "getAgentMetadata",
574
+ type: "function",
575
+ stateMutability: "view",
576
+ inputs: [{ name: "agentId", type: "uint256" }],
577
+ outputs: [
578
+ {
579
+ name: "",
580
+ type: "tuple[]",
581
+ components: [
582
+ { name: "key", type: "string" },
583
+ { name: "value", type: "bytes" }
584
+ ]
585
+ }
586
+ ]
587
+ }
588
+ ];
589
+ var SUBSCRIPTION_MANAGER_ABI = [
590
+ {
591
+ name: "hasActiveSubscription",
592
+ type: "function",
593
+ stateMutability: "view",
594
+ inputs: [
595
+ { name: "subscriber", type: "address" },
596
+ { name: "agentId", type: "uint256" }
597
+ ],
598
+ outputs: [{ name: "", type: "bool" }]
599
+ }
600
+ ];
601
+ var ViemOnChainReader = class {
602
+ constructor(publicClient, chainConfig) {
603
+ this.publicClient = publicClient;
604
+ this.chainConfig = chainConfig;
605
+ }
606
+ publicClient;
607
+ chainConfig;
608
+ async getTokenURI(_agentId) {
609
+ return "";
610
+ }
611
+ async getAttributes(agentId) {
612
+ if (!this.publicClient) throw new Error("Public client not available");
613
+ const entries = await this.publicClient.readContract({
614
+ address: this.chainConfig.contracts.identityRegistry,
615
+ abi: IDENTITY_REGISTRY_ABI,
616
+ functionName: "getAgentMetadata",
617
+ args: [BigInt(agentId)]
618
+ });
619
+ const attrs = {};
620
+ for (const entry of entries) {
621
+ const hexStr = entry.value;
622
+ if (hexStr && hexStr !== "0x") {
623
+ attrs[entry.key] = hexToStringUTF8(hexStr);
624
+ } else {
625
+ attrs[entry.key] = "";
626
+ }
627
+ }
628
+ return attrs;
629
+ }
630
+ async hasActiveSubscription(address, agentId) {
631
+ if (!this.publicClient) return false;
632
+ try {
633
+ return await this.publicClient.readContract({
634
+ address: this.chainConfig.contracts.subscriptionManager,
635
+ abi: SUBSCRIPTION_MANAGER_ABI,
636
+ functionName: "hasActiveSubscription",
637
+ args: [address, BigInt(agentId)]
638
+ });
639
+ } catch {
640
+ return false;
641
+ }
642
+ }
643
+ };
644
+ function hexToStringUTF8(hex) {
645
+ if (!hex.startsWith("0x")) return hex;
646
+ const hexClean = hex.slice(2);
647
+ if (hexClean.length === 0) return "";
648
+ try {
649
+ const bytes = new Uint8Array(hexClean.length / 2);
650
+ for (let i = 0; i < bytes.length; i++) {
651
+ bytes[i] = parseInt(hexClean.substring(i * 2, i * 2 + 2), 16);
652
+ }
653
+ return new TextDecoder().decode(bytes);
654
+ } catch {
655
+ return hex;
656
+ }
657
+ }
658
+ function useAgentRunner(config) {
659
+ const { agentId, chainConfig: chainConfigOverride, ipfsGateways } = config;
660
+ const publicClient = usePublicClient();
661
+ const { data: walletClient } = useWalletClient();
662
+ const [ctx, setCtx] = useState(null);
663
+ const [isLoading, setIsLoading] = useState(false);
664
+ const [error, setError] = useState(null);
665
+ const [refetchKey, setRefetchKey] = useState(0);
666
+ const runnerRef = useRef(null);
667
+ const mountedRef = useRef(true);
668
+ useEffect(() => {
669
+ mountedRef.current = true;
670
+ return () => {
671
+ mountedRef.current = false;
672
+ };
673
+ }, []);
674
+ useEffect(() => {
675
+ if (!publicClient || !walletClient) {
676
+ setError(new Error("Wallet not connected"));
677
+ return;
678
+ }
679
+ const chainConfig = chainConfigOverride ?? (publicClient.chain?.id ? KNOWN_CHAINS[publicClient.chain.id] : void 0);
680
+ if (!chainConfig) {
681
+ setError(new Error(`Chain ${publicClient.chain?.id} not supported`));
682
+ return;
683
+ }
684
+ const reader = new ViemOnChainReader(publicClient, chainConfig);
685
+ const signer = {
686
+ async signMessage(message) {
687
+ if (!walletClient.account) throw new Error("Wallet not connected");
688
+ return walletClient.signMessage({ account: walletClient.account, message });
689
+ },
690
+ async getAddress() {
691
+ if (!walletClient.account) throw new Error("Wallet not connected");
692
+ return walletClient.account.address;
693
+ },
694
+ async getPrivateKey() {
695
+ throw new Error(
696
+ 'Private key not available via wagmi. Use window.ethereum.request({ method: "eth_private_key" }) or inject getPrivateKey via custom WalletSigner.'
697
+ );
698
+ }
699
+ };
700
+ const ipfsFetcher = new IPFSFetcher({
701
+ fallbackGateways: ipfsGateways ?? chainConfig.ipfsGateways ?? [
702
+ "gateway.pinata.cloud",
703
+ "dweb.link",
704
+ "cf-ipfs.com"
705
+ ]
706
+ });
707
+ runnerRef.current = new AgentRunner({
708
+ reader,
709
+ wallet: signer,
710
+ ipfsFetcher
711
+ });
712
+ setIsLoading(true);
713
+ setError(null);
714
+ runnerRef.current.useAgent(agentId).then((result) => {
715
+ if (mountedRef.current) {
716
+ setCtx(result);
717
+ setIsLoading(false);
718
+ }
719
+ }).catch((err) => {
720
+ if (mountedRef.current) {
721
+ setError(err instanceof Error ? err : new Error(String(err)));
722
+ setIsLoading(false);
723
+ }
724
+ });
725
+ return () => {
726
+ mountedRef.current = false;
727
+ };
728
+ }, [agentId, publicClient?.chain?.id, publicClient, walletClient, refetchKey]);
729
+ const refetch = () => setRefetchKey((k) => k + 1);
730
+ return { ctx, isLoading, error, refetch };
731
+ }
732
+ export {
733
+ useAgentRunner
734
+ };
735
+ //# sourceMappingURL=index.mjs.map