@slashfi/agents-sdk 0.77.1 → 0.77.2

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/src/adk-tools.ts CHANGED
@@ -17,10 +17,252 @@
17
17
  * ```
18
18
  */
19
19
 
20
+ import { z } from "zod";
21
+ import { AdkError } from "./adk-error.js";
22
+ import { zodToOpenAiJsonSchema } from "./call-agent-schema.js";
20
23
  import type { Adk } from "./config-store.js";
21
24
  import type { RefEntry, RegistryEntry } from "./define-config.js";
22
25
  import { defineTool } from "./define.js";
23
- import type { ToolContext, ToolDefinition } from "./types.js";
26
+ import type { JsonSchema, ToolContext, ToolDefinition } from "./types.js";
27
+
28
+ const objectRecordSchema = z.record(z.unknown());
29
+ const sourceRegistrySchema = z
30
+ .object({
31
+ url: z.string().min(1).describe("Registry MCP URL."),
32
+ agentPath: z.string().optional().describe("Agent path on that registry."),
33
+ })
34
+ .passthrough();
35
+ const refScopeSchema = z
36
+ .string()
37
+ .optional()
38
+ .describe("Config scope to operate on.");
39
+ const refNameSchema = z.string().min(1).describe("Local connection name.");
40
+
41
+ const refAddOperationSchema = z
42
+ .object({
43
+ operation: z.literal("add"),
44
+ scope: refScopeSchema,
45
+ ref: z
46
+ .string()
47
+ .min(1)
48
+ .optional()
49
+ .describe(
50
+ "Canonical agent path, e.g. 'google-calendar'. Defaults to name when omitted.",
51
+ ),
52
+ name: refNameSchema
53
+ .optional()
54
+ .describe("Local connection name. Defaults to ref when omitted."),
55
+ scheme: z
56
+ .enum(["registry", "mcp", "https"])
57
+ .optional()
58
+ .describe(
59
+ "Connection type. Usually inferred from sourceRegistry or url.",
60
+ ),
61
+ url: z
62
+ .string()
63
+ .min(1)
64
+ .optional()
65
+ .describe("Direct MCP/HTTPS URL. Required for direct mcp/https refs."),
66
+ sourceRegistry: sourceRegistrySchema
67
+ .optional()
68
+ .describe(
69
+ "Registry that serves this agent. Required for registry-backed refs.",
70
+ ),
71
+ config: objectRecordSchema
72
+ .optional()
73
+ .describe("Optional per-instance config."),
74
+ })
75
+ .passthrough()
76
+ .superRefine((input, ctx) => {
77
+ if (!input.ref && !input.name) {
78
+ ctx.addIssue({
79
+ code: z.ZodIssueCode.custom,
80
+ path: ["ref"],
81
+ message: "Either ref or name is required.",
82
+ });
83
+ }
84
+ if (input.scheme === "registry" && !input.sourceRegistry?.url) {
85
+ ctx.addIssue({
86
+ code: z.ZodIssueCode.custom,
87
+ path: ["sourceRegistry", "url"],
88
+ message: "scheme=registry requires sourceRegistry.url.",
89
+ });
90
+ }
91
+ if ((input.scheme === "mcp" || input.scheme === "https") && !input.url) {
92
+ ctx.addIssue({
93
+ code: z.ZodIssueCode.custom,
94
+ path: ["url"],
95
+ message: `scheme=${input.scheme} requires url.`,
96
+ });
97
+ }
98
+ if (!input.url && !input.sourceRegistry?.url) {
99
+ ctx.addIssue({
100
+ code: z.ZodIssueCode.custom,
101
+ path: ["sourceRegistry"],
102
+ message:
103
+ "Connection target is required: provide sourceRegistry.url for a registry ref, or url for a direct mcp/https ref.",
104
+ });
105
+ }
106
+ });
107
+
108
+ const refOperationSchemas = {
109
+ add: refAddOperationSchema,
110
+ remove: z
111
+ .object({
112
+ operation: z.literal("remove"),
113
+ scope: refScopeSchema,
114
+ name: refNameSchema,
115
+ })
116
+ .passthrough(),
117
+ list: z
118
+ .object({ operation: z.literal("list"), scope: refScopeSchema })
119
+ .passthrough(),
120
+ update: z
121
+ .object({
122
+ operation: z.literal("update"),
123
+ scope: refScopeSchema,
124
+ name: refNameSchema,
125
+ ref: z.string().optional(),
126
+ scheme: z.enum(["registry", "mcp", "https"]).optional(),
127
+ url: z.string().optional(),
128
+ sourceRegistry: sourceRegistrySchema.optional(),
129
+ config: objectRecordSchema.optional(),
130
+ })
131
+ .passthrough(),
132
+ inspect: z
133
+ .object({
134
+ operation: z.literal("inspect"),
135
+ scope: refScopeSchema,
136
+ name: refNameSchema,
137
+ full: z.boolean().optional(),
138
+ })
139
+ .passthrough(),
140
+ call: z
141
+ .object({
142
+ operation: z.literal("call"),
143
+ scope: refScopeSchema,
144
+ name: refNameSchema,
145
+ tool: z.string().min(1),
146
+ params: objectRecordSchema.optional(),
147
+ })
148
+ .passthrough(),
149
+ auth: z
150
+ .object({
151
+ operation: z.literal("auth"),
152
+ scope: refScopeSchema,
153
+ name: refNameSchema,
154
+ ref: z.string().optional(),
155
+ apiKey: z.string().optional(),
156
+ credentials: z.record(z.string()).optional(),
157
+ sourceRegistry: sourceRegistrySchema.optional(),
158
+ })
159
+ .passthrough(),
160
+ "auth-status": z
161
+ .object({
162
+ operation: z.literal("auth-status"),
163
+ scope: refScopeSchema,
164
+ name: refNameSchema,
165
+ })
166
+ .passthrough(),
167
+ "refresh-token": z
168
+ .object({
169
+ operation: z.literal("refresh-token"),
170
+ scope: refScopeSchema,
171
+ name: refNameSchema,
172
+ })
173
+ .passthrough(),
174
+ resources: z
175
+ .object({
176
+ operation: z.literal("resources"),
177
+ scope: refScopeSchema,
178
+ name: refNameSchema,
179
+ })
180
+ .passthrough(),
181
+ read: z
182
+ .object({
183
+ operation: z.literal("read"),
184
+ scope: refScopeSchema,
185
+ name: refNameSchema,
186
+ uris: z.array(z.string()),
187
+ })
188
+ .passthrough(),
189
+ } as const;
190
+
191
+ const refToolInputSchema = z.union([
192
+ refOperationSchemas.add,
193
+ refOperationSchemas.remove,
194
+ refOperationSchemas.list,
195
+ refOperationSchemas.update,
196
+ refOperationSchemas.inspect,
197
+ refOperationSchemas.call,
198
+ refOperationSchemas.auth,
199
+ refOperationSchemas["auth-status"],
200
+ refOperationSchemas["refresh-token"],
201
+ refOperationSchemas.resources,
202
+ refOperationSchemas.read,
203
+ ]);
204
+ const refToolInputJsonSchema = zodToOpenAiJsonSchema(
205
+ refToolInputSchema,
206
+ ) as JsonSchema;
207
+
208
+ function parseRefToolInput(
209
+ input: Record<string, unknown>,
210
+ ): Record<string, unknown> {
211
+ const op = typeof input.operation === "string" ? input.operation : undefined;
212
+ const schema =
213
+ op && op in refOperationSchemas
214
+ ? refOperationSchemas[op as keyof typeof refOperationSchemas]
215
+ : refToolInputSchema;
216
+ const result = schema.safeParse(input);
217
+ if (result.success) return result.data as Record<string, unknown>;
218
+
219
+ const operation = op ? `ref.${op}` : "ref";
220
+ throw new AdkError({
221
+ code: "TOOL_INPUT_INVALID",
222
+ message: `Invalid ${operation} input`,
223
+ hint: "The expected input schema is serialized in details.schema; operation-specific schema is in details.operationSchema.",
224
+ details: {
225
+ operation,
226
+ issues: result.error.issues.map((issue) => ({
227
+ path: issue.path.join("."),
228
+ message: issue.message,
229
+ })),
230
+ received: input,
231
+ schema: refToolInputJsonSchema,
232
+ ...(op &&
233
+ op in refOperationSchemas && {
234
+ operationSchema: zodToOpenAiJsonSchema(
235
+ refOperationSchemas[op as keyof typeof refOperationSchemas],
236
+ ),
237
+ }),
238
+ },
239
+ });
240
+ }
241
+
242
+ function withScopeSchema(
243
+ schema: JsonSchema,
244
+ scopeSchema: JsonSchema,
245
+ ): JsonSchema {
246
+ const clone = JSON.parse(JSON.stringify(schema)) as JsonSchema;
247
+ const visit = (value: unknown) => {
248
+ if (!value || typeof value !== "object") return;
249
+ if (Array.isArray(value)) {
250
+ for (const item of value) visit(item);
251
+ return;
252
+ }
253
+
254
+ const record = value as Record<string, unknown>;
255
+ const properties = record.properties as Record<string, unknown> | undefined;
256
+ if (properties?.scope) {
257
+ properties.scope = scopeSchema;
258
+ }
259
+ for (const child of Object.values(record)) {
260
+ visit(child);
261
+ }
262
+ };
263
+ visit(clone);
264
+ return clone;
265
+ }
24
266
 
25
267
  export interface AdkToolsHooks<TCtx extends ToolContext = ToolContext> {
26
268
  /**
@@ -68,97 +310,14 @@ export function createAdkTools<TCtx extends ToolContext = ToolContext>(
68
310
  name: "ref",
69
311
  description:
70
312
  "Manage agent refs. Operations: add, remove, list, update, inspect, call, auth, auth-status, refresh-token, resources, read. For `add`, supply `ref` (canonical agent path, e.g. 'notion') and `name` (local identifier). If `name` is omitted on add, it defaults to `ref`. For every other operation, pass `name`.",
71
- inputSchema: {
72
- type: "object" as const,
73
- properties: {
74
- operation: {
75
- type: "string",
76
- enum: [
77
- "add",
78
- "remove",
79
- "list",
80
- "update",
81
- "inspect",
82
- "call",
83
- "auth",
84
- "auth-status",
85
- "refresh-token",
86
- "resources",
87
- "read",
88
- ],
89
- },
90
- scope: scopeSchema,
91
- ref: {
92
- type: "string",
93
- description:
94
- "Canonical agent path on the remote registry (e.g. 'notion', 'linear', 'github'). Used by `add` to identify which agent definition to connect to. Other operations use `name` instead. If you call `add` with only `name` and no `ref`, `ref` defaults to `name`.",
95
- },
96
- name: {
97
- type: "string",
98
- description:
99
- "Local identifier for this ref, used by all operations to look up the entry. On `add`, defaults to `ref` when omitted.",
100
- },
101
- scheme: {
102
- type: "string",
103
- description:
104
- "Connection scheme: 'mcp' (direct MCP server), 'https' (REST proxy), or 'registry' (discovered via a registry). Auto-inferred from `url` or `sourceRegistry` when omitted.",
105
- },
106
- url: {
107
- type: "string",
108
- description:
109
- "Direct URL to the agent (e.g. https://mcp.notion.com/mcp). Required for 'mcp' and 'https' schemes.",
110
- },
111
- sourceRegistry: {
112
- type: "object",
113
- properties: {
114
- url: { type: "string" },
115
- agentPath: { type: "string" },
116
- },
117
- description:
118
- "When scheme is 'registry', the registry + agent path to resolve through.",
119
- },
120
- config: {
121
- type: "object",
122
- description:
123
- "Per-instance config passed to the agent (headers, credentials, etc.). Supports `{{secret-uri}}` templates.",
124
- },
125
- tool: {
126
- type: "string",
127
- description:
128
- "For `call` operation: the tool name on the ref to invoke.",
129
- },
130
- params: {
131
- type: "object",
132
- description: "For `call` operation: arguments to pass to the tool.",
133
- },
134
- full: {
135
- type: "boolean",
136
- description:
137
- "For `inspect` operation: include full agent definition.",
138
- },
139
- uris: {
140
- type: "array",
141
- items: { type: "string" },
142
- description: "For `read` operation: the resource URIs to read.",
143
- },
144
- apiKey: {
145
- type: "string",
146
- description: "For `auth` operation: pre-provisioned API key.",
147
- },
148
- credentials: {
149
- type: "object",
150
- description:
151
- "For `auth` operation: key-value map of credential fields (keys match field names from the auth challenge).",
152
- },
153
- },
154
- required: ["operation"],
155
- },
313
+ inputSchema: withScopeSchema(refToolInputJsonSchema, scopeSchema),
156
314
  execute: async (input: Record<string, unknown>, ctx) => {
315
+ const parsedInput = parseRefToolInput(input);
157
316
  const adk = await resolveScope(
158
- input.scope as string | undefined,
317
+ parsedInput.scope as string | undefined,
159
318
  ctx as TCtx,
160
319
  );
161
- const op = input.operation as string;
320
+ const op = parsedInput.operation as string;
162
321
 
163
322
  switch (op) {
164
323
  case "add": {
@@ -166,18 +325,24 @@ export function createAdkTools<TCtx extends ToolContext = ToolContext>(
166
325
  // other defaults to it. The stored entry always has an explicit
167
326
  // `name`, so downstream auth/callback state can distinguish the
168
327
  // canonical ref from the local connection handle.
169
- const refValue = (input.ref ?? input.name) as string | undefined;
328
+ const refValue = (parsedInput.ref ?? parsedInput.name) as
329
+ | string
330
+ | undefined;
170
331
  if (!refValue) {
171
332
  throw new Error(
172
333
  "ref.add: must supply either 'ref' (canonical agent path) or 'name' (local identifier); both may be the same string for the common single-instance case.",
173
334
  );
174
335
  }
175
- const nameValue = (input.name ?? refValue) as string;
176
- const entry: Record<string, unknown> = { ref: refValue, name: nameValue };
177
- if (input.scheme) entry.scheme = input.scheme;
178
- if (input.url) entry.url = input.url;
179
- if (input.sourceRegistry) entry.sourceRegistry = input.sourceRegistry;
180
- if (input.config) entry.config = input.config;
336
+ const nameValue = (parsedInput.name ?? refValue) as string;
337
+ const entry: Record<string, unknown> = {
338
+ ref: refValue,
339
+ name: nameValue,
340
+ };
341
+ if (parsedInput.scheme) entry.scheme = parsedInput.scheme;
342
+ if (parsedInput.url) entry.url = parsedInput.url;
343
+ if (parsedInput.sourceRegistry)
344
+ entry.sourceRegistry = parsedInput.sourceRegistry;
345
+ if (parsedInput.config) entry.config = parsedInput.config;
181
346
  const { security } = await adk.ref.add(entry as unknown as RefEntry);
182
347
  return {
183
348
  added: true,
@@ -187,25 +352,25 @@ export function createAdkTools<TCtx extends ToolContext = ToolContext>(
187
352
  };
188
353
  }
189
354
  case "remove":
190
- return { removed: await adk.ref.remove(input.name as string) };
355
+ return { removed: await adk.ref.remove(parsedInput.name as string) };
191
356
  case "list":
192
357
  return { refs: await adk.ref.list() };
193
358
  case "update":
194
359
  return {
195
360
  updated: await adk.ref.update(
196
- input.name as string,
197
- input as unknown as Partial<RefEntry>,
361
+ parsedInput.name as string,
362
+ parsedInput as unknown as Partial<RefEntry>,
198
363
  ),
199
364
  };
200
365
  case "inspect":
201
- return await adk.ref.inspect(input.name as string, {
202
- full: input.full as boolean,
366
+ return await adk.ref.inspect(parsedInput.name as string, {
367
+ full: parsedInput.full as boolean,
203
368
  });
204
369
  case "call":
205
370
  return await adk.ref.call(
206
- input.name as string,
207
- input.tool as string,
208
- input.params as Record<string, unknown>,
371
+ parsedInput.name as string,
372
+ parsedInput.tool as string,
373
+ parsedInput.params as Record<string, unknown>,
209
374
  );
210
375
  case "auth": {
211
376
  const authOpts: {
@@ -213,27 +378,31 @@ export function createAdkTools<TCtx extends ToolContext = ToolContext>(
213
378
  credentials?: Record<string, string>;
214
379
  stateContext?: Record<string, unknown>;
215
380
  } = {};
216
- if (input.apiKey) authOpts.apiKey = input.apiKey as string;
217
- if (input.credentials)
218
- authOpts.credentials = input.credentials as Record<string, string>;
381
+ if (parsedInput.apiKey)
382
+ authOpts.apiKey = parsedInput.apiKey as string;
383
+ if (parsedInput.credentials)
384
+ authOpts.credentials = parsedInput.credentials as Record<
385
+ string,
386
+ string
387
+ >;
219
388
  if (opts.hooks?.getAuthStateContext) {
220
389
  authOpts.stateContext = await opts.hooks.getAuthStateContext(
221
- input,
390
+ parsedInput,
222
391
  ctx as TCtx,
223
392
  );
224
393
  }
225
- return await adk.ref.auth(input.name as string, authOpts);
394
+ return await adk.ref.auth(parsedInput.name as string, authOpts);
226
395
  }
227
396
  case "auth-status":
228
- return await adk.ref.authStatus(input.name as string);
397
+ return await adk.ref.authStatus(parsedInput.name as string);
229
398
  case "refresh-token":
230
- return await adk.ref.refreshToken(input.name as string);
399
+ return await adk.ref.refreshToken(parsedInput.name as string);
231
400
  case "resources":
232
- return await adk.ref.resources(input.name as string);
401
+ return await adk.ref.resources(parsedInput.name as string);
233
402
  case "read":
234
403
  return await adk.ref.read(
235
- input.name as string,
236
- input.uris as string[],
404
+ parsedInput.name as string,
405
+ parsedInput.uris as string[],
237
406
  );
238
407
  default:
239
408
  throw new Error(`Unknown ref operation: ${op}`);
@@ -10,7 +10,7 @@
10
10
  import { describe, expect, test } from "bun:test";
11
11
  import { createAdkTools } from "./adk-tools";
12
12
  import type { FsStore } from "./agent-definitions/config";
13
- import { createAdk } from "./index";
13
+ import { createAdk, createAgentRegistry, defineAgent } from "./index";
14
14
  import type { ToolContext } from "./types";
15
15
 
16
16
  function createMemoryFs(): FsStore {
@@ -326,6 +326,54 @@ describe("ref tool — add operation defaults ref to name", () => {
326
326
  const raw = await fs.readFile("consumer-config.json");
327
327
  expect(raw).toBeNull();
328
328
  });
329
+
330
+ test("invalid add input returns schema details through registry call", async () => {
331
+ const fs = createMemoryFs();
332
+ const adk = createAdk(fs);
333
+ const refTool = makeRefTool(adk);
334
+ const registry = createAgentRegistry();
335
+ registry.register(
336
+ defineAgent({
337
+ path: "@config",
338
+ entrypoint: "Config agent",
339
+ tools: [refTool],
340
+ visibility: "public",
341
+ }),
342
+ );
343
+
344
+ const response = await registry.call({
345
+ action: "execute_tool",
346
+ path: "@config",
347
+ tool: "ref",
348
+ params: {
349
+ operation: "add",
350
+ ref: "google-calendar",
351
+ },
352
+ });
353
+
354
+ expect(response.success).toBe(false);
355
+ if (response.success) throw new Error("expected invalid input error");
356
+ expect(response.code).toBe("TOOL_INPUT_INVALID");
357
+ expect(response.error).toContain("Invalid ref.add input");
358
+ expect(response.details?.issues).toEqual(
359
+ expect.arrayContaining([
360
+ expect.objectContaining({
361
+ path: "sourceRegistry",
362
+ }),
363
+ ]),
364
+ );
365
+ expect(response.details?.schema).toMatchObject({
366
+ anyOf: expect.any(Array),
367
+ });
368
+ expect(response.details?.operationSchema).toMatchObject({
369
+ type: "object",
370
+ });
371
+ expect(response.hint).toContain("details.schema");
372
+ expect(response.details).not.toHaveProperty("examples");
373
+ expect(JSON.stringify(response.details?.operationSchema)).toContain(
374
+ "sourceRegistry",
375
+ );
376
+ });
329
377
  });
330
378
 
331
379
  describe("ref tool — auth state hook", () => {
package/src/registry.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { dirname, resolve } from "node:path";
8
+ import { AdkError } from "./adk-error.js";
8
9
  import type { AgentEvent, BaseEvent, CallAgentToolCallEvent, CustomEventMap, EventCallback, EventType, ListAgentsResult, ListAgentsToolCallEvent } from "./events.js";
9
10
  import { createEventBus } from "./events.js";
10
11
  import type { Logger } from "./logger.js";
@@ -39,6 +40,33 @@ const DEFAULT_SUPPORTED_ACTIONS: AgentAction[] = [
39
40
  "read_resources",
40
41
  ];
41
42
 
43
+ function adkErrorFields(
44
+ err: unknown,
45
+ ): { code: string; hint: string; details: Record<string, unknown> } | null {
46
+ if (err instanceof AdkError) {
47
+ return { code: err.code, hint: err.hint, details: err.details };
48
+ }
49
+ if (!err || typeof err !== "object") return null;
50
+ const candidate = err as {
51
+ name?: unknown;
52
+ code?: unknown;
53
+ hint?: unknown;
54
+ details?: unknown;
55
+ };
56
+ return candidate.name === "AdkError" &&
57
+ typeof candidate.code === "string" &&
58
+ typeof candidate.hint === "string" &&
59
+ !!candidate.details &&
60
+ typeof candidate.details === "object" &&
61
+ !Array.isArray(candidate.details)
62
+ ? {
63
+ code: candidate.code,
64
+ hint: candidate.hint,
65
+ details: candidate.details as Record<string, unknown>,
66
+ }
67
+ : null;
68
+ }
69
+
42
70
  /**
43
71
  * Estimate the token count for a tool schema when serialized to JSON.
44
72
  * Uses a rough heuristic: ~4 characters per token (conservative estimate
@@ -760,10 +788,15 @@ export function createAgentRegistry(
760
788
  })
761
789
  .catch(() => {}); // don't let emit error mask tool error
762
790
 
791
+ const adkErr = adkErrorFields(err);
763
792
  return {
764
793
  success: false,
765
794
  error: err instanceof Error ? err.message : String(err),
766
- code: "TOOL_EXECUTION_ERROR",
795
+ code: adkErr?.code ?? "TOOL_EXECUTION_ERROR",
796
+ ...(adkErr && {
797
+ hint: adkErr.hint,
798
+ details: adkErr.details,
799
+ }),
767
800
  } as CallAgentErrorResponse;
768
801
  }
769
802
 
@@ -784,11 +817,16 @@ export function createAgentRegistry(
784
817
  } as CallAgentExecuteToolResponse;
785
818
  } catch (outerErr) {
786
819
  // Catch-all for unexpected errors (e.g., emit failures)
820
+ const adkErr = adkErrorFields(outerErr);
787
821
  return {
788
822
  success: false,
789
823
  error:
790
824
  outerErr instanceof Error ? outerErr.message : String(outerErr),
791
- code: "TOOL_EXECUTION_ERROR",
825
+ code: adkErr?.code ?? "TOOL_EXECUTION_ERROR",
826
+ ...(adkErr && {
827
+ hint: adkErr.hint,
828
+ details: adkErr.details,
829
+ }),
792
830
  } as CallAgentErrorResponse;
793
831
  }
794
832
  }
package/src/types.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  * Defines the fundamental types for agent definitions, tools, and contexts.
5
5
  */
6
6
 
7
- import type { EventCallback, EventType } from "./events.js";
8
7
  import type { AgentAction, CallerType } from "./call-agent-schema.js";
8
+ import type { EventCallback, EventType } from "./events.js";
9
9
 
10
10
  /** Internal listener entry stored on agents/tools */
11
11
  export interface ListenerEntry {
@@ -22,7 +22,15 @@ export interface ListenerEntry {
22
22
  * JSON Schema definition for tool input parameters.
23
23
  */
24
24
  export type JsonSchema = {
25
- type: "object" | "array" | "string" | "number" | "integer" | "boolean" | "null" | string[];
25
+ type:
26
+ | "object"
27
+ | "array"
28
+ | "string"
29
+ | "number"
30
+ | "integer"
31
+ | "boolean"
32
+ | "null"
33
+ | string[];
26
34
  properties?: Record<string, JsonSchema>;
27
35
  items?: JsonSchema;
28
36
  required?: string[];
@@ -293,7 +301,7 @@ export type SecurityScheme =
293
301
  * directory-level overview (e.g., in list_agents responses).
294
302
  */
295
303
  export interface SecuritySchemeSummary {
296
- type: SecurityScheme['type'];
304
+ type: SecurityScheme["type"];
297
305
  [key: string]: unknown;
298
306
  }
299
307
 
@@ -710,7 +718,7 @@ export interface AgentDefinition<TContext extends ToolContext = ToolContext> {
710
718
  * - 'direct': registry hosts and serves this agent's tools (default)
711
719
  * - 'redirect': registry catalogs this agent but clients connect to `upstream` directly
712
720
  */
713
- mode?: 'direct' | 'redirect';
721
+ mode?: "direct" | "redirect";
714
722
 
715
723
  /**
716
724
  * Upstream URL for redirect-mode agents.
@@ -861,6 +869,8 @@ export interface CallAgentErrorResponse {
861
869
  success: false;
862
870
  error: string;
863
871
  code?: string;
872
+ hint?: string;
873
+ details?: Record<string, unknown>;
864
874
  }
865
875
 
866
876
  /** Union of all response types */
@@ -942,5 +952,10 @@ export type ServerSource =
942
952
  | string
943
953
  | { command: string; args?: string[]; env?: Record<string, string> }
944
954
  | { url: string; headers?: Record<string, string> }
945
- | { spawn: string; args?: string[]; env?: Record<string, string>; port?: number; endpoint?: string };
946
-
955
+ | {
956
+ spawn: string;
957
+ args?: string[];
958
+ env?: Record<string, string>;
959
+ port?: number;
960
+ endpoint?: string;
961
+ };