@slashfi/agents-sdk 0.77.3 → 0.78.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.
@@ -16,12 +16,13 @@
16
16
  * await adk.ref.call('notion', 'notion-search', { query: 'hello' });
17
17
  * ```
18
18
  */
19
+ import { AdkError } from "./adk-error.js";
20
+ import { decryptSecret, encryptSecret } from "./crypto.js";
19
21
  import { normalizeRef } from "./define-config.js";
22
+ import { buildOAuthAuthorizeUrl, discoverOAuthMetadata, dynamicClientRegistration, exchangeCodeForTokens, probeRegistryAuth, refreshAccessToken, } from "./mcp-client.js";
20
23
  import { createRegistryConsumer } from "./registry-consumer.js";
21
- import { decryptSecret, encryptSecret } from "./crypto.js";
22
- import { AdkError } from "./adk-error.js";
23
- import { discoverOAuthMetadata, dynamicClientRegistration, buildOAuthAuthorizeUrl, exchangeCodeForTokens, probeRegistryAuth, refreshAccessToken, } from "./mcp-client.js";
24
24
  const CONFIG_PATH = "consumer-config.json";
25
+ const REGISTRY_CACHE_PATH = "registry-cache.json";
25
26
  const SECRET_PREFIX = "secret:";
26
27
  // ============================================
27
28
  // Internal helpers
@@ -74,7 +75,9 @@ async function decryptConfigSecrets(obj, encryptionKey) {
74
75
  if (typeof value === "string" && value.startsWith(SECRET_PREFIX)) {
75
76
  result[key] = await decryptSecret(value.slice(SECRET_PREFIX.length), encryptionKey);
76
77
  }
77
- else if (value !== null && typeof value === "object" && !Array.isArray(value)) {
78
+ else if (value !== null &&
79
+ typeof value === "object" &&
80
+ !Array.isArray(value)) {
78
81
  result[key] = await decryptConfigSecrets(value, encryptionKey);
79
82
  }
80
83
  else {
@@ -92,7 +95,7 @@ async function decryptConfigSecrets(obj, encryptionKey) {
92
95
  * Fallback: _httpStatus from tool result body
93
96
  */
94
97
  function isUnauthorized(result) {
95
- if (!result || typeof result !== 'object')
98
+ if (!result || typeof result !== "object")
96
99
  return false;
97
100
  const r = result;
98
101
  // Primary: HTTP status forwarded by the registry and set by callRegistry
@@ -107,17 +110,21 @@ function isUnauthorized(result) {
107
110
  // ============================================
108
111
  // Local auth form HTML
109
112
  // ============================================
110
- const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
113
+ const esc = (s) => s
114
+ .replace(/&/g, "&amp;")
115
+ .replace(/</g, "&lt;")
116
+ .replace(/>/g, "&gt;")
117
+ .replace(/"/g, "&quot;");
111
118
  function renderCredentialForm(name, fields, error) {
112
- const fieldHtml = fields.map((f) => `
119
+ const fieldHtml = fields
120
+ .map((f) => `
113
121
  <div class="field">
114
122
  <label for="${esc(f.name)}">${esc(f.label)}</label>
115
123
  ${f.description ? `<p class="desc">${esc(f.description)}</p>` : ""}
116
124
  <input id="${esc(f.name)}" name="${esc(f.name)}" type="${f.secret ? "password" : "text"}" required autocomplete="off" spellcheck="false" />
117
- </div>`).join("");
118
- const errorHtml = error
119
- ? `<div class="error">${esc(error)}</div>`
120
- : "";
125
+ </div>`)
126
+ .join("");
127
+ const errorHtml = error ? `<div class="error">${esc(error)}</div>` : "";
121
128
  return `<!DOCTYPE html>
122
129
  <html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
123
130
  <title>Authenticate \u2014 ${esc(name)}</title>
