@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.
- package/dist/adk-tools.d.ts +1 -1
- package/dist/adk-tools.d.ts.map +1 -1
- package/dist/adk-tools.js +122 -26
- package/dist/adk-tools.js.map +1 -1
- package/dist/adk.js +5 -9
- package/dist/adk.js.map +1 -1
- package/dist/agent-definitions/remote-registry.d.ts +15 -0
- package/dist/agent-definitions/remote-registry.d.ts.map +1 -1
- package/dist/agent-definitions/remote-registry.js +42 -17
- package/dist/agent-definitions/remote-registry.js.map +1 -1
- package/dist/cjs/adk-tools.js +122 -26
- package/dist/cjs/adk-tools.js.map +1 -1
- package/dist/cjs/agent-definitions/remote-registry.js +42 -17
- package/dist/cjs/agent-definitions/remote-registry.js.map +1 -1
- package/dist/cjs/config-store.js +135 -9
- package/dist/cjs/config-store.js.map +1 -1
- package/dist/cjs/define-config.js +9 -2
- package/dist/cjs/define-config.js.map +1 -1
- package/dist/cjs/events.js +11 -3
- package/dist/cjs/events.js.map +1 -1
- package/dist/cjs/fetch-types.js +3 -0
- package/dist/cjs/fetch-types.js.map +1 -0
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/key-manager.js +7 -1
- package/dist/cjs/key-manager.js.map +1 -1
- package/dist/cjs/logger.js +115 -0
- package/dist/cjs/logger.js.map +1 -0
- package/dist/cjs/registry-consumer.js.map +1 -1
- package/dist/cjs/registry.js +1 -1
- package/dist/cjs/registry.js.map +1 -1
- package/dist/cjs/server.js +70 -13
- package/dist/cjs/server.js.map +1 -1
- package/dist/config-store.d.ts +19 -0
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +135 -9
- package/dist/config-store.js.map +1 -1
- package/dist/define-config.d.ts +23 -3
- package/dist/define-config.d.ts.map +1 -1
- package/dist/define-config.js +9 -2
- package/dist/define-config.js.map +1 -1
- package/dist/events.d.ts +6 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +11 -3
- package/dist/events.js.map +1 -1
- package/dist/fetch-types.d.ts +11 -0
- package/dist/fetch-types.d.ts.map +1 -0
- package/dist/fetch-types.js +2 -0
- package/dist/fetch-types.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/key-manager.d.ts +6 -0
- package/dist/key-manager.d.ts.map +1 -1
- package/dist/key-manager.js +7 -1
- package/dist/key-manager.js.map +1 -1
- package/dist/logger.d.ts +42 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +109 -0
- package/dist/logger.js.map +1 -0
- package/dist/registry-consumer.d.ts +8 -2
- package/dist/registry-consumer.d.ts.map +1 -1
- package/dist/registry-consumer.js.map +1 -1
- package/dist/registry.d.ts +6 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +70 -13
- package/dist/server.js.map +1 -1
- package/dist/validate.d.ts +8 -8
- package/package.json +1 -1
- package/src/adk-tools.ts +177 -36
- package/src/adk.ts +5 -10
- package/src/agent-definitions/remote-registry.ts +56 -28
- package/src/config-store.ts +177 -10
- package/src/define-config.ts +25 -4
- package/src/events.ts +16 -6
- package/src/fetch-types.ts +13 -0
- package/src/index.ts +13 -0
- package/src/key-manager.ts +12 -1
- package/src/logger.test.ts +206 -0
- package/src/logger.ts +123 -0
- package/src/ref-naming.test.ts +351 -0
- package/src/registry-consumer.ts +13 -7
- package/src/registry.ts +7 -2
- 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?: (
|
|
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>(
|
|
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
|
-
? {
|
|
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: [
|
|
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: {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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 {
|
|
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, {
|
|
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(
|
|
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: {
|
|
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)
|
|
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(
|
|
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(
|
|
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: [
|
|
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(
|
|
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> = {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
101
|
-
"
|
|
102
|
-
ownerId,
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
303
|
-
"
|
|
304
|
-
|
|
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
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
|
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
|
|
563
|
+
const res = await fetchFn(jwksUri);
|
|
536
564
|
if (!res.ok) {
|
|
537
565
|
return {
|
|
538
566
|
success: false,
|