@slashfi/agents-sdk 0.16.0 → 0.18.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 (96) hide show
  1. package/dist/agent-definitions/auth.d.ts.map +1 -1
  2. package/dist/agent-definitions/auth.js +44 -11
  3. package/dist/agent-definitions/auth.js.map +1 -1
  4. package/dist/agent-definitions/integrations.d.ts.map +1 -1
  5. package/dist/agent-definitions/integrations.js +106 -45
  6. package/dist/agent-definitions/integrations.js.map +1 -1
  7. package/dist/agent-definitions/remote-registry.d.ts.map +1 -1
  8. package/dist/agent-definitions/remote-registry.js +174 -45
  9. package/dist/agent-definitions/remote-registry.js.map +1 -1
  10. package/dist/agent-definitions/secrets.d.ts.map +1 -1
  11. package/dist/agent-definitions/secrets.js +1 -4
  12. package/dist/agent-definitions/secrets.js.map +1 -1
  13. package/dist/agent-definitions/users.d.ts.map +1 -1
  14. package/dist/agent-definitions/users.js +14 -3
  15. package/dist/agent-definitions/users.js.map +1 -1
  16. package/dist/define-config.d.ts +125 -0
  17. package/dist/define-config.d.ts.map +1 -0
  18. package/dist/define-config.js +75 -0
  19. package/dist/define-config.js.map +1 -0
  20. package/dist/define.d.ts +11 -2
  21. package/dist/define.d.ts.map +1 -1
  22. package/dist/define.js +57 -26
  23. package/dist/define.js.map +1 -1
  24. package/dist/events.d.ts +133 -0
  25. package/dist/events.d.ts.map +1 -0
  26. package/dist/events.js +57 -0
  27. package/dist/events.js.map +1 -0
  28. package/dist/index.d.ts +16 -8
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +21 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/integration-interface.d.ts +3 -3
  33. package/dist/integration-interface.d.ts.map +1 -1
  34. package/dist/integration-interface.js +29 -21
  35. package/dist/integration-interface.js.map +1 -1
  36. package/dist/integrations-store.d.ts +2 -2
  37. package/dist/integrations-store.d.ts.map +1 -1
  38. package/dist/integrations-store.js +3 -3
  39. package/dist/integrations-store.js.map +1 -1
  40. package/dist/jwt.d.ts.map +1 -1
  41. package/dist/jwt.js +7 -5
  42. package/dist/jwt.js.map +1 -1
  43. package/dist/key-manager.d.ts.map +1 -1
  44. package/dist/key-manager.js +5 -3
  45. package/dist/key-manager.js.map +1 -1
  46. package/dist/oidc-signin.d.ts +32 -0
  47. package/dist/oidc-signin.d.ts.map +1 -0
  48. package/dist/oidc-signin.js +138 -0
  49. package/dist/oidc-signin.js.map +1 -0
  50. package/dist/registry-consumer.d.ts +104 -0
  51. package/dist/registry-consumer.d.ts.map +1 -0
  52. package/dist/registry-consumer.js +230 -0
  53. package/dist/registry-consumer.js.map +1 -0
  54. package/dist/registry.d.ts +5 -0
  55. package/dist/registry.d.ts.map +1 -1
  56. package/dist/registry.js +76 -4
  57. package/dist/registry.js.map +1 -1
  58. package/dist/secret-collection.d.ts.map +1 -1
  59. package/dist/secret-collection.js.map +1 -1
  60. package/dist/server.d.ts +3 -0
  61. package/dist/server.d.ts.map +1 -1
  62. package/dist/server.js +222 -27
  63. package/dist/server.js.map +1 -1
  64. package/dist/test-utils/mock-oidc-server.d.ts +36 -0
  65. package/dist/test-utils/mock-oidc-server.d.ts.map +1 -0
  66. package/dist/test-utils/mock-oidc-server.js +96 -0
  67. package/dist/test-utils/mock-oidc-server.js.map +1 -0
  68. package/dist/types.d.ts +106 -0
  69. package/dist/types.d.ts.map +1 -1
  70. package/package.json +6 -1
  71. package/src/agent-definitions/auth.ts +106 -38
  72. package/src/agent-definitions/integrations.ts +201 -73
  73. package/src/agent-definitions/remote-registry.ts +262 -65
  74. package/src/agent-definitions/secrets.ts +22 -8
  75. package/src/agent-definitions/users.ts +16 -4
  76. package/src/cli.ts +293 -0
  77. package/src/codegen.test.ts +527 -0
  78. package/src/codegen.ts +1348 -0
  79. package/src/consumer.test.ts +536 -0
  80. package/src/define-config.ts +205 -0
  81. package/src/define.ts +134 -46
  82. package/src/events.ts +237 -0
  83. package/src/index.ts +107 -8
  84. package/src/integration-interface.ts +52 -28
  85. package/src/integrations-store.ts +9 -5
  86. package/src/jwt.ts +48 -19
  87. package/src/key-manager.test.ts +22 -13
  88. package/src/key-manager.ts +8 -10
  89. package/src/oidc-signin.ts +223 -0
  90. package/src/registry-consumer.ts +413 -0
  91. package/src/registry.ts +115 -9
  92. package/src/secret-collection.ts +2 -1
  93. package/src/server.test.ts +304 -238
  94. package/src/server.ts +371 -69
  95. package/src/test-utils/mock-oidc-server.ts +123 -0
  96. package/src/types.ts +172 -18