@@ -180,6 +187,95 @@ export function createAdk(fs, options = {}) {
180
187
  async function writeConfig(config) {
181
188
  await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
182
189
  }
190
+ // -------------------------------------------------------------------------
191
+ // Registry cache helpers
192
+ //
193
+ // The cache is purely an internal optimization for the adk's read paths
194
+ // (`ref.list()`, `ref.get()`). Writes happen as side-effects of methods
195
+ // that already call the registry (`ref.add()`, `ref.inspect()`); the
196
+ // public surface never grows new methods. Cache failures (missing file,
197
+ // malformed JSON, fs errors during write) are swallowed so the registry
198
+ // cache can never break a registry operation.
199
+ // -------------------------------------------------------------------------
200
+ async function readRegistryCache() {
201
+ try {
202
+ const content = await fs.readFile(REGISTRY_CACHE_PATH);
203
+ if (!content)
204
+ return { refs: {} };
205
+ const parsed = JSON.parse(content);
206
+ return { refs: parsed.refs ?? {} };
207
+ }
208
+ catch {
209
+ return { refs: {} };
210
+ }
211
+ }
212
+ async function writeRegistryCache(cache) {
213
+ try {
214
+ await fs.writeFile(REGISTRY_CACHE_PATH, JSON.stringify(cache, null, 2));
215
+ }
216
+ catch {
217
+ // Best-effort. A failed cache write should never break the operation
218
+ // that triggered it.
219
+ }
220
+ }
221
+ /**
222
+ * Project an inspect/list response into the slim shape we cache. Drops
223
+ * `inputSchema` (too large) and `fullTokens` (registry-internal). Returns
224
+ * undefined if the response carries nothing worth caching.
225
+ */
226
+ function buildCacheEntry(ref, info) {
227
+ if (!info)
228
+ return undefined;
229
+ const toolSource = info.tools ?? info.toolSummaries;
230
+ const tools = toolSource?.map((t) => {
231
+ const slim = { name: t.name };
232
+ if (t.description !== undefined)
233
+ slim.description = t.description;
234
+ return slim;
235
+ });
236
+ if (info.description === undefined && (!tools || tools.length === 0)) {
237
+ return undefined;
238
+ }
239
+ const entry = {
240
+ ref,
241
+ fetchedAt: new Date().toISOString(),
242
+ };
243
+ if (info.description !== undefined)
244
+ entry.description = info.description;
245
+ if (tools && tools.length > 0)
246
+ entry.tools = tools;
247
+ return entry;
248
+ }
249
+ async function upsertRegistryCacheEntry(name, entry) {
250
+ if (!entry)
251
+ return;
252
+ const cache = await readRegistryCache();
253
+ cache.refs[name] = entry;
254
+ await writeRegistryCache(cache);
255
+ }
256
+ async function removeRegistryCacheEntry(name) {
257
+ const cache = await readRegistryCache();
258
+ if (!(name in cache.refs))
259
+ return;
260
+ delete cache.refs[name];
261
+ await writeRegistryCache(cache);
262
+ }
263
+ /**
264
+ * Hydrate a `ResolvedRef` with cached registry metadata when available.
265
+ * Pure: never mutates input. Leaves `description` / `tools` undefined when
266
+ * the cache has no entry, so callers can apply their own UX fallback.
267
+ */
268
+ function hydrateFromCache(ref, cache) {
269
+ const cached = cache.refs[ref.name];
270
+ if (!cached)
271
+ return ref;
272
+ const next = { ...ref };
273
+ if (cached.description !== undefined)
274
+ next.description = cached.description;
275
+ if (cached.tools !== undefined)
276
+ next.tools = cached.tools;
277
+ return next;
278
+ }
183
279
  /**
184
280
  * Store a secret value in a ref's config, encrypted if encryptionKey is set.
185
281
  * The value is stored inline as "secret:<encrypted>" in consumer-config.json.
@@ -290,7 +386,10 @@ export function createAdk(fs, options = {}) {
290
386
  let reqId = 0;
291
387
  let sessionId;
292
388
  async function rpc(method, rpcParams) {
293
- const reqHeaders = { ...headers, ...(sessionId ? { "Mcp-Session-Id": sessionId } : {}) };
389
+ const reqHeaders = {
390
+ ...headers,
391
+ ...(sessionId ? { "Mcp-Session-Id": sessionId } : {}),
392
+ };
294
393
  const res = await globalThis.fetch(url, {
295
394
  method: "POST",
296
395
  headers: reqHeaders,
@@ -331,7 +430,7 @@ export function createAdk(fs, options = {}) {
331
430
  }
332
431
  return undefined;
333
432
  }
334
- const json = await res.json();
433
+ const json = (await res.json());
335
434
  if (json.error)
336
435
  throw new Error(`MCP RPC error: ${json.error.message}`);
337
436
  return json.result;
@@ -343,20 +442,32 @@ export function createAdk(fs, options = {}) {
343
442
  clientInfo: { name: "adk", version: "1.0.0" },
344
443
  });
345
444
  await rpc("notifications/initialized").catch(() => { });
346
- const result = await rpc("tools/call", { name: toolName, arguments: params });
445
+ const result = (await rpc("tools/call", {
446
+ name: toolName,
447
+ arguments: params,
448
+ }));
347
449
  const textContent = result?.content?.find((c) => c.type === "text");
348
450
  if (textContent?.text) {
349
451
  try {
350
- return { success: true, result: JSON.parse(textContent.text) };
452
+ return {
453
+ success: true,
454
+ result: JSON.parse(textContent.text),
455
+ };
351
456
  }
352
457
  catch {
353
- return { success: true, result: textContent.text };
458
+ return {
459
+ success: true,
460
+ result: textContent.text,
461
+ };
354
462
  }
355
463
  }
356
464
  return { success: true, result };
357
465
  }
358
466
  catch (err) {
359
- return { success: false, error: err instanceof Error ? err.message : String(err) };
467
+ return {
468
+ success: false,
469
+ error: err instanceof Error ? err.message : String(err),
470
+ };
360
471
  }
361
472
  }
362
473
  function callbackUrl() {
@@ -369,7 +480,7 @@ export function createAdk(fs, options = {}) {
369
480
  const res = await globalThis.fetch(url);
370
481
  if (!res.ok)
371
482
  return null;
372
- const data = await res.json();
483
+ const data = (await res.json());
373
484
  if (data.authorization_endpoint && data.token_endpoint) {
374
485
  return data;
375
486
  }
@@ -739,7 +850,9 @@ export function createAdk(fs, options = {}) {
739
850
  ...final,
740
851
  proxy: {
741
852
  mode: discovered.proxy.mode,
742
- ...(discovered.proxy.agent && { agent: discovered.proxy.agent }),
853
+ ...(discovered.proxy.agent && {
854
+ agent: discovered.proxy.agent,
855
+ }),
743
856
  },
744
857
  };
745
858
  }
@@ -866,7 +979,12 @@ export function createAdk(fs, options = {}) {
866
979
  }));
867
980
  return results.map((r) => r.status === "fulfilled"
868
981
  ? r.value
869
- : { name: "unknown", url: "unknown", status: "error", error: "unknown" });
982
+ : {
983
+ name: "unknown",
984
+ url: "unknown",
985
+ status: "error",
986
+ error: "unknown",
987
+ });
870
988
  },
871
989
  async auth(nameOrUrl, credential) {
872
990
  // Encrypt the secret value up-front so the write path is uniform;
@@ -1146,7 +1264,10 @@ export function createAdk(fs, options = {}) {
1146
1264
  entry = { ...entry, scheme: "registry" };
1147
1265
  }
1148
1266
  else if (entry.url) {
1149
- entry = { ...entry, scheme: entry.url.startsWith("http") ? "https" : "mcp" };
1267
+ entry = {
1268
+ ...entry,
1269
+ scheme: entry.url.startsWith("http") ? "https" : "mcp",
1270
+ };
1150
1271
  }
1151
1272
  else {
1152
1273
  throw new AdkError({
@@ -1174,6 +1295,7 @@ export function createAdk(fs, options = {}) {
1174
1295
  details: { ref: entry.ref, scheme: entry.scheme },
1175
1296
  });
1176
1297
  }
1298
+ let cacheEntry;
1177
1299
  if (hasRegistries || entry.sourceRegistry?.url) {
1178
1300
  try {
1179
1301
  const consumer = await buildConsumerForRef(entry);
@@ -1181,9 +1303,10 @@ export function createAdk(fs, options = {}) {
1181
1303
  const info = await consumer.inspect(agentToInspect);
1182
1304
  const requiresValidation = !!entry.sourceRegistry;
1183
1305
  if (requiresValidation) {
1184
- const hasContent = info && (info.description ||
1185
- (info.tools && info.tools.length > 0) ||
1186
- (info.toolSummaries && info.toolSummaries.length > 0));
1306
+ const hasContent = info &&
1307
+ (info.description ||
1308
+ (info.tools && info.tools.length > 0) ||
1309
+ (info.toolSummaries && info.toolSummaries.length > 0));
1187
1310
  if (!hasContent) {
1188
1311
  // Inspect returned empty — fall back to browse to check if agent exists
1189
1312
  const registryUrl = entry.sourceRegistry?.url;
@@ -1205,7 +1328,11 @@ export function createAdk(fs, options = {}) {
1205
1328
  code: "REF_NOT_FOUND",
1206
1329
  message: `Agent "${entry.ref}" not found on ${registryHint}`,
1207
1330
  hint: "Check available agents with: adk registry browse",
1208
- details: { ref: entry.ref, sourceRegistry: entry.sourceRegistry, scheme: entry.scheme },
1331
+ details: {
1332
+ ref: entry.ref,
1333
+ sourceRegistry: entry.sourceRegistry,
1334
+ scheme: entry.scheme,
1335
+ },
1209
1336
  });
1210
1337
  }
1211
1338
  }
@@ -1215,10 +1342,11 @@ export function createAdk(fs, options = {}) {
1215
1342
  const agentMode = info?.mode;
1216
1343
  if (agentMode)
1217
1344
  entry.mode = agentMode;
1218
- if (info?.upstream && !entry.url && agentMode !== 'api') {
1345
+ if (info?.upstream && !entry.url && agentMode !== "api") {
1219
1346
  entry.url = info.upstream;
1220
1347
  entry.scheme = entry.scheme ?? "mcp";
1221
1348
  }
1349
+ cacheEntry = buildCacheEntry(entry.ref, info);
1222
1350
  }
1223
1351
  catch (err) {
1224
1352
  if (err instanceof AdkError)
@@ -1227,13 +1355,17 @@ export function createAdk(fs, options = {}) {
1227
1355
  code: "REGISTRY_UNREACHABLE",
1228
1356
  message: `Could not reach registry to validate "${entry.ref}"`,
1229
1357
  hint: "Check your registry connection with: adk registry test",
1230
- details: { ref: entry.ref, error: err instanceof Error ? err.message : String(err) },
1358
+ details: {
1359
+ ref: entry.ref,
1360
+ error: err instanceof Error ? err.message : String(err),
1361
+ },
1231
1362
  cause: err,
1232
1363
  });
1233
1364
  }
1234
1365
  }
1235
1366
  const refs = [...(config.refs ?? []), entry];
1236
1367
  await writeConfig({ ...config, refs });
1368
+ await upsertRegistryCacheEntry(name, cacheEntry);
1237
1369
  return { security };
1238
1370
  },
1239
1371
  async remove(name) {
@@ -1245,15 +1377,27 @@ export function createAdk(fs, options = {}) {
1245
1377
  if (refs.length === before)
1246
1378
  return false;
1247
1379
  await writeConfig({ ...config, refs });
1380
+ await removeRegistryCacheEntry(name);
1248
1381
  return true;
1249
1382
  },
1250
1383
  async list() {
1251
- const config = await readConfig();
1252
- return (config.refs ?? []).map(normalizeRef);
1384
+ const [config, cache] = await Promise.all([
1385
+ readConfig(),
1386
+ readRegistryCache(),
1387
+ ]);
1388
+ return (config.refs ?? [])
1389
+ .map(normalizeRef)
1390
+ .map((r) => hydrateFromCache(r, cache));
1253
1391
  },
1254
1392
  async get(name) {
1255
- const config = await readConfig();
1256
- return findRef(config.refs ?? [], name) ?? null;
1393
+ const [config, cache] = await Promise.all([
1394
+ readConfig(),
1395
+ readRegistryCache(),
1396
+ ]);
1397
+ const found = findRef(config.refs ?? [], name);
1398
+ if (!found)
1399
+ return null;
1400
+ return hydrateFromCache(found, cache);
1257
1401
  },
1258
1402
  async update(name, updates) {
1259
1403
  const config = await readConfig();
@@ -1299,27 +1443,35 @@ export function createAdk(fs, options = {}) {
1299
1443
  if (!entry)
1300
1444
  throw new Error(`Ref "${name}" not found`);
1301
1445
  const consumer = await buildConsumerForRef(entry);
1302
- return consumer.inspect(entry.sourceRegistry?.agentPath ?? entry.ref, entry.sourceRegistry?.url, opts);
1446
+ const result = await consumer.inspect(entry.sourceRegistry?.agentPath ?? entry.ref, entry.sourceRegistry?.url, opts);
1447
+ // Side-effect: refresh the registry cache so subsequent ref.list()
1448
+ // / ref.get() calls see the latest description and tool summaries
1449
+ // without another network round-trip. Strips inputSchema (caller's
1450
+ // `result` is unaffected — it still carries the full data).
1451
+ await upsertRegistryCacheEntry(name, buildCacheEntry(entry.ref, result));
1452
+ return result;
1303
1453
  },
1304
1454
  async call(name, tool, params) {
1305
1455
  const config = await readConfig();
1306
1456
  const entry = findRef(config.refs ?? [], name);
1307
1457
  if (!entry)
1308
1458
  throw new Error(`Ref "${name}" not found`);
1309
- let accessToken = await readRefSecret(name, "access_token")
1310
- ?? await readRefSecret(name, "api_key")
1311
- ?? await readRefSecret(name, "token");
1459
+ const accessToken = (await readRefSecret(name, "access_token")) ??
1460
+ (await readRefSecret(name, "api_key")) ??
1461
+ (await readRefSecret(name, "token"));
1312
1462
  // Resolve custom headers from config (e.g. { "X-API-Key": "secret:..." })
1313
1463
  const refConfig = (entry.config ?? {});
1314
1464
  const rawHeaders = refConfig.headers;
1315
1465
  let resolvedHeaders;
1316
- if (rawHeaders && typeof rawHeaders === 'object') {
1466
+ if (rawHeaders && typeof rawHeaders === "object") {
1317
1467
  resolvedHeaders = {};
1318
1468
  for (const [k, v] of Object.entries(rawHeaders)) {
1319
- if (typeof v === 'string' && v.startsWith(SECRET_PREFIX) && options.encryptionKey) {
1469
+ if (typeof v === "string" &&
1470
+ v.startsWith(SECRET_PREFIX) &&
1471
+ options.encryptionKey) {
1320
1472
  resolvedHeaders[k] = await decryptSecret(v.slice(SECRET_PREFIX.length), options.encryptionKey);
1321
1473
  }
1322
- else if (typeof v === 'string') {
1474
+ else if (typeof v === "string") {
1323
1475
  resolvedHeaders[k] = v;
1324
1476
  }
1325
1477
  }
@@ -1327,8 +1479,8 @@ export function createAdk(fs, options = {}) {
1327
1479
  const doCall = async (token) => {
1328
1480
  // Direct MCP only for redirect/proxy agents with an MCP upstream.
1329
1481
  // API-mode agents must go through the registry (it does REST translation).
1330
- const agentMode = entry.mode ?? 'redirect';
1331
- if (token && entry.url && agentMode !== 'api') {
1482
+ const agentMode = entry.mode ?? "redirect";
1483
+ if (token && entry.url && agentMode !== "api") {
1332
1484
  return callMcpDirect(entry.url, tool, params ?? {}, token, resolvedHeaders);
1333
1485
  }
1334
1486
  const consumer = await buildConsumerForRef(entry);
@@ -1444,10 +1596,15 @@ export function createAdk(fs, options = {}) {
1444
1596
  }
1445
1597
  else if (security.type === "apiKey") {
1446
1598
  const apiKeySec = security;
1447
- const toStorageKey = (headerName) => headerName.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
1599
+ const toStorageKey = (headerName) => headerName
1600
+ .toLowerCase()
1601
+ .replace(/[^a-z0-9]+/g, "_")
1602
+ .replace(/^_|_$/g, "");
1448
1603
  // config.headers: { "Header-Name": "value" } — check by header name (case-insensitive)
1449
1604
  const configHeaders = entry?.config?.headers;
1450
- const configHeaderKeys = configHeaders ? Object.keys(configHeaders) : [];
1605
+ const configHeaderKeys = configHeaders
1606
+ ? Object.keys(configHeaders)
1607
+ : [];
1451
1608
  const hasConfigHeader = (name) => configHeaderKeys.some((k) => k.toLowerCase() === name.toLowerCase());
1452
1609
  // Collect all declared header names from the security scheme
1453
1610
  const declaredHeaders = apiKeySec.headers
@@ -1496,7 +1653,9 @@ export function createAdk(fs, options = {}) {
1496
1653
  // agent. The registry owns the client_id/secret and returns an authorize
1497
1654
  // URL pointing at the registry's OAuth callback domain, so the user
1498
1655
  // completes the flow against the registry instead of localhost.
1499
- const proxy = await resolveProxyForRef(entry, { preferLocal: opts?.preferLocal });
1656
+ const proxy = await resolveProxyForRef(entry, {
1657
+ preferLocal: opts?.preferLocal,
1658
+ });
1500
1659
  if (proxy) {
1501
1660
  const params = { name };
1502
1661
  if (opts?.apiKey !== undefined)
@@ -1517,12 +1676,18 @@ export function createAdk(fs, options = {}) {
1517
1676
  }
1518
1677
  if (security.type === "apiKey") {
1519
1678
  const apiKeySec = security;
1520
- const toStorageKey = (headerName) => headerName.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
1679
+ const toStorageKey = (headerName) => headerName
1680
+ .toLowerCase()
1681
+ .replace(/[^a-z0-9]+/g, "_")
1682
+ .replace(/^_|_$/g, "");
1521
1683
  // Check existing config.headers
1522
1684
  const existingHeaders = (entry.config ?? {}).headers;
1523
1685
  // Collect declared headers: from security.headers or security.name
1524
1686
  const declaredHeaders = apiKeySec.headers
1525
- ? Object.entries(apiKeySec.headers).map(([h, meta]) => ({ headerName: h, description: meta.description }))
1687
+ ? Object.entries(apiKeySec.headers).map(([h, meta]) => ({
1688
+ headerName: h,
1689
+ description: meta.description,
1690
+ }))
1526
1691
  : apiKeySec.name
1527
1692
  ? [{ headerName: apiKeySec.name }]
1528
1693
  : [];
@@ -1532,12 +1697,13 @@ export function createAdk(fs, options = {}) {
1532
1697
  for (const { headerName, description } of declaredHeaders) {
1533
1698
  const storageKey = toStorageKey(headerName);
1534
1699
  // Check: credentials param → existing config.headers → legacy config key → resolve callback
1535
- const value = opts?.credentials?.[storageKey]
1536
- ?? opts?.credentials?.[headerName]
1537
- ?? (existingHeaders && Object.entries(existingHeaders).find(([k]) => k.toLowerCase() === headerName.toLowerCase())?.[1])
1538
- ?? opts?.apiKey
1539
- ?? await readRefSecret(name, storageKey)
1540
- ?? await tryResolve(storageKey);
1700
+ const value = opts?.credentials?.[storageKey] ??
1701
+ opts?.credentials?.[headerName] ??
1702
+ (existingHeaders &&
1703
+ Object.entries(existingHeaders).find(([k]) => k.toLowerCase() === headerName.toLowerCase())?.[1]) ??
1704
+ opts?.apiKey ??
1705
+ (await readRefSecret(name, storageKey)) ??
1706
+ (await tryResolve(storageKey));
1541
1707
  if (value) {
1542
1708
  resolvedHeaders[headerName] = value;
1543
1709
  }
@@ -1557,22 +1723,28 @@ export function createAdk(fs, options = {}) {
1557
1723
  const encKey = options.encryptionKey;
1558
1724
  const headersToStore = {};
1559
1725
  for (const [h, v] of Object.entries(resolvedHeaders)) {
1560
- headersToStore[h] = encKey ? `${SECRET_PREFIX}${await encryptSecret(v, encKey)}` : v;
1726
+ headersToStore[h] = encKey
1727
+ ? `${SECRET_PREFIX}${await encryptSecret(v, encKey)}`
1728
+ : v;
1561
1729
  }
1562
1730
  await ref.update(name, { config: { headers: headersToStore } });
1563
1731
  return { type: "apiKey", complete: true };
1564
1732
  }
1565
1733
  // Fallback: no headers declared → generic api_key
1566
- const key = opts?.credentials?.["api_key"] ?? opts?.apiKey ?? await tryResolve("api_key");
1734
+ const key = opts?.credentials?.["api_key"] ??
1735
+ opts?.apiKey ??
1736
+ (await tryResolve("api_key"));
1567
1737
  if (!key) {
1568
1738
  return {
1569
1739
  type: "apiKey",
1570
1740
  complete: false,
1571
- fields: [{
1741
+ fields: [
1742
+ {
1572
1743
  name: "api_key",
1573
1744
  label: "API Key",
1574
1745
  secret: true,
1575
- }],
1746
+ },
1747
+ ],
1576
1748
  };
1577
1749
  }
1578
1750
  await storeRefSecret(name, "api_key", key);
@@ -1582,14 +1754,22 @@ export function createAdk(fs, options = {}) {
1582
1754
  const httpSec = security;
1583
1755
  const isBasic = httpSec.scheme === "basic";
1584
1756
  if (isBasic) {
1585
- const username = opts?.credentials?.["username"] ?? await tryResolve("username");
1586
- const password = opts?.credentials?.["password"] ?? await tryResolve("password");
1757
+ const username = opts?.credentials?.["username"] ?? (await tryResolve("username"));
1758
+ const password = opts?.credentials?.["password"] ?? (await tryResolve("password"));
1587
1759
  if (!username || !password) {
1588
1760
  const missingFields = [];
1589
1761
  if (!username)
1590
- missingFields.push({ name: "username", label: "Username", secret: false });
1762
+ missingFields.push({
1763
+ name: "username",
1764
+ label: "Username",
1765
+ secret: false,
1766
+ });
1591
1767
  if (!password)
1592
- missingFields.push({ name: "password", label: "Password", secret: true });
1768
+ missingFields.push({
1769
+ name: "password",
1770
+ label: "Password",
1771
+ secret: true,
1772
+ });
1593
1773
  return { type: "http", complete: false, fields: missingFields };
1594
1774
  }
1595
1775
  // Store as base64 encoded basic auth token
@@ -1598,7 +1778,9 @@ export function createAdk(fs, options = {}) {
1598
1778
  return { type: "http", complete: true };
1599
1779
  }
1600
1780
  // Bearer token
1601
- const token = opts?.credentials?.["token"] ?? opts?.apiKey ?? await tryResolve("token");
1781
+ const token = opts?.credentials?.["token"] ??
1782
+ opts?.apiKey ??
1783
+ (await tryResolve("token"));
1602
1784
  if (!token) {
1603
1785
  return {
1604
1786
  type: "http",
@@ -1655,8 +1837,9 @@ export function createAdk(fs, options = {}) {
1655
1837
  const supportedAuthMethods = metadata.token_endpoint_auth_methods_supported ?? ["none"];
1656
1838
  const preferredMethod = supportedAuthMethods.includes("none")
1657
1839
  ? "none"
1658
- : supportedAuthMethods[0] ?? "client_secret_post";
1659
- const securityClientName = security.clientName;
1840
+ : (supportedAuthMethods[0] ?? "client_secret_post");
1841
+ const securityClientName = security
1842
+ .clientName;
1660
1843
  const reg = await dynamicClientRegistration(metadata.registration_endpoint, {
1661
1844
  clientName: securityClientName ?? options.oauthClientName ?? "adk",
1662
1845
  redirectUris: [redirectUri],
@@ -1674,10 +1857,18 @@ export function createAdk(fs, options = {}) {
1674
1857
  // Return fields telling the caller what OAuth credentials to provide
1675
1858
  const missingFields = [];
1676
1859
  if (!clientId) {
1677
- missingFields.push({ name: "client_id", label: "Client ID", secret: false });
1860
+ missingFields.push({
1861
+ name: "client_id",
1862
+ label: "Client ID",
1863
+ secret: false,
1864
+ });
1678
1865
  }
1679
1866
  // Always ask for client_secret alongside client_id — most providers need it
1680
- missingFields.push({ name: "client_secret", label: "Client Secret", secret: true });
1867
+ missingFields.push({
1868
+ name: "client_secret",
1869
+ label: "Client Secret",
1870
+ secret: true,
1871
+ });
1681
1872
  return { type: "oauth2", complete: false, fields: missingFields };
1682
1873
  }
1683
1874
  // State ties the callback back to this ref. Encode as base64 JSON
@@ -1699,7 +1890,9 @@ export function createAdk(fs, options = {}) {
1699
1890
  const scopes = agentScopes.length > 0
1700
1891
  ? [
1701
1892
  ...agentScopes,
1702
- ...(metadata.scopes_supported?.includes('openid') ? ['openid'] : []),
1893
+ ...(metadata.scopes_supported?.includes("openid")
1894
+ ? ["openid"]
1895
+ : []),
1703
1896
  ]
1704
1897
  : metadata.scopes_supported;
1705
1898
  // Read provider-specific authorization params from the agent's security section
@@ -1748,7 +1941,9 @@ export function createAdk(fs, options = {}) {
1748
1941
  // owns the credential store, so the user needs to submit via
1749
1942
  // whatever UI the registry exposes. Supporting this through the
1750
1943
  // proxy would need a remote form endpoint — out of scope here.
1751
- if (result.fields && result.fields.length > 0 && result.type !== "oauth2") {
1944
+ if (result.fields &&
1945
+ result.fields.length > 0 &&
1946
+ result.type !== "oauth2") {
1752
1947
  if (proxy) {
1753
1948
  throw new Error(`Ref "${name}" is sourced from a proxied registry; submit credentials through ${proxy.agent} instead of a local form.`);
1754
1949
  }
@@ -1908,7 +2103,7 @@ export function createAdk(fs, options = {}) {
1908
2103
  });
1909
2104
  if (!res.ok)
1910
2105
  return null;
1911
- const data = await res.json();
2106
+ const data = (await res.json());
1912
2107
  const newAccessToken = data.access_token;
1913
2108
  if (!newAccessToken)
1914
2109
  return null;
@@ -1943,7 +2138,9 @@ export function createAdk(fs, options = {}) {
1943
2138
  try {
1944
2139
  stateContext = JSON.parse(atob(params.state));
1945
2140
  }
1946
- catch { /* state wasn't base64 JSON — legacy format */ }
2141
+ catch {
2142
+ /* state wasn't base64 JSON — legacy format */
2143
+ }
1947
2144
  return { refName: pending.refName, complete: true, stateContext };
1948
2145
  }
1949
2146
  return { registry, ref, readConfig, writeConfig, handleCallback };