@slashfi/agents-sdk 0.72.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.
Files changed (89) hide show
  1. package/dist/adk-tools.d.ts +1 -1
  2. package/dist/adk-tools.d.ts.map +1 -1
  3. package/dist/adk-tools.js +122 -26
  4. package/dist/adk-tools.js.map +1 -1
  5. package/dist/adk.js +5 -9
  6. package/dist/adk.js.map +1 -1
  7. package/dist/agent-definitions/remote-registry.d.ts +15 -0
  8. package/dist/agent-definitions/remote-registry.d.ts.map +1 -1
  9. package/dist/agent-definitions/remote-registry.js +42 -17
  10. package/dist/agent-definitions/remote-registry.js.map +1 -1
  11. package/dist/cjs/adk-tools.js +122 -26
  12. package/dist/cjs/adk-tools.js.map +1 -1
  13. package/dist/cjs/agent-definitions/remote-registry.js +42 -17
  14. package/dist/cjs/agent-definitions/remote-registry.js.map +1 -1
  15. package/dist/cjs/config-store.js +135 -9
  16. package/dist/cjs/config-store.js.map +1 -1
  17. package/dist/cjs/define-config.js +9 -2
  18. package/dist/cjs/define-config.js.map +1 -1
  19. package/dist/cjs/events.js +11 -3
  20. package/dist/cjs/events.js.map +1 -1
  21. package/dist/cjs/fetch-types.js +3 -0
  22. package/dist/cjs/fetch-types.js.map +1 -0
  23. package/dist/cjs/index.js +8 -2
  24. package/dist/cjs/index.js.map +1 -1
  25. package/dist/cjs/key-manager.js +7 -1
  26. package/dist/cjs/key-manager.js.map +1 -1
  27. package/dist/cjs/logger.js +115 -0
  28. package/dist/cjs/logger.js.map +1 -0
  29. package/dist/cjs/registry-consumer.js.map +1 -1
  30. package/dist/cjs/registry.js +1 -1
  31. package/dist/cjs/registry.js.map +1 -1
  32. package/dist/cjs/server.js +70 -13
  33. package/dist/cjs/server.js.map +1 -1
  34. package/dist/config-store.d.ts +19 -0
  35. package/dist/config-store.d.ts.map +1 -1
  36. package/dist/config-store.js +135 -9
  37. package/dist/config-store.js.map +1 -1
  38. package/dist/define-config.d.ts +23 -3
  39. package/dist/define-config.d.ts.map +1 -1
  40. package/dist/define-config.js +9 -2
  41. package/dist/define-config.js.map +1 -1
  42. package/dist/events.d.ts +6 -1
  43. package/dist/events.d.ts.map +1 -1
  44. package/dist/events.js +11 -3
  45. package/dist/events.js.map +1 -1
  46. package/dist/fetch-types.d.ts +11 -0
  47. package/dist/fetch-types.d.ts.map +1 -0
  48. package/dist/fetch-types.js +2 -0
  49. package/dist/fetch-types.js.map +1 -0
  50. package/dist/index.d.ts +4 -1
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +2 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/key-manager.d.ts +6 -0
  55. package/dist/key-manager.d.ts.map +1 -1
  56. package/dist/key-manager.js +7 -1
  57. package/dist/key-manager.js.map +1 -1
  58. package/dist/logger.d.ts +42 -0
  59. package/dist/logger.d.ts.map +1 -0
  60. package/dist/logger.js +109 -0
  61. package/dist/logger.js.map +1 -0
  62. package/dist/registry-consumer.d.ts +8 -2
  63. package/dist/registry-consumer.d.ts.map +1 -1
  64. package/dist/registry-consumer.js.map +1 -1
  65. package/dist/registry.d.ts +6 -0
  66. package/dist/registry.d.ts.map +1 -1
  67. package/dist/registry.js +1 -1
  68. package/dist/registry.js.map +1 -1
  69. package/dist/server.d.ts +7 -0
  70. package/dist/server.d.ts.map +1 -1
  71. package/dist/server.js +70 -13
  72. package/dist/server.js.map +1 -1
  73. package/dist/validate.d.ts +8 -8
  74. package/package.json +1 -1
  75. package/src/adk-tools.ts +177 -36
  76. package/src/adk.ts +5 -10
  77. package/src/agent-definitions/remote-registry.ts +56 -28
  78. package/src/config-store.ts +177 -10
  79. package/src/define-config.ts +25 -4
  80. package/src/events.ts +16 -6
  81. package/src/fetch-types.ts +13 -0
  82. package/src/index.ts +13 -0
  83. package/src/key-manager.ts +12 -1
  84. package/src/logger.test.ts +206 -0
  85. package/src/logger.ts +123 -0
  86. package/src/ref-naming.test.ts +351 -0
  87. package/src/registry-consumer.ts +13 -7
  88. package/src/registry.ts +7 -2
  89. package/src/server.ts +76 -42
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":
package/src/adk.ts CHANGED
@@ -75,7 +75,7 @@ const HELP_SECTIONS: Record<string, string> = {
75
75
  adk ref call <name> <tool> [params_json]
76
76
  adk ref resources <name>
77
77
  adk ref read <name> <uri> [uri...]
78
- adk ref auth <name> [--api-key <key>]
78
+ adk ref auth <name> [--api-key <key>] [--<field> <value> ...]
79
79
  adk ref auth-status <name>
80
80
 
81
81
  Examples:
@@ -125,7 +125,7 @@ Ref operations:
125
125
  adk ref call <name> <tool> [params_json]
126
126
  adk ref resources <name>
127
127
  adk ref read <name> <uri> [uri...]
128
- adk ref auth <name> [--api-key <key>]
128
+ adk ref auth <name> [--api-key <key>] [--<field> <value> ...]
129
129
  adk ref auth-status <name>
130
130
 
131
131
  Init targets (presets):
@@ -463,19 +463,14 @@ async function runRef() {
463
463
  break;
464
464
  }
465
465
 
466
- if (status.security?.type === "apiKey" || status.security?.type === "http") {
467
- console.error(`Provide a key: adk ref auth ${name} --api-key <your-key>`);
468
- process.exit(1);
469
- }
470
-
471
- // OAuth — run locally with browser open
466
+ // authLocal handles both OAuth (browser redirect) and apiKey/http (local credential form)
472
467
  try {
473
468
  const result = await adk.ref.authLocal(name, {
474
469
  onAuthorizeUrl: (url) => {
475
- console.log(`\nOpen this URL to authorize:\n\n ${url}\n`);
470
+ console.log(`\nOpen this URL to authenticate:\n\n ${url}\n`);
476
471
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
477
472
  import("node:child_process").then(({ exec }) => exec(`${opener} "${url}"`)).catch(() => {});
478
- console.log("Waiting for callback ...");
473
+ console.log("Waiting ...");
479
474
  },
480
475
  });
481
476
  if (result.complete) {
@@ -25,6 +25,8 @@
25
25
  */
26
26
 
27
27
  import { defineAgent, defineTool } from "../define.js";
28
+ import type { FetchFn } from "../fetch-types.js";
29
+ import { getDefaultLogger, type Logger } from "../logger.js";
28
30
  import type {
29
31
  AgentDefinition,
30
32
  IntegrationMethodResult,
@@ -40,6 +42,19 @@ export interface RemoteRegistryAgentOptions {
40
42
  signJwt: (claims: Record<string, unknown>) => Promise<string>;
41
43
  /** Add a trusted JWKS issuer (optional — for bidirectional trust) */
42
44
  addTrustedIssuer?: (issuerUrl: string) => Promise<void>;
45
+ /**
46
+ * Structured logger for connection-store traces and setup flow. Defaults
47
+ * to the module-level default logger. Traces are emitted at debug level.
48
+ */
49
+ logger?: Logger;
50
+ /**
51
+ * Custom fetch implementation for outbound JWKS / oauth/token / MCP calls
52
+ * to remote registries. Defaults to `globalThis.fetch`. Hosts in
53
+ * long-running processes should pass a hardened fetch (e.g. one backed
54
+ * by undici.Agent with short timeouts, keepalive, and retry) to avoid
55
+ * dead-socket hangs on rolling deploys.
56
+ */
57
+ fetch?: FetchFn;
43
58
  }
44
59
 
45
60
  /** Stored connection to a remote registry */
@@ -90,6 +105,8 @@ export function createRemoteRegistryAgent(
90
105
  options: RemoteRegistryAgentOptions,
91
106
  ): AgentDefinition {
92
107
  const { secretStore, signJwt, addTrustedIssuer } = options;
108
+ const logger = options.logger ?? getDefaultLogger();
109
+ const fetchFn: FetchFn = options.fetch ?? globalThis.fetch;
93
110
 
94
111
  // --- Connection storage (KV via SecretStore) ---
95
112
 
@@ -97,12 +114,11 @@ export function createRemoteRegistryAgent(
97
114
  ownerId: string,
98
115
  conn: RegistryConnection,
99
116
  ): Promise<void> {
100
- console.error(
101
- "[remote-registry] storeConnection for owner:",
102
- ownerId,
103
- "conn:",
104
- conn.id,
105
- );
117
+ logger.debug("remote_registry_store_connection", {
118
+ component: "agents-sdk.remote-registry",
119
+ owner_id: ownerId,
120
+ connection_id: conn.id,
121
+ });
106
122
  const all = await loadAllConnections(ownerId);
107
123
  all[conn.id] = conn;
108
124
  const value = JSON.stringify(all);
@@ -116,7 +132,10 @@ export function createRemoteRegistryAgent(
116
132
  async function loadAllConnections(
117
133
  ownerId: string,
118
134
  ): Promise<Record<string, RegistryConnection>> {
119
- console.error("[remote-registry] loadAllConnections for owner:", ownerId);
135
+ logger.debug("remote_registry_load_connections", {
136
+ component: "agents-sdk.remote-registry",
137
+ owner_id: ownerId,
138
+ });
120
139
  if (secretStore.resolveByEntity) {
121
140
  const scope = { tenantId: ownerId };
122
141
  const secretIds = await secretStore.resolveByEntity(
@@ -156,7 +175,7 @@ export function createRemoteRegistryAgent(
156
175
  jwt: string,
157
176
  request: Record<string, unknown>,
158
177
  ): Promise<unknown> {
159
- const res = await globalThis.fetch(url, {
178
+ const res = await fetchFn(url, {
160
179
  method: "POST",
161
180
  headers: {
162
181
  "Content-Type": "application/json",
@@ -299,10 +318,10 @@ export function createRemoteRegistryAgent(
299
318
  params: Record<string, unknown>,
300
319
  _ctx: ToolContext,
301
320
  ): Promise<IntegrationMethodResult> => {
302
- console.log(
303
- "[remote-registry] setupFn called with:",
304
- JSON.stringify(params),
305
- );
321
+ logger.debug("remote_registry_setup_called", {
322
+ component: "agents-sdk.remote-registry",
323
+ params,
324
+ });
306
325
  const url = params.url as string;
307
326
  const name = (params.name as string) ?? "registry";
308
327
  const oidcUserId = params.oidcUserId as string | undefined;
@@ -317,7 +336,7 @@ export function createRemoteRegistryAgent(
317
336
  action: "setup",
318
337
  type: "agent-registry",
319
338
  });
320
- const tokenRes = await globalThis.fetch(`${baseUrl}/oauth/token`, {
339
+ const tokenRes = await fetchFn(`${baseUrl}/oauth/token`, {
321
340
  method: "POST",
322
341
  headers: { "Content-Type": "application/json" },
323
342
  body: JSON.stringify({
@@ -354,29 +373,39 @@ export function createRemoteRegistryAgent(
354
373
 
355
374
  // Phase 1: Verify JWKS at origin, establish trust, then request OIDC
356
375
  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);
376
+ logger.debug("remote_registry_setup_fetching_jwks", {
377
+ component: "agents-sdk.remote-registry",
378
+ jwks_uri: jwksUri,
379
+ });
380
+ const jwksRes = await fetchFn(jwksUri);
381
+ logger.debug("remote_registry_setup_jwks_status", {
382
+ component: "agents-sdk.remote-registry",
383
+ status: jwksRes.status,
384
+ });
360
385
  if (!jwksRes.ok)
361
386
  return {
362
387
  success: false,
363
388
  error: `JWKS not reachable at ${jwksUri}`,
364
389
  };
365
390
  if (addTrustedIssuer) {
366
- console.log("[setupFn] adding trusted issuer:", baseUrl);
391
+ logger.debug("remote_registry_setup_adding_trusted_issuer", {
392
+ component: "agents-sdk.remote-registry",
393
+ issuer: baseUrl,
394
+ });
367
395
  await addTrustedIssuer(baseUrl);
368
- console.log("[setupFn] added trusted issuer");
369
396
  }
370
397
 
371
398
  // Request identity — atlas will return authorize URL for Slack OIDC
372
- console.log("[setupFn] Phase 1: requesting identity via jwt_exchange");
399
+ logger.debug("remote_registry_setup_phase1_jwt_exchange", {
400
+ component: "agents-sdk.remote-registry",
401
+ target_url: `${baseUrl}/oauth/token`,
402
+ });
373
403
  const jwt = await signJwt({
374
404
  action: "setup",
375
405
  type: "agent-registry",
376
406
  targetUrl: url,
377
407
  });
378
- console.log("[setupFn] POSTing to:", `${baseUrl}/oauth/token`);
379
- const tokenRes = await globalThis.fetch(`${baseUrl}/oauth/token`, {
408
+ const tokenRes = await fetchFn(`${baseUrl}/oauth/token`, {
380
409
  method: "POST",
381
410
  headers: { "Content-Type": "application/json" },
382
411
  body: JSON.stringify({
@@ -386,12 +415,11 @@ export function createRemoteRegistryAgent(
386
415
  redirect_uri: params.redirect_uri ?? "",
387
416
  }),
388
417
  });
389
- console.log("[setupFn] token status:", tokenRes.status);
390
418
  const tokenData = (await tokenRes.json()) as OAuthTokenJsonBody;
391
- console.log(
392
- "[setupFn] tokenData:",
393
- JSON.stringify(tokenData).substring(0, 300),
394
- );
419
+ logger.debug("remote_registry_setup_phase1_response", {
420
+ component: "agents-sdk.remote-registry",
421
+ status: tokenRes.status,
422
+ });
395
423
 
396
424
  // If already set up (user linked), store connection directly
397
425
  if (tokenData.access_token) {
@@ -460,7 +488,7 @@ export function createRemoteRegistryAgent(
460
488
  action: "connect",
461
489
  type: "agent-registry",
462
490
  });
463
- const tokenRes = await globalThis.fetch(`${conn.url}/oauth/token`, {
491
+ const tokenRes = await fetchFn(`${conn.url}/oauth/token`, {
464
492
  method: "POST",
465
493
  headers: { "Content-Type": "application/json" },
466
494
  body: JSON.stringify({
@@ -532,7 +560,7 @@ export function createRemoteRegistryAgent(
532
560
  const base = url.replace(/\/$/, "");
533
561
  const origin = new URL(base).origin;
534
562
  const jwksUri = `${origin}/.well-known/jwks.json`;
535
- const res = await globalThis.fetch(jwksUri);
563
+ const res = await fetchFn(jwksUri);
536
564
  if (!res.ok) {
537
565
  return {
538
566
  success: false,