@slashfi/agents-sdk 0.15.0 → 0.17.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 (93) 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 +9 -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 +20 -1
  55. package/dist/registry.d.ts.map +1 -1
  56. package/dist/registry.js +167 -20
  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 +27 -0
  69. package/dist/types.d.ts.map +1 -1
  70. package/package.json +1 -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/consumer.test.ts +536 -0
  77. package/src/define-config.ts +205 -0
  78. package/src/define.ts +134 -46
  79. package/src/events.ts +237 -0
  80. package/src/index.ts +90 -8
  81. package/src/integration-interface.ts +52 -28
  82. package/src/integrations-store.ts +9 -5
  83. package/src/jwt.ts +48 -19
  84. package/src/key-manager.test.ts +22 -13
  85. package/src/key-manager.ts +8 -10
  86. package/src/oidc-signin.ts +223 -0
  87. package/src/registry-consumer.ts +413 -0
  88. package/src/registry.ts +237 -29
  89. package/src/secret-collection.ts +2 -1
  90. package/src/server.test.ts +304 -238
  91. package/src/server.ts +371 -69
  92. package/src/test-utils/mock-oidc-server.ts +123 -0
  93. package/src/types.ts +80 -18
package/src/registry.ts CHANGED
@@ -4,13 +4,22 @@
4
4
  * Manages registered agents and handles callAgent requests.
5
5
  */
6
6
 
