@slashfi/agents-sdk 0.89.2 → 0.90.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.
@@ -47,7 +47,14 @@ import type {
47
47
  RegistryConfiguration,
48
48
  RegistryConsumer,
49
49
  } from "./registry-consumer.js";
50
- import type { CallAgentResponse, SecuritySchemeSummary } from "./types.js";
50
+ import type {
51
+ CallAgentErrorResponse,
52
+ CallAgentExecuteToolResponse,
53
+ CallAgentListResourcesResponse,
54
+ CallAgentReadResourcesResponse,
55
+ CallAgentResponse,
56
+ SecuritySchemeSummary,
57
+ } from "./types.js";
51
58
 
52
59
  const CONFIG_PATH = "consumer-config.json";
53
60
  const REGISTRY_CACHE_PATH = "registry-cache.json";
@@ -159,6 +166,40 @@ export interface RefAuthCompleteOptions {
159
166
  * force callers to choose a default that's wrong half the time;
160
167
  * `null` lets them branch explicitly.
161
168
  */
169
+ function normalizeCredentialKey(key: string): string {
170
+ return key
171
+ .toLowerCase()
172
+ .replace(/[^a-z0-9]+/g, "_")
173
+ .replace(/^_|_$/g, "");
174
+ }
175
+
176
+ function hasCredentialField(
177
+ config: Record<string, unknown>,
178
+ field: string,
179
+ ): boolean {
180
+ const wanted = normalizeCredentialKey(field);
181
+
182
+ // Top-level config keys cover legacy entries such as api_key/token and
183
+ // refs whose credentials are stored directly under the cached field name.
184
+ for (const key of Object.keys(config)) {
185
+ if (normalizeCredentialKey(key) === wanted) return true;
186
+ }
187
+
188
+ // API-key refs store header credentials under config.headers using the
189
+ // original HTTP header name (for example "x-api-key"), while authStatus
190
+ // caches the normalized field name ("x_api_key"). Treat header keys as
191
+ // case-insensitive and delimiter-insensitive so the local connected check
192
+ // matches authStatus/ref.call behavior.
193
+ const headers = config.headers;
194
+ if (headers && typeof headers === "object" && !Array.isArray(headers)) {
195
+ for (const key of Object.keys(headers as Record<string, unknown>)) {
196
+ if (normalizeCredentialKey(key) === wanted) return true;
197
+ }
198
+ }
199
+
200
+ return false;
201
+ }
202
+
162
203
  export function isRefAuthComplete(
163
204
  entry: RefEntry,
164
205
  cacheEntry: RegistryCacheEntry | undefined,
@@ -175,8 +216,8 @@ export function isRefAuthComplete(
175
216
  for (const [field, info] of Object.entries(authFields)) {
176
217
  if (!info.required) continue;
177
218
  if (info.automated) continue;
178
- if (field in config) continue;
179
- if (resolvable && resolvable.has(field)) continue;
219
+ if (hasCredentialField(config, field)) continue;
220
+ if (resolvable?.has(field)) continue;
180
221
  return false;
181
222
  }
182
223
  return true;
@@ -367,6 +408,33 @@ export interface AuthStartResult {
367
408
  fields?: AuthChallengeField[];
368
409
  }
369
410
 
411
+ export type AdkRefCallResult =
412
+ | CallAgentExecuteToolResponse
413
+ | CallAgentErrorResponse;
414
+ export type AdkRefResourcesResult =
415
+ | CallAgentListResourcesResponse
416
+ | CallAgentErrorResponse;
417
+ export type AdkRefReadResult =
418
+ | CallAgentReadResourcesResponse
419
+ | CallAgentErrorResponse;
420
+
421
+ type AdkRefActionResult =
422
+ | AdkRefCallResult
423
+ | AdkRefResourcesResult
424
+ | AdkRefReadResult;
425
+
426
+ function toAdkRefActionResult<T extends AdkRefActionResult>(
427
+ result: CallAgentResponse,
428
+ expectedKey: "result" | "resources",
429
+ code: string,
430
+ error: string,
431
+ ): T {
432
+ if (result.success === false) return result as T;
433
+ if (expectedKey in result) return result as T;
434
+
435
+ return { success: false, error, code } as T;
436
+ }
437
+
370
438
  /**
371
439
  * Type slot for adk.ref.call() type safety.
372
440
  * Empty by default — populated by `adk sync` which generates `adk.d.ts`.
@@ -391,13 +459,13 @@ type AdkRefCallFn = keyof AdkAgentRegistry extends never
391
459
  name: string,
392
460
  tool: string,
393
461
  params?: Record<string, unknown>,
394
- ) => Promise<CallAgentResponse>
462
+ ) => Promise<AdkRefCallResult>
395
463
  : // Registry populated — strict typed overload
396
464
  <A extends AgentPath, T extends ToolsOf<A>>(
397
465
  name: A,
398
466
  tool: T,
399
467
  params: ParamsOf<A, T>,
400
- ) => Promise<CallAgentResponse>;
468
+ ) => Promise<AdkRefCallResult>;
401
469
 
402
470
  export interface AdkRefApi {
403
471
  add(entry: RefAddInput): Promise<{ security: SecuritySchemeSummary | null }>;
@@ -410,8 +478,8 @@ export interface AdkRefApi {
410
478
  options?: { full?: boolean },
411
479
  ): Promise<AgentInspection | null>;
412
480
  call: AdkRefCallFn;
413
- resources(name: string): Promise<CallAgentResponse>;
414
- read(name: string, uris: string[]): Promise<CallAgentResponse>;
481
+ resources(name: string): Promise<AdkRefResourcesResult>;
482
+ read(name: string, uris: string[]): Promise<AdkRefReadResult>;
415
483
  /** Check auth status — what's needed vs what's stored */
416
484
  authStatus(name: string): Promise<RefAuthStatus>;
417
485
  /**
@@ -1935,7 +2003,10 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
1935
2003
  scheme: entry.scheme,
1936
2004
  received: { sourceRegistry: entry.sourceRegistry },
1937
2005
  requiredShape: {
1938
- sourceRegistry: { url: "<registry URL>", agentPath: "<optional agent path>" },
2006
+ sourceRegistry: {
2007
+ url: "<registry URL>",
2008
+ agentPath: "<optional agent path>",
2009
+ },
1939
2010
  },
1940
2011
  },
1941
2012
  });
@@ -2137,7 +2208,7 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
2137
2208
  name: string,
2138
2209
  tool: string,
2139
2210
  params?: Record<string, unknown>,
2140
- ): Promise<CallAgentResponse> {
2211
+ ): Promise<AdkRefCallResult> {
2141
2212
  const config = await readConfig();
2142
2213
  const entry = findRef(config.refs ?? [], name);
2143
2214
  if (!entry) throw new Error(`Ref "${name}" not found`);
@@ -2181,7 +2252,11 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
2181
2252
  code: "encryption_key_mismatch",
2182
2253
  message: `ref.call(${name}): failed to decrypt header "${k}". The configured encryptionKey does not match the key used to encrypt this value.`,
2183
2254
  hint: "Re-encrypt the ref's headers with the current encryptionKey, or restore the previous key. Decrypting an unrelated value would have leaked ciphertext as a header before this fix.",
2184
- details: { ref: name, header: k, cause: (err as Error)?.message },
2255
+ details: {
2256
+ ref: name,
2257
+ header: k,
2258
+ cause: (err as Error)?.message,
2259
+ },
2185
2260
  });
2186
2261
  }
2187
2262
  } else {
@@ -2231,14 +2306,24 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
2231
2306
  if (accessToken && isUnauthorized(result)) {
2232
2307
  const refreshed = await ref.refreshToken(name);
2233
2308
  if (refreshed) {
2234
- return doCall(refreshed.accessToken);
2309
+ return toAdkRefActionResult<AdkRefCallResult>(
2310
+ await doCall(refreshed.accessToken),
2311
+ "result",
2312
+ "unexpected_ref_call_response",
2313
+ "Expected execute_tool response from ref.call",
2314
+ );
2235
2315
  }
2236
2316
  }
2237
2317
 
2238
- return result;
2318
+ return toAdkRefActionResult<AdkRefCallResult>(
2319
+ result,
2320
+ "result",
2321
+ "unexpected_ref_call_response",
2322
+ "Expected execute_tool response from ref.call",
2323
+ );
2239
2324
  },
2240
2325
 
2241
- async resources(name: string): Promise<CallAgentResponse> {
2326
+ async resources(name: string): Promise<AdkRefResourcesResult> {
2242
2327
  const config = await readConfig();
2243
2328
  const entry = findRef(config.refs ?? [], name);
2244
2329
  if (!entry) throw new Error(`Ref "${name}" not found`);
@@ -2246,13 +2331,18 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
2246
2331
  const consumer = await buildConsumerForRef(entry);
2247
2332
  const reg = resolveRegistryForRef(consumer, entry);
2248
2333
 
2249
- return consumer.callRegistry(reg, {
2250
- action: "list_resources",
2251
- path: entry.sourceRegistry?.agentPath ?? entry.ref,
2252
- });
2334
+ return toAdkRefActionResult<AdkRefResourcesResult>(
2335
+ await consumer.callRegistry(reg, {
2336
+ action: "list_resources",
2337
+ path: entry.sourceRegistry?.agentPath ?? entry.ref,
2338
+ }),
2339
+ "resources",
2340
+ "unexpected_ref_resources_response",
2341
+ "Expected list_resources response from ref.resources",
2342
+ );
2253
2343
  },
2254
2344
 
2255
- async read(name: string, uris: string[]): Promise<CallAgentResponse> {
2345
+ async read(name: string, uris: string[]): Promise<AdkRefReadResult> {
2256
2346
  const config = await readConfig();
2257
2347
  const entry = findRef(config.refs ?? [], name);
2258
2348
  if (!entry) throw new Error(`Ref "${name}" not found`);
@@ -2260,11 +2350,16 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
2260
2350
  const consumer = await buildConsumerForRef(entry);
2261
2351
  const reg = resolveRegistryForRef(consumer, entry);
2262
2352
 
2263
- return consumer.callRegistry(reg, {
2264
- action: "read_resources",
2265
- path: entry.sourceRegistry?.agentPath ?? entry.ref,
2266
- uris,
2267
- });
2353
+ return toAdkRefActionResult<AdkRefReadResult>(
2354
+ await consumer.callRegistry(reg, {
2355
+ action: "read_resources",
2356
+ path: entry.sourceRegistry?.agentPath ?? entry.ref,
2357
+ uris,
2358
+ }),
2359
+ "resources",
2360
+ "unexpected_ref_read_response",
2361
+ "Expected read_resources response from ref.read",
2362
+ );
2268
2363
  },
2269
2364
 
2270
2365
  async authStatus(name: string): Promise<RefAuthStatus> {