@slashfi/agents-sdk 0.34.1 → 0.36.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/README.md +2 -1
- package/dist/agent-definitions/auth.d.ts +3 -3
- package/dist/agent-definitions/auth.d.ts.map +1 -1
- package/dist/agent-definitions/auth.js +10 -4
- package/dist/agent-definitions/auth.js.map +1 -1
- package/dist/agent-definitions/config.d.ts.map +1 -1
- package/dist/agent-definitions/config.js.map +1 -1
- package/dist/agent-definitions/integrations.d.ts +12 -3
- package/dist/agent-definitions/integrations.d.ts.map +1 -1
- package/dist/agent-definitions/integrations.js +35 -16
- package/dist/agent-definitions/integrations.js.map +1 -1
- package/dist/agent-definitions/remote-registry.d.ts.map +1 -1
- package/dist/agent-definitions/remote-registry.js +17 -22
- package/dist/agent-definitions/remote-registry.js.map +1 -1
- package/dist/agent-definitions/users.d.ts.map +1 -1
- package/dist/agent-definitions/users.js.map +1 -1
- package/dist/auth-governance.js.map +1 -1
- package/dist/call-agent-schema.d.ts.map +1 -1
- package/dist/call-agent-schema.js +1 -2
- package/dist/call-agent-schema.js.map +1 -1
- package/dist/cjs/agent-definitions/auth.js +10 -4
- package/dist/cjs/agent-definitions/auth.js.map +1 -1
- package/dist/cjs/agent-definitions/config.js.map +1 -1
- package/dist/cjs/agent-definitions/integrations.js +35 -16
- package/dist/cjs/agent-definitions/integrations.js.map +1 -1
- package/dist/cjs/agent-definitions/remote-registry.js +17 -22
- package/dist/cjs/agent-definitions/remote-registry.js.map +1 -1
- package/dist/cjs/agent-definitions/users.js.map +1 -1
- package/dist/cjs/auth-governance.js.map +1 -1
- package/dist/cjs/call-agent-schema.js +1 -2
- package/dist/cjs/call-agent-schema.js.map +1 -1
- package/dist/cjs/define.js.map +1 -1
- package/dist/cjs/events.js.map +1 -1
- package/dist/cjs/index.js +6 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/key-manager.js.map +1 -1
- package/dist/cjs/registry-consumer.js +60 -15
- package/dist/cjs/registry-consumer.js.map +1 -1
- package/dist/cjs/registry.js +61 -11
- package/dist/cjs/registry.js.map +1 -1
- package/dist/cjs/server.js +143 -192
- package/dist/cjs/server.js.map +1 -1
- package/dist/cjs/types.js +13 -0
- package/dist/cjs/types.js.map +1 -1
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js.map +1 -1
- package/dist/events.d.ts +85 -9
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/key-manager.d.ts.map +1 -1
- package/dist/key-manager.js +1 -1
- package/dist/key-manager.js.map +1 -1
- package/dist/registry-consumer.d.ts +8 -8
- package/dist/registry-consumer.d.ts.map +1 -1
- package/dist/registry-consumer.js +60 -15
- package/dist/registry-consumer.js.map +1 -1
- package/dist/registry.d.ts +16 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +61 -11
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +136 -185
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +10 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/agent-definitions/auth.ts +31 -14
- package/src/agent-definitions/config.ts +4 -4
- package/src/agent-definitions/integrations.ts +119 -63
- package/src/agent-definitions/remote-registry.ts +65 -38
- package/src/agent-definitions/users.ts +36 -3
- package/src/auth-governance.ts +2 -2
- package/src/call-agent-schema.test.ts +4 -1
- package/src/call-agent-schema.ts +4 -3
- package/src/consumer.test.ts +4 -1
- package/src/define.ts +18 -12
- package/src/events.ts +83 -9
- package/src/hooks.test.ts +439 -0
- package/src/index.ts +14 -1
- package/src/key-manager.ts +9 -2
- package/src/registry-consumer.ts +85 -24
- package/src/registry.ts +88 -13
- package/src/server.ts +215 -239
- package/src/types.ts +62 -0
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
import { defineAgent, defineTool } from "../define.js";
|
|
28
28
|
import type {
|
|
29
29
|
AgentDefinition,
|
|
30
|
-
IntegrationMethodContext,
|
|
31
30
|
IntegrationMethodResult,
|
|
32
31
|
ToolContext,
|
|
32
|
+
ToolDefinition,
|
|
33
33
|
} from "../types.js";
|
|
34
34
|
import type { SecretStore } from "./secrets.js";
|
|
35
35
|
|
|
@@ -53,6 +53,39 @@ interface RegistryConnection {
|
|
|
53
53
|
|
|
54
54
|
const ENTITY_TYPE = "remote-registry-connections";
|
|
55
55
|
|
|
56
|
+
/** JSON-RPC response for MCP `tools/call` over HTTP. */
|
|
57
|
+
interface McpToolsCallRpcBody {
|
|
58
|
+
result?: {
|
|
59
|
+
content?: Array<{ type: string; text?: string }>;
|
|
60
|
+
};
|
|
61
|
+
error?: { message: string };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface ProxyCallToolInput {
|
|
65
|
+
registryId: string;
|
|
66
|
+
action: string;
|
|
67
|
+
path: string;
|
|
68
|
+
tool: string;
|
|
69
|
+
params?: Record<string, unknown>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface AddConnectionToolInput {
|
|
73
|
+
id: string;
|
|
74
|
+
name?: string;
|
|
75
|
+
url: string;
|
|
76
|
+
remoteTenantId?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Typical fields from POST /oauth/token JSON body. */
|
|
80
|
+
interface OAuthTokenJsonBody {
|
|
81
|
+
access_token?: string;
|
|
82
|
+
tenant_id?: string;
|
|
83
|
+
user_id?: string;
|
|
84
|
+
error?: string;
|
|
85
|
+
error_description?: string;
|
|
86
|
+
authorize_url?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
56
89
|
export function createRemoteRegistryAgent(
|
|
57
90
|
options: RemoteRegistryAgentOptions,
|
|
58
91
|
): AgentDefinition {
|
|
@@ -122,7 +155,7 @@ export function createRemoteRegistryAgent(
|
|
|
122
155
|
url: string,
|
|
123
156
|
jwt: string,
|
|
124
157
|
request: Record<string, unknown>,
|
|
125
|
-
): Promise<
|
|
158
|
+
): Promise<unknown> {
|
|
126
159
|
const res = await globalThis.fetch(url, {
|
|
127
160
|
method: "POST",
|
|
128
161
|
headers: {
|
|
@@ -136,7 +169,7 @@ export function createRemoteRegistryAgent(
|
|
|
136
169
|
params: { name: "call_agent", arguments: { request } },
|
|
137
170
|
}),
|
|
138
171
|
});
|
|
139
|
-
const rpc = (await res.json()) as
|
|
172
|
+
const rpc = (await res.json()) as McpToolsCallRpcBody;
|
|
140
173
|
const text = rpc.result?.content?.[0]?.text;
|
|
141
174
|
if (!text) return rpc.result;
|
|
142
175
|
const parsed = JSON.parse(text);
|
|
@@ -167,7 +200,7 @@ export function createRemoteRegistryAgent(
|
|
|
167
200
|
tool: string;
|
|
168
201
|
params?: Record<string, unknown>;
|
|
169
202
|
},
|
|
170
|
-
): Promise<
|
|
203
|
+
): Promise<unknown> {
|
|
171
204
|
const conn = await loadConnection(ownerId, registryId);
|
|
172
205
|
if (!conn) {
|
|
173
206
|
throw new Error(
|
|
@@ -202,7 +235,7 @@ export function createRemoteRegistryAgent(
|
|
|
202
235
|
},
|
|
203
236
|
required: ["registryId", "action", "path", "tool"],
|
|
204
237
|
},
|
|
205
|
-
execute: async (input:
|
|
238
|
+
execute: async (input: ProxyCallToolInput, _ctx: ToolContext) => {
|
|
206
239
|
return proxyCall("system", input.registryId, {
|
|
207
240
|
action: input.action,
|
|
208
241
|
path: input.path,
|
|
@@ -230,7 +263,7 @@ export function createRemoteRegistryAgent(
|
|
|
230
263
|
},
|
|
231
264
|
required: ["id", "url"],
|
|
232
265
|
},
|
|
233
|
-
execute: async (input:
|
|
266
|
+
execute: async (input: AddConnectionToolInput, _ctx: ToolContext) => {
|
|
234
267
|
const conn: RegistryConnection = {
|
|
235
268
|
id: input.id,
|
|
236
269
|
name: input.name ?? input.id,
|
|
@@ -248,7 +281,7 @@ export function createRemoteRegistryAgent(
|
|
|
248
281
|
description: "List all connected remote registries.",
|
|
249
282
|
visibility: "public" as const,
|
|
250
283
|
inputSchema: { type: "object" as const, properties: {} },
|
|
251
|
-
execute: async (_input:
|
|
284
|
+
execute: async (_input: Record<string, unknown>, _ctx: ToolContext) => {
|
|
252
285
|
const all = await loadAllConnections("system");
|
|
253
286
|
return {
|
|
254
287
|
connections: Object.values(all).map((c) => ({
|
|
@@ -264,7 +297,7 @@ export function createRemoteRegistryAgent(
|
|
|
264
297
|
// Extract setup/connect as standalone functions to avoid circular reference
|
|
265
298
|
const setupFn = async (
|
|
266
299
|
params: Record<string, unknown>,
|
|
267
|
-
_ctx:
|
|
300
|
+
_ctx: ToolContext,
|
|
268
301
|
): Promise<IntegrationMethodResult> => {
|
|
269
302
|
console.log(
|
|
270
303
|
"[remote-registry] setupFn called with:",
|
|
@@ -294,7 +327,7 @@ export function createRemoteRegistryAgent(
|
|
|
294
327
|
redirect_uri: params.redirect_uri ?? "",
|
|
295
328
|
}),
|
|
296
329
|
});
|
|
297
|
-
const tokenData = (await tokenRes.json()) as
|
|
330
|
+
const tokenData = (await tokenRes.json()) as OAuthTokenJsonBody;
|
|
298
331
|
if (!tokenData.access_token && !tokenData.tenant_id) {
|
|
299
332
|
return {
|
|
300
333
|
success: false,
|
|
@@ -319,23 +352,16 @@ export function createRemoteRegistryAgent(
|
|
|
319
352
|
};
|
|
320
353
|
}
|
|
321
354
|
|
|
322
|
-
// Phase 1:
|
|
323
|
-
const
|
|
324
|
-
console.log("[setupFn] fetching
|
|
325
|
-
const
|
|
326
|
-
console.log("[setupFn]
|
|
327
|
-
if (!
|
|
355
|
+
// Phase 1: Verify JWKS at origin, establish trust, then request OIDC
|
|
356
|
+
const jwksUri = `${new URL(baseUrl).origin}/.well-known/jwks.json`;
|
|
357
|
+
console.log("[setupFn] fetching JWKS:", jwksUri);
|
|
358
|
+
const jwksRes = await globalThis.fetch(jwksUri);
|
|
359
|
+
console.log("[setupFn] JWKS status:", jwksRes.status);
|
|
360
|
+
if (!jwksRes.ok)
|
|
328
361
|
return {
|
|
329
362
|
success: false,
|
|
330
|
-
error: `
|
|
363
|
+
error: `JWKS not reachable at ${jwksUri}`,
|
|
331
364
|
};
|
|
332
|
-
const remoteConfig = (await configRes.json()) as any;
|
|
333
|
-
if (remoteConfig.jwks_uri) {
|
|
334
|
-
console.log("[setupFn] fetching JWKS:", remoteConfig.jwks_uri);
|
|
335
|
-
const jwksRes = await globalThis.fetch(remoteConfig.jwks_uri);
|
|
336
|
-
console.log("[setupFn] JWKS status:", jwksRes.status);
|
|
337
|
-
if (!jwksRes.ok) return { success: false, error: "JWKS not reachable" };
|
|
338
|
-
}
|
|
339
365
|
if (addTrustedIssuer) {
|
|
340
366
|
console.log("[setupFn] adding trusted issuer:", baseUrl);
|
|
341
367
|
await addTrustedIssuer(baseUrl);
|
|
@@ -361,7 +387,7 @@ export function createRemoteRegistryAgent(
|
|
|
361
387
|
}),
|
|
362
388
|
});
|
|
363
389
|
console.log("[setupFn] token status:", tokenRes.status);
|
|
364
|
-
const tokenData = (await tokenRes.json()) as
|
|
390
|
+
const tokenData = (await tokenRes.json()) as OAuthTokenJsonBody;
|
|
365
391
|
console.log(
|
|
366
392
|
"[setupFn] tokenData:",
|
|
367
393
|
JSON.stringify(tokenData).substring(0, 300),
|
|
@@ -414,7 +440,7 @@ export function createRemoteRegistryAgent(
|
|
|
414
440
|
|
|
415
441
|
const connectFn = async (
|
|
416
442
|
params: Record<string, unknown>,
|
|
417
|
-
ctx:
|
|
443
|
+
ctx: ToolContext,
|
|
418
444
|
): Promise<IntegrationMethodResult> => {
|
|
419
445
|
const registryId = params.registryId as string;
|
|
420
446
|
const redirectUri = (params.redirectUri as string) ?? "";
|
|
@@ -443,7 +469,7 @@ export function createRemoteRegistryAgent(
|
|
|
443
469
|
redirect_uri: redirectUri,
|
|
444
470
|
}),
|
|
445
471
|
});
|
|
446
|
-
const tokenData = (await tokenRes.json()) as
|
|
472
|
+
const tokenData = (await tokenRes.json()) as OAuthTokenJsonBody;
|
|
447
473
|
if (tokenData.access_token)
|
|
448
474
|
return {
|
|
449
475
|
success: true,
|
|
@@ -498,27 +524,28 @@ export function createRemoteRegistryAgent(
|
|
|
498
524
|
category: "infrastructure",
|
|
499
525
|
description:
|
|
500
526
|
"Connect to a remote agent registry via JWKS trust exchange.",
|
|
501
|
-
setup: (params, ctx) => setupFn(params, ctx
|
|
502
|
-
connect: (params, ctx) => connectFn(params, ctx
|
|
527
|
+
setup: (params, ctx) => setupFn(params, ctx),
|
|
528
|
+
connect: (params, ctx) => connectFn(params, ctx),
|
|
503
529
|
async discover(params) {
|
|
504
530
|
const url = (params.url as string) ?? "";
|
|
505
531
|
try {
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
532
|
+
const base = url.replace(/\/$/, "");
|
|
533
|
+
const origin = new URL(base).origin;
|
|
534
|
+
const jwksUri = `${origin}/.well-known/jwks.json`;
|
|
535
|
+
const res = await globalThis.fetch(jwksUri);
|
|
536
|
+
if (!res.ok) {
|
|
510
537
|
return {
|
|
511
538
|
success: false,
|
|
512
|
-
error: `
|
|
539
|
+
error: `JWKS not reachable at ${jwksUri}`,
|
|
513
540
|
};
|
|
514
|
-
|
|
541
|
+
}
|
|
515
542
|
return {
|
|
516
543
|
success: true,
|
|
517
544
|
data: {
|
|
518
545
|
url,
|
|
519
|
-
issuer:
|
|
520
|
-
grantTypes:
|
|
521
|
-
jwksUri
|
|
546
|
+
issuer: origin,
|
|
547
|
+
grantTypes: ["client_credentials", "jwt_exchange"],
|
|
548
|
+
jwksUri,
|
|
522
549
|
},
|
|
523
550
|
};
|
|
524
551
|
} catch (err) {
|
|
@@ -558,6 +585,6 @@ export function createRemoteRegistryAgent(
|
|
|
558
585
|
return { success: true, data: conn };
|
|
559
586
|
},
|
|
560
587
|
},
|
|
561
|
-
tools: [proxyTool, listTool, addConnectionTool] as
|
|
588
|
+
tools: [proxyTool, listTool, addConnectionTool] as ToolDefinition<ToolContext>[],
|
|
562
589
|
});
|
|
563
590
|
}
|
|
@@ -230,6 +230,39 @@ export interface UsersAgentOptions {
|
|
|
230
230
|
store: UserStore;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
interface CreateUserToolInput {
|
|
234
|
+
id?: string;
|
|
235
|
+
tenantId: string;
|
|
236
|
+
email?: string;
|
|
237
|
+
name?: string;
|
|
238
|
+
avatarUrl?: string;
|
|
239
|
+
metadata?: Record<string, unknown>;
|
|
240
|
+
externalRef?: { issuer: string; userId: string };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
interface UpdateUserToolInput {
|
|
244
|
+
userId: string;
|
|
245
|
+
email?: string;
|
|
246
|
+
name?: string;
|
|
247
|
+
avatarUrl?: string;
|
|
248
|
+
metadata?: Record<string, unknown>;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
interface LinkIdentityToolInput {
|
|
252
|
+
userId: string;
|
|
253
|
+
provider: string;
|
|
254
|
+
providerUserId: string;
|
|
255
|
+
email?: string;
|
|
256
|
+
name?: string;
|
|
257
|
+
avatarUrl?: string;
|
|
258
|
+
accessToken?: string;
|
|
259
|
+
refreshToken?: string;
|
|
260
|
+
expiresAt?: number;
|
|
261
|
+
tokenType?: string;
|
|
262
|
+
scopes?: string[];
|
|
263
|
+
metadata?: Record<string, unknown>;
|
|
264
|
+
}
|
|
265
|
+
|
|
233
266
|
export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
|
|
234
267
|
const { store } = options;
|
|
235
268
|
|
|
@@ -268,7 +301,7 @@ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
|
|
|
268
301
|
},
|
|
269
302
|
required: ["tenantId"],
|
|
270
303
|
},
|
|
271
|
-
execute: async (input:
|
|
304
|
+
execute: async (input: CreateUserToolInput, __ctx: ToolContext) => {
|
|
272
305
|
// If externalRef provided, check if identity already exists
|
|
273
306
|
if (input.externalRef) {
|
|
274
307
|
const existing = await store.findIdentityByProviderUserId(
|
|
@@ -365,7 +398,7 @@ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
|
|
|
365
398
|
},
|
|
366
399
|
required: ["userId"],
|
|
367
400
|
},
|
|
368
|
-
execute: async (input:
|
|
401
|
+
execute: async (input: UpdateUserToolInput, __ctx: ToolContext) => {
|
|
369
402
|
const { userId, ...updates } = input;
|
|
370
403
|
const user = await store.updateUser(userId, updates);
|
|
371
404
|
if (!user) return { error: `User '${userId}' not found` };
|
|
@@ -416,7 +449,7 @@ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
|
|
|
416
449
|
},
|
|
417
450
|
required: ["userId", "provider", "providerUserId"],
|
|
418
451
|
},
|
|
419
|
-
execute: async (input:
|
|
452
|
+
execute: async (input: LinkIdentityToolInput, __ctx: ToolContext) => {
|
|
420
453
|
// Check if identity already exists
|
|
421
454
|
const existing = await store.getIdentityByProvider(
|
|
422
455
|
input.userId,
|
package/src/auth-governance.ts
CHANGED
|
@@ -39,7 +39,7 @@ export function canSeeAgent(
|
|
|
39
39
|
agent: AgentDefinition,
|
|
40
40
|
auth: ResolvedAuth | null,
|
|
41
41
|
): boolean {
|
|
42
|
-
const visibility = (
|
|
42
|
+
const visibility = (agent.visibility ??
|
|
43
43
|
agent.config?.visibility ??
|
|
44
44
|
"internal") as Visibility;
|
|
45
45
|
if (hasAdminScope(auth)) return true;
|
|
@@ -87,7 +87,7 @@ export function getVisibleTools(
|
|
|
87
87
|
agent: AgentDefinition,
|
|
88
88
|
auth: ResolvedAuth | null,
|
|
89
89
|
): typeof agent.tools {
|
|
90
|
-
const agentVisibility = (
|
|
90
|
+
const agentVisibility = (agent.visibility ??
|
|
91
91
|
agent.config?.visibility ??
|
|
92
92
|
"internal") as Visibility;
|
|
93
93
|
return agent.tools.filter((t) => canSeeTool(t, auth, agentVisibility));
|
|
@@ -293,7 +293,10 @@ describe("zodToOpenAiJsonSchema", () => {
|
|
|
293
293
|
required: z.string(),
|
|
294
294
|
optional: z.string().optional(),
|
|
295
295
|
});
|
|
296
|
-
const jsonSchema = zodToOpenAiJsonSchema(schema) as
|
|
296
|
+
const jsonSchema = zodToOpenAiJsonSchema(schema) as Record<
|
|
297
|
+
string,
|
|
298
|
+
unknown
|
|
299
|
+
>;
|
|
297
300
|
|
|
298
301
|
// Required field should be in required array
|
|
299
302
|
expect(jsonSchema.required).toContain("required");
|
package/src/call-agent-schema.ts
CHANGED
|
@@ -101,8 +101,7 @@ function normalizeJsonSchema(schema: Record<string, unknown>): Record<string, un
|
|
|
101
101
|
export function zodToOpenAiJsonSchema(
|
|
102
102
|
schema: ZodTypeAny,
|
|
103
103
|
): Record<string, unknown> {
|
|
104
|
-
|
|
105
|
-
const raw = zodToJsonSchema(schema as any, { target: "openAi" }) as Record<
|
|
104
|
+
const raw = zodToJsonSchema(schema, { target: "openAi" }) as Record<
|
|
106
105
|
string,
|
|
107
106
|
unknown
|
|
108
107
|
>;
|
|
@@ -170,7 +169,9 @@ export const describeToolsActionSchema = callAgentBaseSchema.extend({
|
|
|
170
169
|
tools: z
|
|
171
170
|
.array(z.string())
|
|
172
171
|
.optional()
|
|
173
|
-
.describe(
|
|
172
|
+
.describe(
|
|
173
|
+
"Optional filter: specific tool names. Use undefined / omit for all tools; do not use [] (empty array is not 'all tools').",
|
|
174
|
+
),
|
|
174
175
|
});
|
|
175
176
|
|
|
176
177
|
/** Load: get agent definition */
|
package/src/consumer.test.ts
CHANGED
|
@@ -70,7 +70,7 @@ describe("Registry Consumer E2E", () => {
|
|
|
70
70
|
await server.stop();
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
test("discover registry via
|
|
73
|
+
test("discover registry via MCP initialize", async () => {
|
|
74
74
|
const config = {
|
|
75
75
|
registries: [`http://localhost:${PORT}`],
|
|
76
76
|
};
|
|
@@ -80,6 +80,9 @@ describe("Registry Consumer E2E", () => {
|
|
|
80
80
|
|
|
81
81
|
expect(discovery).toBeDefined();
|
|
82
82
|
expect(discovery.issuer).toBeDefined();
|
|
83
|
+
expect(discovery.token_endpoint).toBe(
|
|
84
|
+
`http://localhost:${PORT}/oauth/token`,
|
|
85
|
+
);
|
|
83
86
|
});
|
|
84
87
|
|
|
85
88
|
test("list agents from registry", async () => {
|
package/src/define.ts
CHANGED
|
@@ -240,8 +240,9 @@ export function defineAgent<TContext extends ToolContext = ToolContext>(
|
|
|
240
240
|
config: { type: "object" },
|
|
241
241
|
},
|
|
242
242
|
},
|
|
243
|
-
execute: (input:
|
|
244
|
-
|
|
243
|
+
execute: (input: Record<string, unknown>, ctx: ToolContext) =>
|
|
244
|
+
fn(input, ctx),
|
|
245
|
+
}) as ToolDefinition<ToolContext>,
|
|
245
246
|
);
|
|
246
247
|
}
|
|
247
248
|
if (h.connect) {
|
|
@@ -260,8 +261,9 @@ export function defineAgent<TContext extends ToolContext = ToolContext>(
|
|
|
260
261
|
},
|
|
261
262
|
required: ["registryId"] as const,
|
|
262
263
|
},
|
|
263
|
-
execute: (input:
|
|
264
|
-
|
|
264
|
+
execute: (input: Record<string, unknown>, ctx: ToolContext) =>
|
|
265
|
+
fn(input, ctx),
|
|
266
|
+
}) as ToolDefinition<ToolContext>,
|
|
265
267
|
);
|
|
266
268
|
}
|
|
267
269
|
if (h.discover) {
|
|
@@ -275,8 +277,9 @@ export function defineAgent<TContext extends ToolContext = ToolContext>(
|
|
|
275
277
|
type: "object" as const,
|
|
276
278
|
properties: { url: { type: "string" } },
|
|
277
279
|
},
|
|
278
|
-
execute: (input:
|
|
279
|
-
|
|
280
|
+
execute: (input: Record<string, unknown>, ctx: ToolContext) =>
|
|
281
|
+
fn(input, ctx),
|
|
282
|
+
}) as ToolDefinition<ToolContext>,
|
|
280
283
|
);
|
|
281
284
|
}
|
|
282
285
|
if (h.list) {
|
|
@@ -287,8 +290,9 @@ export function defineAgent<TContext extends ToolContext = ToolContext>(
|
|
|
287
290
|
description: `List connected ${h.displayName} instances.`,
|
|
288
291
|
visibility: "public" as const,
|
|
289
292
|
inputSchema: { type: "object" as const, properties: {} },
|
|
290
|
-
execute: (input:
|
|
291
|
-
|
|
293
|
+
execute: (input: Record<string, unknown>, ctx: ToolContext) =>
|
|
294
|
+
fn(input, ctx),
|
|
295
|
+
}) as ToolDefinition<ToolContext>,
|
|
292
296
|
);
|
|
293
297
|
}
|
|
294
298
|
if (h.get) {
|
|
@@ -303,8 +307,9 @@ export function defineAgent<TContext extends ToolContext = ToolContext>(
|
|
|
303
307
|
properties: { registryId: { type: "string" } },
|
|
304
308
|
required: ["registryId"] as const,
|
|
305
309
|
},
|
|
306
|
-
execute: (input:
|
|
307
|
-
|
|
310
|
+
execute: (input: Record<string, unknown>, ctx: ToolContext) =>
|
|
311
|
+
fn(input, ctx),
|
|
312
|
+
}) as ToolDefinition<ToolContext>,
|
|
308
313
|
);
|
|
309
314
|
}
|
|
310
315
|
if (h.update) {
|
|
@@ -323,8 +328,9 @@ export function defineAgent<TContext extends ToolContext = ToolContext>(
|
|
|
323
328
|
},
|
|
324
329
|
required: ["registryId"] as const,
|
|
325
330
|
},
|
|
326
|
-
execute: (input:
|
|
327
|
-
|
|
331
|
+
execute: (input: Record<string, unknown>, ctx: ToolContext) =>
|
|
332
|
+
fn(input, ctx),
|
|
333
|
+
}) as ToolDefinition<ToolContext>,
|
|
328
334
|
);
|
|
329
335
|
}
|
|
330
336
|
}
|
package/src/events.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Filtering happens in the callback, not the API.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type { CallAgentRequest, CallAgentResponse } from "./types.js";
|
|
13
|
+
import type { AgentDefinition, CallAgentRequest, CallAgentResponse } from "./types.js";
|
|
14
14
|
// =============================================================================
|
|
15
15
|
// Event Types
|
|
16
16
|
// =============================================================================
|
|
@@ -24,7 +24,8 @@ export type SystemEventType =
|
|
|
24
24
|
| "tool/error"
|
|
25
25
|
| "step"
|
|
26
26
|
| "invoke"
|
|
27
|
-
| "call"
|
|
27
|
+
| "tools/call/call_agent"
|
|
28
|
+
| "tools/call/list_agents";
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Augmentable map for custom event types. Consumers extend this
|
|
@@ -124,12 +125,28 @@ export interface InvokeEvent extends BaseEvent {
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
/**
|
|
127
|
-
* Event emitted when
|
|
128
|
-
*
|
|
129
|
-
*
|
|
128
|
+
* Event emitted when the `call_agent` MCP tool is invoked.
|
|
129
|
+
* Replaces the legacy `call` event with a namespaced type.
|
|
130
|
+
*
|
|
131
|
+
* Call `next()` to run the default call handler (optionally with a modified request).
|
|
132
|
+
* Call `resolve(response)` to short-circuit with a custom response.
|
|
133
|
+
* If neither is called, the default handler runs.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* registry.on('tools/call/call_agent', async (event) => {
|
|
138
|
+
* // Proxy to a remote registry
|
|
139
|
+
* if (isRemoteAgent(event.request.path)) {
|
|
140
|
+
* const result = await proxyToRemote(event.request);
|
|
141
|
+
* event.resolve(result);
|
|
142
|
+
* return;
|
|
143
|
+
* }
|
|
144
|
+
* // Fall through to default handler
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
130
147
|
*/
|
|
131
|
-
export interface
|
|
132
|
-
type: "call";
|
|
148
|
+
export interface CallAgentToolCallEvent extends BaseEvent {
|
|
149
|
+
type: "tools/call/call_agent";
|
|
133
150
|
/** The incoming call_agent request */
|
|
134
151
|
request: CallAgentRequest;
|
|
135
152
|
/** Run the default call handler and return its result.
|
|
@@ -139,6 +156,61 @@ export interface CallEvent extends BaseEvent {
|
|
|
139
156
|
resolve(response: CallAgentResponse): void;
|
|
140
157
|
}
|
|
141
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Result shape for list_agents responses.
|
|
161
|
+
*/
|
|
162
|
+
export interface ListAgentsResult {
|
|
163
|
+
success: true;
|
|
164
|
+
total: number;
|
|
165
|
+
nextCursor?: string;
|
|
166
|
+
agents: Array<{
|
|
167
|
+
path: string;
|
|
168
|
+
name?: string;
|
|
169
|
+
description?: string;
|
|
170
|
+
supportedActions?: string[];
|
|
171
|
+
integration?: unknown;
|
|
172
|
+
security?: { type: string };
|
|
173
|
+
resources?: Array<{ uri: string; name?: string; mimeType?: string }>;
|
|
174
|
+
tools: string[];
|
|
175
|
+
}>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Event emitted when the `list_agents` MCP tool is invoked.
|
|
180
|
+
*
|
|
181
|
+
* Gives hosts a chance to inject additional agents (e.g., from remote registries
|
|
182
|
+
* or consumer config) before BM25 search and pagination run.
|
|
183
|
+
*
|
|
184
|
+
* Call `next(additionalAgents?)` to continue default behavior with optional
|
|
185
|
+
* extra agents merged into the base set.
|
|
186
|
+
* Call `resolve(result)` to short-circuit with a fully formed response.
|
|
187
|
+
* If neither is called, the default handler runs with the base agents.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* registry.on('tools/call/list_agents', async (event) => {
|
|
192
|
+
* const remoteAgents = await fetchRemoteAgents();
|
|
193
|
+
* await event.next(remoteAgents);
|
|
194
|
+
* });
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
export interface ListAgentsToolCallEvent extends BaseEvent {
|
|
198
|
+
type: "tools/call/list_agents";
|
|
199
|
+
/** Agents from the local registry (before search/pagination) */
|
|
200
|
+
baseAgents: AgentDefinition[];
|
|
201
|
+
/** Search query, if provided */
|
|
202
|
+
query?: string;
|
|
203
|
+
/** Requested page size */
|
|
204
|
+
limit?: number;
|
|
205
|
+
/** Pagination cursor */
|
|
206
|
+
cursor?: string;
|
|
207
|
+
/** Continue with default BM25/pagination behavior.
|
|
208
|
+
* Pass additional agents to merge into the base set. */
|
|
209
|
+
next(additionalAgents?: AgentDefinition[]): Promise<ListAgentsResult>;
|
|
210
|
+
/** Short-circuit with a complete response (same shape as list_agents output) */
|
|
211
|
+
resolve(result: ListAgentsResult): void;
|
|
212
|
+
}
|
|
213
|
+
|
|
142
214
|
/**
|
|
143
215
|
* Union of all built-in event types.
|
|
144
216
|
*/
|
|
@@ -148,7 +220,8 @@ export type AgentEvent =
|
|
|
148
220
|
| ToolErrorEvent
|
|
149
221
|
| StepEvent
|
|
150
222
|
| InvokeEvent
|
|
151
|
-
|
|
|
223
|
+
| CallAgentToolCallEvent
|
|
224
|
+
| ListAgentsToolCallEvent;
|
|
152
225
|
|
|
153
226
|
/**
|
|
154
227
|
* Map from system event type string to event interface.
|
|
@@ -159,7 +232,8 @@ export interface SystemEventMap {
|
|
|
159
232
|
"tool/error": ToolErrorEvent;
|
|
160
233
|
step: StepEvent;
|
|
161
234
|
invoke: InvokeEvent;
|
|
162
|
-
call:
|
|
235
|
+
"tools/call/call_agent": CallAgentToolCallEvent;
|
|
236
|
+
"tools/call/list_agents": ListAgentsToolCallEvent;
|
|
163
237
|
}
|
|
164
238
|
|
|
165
239
|
/**
|