@@ -60,8 +60,16 @@ export function createRemoteRegistryAgent(
60
60
 
61
61
  // --- Connection storage (KV via SecretStore) ---
62
62
 
63
- async function storeConnection(ownerId: string, conn: RegistryConnection): Promise<void> {
64
- console.error("[remote-registry] storeConnection for owner:", ownerId, "conn:", conn.id);
63
+ async function storeConnection(
64
+ ownerId: string,
65
+ conn: RegistryConnection,
66
+ ): Promise<void> {
67
+ console.error(
68
+ "[remote-registry] storeConnection for owner:",
69
+ ownerId,
70
+ "conn:",
71
+ conn.id,
72
+ );
65
73
  const all = await loadAllConnections(ownerId);
66
74
  all[conn.id] = conn;
67
75
  const value = JSON.stringify(all);
@@ -72,29 +80,49 @@ export function createRemoteRegistryAgent(
72
80
  }
73
81
  }
74
82
 
75
- async function loadAllConnections(ownerId: string): Promise<Record<string, RegistryConnection>> {
83
+ async function loadAllConnections(
84
+ ownerId: string,
85
+ ): Promise<Record<string, RegistryConnection>> {
76
86
  console.error("[remote-registry] loadAllConnections for owner:", ownerId);
77
87
  if (secretStore.resolveByEntity) {
78
88
  const scope = { tenantId: ownerId };
79
- const secretIds = await secretStore.resolveByEntity(ENTITY_TYPE, ownerId, scope);
89
+ const secretIds = await secretStore.resolveByEntity(
90
+ ENTITY_TYPE,
91
+ ownerId,
92
+ scope,
93
+ );
80
94
  if (secretIds?.length) {
81
- const raw = await secretStore.resolve(secretIds[secretIds.length - 1], ownerId);
95
+ const raw = await secretStore.resolve(
96
+ secretIds[secretIds.length - 1],
97
+ ownerId,
98
+ );
82
99
  if (raw) {
83
- try { return JSON.parse(raw); } catch { return {}; }
100
+ try {
101
+ return JSON.parse(raw);
102
+ } catch {
103
+ return {};
104
+ }
84
105
  }
85
106
  }
86
107
  }
87
108
  return {};
88
109
  }
89
110
 
90
- async function loadConnection(ownerId: string, registryId: string): Promise<RegistryConnection | null> {
111
+ async function loadConnection(
112
+ ownerId: string,
113
+ registryId: string,
114
+ ): Promise<RegistryConnection | null> {
91
115
  const all = await loadAllConnections(ownerId);
92
116
  return all[registryId] ?? null;
93
117
  }
94
118
 
95
119
  // --- MCP call helper ---
96
120
 
97
- async function mcpCall(url: string, jwt: string, request: Record<string, unknown>): Promise<any> {
121
+ async function mcpCall(
122
+ url: string,
123
+ jwt: string,
124
+ request: Record<string, unknown>,
125
+ ): Promise<any> {
98
126
  const res = await globalThis.fetch(url, {
99
127
  method: "POST",
100
128
  headers: {
@@ -108,13 +136,18 @@ export function createRemoteRegistryAgent(
108
136
  params: { name: "call_agent", arguments: { request } },
109
137
  }),
110
138
  });
111
- const rpc = await res.json() as any;
139
+ const rpc = (await res.json()) as any;
112
140
  const text = rpc.result?.content?.[0]?.text;
113
141
  if (!text) return rpc.result;
114
142
  const parsed = JSON.parse(text);
115
143
  // Unwrap the remote call_agent envelope: { success, result } → just result
116
144
  // The caller (proxyCall) will re-wrap with its own { success, result }
117
- if (parsed && typeof parsed === "object" && "success" in parsed && "result" in parsed) {
145
+ if (
146
+ parsed &&
147
+ typeof parsed === "object" &&
148
+ "success" in parsed &&
149
+ "result" in parsed
150
+ ) {
118
151
  if (!parsed.success) {
119
152
  throw new Error(parsed.error ?? "Remote call failed");
120
153
  }
@@ -128,13 +161,24 @@ export function createRemoteRegistryAgent(
128
161
  async function proxyCall(
129
162
  ownerId: string,
130
163
  registryId: string,
131
- request: { action: string; path: string; tool: string; params?: Record<string, unknown> },
164
+ request: {
165
+ action: string;
166
+ path: string;
167
+ tool: string;
168
+ params?: Record<string, unknown>;
169
+ },
132
170
  ): Promise<any> {
133
171
  const conn = await loadConnection(ownerId, registryId);
134
172
  if (!conn) {
135
- throw new Error(`No connection '${registryId}'. Use setup_integration first.`);
173
+ throw new Error(
174
+ `No connection '${registryId}'. Use setup_integration first.`,
175
+ );
136
176
  }
137
- const jwt = await signJwt({ tenantId: conn.remoteTenantId, action: "proxy", type: "agent-registry" });
177
+ const jwt = await signJwt({
178
+ tenantId: conn.remoteTenantId,
179
+ action: "proxy",
180
+ type: "agent-registry",
181
+ });
138
182
  // mcpCall already unwraps the remote call_agent envelope,
139
183
  // so this returns the remote tool's result directly.
140
184
  // registry.call() will wrap it in { success: true, result } for us.
@@ -170,7 +214,8 @@ export function createRemoteRegistryAgent(
170
214
 
171
215
  const addConnectionTool = defineTool({
172
216
  name: "add_connection",
173
- description: "Directly store a connection to a remote registry (no OAuth exchange). Used for reverse registration.",
217
+ description:
218
+ "Directly store a connection to a remote registry (no OAuth exchange). Used for reverse registration.",
174
219
  visibility: "public" as const,
175
220
  inputSchema: {
176
221
  type: "object" as const,
@@ -178,7 +223,10 @@ export function createRemoteRegistryAgent(
178
223
  id: { type: "string", description: "Connection ID" },
179
224
  name: { type: "string", description: "Display name" },
180
225
  url: { type: "string", description: "Remote registry URL" },
181
- remoteTenantId: { type: "string", description: "Tenant ID on the remote side" },
226
+ remoteTenantId: {
227
+ type: "string",
228
+ description: "Tenant ID on the remote side",
229
+ },
182
230
  },
183
231
  required: ["id", "url"],
184
232
  },
@@ -203,7 +251,7 @@ export function createRemoteRegistryAgent(
203
251
  execute: async (_input: any, _ctx: ToolContext) => {
204
252
  const all = await loadAllConnections("system");
205
253
  return {
206
- connections: Object.values(all).map(c => ({
254
+ connections: Object.values(all).map((c) => ({
207
255
  id: c.id,
208
256
  name: c.name,
209
257
  url: c.url,
@@ -213,10 +261,15 @@ export function createRemoteRegistryAgent(
213
261
  },
214
262
  });
215
263
 
216
-
217
264
  // Extract setup/connect as standalone functions to avoid circular reference
218
- const setupFn = async (params: Record<string, unknown>, _ctx: IntegrationMethodContext): Promise<IntegrationMethodResult> => {
219
- console.log("[remote-registry] setupFn called with:", JSON.stringify(params));
265
+ const setupFn = async (
266
+ params: Record<string, unknown>,
267
+ _ctx: IntegrationMethodContext,
268
+ ): Promise<IntegrationMethodResult> => {
269
+ console.log(
270
+ "[remote-registry] setupFn called with:",
271
+ JSON.stringify(params),
272
+ );
220
273
  const url = params.url as string;
221
274
  const name = (params.name as string) ?? "registry";
222
275
  const oidcUserId = params.oidcUserId as string | undefined;
@@ -226,68 +279,143 @@ export function createRemoteRegistryAgent(
226
279
 
227
280
  // Phase 2: Complete setup after OIDC — store connection with resolved tenant
228
281
  if (oidcUserId) {
229
- const jwt = await signJwt({ sub: oidcUserId, action: "setup", type: "agent-registry" });
230
- const tokenRes = await globalThis.fetch(baseUrl + "/oauth/token", {
231
- method: "POST", headers: { "Content-Type": "application/json" },
232
- body: JSON.stringify({ grant_type: "jwt_exchange", assertion: jwt, scope: "setup", redirect_uri: params.redirect_uri ?? "" }),
282
+ const jwt = await signJwt({
283
+ sub: oidcUserId,
284
+ action: "setup",
285
+ type: "agent-registry",
286
+ });
287
+ const tokenRes = await globalThis.fetch(`${baseUrl}/oauth/token`, {
288
+ method: "POST",
289
+ headers: { "Content-Type": "application/json" },
290
+ body: JSON.stringify({
291
+ grant_type: "jwt_exchange",
292
+ assertion: jwt,
293
+ scope: "setup",
294
+ redirect_uri: params.redirect_uri ?? "",
295
+ }),
233
296
  });
234
- const tokenData = await tokenRes.json() as any;
297
+ const tokenData = (await tokenRes.json()) as any;
235
298
  if (!tokenData.access_token && !tokenData.tenant_id) {
236
- return { success: false, error: tokenData.error_description ?? tokenData.error ?? "Setup completion failed" };
299
+ return {
300
+ success: false,
301
+ error:
302
+ tokenData.error_description ??
303
+ tokenData.error ??
304
+ "Setup completion failed",
305
+ };
237
306
  }
238
307
  const remoteTenantId = tokenData.tenant_id ?? name;
239
308
  const ownerId = "system";
240
- await storeConnection(ownerId, { id: name, name, url: baseUrl, remoteTenantId, createdAt: Date.now() });
241
- return { success: true, data: { registryId: name, url, remoteTenantId } };
309
+ await storeConnection(ownerId, {
310
+ id: name,
311
+ name,
312
+ url: baseUrl,
313
+ remoteTenantId,
314
+ createdAt: Date.now(),
315
+ });
316
+ return {
317
+ success: true,
318
+ data: { registryId: name, url, remoteTenantId },
319
+ };
242
320
  }
243
321
 
244
322
  // Phase 1: Discover JWKS, establish trust, then request OIDC
245
- const configUrl = baseUrl + "/.well-known/configuration";
323
+ const configUrl = `${baseUrl}/.well-known/configuration`;
246
324
  console.log("[setupFn] fetching config:", configUrl);
247
325
  const configRes = await globalThis.fetch(configUrl);
248
326
  console.log("[setupFn] config status:", configRes.status);
249
- if (!configRes.ok) return { success: false, error: "Failed to discover registry at " + configUrl };
250
- const remoteConfig = await configRes.json() as any;
327
+ if (!configRes.ok)
328
+ return {
329
+ success: false,
330
+ error: `Failed to discover registry at ${configUrl}`,
331
+ };
332
+ const remoteConfig = (await configRes.json()) as any;
251
333
  if (remoteConfig.jwks_uri) {
252
334
  console.log("[setupFn] fetching JWKS:", remoteConfig.jwks_uri);
253
335
  const jwksRes = await globalThis.fetch(remoteConfig.jwks_uri);
254
336
  console.log("[setupFn] JWKS status:", jwksRes.status);
255
337
  if (!jwksRes.ok) return { success: false, error: "JWKS not reachable" };
256
338
  }
257
- if (addTrustedIssuer) { console.log("[setupFn] adding trusted issuer:", baseUrl); await addTrustedIssuer(baseUrl); console.log("[setupFn] added trusted issuer"); }
339
+ if (addTrustedIssuer) {
340
+ console.log("[setupFn] adding trusted issuer:", baseUrl);
341
+ await addTrustedIssuer(baseUrl);
342
+ console.log("[setupFn] added trusted issuer");
343
+ }
258
344
 
259
345
  // Request identity — atlas will return authorize URL for Slack OIDC
260
346
  console.log("[setupFn] Phase 1: requesting identity via jwt_exchange");
261
- const jwt = await signJwt({ action: "setup", type: "agent-registry", targetUrl: url });
262
- console.log("[setupFn] POSTing to:", baseUrl + "/oauth/token");
263
- const tokenRes = await globalThis.fetch(baseUrl + "/oauth/token", {
264
- method: "POST", headers: { "Content-Type": "application/json" },
265
- body: JSON.stringify({ grant_type: "jwt_exchange", assertion: jwt, scope: "setup", redirect_uri: params.redirect_uri ?? "" }),
347
+ const jwt = await signJwt({
348
+ action: "setup",
349
+ type: "agent-registry",
350
+ targetUrl: url,
351
+ });
352
+ console.log("[setupFn] POSTing to:", `${baseUrl}/oauth/token`);
353
+ const tokenRes = await globalThis.fetch(`${baseUrl}/oauth/token`, {
354
+ method: "POST",
355
+ headers: { "Content-Type": "application/json" },
356
+ body: JSON.stringify({
357
+ grant_type: "jwt_exchange",
358
+ assertion: jwt,
359
+ scope: "setup",
360
+ redirect_uri: params.redirect_uri ?? "",
361
+ }),
266
362
  });
267
363
  console.log("[setupFn] token status:", tokenRes.status);
268
- const tokenData = await tokenRes.json() as any;
269
- console.log("[setupFn] tokenData:", JSON.stringify(tokenData).substring(0, 300));
364
+ const tokenData = (await tokenRes.json()) as any;
365
+ console.log(
366
+ "[setupFn] tokenData:",
367
+ JSON.stringify(tokenData).substring(0, 300),
368
+ );
270
369
 
271
370
  // If already set up (user linked), store connection directly
272
371
  if (tokenData.access_token) {
273
372
  const remoteTenantId = tokenData.tenant_id ?? name;
274
373
  const ownerId = "system";
275
- await storeConnection(ownerId, { id: name, name, url: baseUrl, remoteTenantId, createdAt: Date.now() });
276
- return { success: true, data: { registryId: name, url, remoteTenantId } };
374
+ await storeConnection(ownerId, {
375
+ id: name,
376
+ name,
377
+ url: baseUrl,
378
+ remoteTenantId,
379
+ createdAt: Date.now(),
380
+ });
381
+ return {
382
+ success: true,
383
+ data: { registryId: name, url, remoteTenantId },
384
+ };
277
385
  }
278
386
 
279
387
  // Need OIDC — return authorize URL to caller
280
388
  if (tokenData.error === "identity_required") {
281
- return { success: false, error: "identity_required", data: { authorizeUrl: tokenData.authorize_url, registryId: name, url } };
389
+ return {
390
+ success: false,
391
+ error: "identity_required",
392
+ data: {
393
+ authorizeUrl: tokenData.authorize_url,
394
+ registryId: name,
395
+ url,
396
+ },
397
+ };
282
398
  }
283
399
 
284
- return { success: false, error: tokenData.error_description ?? tokenData.error ?? "Unexpected response from token endpoint" };
400
+ return {
401
+ success: false,
402
+ error:
403
+ tokenData.error_description ??
404
+ tokenData.error ??
405
+ "Unexpected response from token endpoint",
406
+ };
285
407
  } catch (err) {
286
- return { success: false, error: err instanceof Error ? err.message : String(err) };
408
+ return {
409
+ success: false,
410
+ error: err instanceof Error ? err.message : String(err),
411
+ };
287
412
  }
288
413
  };
289
414
 
290
- const connectFn = async (params: Record<string, unknown>, ctx: IntegrationMethodContext): Promise<IntegrationMethodResult> => {
415
+ const connectFn = async (
416
+ params: Record<string, unknown>,
417
+ ctx: IntegrationMethodContext,
418
+ ): Promise<IntegrationMethodResult> => {
291
419
  const registryId = params.registryId as string;
292
420
  const redirectUri = (params.redirectUri as string) ?? "";
293
421
  const oidcUserId = params.oidcUserId as string | undefined;
@@ -295,20 +423,58 @@ export function createRemoteRegistryAgent(
295
423
  try {
296
424
  const ownerId = "system"; // tenant-scoped
297
425
  const conn = await loadConnection(ownerId, registryId);
298
- if (!conn) return { success: false, error: "No connection '" + registryId + "'" };
426
+ if (!conn)
427
+ return { success: false, error: `No connection '${registryId}'` };
299
428
  // Use OIDC-issued identity if available, never send "anonymous" as sub
300
- const sub = oidcUserId ?? (ctx.callerId !== "anonymous" ? ctx.callerId : undefined);
301
- const jwt = await signJwt({ ...(sub ? { sub } : {}), tenantId: conn.remoteTenantId, action: "connect", type: "agent-registry" });
302
- const tokenRes = await globalThis.fetch(conn.url + "/oauth/token", {
303
- method: "POST", headers: { "Content-Type": "application/json" },
304
- body: JSON.stringify({ grant_type: "jwt_exchange", assertion: jwt, redirect_uri: redirectUri }),
429
+ const sub =
430
+ oidcUserId ?? (ctx.callerId !== "anonymous" ? ctx.callerId : undefined);
431
+ const jwt = await signJwt({
432
+ ...(sub ? { sub } : {}),
433
+ tenantId: conn.remoteTenantId,
434
+ action: "connect",
435
+ type: "agent-registry",
436
+ });
437
+ const tokenRes = await globalThis.fetch(`${conn.url}/oauth/token`, {
438
+ method: "POST",
439
+ headers: { "Content-Type": "application/json" },
440
+ body: JSON.stringify({
441
+ grant_type: "jwt_exchange",
442
+ assertion: jwt,
443
+ redirect_uri: redirectUri,
444
+ }),
305
445
  });
306
- const tokenData = await tokenRes.json() as any;
307
- if (tokenData.access_token) return { success: true, data: { registryId, accessToken: tokenData.access_token, userId: tokenData.user_id, tenantId: tokenData.tenant_id } };
308
- if (tokenData.error === "identity_required") return { success: false, error: "identity_required", data: { authorizeUrl: tokenData.authorize_url, tenantId: tokenData.tenant_id } };
309
- return { success: false, error: tokenData.error_description ?? tokenData.error ?? "Token exchange failed" };
446
+ const tokenData = (await tokenRes.json()) as any;
447
+ if (tokenData.access_token)
448
+ return {
449
+ success: true,
450
+ data: {
451
+ registryId,
452
+ accessToken: tokenData.access_token,
453
+ userId: tokenData.user_id,
454
+ tenantId: tokenData.tenant_id,
455
+ },
456
+ };
457
+ if (tokenData.error === "identity_required")
458
+ return {
459
+ success: false,
460
+ error: "identity_required",
461
+ data: {
462
+ authorizeUrl: tokenData.authorize_url,
463
+ tenantId: tokenData.tenant_id,
464
+ },
465
+ };
466
+ return {
467
+ success: false,
468
+ error:
469
+ tokenData.error_description ??
470
+ tokenData.error ??
471
+ "Token exchange failed",
472
+ };
310
473
  } catch (err) {
311
- return { success: false, error: err instanceof Error ? err.message : String(err) };
474
+ return {
475
+ success: false,
476
+ error: err instanceof Error ? err.message : String(err),
477
+ };
312
478
  }
313
479
  };
314
480
 
@@ -320,7 +486,8 @@ export function createRemoteRegistryAgent(
320
486
  "and proxy_call to make authenticated calls.",
321
487
  config: {
322
488
  name: "Remote Registry",
323
- description: "Connect to remote agent registries via JWKS trust + jwt_exchange",
489
+ description:
490
+ "Connect to remote agent registries via JWKS trust + jwt_exchange",
324
491
  supportedActions: ["execute_tool", "describe_tools", "load"],
325
492
  },
326
493
  visibility: "public",
@@ -329,32 +496,62 @@ export function createRemoteRegistryAgent(
329
496
  displayName: "Agent Registry",
330
497
  icon: "server",
331
498
  category: "infrastructure",
332
- description: "Connect to a remote agent registry via JWKS trust exchange.",
499
+ description:
500
+ "Connect to a remote agent registry via JWKS trust exchange.",
333
501
  setup: (params, ctx) => setupFn(params, ctx as any),
334
502
  connect: (params, ctx) => connectFn(params, ctx as any),
335
503
  async discover(params) {
336
504
  const url = (params.url as string) ?? "";
337
505
  try {
338
- const res = await globalThis.fetch(url.replace(/\/$/, "") + "/.well-known/configuration");
339
- if (!res.ok) return { success: false, error: "No configuration endpoint at " + url };
340
- const config = await res.json() as any;
341
- return { success: true, data: { url, issuer: config.issuer, grantTypes: config.supported_grant_types, jwksUri: config.jwks_uri } };
342
- } catch (err) { return { success: false, error: err instanceof Error ? err.message : String(err) }; }
506
+ const res = await globalThis.fetch(
507
+ `${url.replace(/\/$/, "")}/.well-known/configuration`,
508
+ );
509
+ if (!res.ok)
510
+ return {
511
+ success: false,
512
+ error: `No configuration endpoint at ${url}`,
513
+ };
514
+ const config = (await res.json()) as any;
515
+ return {
516
+ success: true,
517
+ data: {
518
+ url,
519
+ issuer: config.issuer,
520
+ grantTypes: config.supported_grant_types,
521
+ jwksUri: config.jwks_uri,
522
+ },
523
+ };
524
+ } catch (err) {
525
+ return {
526
+ success: false,
527
+ error: err instanceof Error ? err.message : String(err),
528
+ };
529
+ }
343
530
  },
344
531
  async list() {
345
532
  const all = await loadAllConnections("system");
346
- return { success: true, data: { connections: Object.values(all).map(c => ({ id: c.id, name: c.name, url: c.url, remoteTenantId: c.remoteTenantId })) } };
533
+ return {
534
+ success: true,
535
+ data: {
536
+ connections: Object.values(all).map((c) => ({
537
+ id: c.id,
538
+ name: c.name,
539
+ url: c.url,
540
+ remoteTenantId: c.remoteTenantId,
541
+ })),
542
+ },
543
+ };
347
544
  },
348
545
  async get(params) {
349
546
  const id = (params.registryId as string) ?? "";
350
547
  const conn = await loadConnection("system", id);
351
- if (!conn) return { success: false, error: "No connection '" + id + "'" };
548
+ if (!conn) return { success: false, error: `No connection '${id}'` };
352
549
  return { success: true, data: conn };
353
550
  },
354
551
  async update(params) {
355
552
  const id = (params.registryId as string) ?? "";
356
553
  const conn = await loadConnection("system", id);
357
- if (!conn) return { success: false, error: "No connection '" + id + "'" };
554
+ if (!conn) return { success: false, error: `No connection '${id}'` };
358
555
  if (params.name) conn.name = params.name as string;
359
556
  if (params.url) conn.url = params.url as string;
360
557
  await storeConnection("system", conn);
@@ -34,7 +34,11 @@ export interface SecretStore {
34
34
  store(value: string, ownerId: string, scope?: SecretScope): Promise<string>;
35
35
 
36
36
  /** Resolve a secret ID to its decrypted value. */
37
- resolve(id: string, ownerId: string, scope?: SecretScope): Promise<string | null>;
37
+ resolve(
38
+ id: string,
39
+ ownerId: string,
40
+ scope?: SecretScope,
41
+ ): Promise<string | null>;
38
42
 
39
43
  /** Delete a secret. */
40
44
  delete(id: string, ownerId: string, scope?: SecretScope): Promise<boolean>;
@@ -43,19 +47,32 @@ export interface SecretStore {
43
47
  * Store multiple secrets in a single operation.
44
48
  * Returns an array of secret IDs in the same order as the input values.
45
49
  */
46
- storeBatch?(values: string[], ownerId: string, scope?: SecretScope): Promise<string[]>;
50
+ storeBatch?(
51
+ values: string[],
52
+ ownerId: string,
53
+ scope?: SecretScope,
54
+ ): Promise<string[]>;
47
55
 
48
56
  /**
49
57
  * Associate a secret with an entity (e.g., a provider config, a connection).
50
58
  * Enables lookup of secrets by entity rather than by ID.
51
59
  */
52
- associate?(secretId: string, entityType: string, entityId: string, scope?: SecretScope): Promise<void>;
60
+ associate?(
61
+ secretId: string,
62
+ entityType: string,
63
+ entityId: string,
64
+ scope?: SecretScope,
65
+ ): Promise<void>;
53
66
 
54
67
  /**
55
68
  * Resolve secrets associated with an entity.
56
69
  * Returns all secret IDs linked to the given entity.
57
70
  */
58
- resolveByEntity?(entityType: string, entityId: string, scope?: SecretScope): Promise<string[]>;
71
+ resolveByEntity?(
72
+ entityType: string,
73
+ entityId: string,
74
+ scope?: SecretScope,
75
+ ): Promise<string[]>;
59
76
  }
60
77
 
61
78
  // ============================================
@@ -218,10 +235,7 @@ export function createSecretsAgent(
218
235
  description: "Encrypted secret storage and management",
219
236
  visibility: "internal",
220
237
  },
221
- tools: [
222
- storeSecretTool,
223
- revokeSecretTool,
224
- ] as ToolDefinition<ToolContext>[],
238
+ tools: [storeSecretTool, revokeSecretTool] as ToolDefinition<ToolContext>[],
225
239
  });
226
240
  }
227
241
 
@@ -252,10 +252,17 @@ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
252
252
  metadata: { type: "object", description: "Additional metadata" },
253
253
  externalRef: {
254
254
  type: "object",
255
- description: "Link to a user on a remote system. Creates identity automatically.",
255
+ description:
256
+ "Link to a user on a remote system. Creates identity automatically.",
256
257
  properties: {
257
- issuer: { type: "string", description: "Issuer URL of the remote system" },
258
- userId: { type: "string", description: "User ID on the remote system" },
258
+ issuer: {
259
+ type: "string",
260
+ description: "Issuer URL of the remote system",
261
+ },
262
+ userId: {
263
+ type: "string",
264
+ description: "User ID on the remote system",
265
+ },
259
266
  },
260
267
  },
261
268
  },
@@ -270,7 +277,12 @@ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
270
277
  );
271
278
  if (existing) {
272
279
  const user = await store.getUser(existing.userId);
273
- return { success: true, user, identity: existing, alreadyLinked: true };
280
+ return {
281
+ success: true,
282
+ user,
283
+ identity: existing,
284
+ alreadyLinked: true,
285
+ };
274
286
  }
275
287
  }
276
288