7
+ import { dirname, resolve } from "node:path";
8
+ import type {
9
+ AgentEvent,
10
+ EventCallback,
11
+ EventType,
12
+ } from "./events.js";
13
+ import { createEventBus } from "./events.js";
7
14
  import type {
8
15
  AgentAction,
9
16
  AgentDefinition,
17
+ AgentRefEntry,
10
18
  CallAgentDescribeToolsResponse,
11
19
  CallAgentErrorResponse,
12
20
  CallAgentExecuteToolResponse,
13
21
  CallAgentLearnResponse,
22
+ CallAgentLoadRequest,
14
23
  CallAgentLoadResponse,
15
24
  CallAgentRequest,
16
25
  CallAgentResponse,
@@ -31,6 +40,25 @@ const DEFAULT_SUPPORTED_ACTIONS: AgentAction[] = [
31
40
  // Agent Registry Interface
32
41
  // ============================================
33
42
 
43
+ /**
44
+ * Middleware hooks for registry lifecycle actions.
45
+ * Each hook receives the default handler fn and context,
46
+ * giving full control: call default, skip it, try/catch, or enhance.
47
+ */
48
+ export interface RegistryMiddleware {
49
+ load?: (
50
+ defaultFn: (
51
+ agent: AgentDefinition,
52
+ request: CallAgentLoadRequest,
53
+ ) => Promise<CallAgentLoadResponse>,
54
+ ctx: {
55
+ agent: AgentDefinition;
56
+ request: CallAgentLoadRequest;
57
+ registry: AgentRegistry;
58
+ },
59
+ ) => Promise<CallAgentLoadResponse>;
60
+ }
61
+
34
62
  /**
35
63
  * Options for creating an agent registry.
36
64
  */
@@ -39,6 +67,8 @@ export interface AgentRegistryOptions {
39
67
  defaultVisibility?: Visibility;
40
68
  /** Factory to enrich ToolContext with application-specific data */
41
69
  contextFactory?: ContextFactory;
70
+ /** Lifecycle middleware hooks */
71
+ middleware?: RegistryMiddleware;
42
72
  }
43
73
 
44
74
  /**
@@ -62,6 +92,12 @@ export interface AgentRegistry {
62
92
 
63
93
  /** Call an agent (execute action) */
64
94
  call(request: CallAgentRequest): Promise<CallAgentResponse>;
95
+
96
+ /** Register an event listener (global scope — fires for all agents) */
97
+ on<T extends EventType>(eventType: T, callback: EventCallback<T>): void;
98
+
99
+ /** Emit an event to all listeners. Used by the runtime to push lifecycle events. */
100
+ emit(event: AgentEvent): Promise<void>;
65
101
  }
66
102
 
67
103
  // ============================================
@@ -88,13 +124,16 @@ export interface AgentRegistry {
88
124
  * Factory function that enriches the base ToolContext with application-specific data.
89
125
  * Called before every tool execution.
90
126
  */
91
- export type ContextFactory = (baseCtx: import("./types.js").ToolContext) => import("./types.js").ToolContext;
127
+ export type ContextFactory = (
128
+ baseCtx: import("./types.js").ToolContext,
129
+ ) => import("./types.js").ToolContext;
92
130
 
93
131
  export function createAgentRegistry(
94
132
  options: AgentRegistryOptions = {},
95
133
  ): AgentRegistry {
96
134
  const { defaultVisibility = "internal" } = options;
97
135
  const agents = new Map<string, AgentDefinition>();
136
+ const eventBus = createEventBus();
98
137
 
99
138
  /**
100
139
  * Check if agent supports the requested action.
@@ -182,9 +221,143 @@ export function createAgentRegistry(
182
221
  }
183
222
  }
184
223
 
224
+ function resolveRefPath(currentPath: string, ref: string): string {
225
+ if (ref.startsWith("@") && !ref.includes("/")) {
226
+ return `/agents/${ref}`;
227
+ }
228
+ if (ref.startsWith("../") || ref.startsWith("./")) {
229
+ const dir = dirname(currentPath);
230
+ return resolve(dir, ref);
231
+ }
232
+ if (ref.startsWith("/")) {
233
+ return ref;
234
+ }
235
+ return `/agents/${ref}`;
236
+ }
237
+
238
+ function buildToolsSection(
239
+ ownTools: ToolSchema[],
240
+ agentRefs: AgentRefEntry[],
241
+ ): string {
242
+ const hasOwnTools = ownTools.length > 0;
243
+ const hasRefTools = agentRefs.some((ref) => ref.tools.length > 0);
244
+ if (!hasOwnTools && !hasRefTools) return "";
245
+
246
+ const lines: string[] = ["\n\n## Available Tools\n"];
247
+
248
+ if (hasOwnTools) {
249
+ lines.push("| Tool | Description |", "|------|-------------|");
250
+ for (const t of ownTools) {
251
+ lines.push(`| ${t.name} | ${t.description} |`);
252
+ }
253
+ lines.push("");
254
+ }
255
+
256
+ for (const ref of agentRefs) {
257
+ if (ref.tools.length > 0) {
258
+ lines.push(`### From ${ref.key} (${ref.path})\n`);
259
+ lines.push("| Tool | Description |", "|------|-------------|");
260
+ for (const t of ref.tools) {
261
+ lines.push(`| ${t.name} | ${t.description} |`);
262
+ }
263
+ lines.push("");
264
+ }
265
+ }
266
+
267
+ return lines.join("\n");
268
+ }
269
+
270
+ async function defaultLoad(
271
+ agent: AgentDefinition,
272
+ request: CallAgentLoadRequest,
273
+ ): Promise<CallAgentLoadResponse> {
274
+ const toolSchemas: ToolSchema[] = agent.tools
275
+ .filter((t: ToolDefinition) =>
276
+ checkToolAccess(agent, t.name, request.callerId, request.callerType),
277
+ )
278
+ .map((t: ToolDefinition) => ({
279
+ name: t.name,
280
+ description: t.description,
281
+ inputSchema: t.inputSchema,
282
+ ...(t.outputSchema && { outputSchema: t.outputSchema }),
283
+ }));
284
+
285
+ const agentRefs: AgentRefEntry[] = [];
286
+ const refs = agent.config?.refs;
287
+ if (refs) {
288
+ for (const [key, refConfig] of Object.entries(refs)) {
289
+ const refPath = resolveRefPath(agent.path, key);
290
+ const refAgent = agents.get(refPath);
291
+ const allTools = (refAgent?.tools ?? [])
292
+ .filter((t: ToolDefinition) =>
293
+ checkToolAccess(
294
+ refAgent!,
295
+ t.name,
296
+ request.callerId,
297
+ request.callerType,
298
+ ),
299
+ )
300
+ .map((t: ToolDefinition) => ({
301
+ name: t.name,
302
+ description: t.description,
303
+ inputSchema: t.inputSchema,
304
+ ...(t.outputSchema && { outputSchema: t.outputSchema }),
305
+ }));
306
+ const publicFilter = refAgent?.config?.public?.tools;
307
+ const tools = publicFilter
308
+ ? allTools.filter((t) => publicFilter.includes(t.name))
309
+ : allTools;
310
+ agentRefs.push({
311
+ key,
312
+ path: refPath,
313
+ description: refConfig.description ?? key,
314
+ tools,
315
+ });
316
+ }
317
+ }
318
+
319
+ const systemPrompt =
320
+ agent.entrypoint + buildToolsSection(toolSchemas, agentRefs);
321
+
322
+ return {
323
+ success: true,
324
+ result: {
325
+ path: agent.path,
326
+ entrypoint: agent.entrypoint,
327
+ systemPrompt,
328
+ contextMessages: [],
329
+ config: agent.config,
330
+ tools: toolSchemas,
331
+ agentRefs,
332
+ },
333
+ };
334
+ }
335
+
185
336
  const registry: AgentRegistry = {
186
337
  register(agent: AgentDefinition): void {
187
338
  agents.set(agent.path, agent);
339
+
340
+ // Collect agent-level listeners into the bus
341
+ if (agent._listeners) {
342
+ for (const entry of agent._listeners) {
343
+ eventBus._onScoped(entry.eventType, entry.callback, {
344
+ agentPath: agent.path,
345
+ toolName: entry.toolScope,
346
+ });
347
+ }
348
+ }
349
+
350
+ // Collect tool-level listeners into the bus
351
+ for (const tool of agent.tools) {
352
+ if (tool._listeners) {
353
+ for (const entry of tool._listeners) {
354
+ eventBus._onScoped(entry.eventType, entry.callback, {
355
+ agentPath: agent.path,
356
+ toolName: tool.name,
357
+ });
358
+ }
359
+ }
360
+ }
188
361
  },
189
362
 
190
363
  get(path: string): AgentDefinition | undefined {
@@ -203,6 +376,14 @@ export function createAgentRegistry(
203
376
  return Array.from(agents.keys());
204
377
  },
205
378
 
379
+ on<T extends EventType>(eventType: T, callback: EventCallback<T>): void {
380
+ eventBus.on(eventType, callback);
381
+ },
382
+
383
+ async emit(event: AgentEvent): Promise<void> {
384
+ await eventBus.emit(event);
385
+ },
386
+
206
387
  async call(request: CallAgentRequest): Promise<CallAgentResponse> {
207
388
  const agent = agents.get(request.path);
208
389
 
@@ -311,15 +492,59 @@ export function createAgentRegistry(
311
492
  error: `Tool ${request.tool} has no execute function`,
312
493
  } as CallAgentErrorResponse;
313
494
  }
314
- const result = await tool.execute(request.params, ctx);
495
+
496
+ // Emit tool/call before execution
497
+ const startMs = Date.now();
498
+ await eventBus.emit({
499
+ type: "tool/call",
500
+ agentPath: agent.path,
501
+ tool: request.tool!,
502
+ params: request.params,
503
+ timestamp: startMs,
504
+ });
505
+
506
+ let result: unknown;
507
+ try {
508
+ result = await tool.execute(request.params, ctx);
509
+ } catch (err) {
510
+ // Emit tool/error on failure
511
+ await eventBus.emit({
512
+ type: "tool/error",
513
+ agentPath: agent.path,
514
+ tool: request.tool!,
515
+ params: request.params,
516
+ error: err,
517
+ durationMs: Date.now() - startMs,
518
+ timestamp: Date.now(),
519
+ }).catch(() => {}); // don't let emit error mask tool error
520
+
521
+ return {
522
+ success: false,
523
+ error: err instanceof Error ? err.message : String(err),
524
+ code: "TOOL_EXECUTION_ERROR",
525
+ } as CallAgentErrorResponse;
526
+ }
527
+
528
+ // Emit tool/result after success
529
+ await eventBus.emit({
530
+ type: "tool/result",
531
+ agentPath: agent.path,
532
+ tool: request.tool!,
533
+ params: request.params,
534
+ result,
535
+ durationMs: Date.now() - startMs,
536
+ timestamp: Date.now(),
537
+ });
538
+
315
539
  return {
316
540
  success: true,
317
541
  result,
318
542
  } as CallAgentExecuteToolResponse;
319
- } catch (err) {
543
+ } catch (outerErr) {
544
+ // Catch-all for unexpected errors (e.g., emit failures)
320
545
  return {
321
546
  success: false,
322
- error: err instanceof Error ? err.message : String(err),
547
+ error: outerErr instanceof Error ? outerErr.message : String(outerErr),
323
548
  code: "TOOL_EXECUTION_ERROR",
324
549
  } as CallAgentErrorResponse;
325
550
  }
@@ -352,31 +577,14 @@ export function createAgentRegistry(
352
577
  }
353
578
 
354
579
  case "load": {
355
- const toolSchemas: ToolSchema[] = agent.tools
356
- .filter((t: ToolDefinition) =>
357
- checkToolAccess(
358
- agent,
359
- t.name,
360
- request.callerId,
361
- request.callerType,
362
- ),
363
- )
364
- .map((t: ToolDefinition) => ({
365
- name: t.name,
366
- description: t.description,
367
- inputSchema: t.inputSchema,
368
- ...(t.outputSchema && { outputSchema: t.outputSchema }),
369
- }));
370
-
371
- return {
372
- success: true,
373
- result: {
374
- path: agent.path,
375
- entrypoint: agent.entrypoint,
376
- config: agent.config,
377
- tools: toolSchemas,
378
- },
379
- } as CallAgentLoadResponse;
580
+ if (options.middleware?.load) {
581
+ return options.middleware.load(defaultLoad, {
582
+ agent,
583
+ request,
584
+ registry,
585
+ });
586
+ }
587
+ return defaultLoad(agent, request);
380
588
  }
381
589
 
382
590
  case "learn": {
@@ -44,7 +44,8 @@ export const pendingCollections = new Map<string, PendingCollection>();
44
44
 
45
45
  /** Generate a random one-time token for secret collection */
46
46
  export function generateCollectionToken(): string {
47
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
47
+ const chars =
48
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
48
49
  let token = "";
49
50
  for (let i = 0; i < 48; i++) {
50
51
  token += chars[Math.floor(Math.random() * chars.length)];