@slashfi/agents-sdk 0.73.0 → 0.74.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.
@@ -25,11 +25,18 @@
25
25
  // ============================================
26
26
  // Helpers
27
27
  // ============================================
28
- /** Normalize a ref entry to its full form */
28
+ /**
29
+ * Normalize a ref entry to its full form.
30
+ *
31
+ * Local identifier resolution order: `entry.name` → `entry.as` (legacy)
32
+ * → `entry.ref` (canonical). This order makes the tool/API surface
33
+ * consistent with the `ref.add({ ref, name })` contract while still
34
+ * reading old `{ ref, as }` entries from pre-0.74 consumer-config.json.
35
+ */
29
36
  export function normalizeRef(entry) {
30
37
  return {
31
38
  ...entry,
32
- name: entry.as ?? entry.ref,
39
+ name: entry.name ?? entry.as ?? entry.ref,
33
40
  config: entry.config ?? {},
34
41
  };
35
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"define-config.js","sourceRoot":"","sources":["../src/define-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAuJH,+CAA+C;AAC/C,UAAU;AACV,+CAA+C;AAE/C,6CAA6C;AAC7C,MAAM,UAAU,YAAY,CAAC,KAAe;IAC1C,OAAO;QACL,GAAG,KAAK;QACR,IAAI,EAAE,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,GAAG;QAC3B,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;KAC3B,CAAC;AACJ,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,iBAAiB,CAC/B,KAA6B;IAE7B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO;YACL,GAAG,EAAE,KAAK;YACV,IAAI,EAAE,GAAG,CAAC,QAAQ;YAClB,SAAS,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;SACvB,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,GAAG,CAAC,QAAQ;QAChC,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACxD,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;QACpC,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;KACjD,CAAC;AACJ,CAAC;AAED,mCAAmC;AACnC,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAE5D,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC"}
1
+ {"version":3,"file":"define-config.js","sourceRoot":"","sources":["../src/define-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAqKH,+CAA+C;AAC/C,UAAU;AACV,+CAA+C;AAE/C;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAe;IAC1C,OAAO;QACL,GAAG,KAAK;QACR,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,GAAG;QACzC,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;KAC3B,CAAC;AACJ,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,iBAAiB,CAC/B,KAA6B;IAE7B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO;YACL,GAAG,EAAE,KAAK;YACV,IAAI,EAAE,GAAG,CAAC,QAAQ;YAClB,SAAS,EAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;SACvB,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,GAAG,CAAC,QAAQ;QAChC,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACxD,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;QACpC,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;KACjD,CAAC;AACJ,CAAC;AAED,mCAAmC;AACnC,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAE5D,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC"}
@@ -16,13 +16,13 @@ export declare const SerializedToolSchema: z.ZodObject<{
16
16
  inputSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
17
17
  outputSchema: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>;
18
18
  }, "strip", z.ZodTypeAny, {
19
- name: string;
20
19
  description: string;
20
+ name: string;
21
21
  inputSchema: Record<string, unknown>;
22
22
  outputSchema?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
23
23
  }, {
24
- name: string;
25
24
  description: string;
25
+ name: string;
26
26
  inputSchema?: Record<string, unknown> | undefined;
27
27
  outputSchema?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
28
28
  }>;
@@ -50,13 +50,13 @@ export declare const SerializedAgentDefinitionSchema: z.ZodObject<{
50
50
  inputSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
51
51
  outputSchema: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>;
52
52
  }, "strip", z.ZodTypeAny, {
53
- name: string;
54
53
  description: string;
54
+ name: string;
55
55
  inputSchema: Record<string, unknown>;
56
56
  outputSchema?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
57
57
  }, {
58
- name: string;
59
58
  description: string;
59
+ name: string;
60
60
  inputSchema?: Record<string, unknown> | undefined;
61
61
  outputSchema?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
62
62
  }>, "many">;
@@ -86,13 +86,13 @@ export declare const SerializedAgentDefinitionSchema: z.ZodObject<{
86
86
  inputSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
87
87
  outputSchema: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>;
88
88
  }, "strip", z.ZodTypeAny, {
89
- name: string;
90
89
  description: string;
90
+ name: string;
91
91
  inputSchema: Record<string, unknown>;
92
92
  outputSchema?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
93
93
  }, {
94
- name: string;
95
94
  description: string;
95
+ name: string;
96
96
  inputSchema?: Record<string, unknown> | undefined;
97
97
  outputSchema?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
98
98
  }>, "many">;
@@ -122,13 +122,13 @@ export declare const SerializedAgentDefinitionSchema: z.ZodObject<{
122
122
  inputSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
123
123
  outputSchema: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>;
124
124
  }, "strip", z.ZodTypeAny, {
125
- name: string;
126
125
  description: string;
126
+ name: string;
127
127
  inputSchema: Record<string, unknown>;
128
128
  outputSchema?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
129
129
  }, {
130
- name: string;
131
130
  description: string;
131
+ name: string;
132
132
  inputSchema?: Record<string, unknown> | undefined;
133
133
  outputSchema?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
134
134
  }>, "many">;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slashfi/agents-sdk",
3
- "version": "0.73.0",
3
+ "version": "0.74.0",
4
4
  "author": "Slash Financial",
5
5
  "repository": {
6
6
  "type": "git",
package/src/adk-tools.ts CHANGED
@@ -17,10 +17,10 @@
17
17
  * ```
18
18
  */
19
19
 
20
- import { defineTool } from "./define.js";
21
- import type { ToolDefinition, ToolContext } from "./types.js";
22
20
  import type { Adk } from "./config-store.js";
23
21
  import type { RefEntry, RegistryEntry } from "./define-config.js";
22
+ import { defineTool } from "./define.js";
23
+ import type { ToolContext, ToolDefinition } from "./types.js";
24
24
 
25
25
  export interface AdkToolsHooks<TCtx extends ToolContext = ToolContext> {
26
26
  /**
@@ -33,7 +33,9 @@ export interface AdkToolsHooks<TCtx extends ToolContext = ToolContext> {
33
33
  * getAuthStateContext: async (ctx) => ({ tid: ctx.tenantId, uid: ctx.userId })
34
34
  * ```
35
35
  */
36
- getAuthStateContext?: (ctx: TCtx) => Record<string, unknown> | Promise<Record<string, unknown>>;
36
+ getAuthStateContext?: (
37
+ ctx: TCtx,
38
+ ) => Record<string, unknown> | Promise<Record<string, unknown>>;
37
39
  }
38
40
 
39
41
  export interface CreateAdkToolsOptions<TCtx extends ToolContext = ToolContext> {
@@ -48,72 +50,184 @@ export interface CreateAdkToolsOptions<TCtx extends ToolContext = ToolContext> {
48
50
  hooks?: AdkToolsHooks<TCtx>;
49
51
  }
50
52
 
51
- export function createAdkTools<TCtx extends ToolContext = ToolContext>(opts: CreateAdkToolsOptions<TCtx>): ToolDefinition<TCtx>[] {
53
+ export function createAdkTools<TCtx extends ToolContext = ToolContext>(
54
+ opts: CreateAdkToolsOptions<TCtx>,
55
+ ): ToolDefinition<TCtx>[] {
52
56
  const { resolveScope, scopes } = opts;
53
57
 
54
58
  const scopeSchema = scopes
55
- ? { type: "string" as const, enum: scopes, description: "Config scope to operate on" }
59
+ ? {
60
+ type: "string" as const,
61
+ enum: scopes,
62
+ description: "Config scope to operate on",
63
+ }
56
64
  : { type: "string" as const, description: "Config scope (optional)" };
57
65
 
58
66
  const refTool = defineTool({
59
67
  name: "ref",
60
68
  description:
61
- "Manage agent refs. Operations: add, remove, list, update, inspect, call, auth, auth-status, refresh-token, resources, read.",
69
+ "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 optionally `name` for a local alias; either one uniquely identifies the ref. For every other operation, pass `name` (the local identifier you used on add — defaults to `ref` when you didn't set it explicitly).",
62
70
  inputSchema: {
63
71
  type: "object" as const,
64
72
  properties: {
65
73
  operation: {
66
74
  type: "string",
67
- enum: ["add", "remove", "list", "update", "inspect", "call", "auth", "auth-status", "refresh-token", "resources", "read"],
75
+ enum: [
76
+ "add",
77
+ "remove",
78
+ "list",
79
+ "update",
80
+ "inspect",
81
+ "call",
82
+ "auth",
83
+ "auth-status",
84
+ "refresh-token",
85
+ "resources",
86
+ "read",
87
+ ],
68
88
  },
69
89
  scope: scopeSchema,
70
- ref: { type: "string" },
71
- name: { type: "string" },
72
- scheme: { type: "string" },
73
- url: { type: "string" },
74
- as: { type: "string" },
75
- sourceRegistry: { type: "object", properties: { url: { type: "string" }, agentPath: { type: "string" } } },
76
- config: { type: "object" },
77
- tool: { type: "string" },
78
- params: { type: "object" },
79
- full: { type: "boolean" },
80
- uris: { type: "array", items: { type: "string" } },
81
- apiKey: { type: "string" },
82
- credentials: { type: "object", description: "Key-value map of credential fields (keys match field names from auth challenge)" },
90
+ ref: {
91
+ type: "string",
92
+ description:
93
+ "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`.",
94
+ },
95
+ name: {
96
+ type: "string",
97
+ description:
98
+ "Local identifier for this ref, used by all operations except `add` to look up the entry. On `add`, `name` is optional — it only needs to differ from `ref` when you want multiple local instances of the same agent (e.g. `{ ref: 'notion', name: 'work-notion' }`). Omit it and the ref is identified by its canonical path.",
99
+ },
100
+ scheme: {
101
+ type: "string",
102
+ description:
103
+ "Connection scheme: 'mcp' (direct MCP server), 'https' (REST proxy), or 'registry' (discovered via a registry). Auto-inferred from `url` or `sourceRegistry` when omitted.",
104
+ },
105
+ url: {
106
+ type: "string",
107
+ description:
108
+ "Direct URL to the agent (e.g. https://mcp.notion.com/mcp). Required for 'mcp' and 'https' schemes.",
109
+ },
110
+ sourceRegistry: {
111
+ type: "object",
112
+ properties: {
113
+ url: { type: "string" },
114
+ agentPath: { type: "string" },
115
+ },
116
+ description:
117
+ "When scheme is 'registry', the registry + agent path to resolve through.",
118
+ },
119
+ config: {
120
+ type: "object",
121
+ description:
122
+ "Per-instance config passed to the agent (headers, credentials, etc.). Supports `{{secret-uri}}` templates.",
123
+ },
124
+ tool: {
125
+ type: "string",
126
+ description:
127
+ "For `call` operation: the tool name on the ref to invoke.",
128
+ },
129
+ params: {
130
+ type: "object",
131
+ description: "For `call` operation: arguments to pass to the tool.",
132
+ },
133
+ full: {
134
+ type: "boolean",
135
+ description:
136
+ "For `inspect` operation: include full agent definition.",
137
+ },
138
+ uris: {
139
+ type: "array",
140
+ items: { type: "string" },
141
+ description: "For `read` operation: the resource URIs to read.",
142
+ },
143
+ apiKey: {
144
+ type: "string",
145
+ description: "For `auth` operation: pre-provisioned API key.",
146
+ },
147
+ credentials: {
148
+ type: "object",
149
+ description:
150
+ "For `auth` operation: key-value map of credential fields (keys match field names from the auth challenge).",
151
+ },
83
152
  },
84
153
  required: ["operation"],
85
154
  },
86
155
  execute: async (input: Record<string, unknown>, ctx) => {
87
- const adk = await resolveScope(input.scope as string | undefined, ctx as TCtx);
156
+ const adk = await resolveScope(
157
+ input.scope as string | undefined,
158
+ ctx as TCtx,
159
+ );
88
160
  const op = input.operation as string;
89
161
 
90
162
  switch (op) {
91
163
  case "add": {
92
- const entry: Record<string, unknown> = { ref: input.ref };
164
+ // Accept `ref` or `name` (or both). If only one is given, the
165
+ // other defaults to it. This matches the "Add a ref called X"
166
+ // natural-language phrasing — LLMs that pick `name` get the
167
+ // same behavior as ones that pick `ref`, eliminating
168
+ // non-determinism on the identifier field. Throws when both
169
+ // are missing, so misuse is loud instead of silently storing
170
+ // `{ ref: undefined }`.
171
+ const refValue = (input.ref ?? input.name) as string | undefined;
172
+ if (!refValue) {
173
+ throw new Error(
174
+ "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.",
175
+ );
176
+ }
177
+ const entry: Record<string, unknown> = { ref: refValue };
93
178
  if (input.scheme) entry.scheme = input.scheme;
94
179
  if (input.url) entry.url = input.url;
95
- if (input.as) entry.as = input.as;
180
+ // Only store `name` when it's meaningfully different from
181
+ // `ref` (the multi-instance aliasing case). Avoids a
182
+ // redundant `{ name: 'notion', ref: 'notion' }` stored shape.
183
+ const nameValue = input.name as string | undefined;
184
+ if (nameValue && nameValue !== refValue) {
185
+ entry.name = nameValue;
186
+ }
96
187
  if (input.sourceRegistry) entry.sourceRegistry = input.sourceRegistry;
97
188
  if (input.config) entry.config = input.config;
98
189
  const { security } = await adk.ref.add(entry as unknown as RefEntry);
99
- return { added: true, ref: input.ref, name: (input.as ?? input.ref) as string, security };
190
+ return {
191
+ added: true,
192
+ ref: refValue,
193
+ name: (entry.name ?? refValue) as string,
194
+ security,
195
+ };
100
196
  }
101
197
  case "remove":
102
198
  return { removed: await adk.ref.remove(input.name as string) };
103
199
  case "list":
104
200
  return { refs: await adk.ref.list() };
105
201
  case "update":
106
- return { updated: await adk.ref.update(input.name as string, input as unknown as Partial<RefEntry>) };
202
+ return {
203
+ updated: await adk.ref.update(
204
+ input.name as string,
205
+ input as unknown as Partial<RefEntry>,
206
+ ),
207
+ };
107
208
  case "inspect":
108
- return await adk.ref.inspect(input.name as string, { full: input.full as boolean });
209
+ return await adk.ref.inspect(input.name as string, {
210
+ full: input.full as boolean,
211
+ });
109
212
  case "call":
110
- return await adk.ref.call(input.name as string, input.tool as string, input.params as Record<string, unknown>);
213
+ return await adk.ref.call(
214
+ input.name as string,
215
+ input.tool as string,
216
+ input.params as Record<string, unknown>,
217
+ );
111
218
  case "auth": {
112
- const authOpts: { apiKey?: string; credentials?: Record<string, string>; stateContext?: Record<string, unknown> } = {};
219
+ const authOpts: {
220
+ apiKey?: string;
221
+ credentials?: Record<string, string>;
222
+ stateContext?: Record<string, unknown>;
223
+ } = {};
113
224
  if (input.apiKey) authOpts.apiKey = input.apiKey as string;
114
- if (input.credentials) authOpts.credentials = input.credentials as Record<string, string>;
225
+ if (input.credentials)
226
+ authOpts.credentials = input.credentials as Record<string, string>;
115
227
  if (opts.hooks?.getAuthStateContext) {
116
- authOpts.stateContext = await opts.hooks.getAuthStateContext(ctx as TCtx);
228
+ authOpts.stateContext = await opts.hooks.getAuthStateContext(
229
+ ctx as TCtx,
230
+ );
117
231
  }
118
232
  return await adk.ref.auth(input.name as string, authOpts);
119
233
  }
@@ -124,7 +238,10 @@ export function createAdkTools<TCtx extends ToolContext = ToolContext>(opts: Cre
124
238
  case "resources":
125
239
  return await adk.ref.resources(input.name as string);
126
240
  case "read":
127
- return await adk.ref.read(input.name as string, input.uris as string[]);
241
+ return await adk.ref.read(
242
+ input.name as string,
243
+ input.uris as string[],
244
+ );
128
245
  default:
129
246
  throw new Error(`Unknown ref operation: ${op}`);
130
247
  }
@@ -140,7 +257,15 @@ export function createAdkTools<TCtx extends ToolContext = ToolContext>(opts: Cre
140
257
  properties: {
141
258
  operation: {
142
259
  type: "string",
143
- enum: ["add", "remove", "list", "update", "browse", "inspect", "test"],
260
+ enum: [
261
+ "add",
262
+ "remove",
263
+ "list",
264
+ "update",
265
+ "browse",
266
+ "inspect",
267
+ "test",
268
+ ],
144
269
  },
145
270
  scope: scopeSchema,
146
271
  url: { type: "string" },
@@ -152,12 +277,18 @@ export function createAdkTools<TCtx extends ToolContext = ToolContext>(opts: Cre
152
277
  required: ["operation"],
153
278
  },
154
279
  execute: async (input: Record<string, unknown>, ctx) => {
155
- const adk = await resolveScope(input.scope as string | undefined, ctx as TCtx);
280
+ const adk = await resolveScope(
281
+ input.scope as string | undefined,
282
+ ctx as TCtx,
283
+ );
156
284
  const op = input.operation as string;
157
285
 
158
286
  switch (op) {
159
287
  case "add": {
160
- const entry: Record<string, unknown> = { url: input.url, name: input.name };
288
+ const entry: Record<string, unknown> = {
289
+ url: input.url,
290
+ name: input.name,
291
+ };
161
292
  if (input.auth) entry.auth = input.auth;
162
293
  if (input.headers) entry.headers = input.headers;
163
294
  await adk.registry.add(entry as unknown as RegistryEntry);
@@ -173,10 +304,20 @@ export function createAdkTools<TCtx extends ToolContext = ToolContext>(opts: Cre
173
304
  if (input.name !== undefined) updates.name = input.name;
174
305
  if (input.auth) updates.auth = input.auth;
175
306
  if (input.headers) updates.headers = input.headers;
176
- return { updated: await adk.registry.update(input.name as string, updates as unknown as Partial<RegistryEntry>) };
307
+ return {
308
+ updated: await adk.registry.update(
309
+ input.name as string,
310
+ updates as unknown as Partial<RegistryEntry>,
311
+ ),
312
+ };
177
313
  }
178
314
  case "browse":
179
- return { agents: await adk.registry.browse(input.name as string, input.query as string) };
315
+ return {
316
+ agents: await adk.registry.browse(
317
+ input.name as string,
318
+ input.query as string,
319
+ ),
320
+ };
180
321
  case "inspect":
181
322
  return await adk.registry.inspect(input.name as string);
182
323
  case "test":
@@ -976,7 +976,15 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
976
976
  found = true;
977
977
  const updated = { ...r };
978
978
  if (updates.url) updated.url = updates.url;
979
- if (updates.as) updated.as = updates.as;
979
+ // Rename: prefer `name`, fall back to legacy `as`. When the
980
+ // caller passes `name`, clear the legacy `as` so the stored
981
+ // entry has one source of truth.
982
+ if (updates.name !== undefined) {
983
+ updated.name = updates.name;
984
+ if (updated.as !== undefined) updated.as = undefined;
985
+ } else if (updates.as !== undefined) {
986
+ updated.as = updates.as;
987
+ }
980
988
  if (updates.scheme) updated.scheme = updates.scheme;
981
989
  if (updates.config) updated.config = { ...updated.config, ...updates.config };
982
990
  if (updates.sourceRegistry) updated.sourceRegistry = updates.sourceRegistry;
@@ -64,16 +64,30 @@ export type RefConfig = Record<string, unknown>;
64
64
 
65
65
  /** A ref entry — describes how to connect to an agent */
66
66
  export type RefEntry = {
67
- /** Agent definition path (resolved from registries) */
67
+ /** Canonical agent path on the remote registry (e.g. `notion`, `linear`). */
68
68
  ref: string;
69
69
 
70
+ /**
71
+ * Local identifier for this ref. Used by all operations
72
+ * (call/remove/auth/update/…) to look up the entry. If omitted,
73
+ * the canonical `ref` string is used as the identifier — the
74
+ * common case "one local instance per agent" requires only
75
+ * `{ ref: 'notion', ... }`. Set `name` to a different value only
76
+ * when you need multiple local instances of the same remote
77
+ * agent (e.g. `{ ref: 'notion', name: 'work-notion' }`).
78
+ */
79
+ name?: string;
80
+
70
81
  /** Connection scheme */
71
82
  scheme?: 'mcp' | 'https' | 'registry';
72
83
 
73
84
  /** Direct URL to the agent (e.g. https://mcp.notion.com/mcp) */
74
85
  url?: string;
75
86
 
76
- /** Local alias for this instance (required for multi-instance) */
87
+ /**
88
+ * @deprecated Use `name` instead. `as` is preserved for reading
89
+ * old consumer-config.json files; new writes emit `name`.
90
+ */
77
91
  as?: string;
78
92
 
79
93
  /** Per-instance config (headers, secrets, etc. — values support {{secret-uri}} templates) */
@@ -176,11 +190,18 @@ export interface ResolvedConfig {
176
190
  // Helpers
177
191
  // ============================================
178
192
 
179
- /** Normalize a ref entry to its full form */
193
+ /**
194
+ * Normalize a ref entry to its full form.
195
+ *
196
+ * Local identifier resolution order: `entry.name` → `entry.as` (legacy)
197
+ * → `entry.ref` (canonical). This order makes the tool/API surface
198
+ * consistent with the `ref.add({ ref, name })` contract while still
199
+ * reading old `{ ref, as }` entries from pre-0.74 consumer-config.json.
200
+ */
180
201
  export function normalizeRef(entry: RefEntry): ResolvedRef {
181
202
  return {
182
203
  ...entry,
183
- name: entry.as ?? entry.ref,
204
+ name: entry.name ?? entry.as ?? entry.ref,
184
205
  config: entry.config ?? {},
185
206
  };
186
207
  }