@slashfi/agents-sdk 0.89.0 → 0.89.2

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.
@@ -119,6 +119,22 @@ const callAgentBaseSchema = z.object({
119
119
  callerId: z.string().optional().describe("Caller ID for access control"),
120
120
  callerType: callerTypeSchema.optional().describe("Caller type"),
121
121
  metadata: z.object({}).passthrough().optional().describe("Additional metadata"),
122
+ maxResultTokens: z
123
+ .number()
124
+ .int()
125
+ .min(1)
126
+ .nullable()
127
+ .optional()
128
+ .describe(
129
+ "Maximum token count for the call result. If null, result limiting is disabled. If omitted, the registry default applies.",
130
+ ),
131
+ overflow: z
132
+ .enum(["error", "truncate"])
133
+ .nullable()
134
+ .optional()
135
+ .describe(
136
+ 'What to do when the result exceeds maxResultTokens. "error" returns an error, "truncate" returns a partial result.',
137
+ ),
122
138
  });
123
139
 
124
140
  // ─────────────────────────────────────────────────────────────────────────────
@@ -583,6 +583,99 @@ describe("ADK ref.call() full auto-refresh flow", () => {
583
583
  expect(cache.refs.math.authFields).toEqual({});
584
584
  });
585
585
 
586
+ test("ref.authStatus maps form security to required access_token authFields", async () => {
587
+ // Form security (e.g. databases) asks the user for structured
588
+ // connection fields, but the ADK call path stores the encoded form
589
+ // payload under `config.access_token` and forwards it to registry
590
+ // executors as `params.accessToken`. The cached authFields shape must
591
+ // therefore require `access_token`; otherwise host-side
592
+ // `isRefAuthComplete` / `isRefConnected` checks treat empty form refs
593
+ // as connected because there are no required fields to satisfy.
594
+ const fs = createMemoryFs();
595
+ const fetch: typeof globalThis.fetch = async () =>
596
+ Response.json({
597
+ jsonrpc: "2.0",
598
+ id: "call-1",
599
+ result: {
600
+ content: [
601
+ {
602
+ type: "text",
603
+ text: JSON.stringify({
604
+ success: true,
605
+ toolSummaries: [{ name: "query", description: "Execute SQL" }],
606
+ description: "Form auth agent",
607
+ security: {
608
+ type: "form",
609
+ fields: [
610
+ { name: "host", type: "string", required: true },
611
+ { name: "password", type: "password", required: true },
612
+ ],
613
+ },
614
+ }),
615
+ },
616
+ ],
617
+ },
618
+ });
619
+ const adk = createAdk(fs, {
620
+ encryptionKey: "test-key-32-chars-long-enough!!",
621
+ fetch,
622
+ });
623
+
624
+ await adk.registry.add({
625
+ name: "form-reg",
626
+ url: "http://registry.test",
627
+ });
628
+ const initialConfig = await adk.readConfig();
629
+ await adk.writeConfig({
630
+ ...initialConfig,
631
+ refs: [
632
+ ...(initialConfig.refs ?? []),
633
+ {
634
+ ref: "form-api",
635
+ name: "form-api-unauthed",
636
+ scheme: "registry",
637
+ sourceRegistry: {
638
+ url: "http://registry.test",
639
+ agentPath: "form-api",
640
+ },
641
+ },
642
+ ],
643
+ });
644
+
645
+ const status = await adk.ref.authStatus("form-api-unauthed");
646
+ expect(status.complete).toBe(false);
647
+ expect(status.fields?.access_token).toEqual({
648
+ required: true,
649
+ automated: false,
650
+ present: false,
651
+ resolvable: false,
652
+ });
653
+
654
+ const cacheRaw = await fs.readFile("registry-cache.json");
655
+ expect(cacheRaw).not.toBeNull();
656
+ if (!cacheRaw) throw new Error("registry-cache.json missing");
657
+ const cache = JSON.parse(cacheRaw) as {
658
+ refs: Record<string, { authFields?: Record<string, unknown> }>;
659
+ };
660
+ expect(cache.refs["form-api-unauthed"].authFields).toEqual({
661
+ access_token: { required: true, automated: false },
662
+ });
663
+
664
+ const config = await adk.readConfig();
665
+ await adk.writeConfig({
666
+ ...config,
667
+ refs: config.refs?.map((r) =>
668
+ r.name === "form-api-unauthed"
669
+ ? { ...r, config: { ...r.config, access_token: "encoded-form" } }
670
+ : r,
671
+ ),
672
+ });
673
+
674
+ const authedStatus = await adk.ref.authStatus("form-api-unauthed");
675
+ expect(authedStatus.complete).toBe(true);
676
+ expect(authedStatus.fields?.access_token?.present).toBe(true);
677
+ });
678
+
586
679
  test("ref.authStatus does NOT persist authFields when inspect fails (registry unreachable)", async () => {
587
680
  // Sibling guard: if the registry inspect call throws / returns null
588
681
  // (network error, registry doesn't host the ref, etc.), we must NOT
@@ -214,6 +214,17 @@ export interface AdkOptions {
214
214
  encryptionKey?: string;
215
215
  /** Bearer token for authenticated registries */
216
216
  token?: string;
217
+ /**
218
+ * Default result token limit to pass through for `ref.call` registry requests.
219
+ * Use `null` to explicitly disable remote result limiting for in-process
220
+ * scripting boundaries like `adk run`; omit to use the registry default.
221
+ */
222
+ refCallMaxResultTokens?: number | null;
223
+ /**
224
+ * Default overflow behavior to pass through for `ref.call` registry requests.
225
+ * Only applies when the remote registry enforces a result limit.
226
+ */
227
+ refCallOverflow?: "error" | "truncate" | null;
217
228
  /**
218
229
  * OAuth callback URL. Defaults to http://localhost:8919/callback.
219
230
  * Set this to your server's callback endpoint in non-local environments
@@ -2200,6 +2211,12 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
2200
2211
  action: "execute_tool",
2201
2212
  path: entry.sourceRegistry?.agentPath ?? entry.ref,
2202
2213
  tool,
2214
+ ...("refCallMaxResultTokens" in options && {
2215
+ maxResultTokens: options.refCallMaxResultTokens,
2216
+ }),
2217
+ ...("refCallOverflow" in options && {
2218
+ overflow: options.refCallOverflow,
2219
+ }),
2203
2220
  params: {
2204
2221
  ...(params ?? {}),
2205
2222
  ...(token && { accessToken: token }),
@@ -2425,6 +2442,21 @@ export function createAdk(fs: FsStore, options: AdkOptions = {}): Adk {
2425
2442
  present: configKeys.includes("token"),
2426
2443
  resolvable: await canResolve("token"),
2427
2444
  };
2445
+ } else if (security.type === "form") {
2446
+ // Form-based refs collect structured user input at connect time
2447
+ // (for example database host/user/password), then store the encoded
2448
+ // form payload in the canonical credential slot that `ref.call`
2449
+ // already reads and forwards to registry executors as
2450
+ // `params.accessToken`. Cache that derived credential requirement
2451
+ // instead of the individual form fields so host-side connected checks
2452
+ // answer the same question as the call path: "does this ref carry
2453
+ // the opaque credential blob needed to invoke it?"
2454
+ fields.access_token = {
2455
+ required: true,
2456
+ automated: false,
2457
+ present: configKeys.includes("access_token"),
2458
+ resolvable: await canResolve("access_token"),
2459
+ };
2428
2460
  }
2429
2461
 
2430
2462
  const complete = Object.values(fields).every(
package/src/index.ts CHANGED
@@ -85,6 +85,7 @@ export type {
85
85
  ToolSelectionContext,
86
86
  IntegrationConfig,
87
87
  ApiKeySecurityScheme,
88
+ FormSecurityScheme,
88
89
  HttpSecurityScheme,
89
90
  NoneSecurityScheme,
90
91
  OAuth2SecurityScheme,
package/src/types.ts CHANGED
@@ -243,6 +243,17 @@ export interface HttpSecurityScheme {
243
243
  scheme: "bearer" | "basic";
244
244
  }
245
245
 
246
+ /**
247
+ * Form-based authentication. Consumers collect arbitrary structured fields
248
+ * (for example database connection settings), then store the encoded form
249
+ * payload in the ref's `access_token` credential slot. At call time ADK
250
+ * forwards that value as `params.accessToken` to the registry executor.
251
+ */
252
+ export interface FormSecurityScheme {
253
+ type: "form";
254
+ [key: string]: unknown;
255
+ }
256
+
246
257
  /**
247
258
  * No authentication required.
248
259
  */
@@ -285,6 +296,7 @@ export type SecurityScheme =
285
296
  | OAuth2SecurityScheme
286
297
  | ApiKeySecurityScheme
287
298
  | HttpSecurityScheme
299
+ | FormSecurityScheme
288
300
  | NoneSecurityScheme;
289
301
 
290
302
  /**