@runtypelabs/sdk 10.5.2 → 10.6.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/index.cjs CHANGED
@@ -2352,12 +2352,13 @@ const DEFAULT_BLOCKED_CODE_PATTERNS = [
2352
2352
  /\bsubprocess\b/i,
2353
2353
  /\bos\.system\s*\(/i
2354
2354
  ];
2355
- const DEFAULT_ALLOWED_SANDBOX_PROVIDERS = [
2355
+ const CUSTOM_TOOL_SANDBOX_PROVIDERS = [
2356
2356
  "quickjs",
2357
2357
  "daytona",
2358
2358
  "cloudflare-worker",
2359
- "cloudflare-sandbox"
2359
+ "runtype-sandbox"
2360
2360
  ];
2361
+ const DEFAULT_ALLOWED_SANDBOX_PROVIDERS = [...CUSTOM_TOOL_SANDBOX_PROVIDERS, "cloudflare-sandbox"];
2361
2362
  const DEFAULT_ALLOWED_LANGUAGES = [
2362
2363
  "javascript",
2363
2364
  "typescript",
@@ -2379,7 +2380,21 @@ function isLanguage(value) {
2379
2380
  return value === "javascript" || value === "typescript" || value === "python";
2380
2381
  }
2381
2382
  function isSandboxProvider(value) {
2382
- return value === "quickjs" || value === "daytona" || value === "cloudflare-worker";
2383
+ return CUSTOM_TOOL_SANDBOX_PROVIDERS.includes(value);
2384
+ }
2385
+ function isNetworkAccess(value) {
2386
+ if (value === "off" || value === "on") return true;
2387
+ if (!isObject(value) || !Array.isArray(value.allowedHostnames)) return false;
2388
+ const hosts = value.allowedHostnames;
2389
+ return hosts.length > 0 && hosts.every((host) => typeof host === "string" && host.length > 0);
2390
+ }
2391
+ /** Why the requested posture exceeds what the caller allowed, or null when it fits. */
2392
+ function networkAccessViolation(requested, allowed) {
2393
+ if (requested === void 0 || requested === "off" || allowed === true) return null;
2394
+ if (!allowed) return "Generated tool requests network access, which this gate does not allow";
2395
+ if (requested === "on") return "Generated tool requests unrestricted network access; only an allowedHostnames list is allowed";
2396
+ const outside = requested.allowedHostnames.filter((host) => !allowed.allowedHostnames.includes(host));
2397
+ return outside.length > 0 ? `Generated tool requests hosts outside the allowed list: ${outside.join(", ")}` : null;
2383
2398
  }
2384
2399
  function isJSONSchema(value) {
2385
2400
  if (!isObject(value)) return false;
@@ -2426,6 +2441,12 @@ function normalizeGeneratedProposal(proposal, violations) {
2426
2441
  const sandboxProviderRaw = config.sandboxProvider;
2427
2442
  const languageRaw = config.language;
2428
2443
  const timeoutRaw = config.timeout;
2444
+ const sandboxProvider = isSandboxProvider(sandboxProviderRaw) ? sandboxProviderRaw : "cloudflare-worker";
2445
+ const language = isLanguage(languageRaw) ? languageRaw : "javascript";
2446
+ const timeout = asNumber(timeoutRaw);
2447
+ if (Array.isArray(config.secrets) && config.secrets.length > 0) violations.push("Generated tools cannot declare config.secrets (managed credentials)");
2448
+ const networkAccess = config.networkAccess;
2449
+ if (networkAccess !== void 0 && !isNetworkAccess(networkAccess)) violations.push("config.networkAccess must be 'off', 'on', or { allowedHostnames: string[] }");
2429
2450
  return {
2430
2451
  name,
2431
2452
  description,
@@ -2433,9 +2454,10 @@ function normalizeGeneratedProposal(proposal, violations) {
2433
2454
  parametersSchema,
2434
2455
  config: {
2435
2456
  code,
2436
- sandboxProvider: isSandboxProvider(sandboxProviderRaw) ? sandboxProviderRaw : "cloudflare-worker",
2437
- language: isLanguage(languageRaw) ? languageRaw : "javascript",
2438
- timeout: asNumber(timeoutRaw)
2457
+ sandboxProvider,
2458
+ language,
2459
+ timeout,
2460
+ ...isNetworkAccess(networkAccess) ? { networkAccess } : {}
2439
2461
  }
2440
2462
  };
2441
2463
  }
@@ -2488,6 +2510,8 @@ function evaluateGeneratedRuntimeToolProposal(proposal, options = {}) {
2488
2510
  violations.push(`Generated code matched blocked pattern: ${pattern}`);
2489
2511
  break;
2490
2512
  }
2513
+ const networkViolation = networkAccessViolation(normalized.config.networkAccess, options.allowNetworkAccess);
2514
+ if (networkViolation) violations.push(networkViolation);
2491
2515
  }
2492
2516
  const tool = {
2493
2517
  name: normalized.name,
@@ -13457,7 +13481,7 @@ function transformQueryParams(params) {
13457
13481
  }
13458
13482
  //#endregion
13459
13483
  //#region src/version.ts
13460
- const SDK_VERSION = "10.5.2";
13484
+ const SDK_VERSION = "10.6.0";
13461
13485
  /**
13462
13486
  * Canonical client identity the API uses for attribution
13463
13487
  * (`detectActorSource` in apps/api/src/lib/audit-log.ts keys `'sdk'` off the
@@ -15388,6 +15412,10 @@ const STEP_FIELD_REGISTRY = {
15388
15412
  key: "maxRetries",
15389
15413
  format: "raw"
15390
15414
  },
15415
+ {
15416
+ key: "retryPost",
15417
+ format: "raw"
15418
+ },
15391
15419
  {
15392
15420
  key: "outputVariable",
15393
15421
  format: "json"
package/dist/index.d.cts CHANGED
@@ -117,6 +117,45 @@ interface ContextErrorHandling {
117
117
  * Do not make direct changes to the file.
118
118
  */
119
119
  interface paths {
120
+ "/.well-known/jwks.json": {
121
+ parameters: {
122
+ query?: never;
123
+ header?: never;
124
+ path?: never;
125
+ cookie?: never;
126
+ };
127
+ /**
128
+ * Identity assertion signing keys (JWKS)
129
+ * @description Public keys that verify the Runtype-signed `{{_identity.token}}` a tool call carries. Verify offline: check the ES256 signature against the key whose `kid` matches the token header, then `iss` (pin it to the one Runtype organization you trust: `<API origin>/orgs/<organizationId>`), `aud` (your host), `exp`, and the per-scope assurance in the `runtype` claim. Cache the response for up to five minutes; re-fetch when a token names an unknown `kid`.
130
+ */
131
+ get: {
132
+ parameters: {
133
+ query?: never;
134
+ header?: never;
135
+ path?: never;
136
+ cookie?: never;
137
+ };
138
+ requestBody?: never;
139
+ responses: {
140
+ /** @description The published key set. Empty when this environment has no signing key configured. */
141
+ 200: {
142
+ headers: {
143
+ [name: string]: unknown;
144
+ };
145
+ content: {
146
+ "application/json": components["schemas"]["IdentityAssertionJwks"];
147
+ };
148
+ };
149
+ };
150
+ };
151
+ put?: never;
152
+ post?: never;
153
+ delete?: never;
154
+ options?: never;
155
+ head?: never;
156
+ patch?: never;
157
+ trace?: never;
158
+ };
120
159
  "/v1/agent-aliases": {
121
160
  parameters: {
122
161
  query?: never;
@@ -11835,6 +11874,15 @@ interface paths {
11835
11874
  "application/json": components["schemas"]["Error"];
11836
11875
  };
11837
11876
  };
11877
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
11878
+ 503: {
11879
+ headers: {
11880
+ [name: string]: unknown;
11881
+ };
11882
+ content: {
11883
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
11884
+ };
11885
+ };
11838
11886
  };
11839
11887
  };
11840
11888
  delete?: never;
@@ -12072,6 +12120,15 @@ interface paths {
12072
12120
  "application/json": components["schemas"]["Error"];
12073
12121
  };
12074
12122
  };
12123
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
12124
+ 503: {
12125
+ headers: {
12126
+ [name: string]: unknown;
12127
+ };
12128
+ content: {
12129
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
12130
+ };
12131
+ };
12075
12132
  };
12076
12133
  };
12077
12134
  post?: never;
@@ -40343,6 +40400,15 @@ interface paths {
40343
40400
  "application/json": components["schemas"]["Error"];
40344
40401
  };
40345
40402
  };
40403
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
40404
+ 503: {
40405
+ headers: {
40406
+ [name: string]: unknown;
40407
+ };
40408
+ content: {
40409
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
40410
+ };
40411
+ };
40346
40412
  };
40347
40413
  };
40348
40414
  delete?: never;
@@ -40555,6 +40621,15 @@ interface paths {
40555
40621
  "application/json": components["schemas"]["Error"];
40556
40622
  };
40557
40623
  };
40624
+ /** @description A target record changed while the edit was applied (`record_conflict`); nothing was written, retry the edit */
40625
+ 409: {
40626
+ headers: {
40627
+ [name: string]: unknown;
40628
+ };
40629
+ content: {
40630
+ "application/json": components["schemas"]["Error"];
40631
+ };
40632
+ };
40558
40633
  /** @description A record's post-merge metadata violates its type's collection schema (enforce mode); the whole edit is rejected */
40559
40634
  422: {
40560
40635
  headers: {
@@ -40573,6 +40648,15 @@ interface paths {
40573
40648
  "application/json": components["schemas"]["Error"];
40574
40649
  };
40575
40650
  };
40651
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
40652
+ 503: {
40653
+ headers: {
40654
+ [name: string]: unknown;
40655
+ };
40656
+ content: {
40657
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
40658
+ };
40659
+ };
40576
40660
  };
40577
40661
  };
40578
40662
  delete?: never;
@@ -41179,7 +41263,7 @@ interface paths {
41179
41263
  /** @enum {string} */
41180
41264
  role: "user" | "assistant";
41181
41265
  }[] | null;
41182
- /** @default {} */
41266
+ /** @description Replaces the whole metadata object. Omit to leave metadata unchanged. */
41183
41267
  metadata?: {
41184
41268
  [key: string]: unknown;
41185
41269
  };
@@ -41270,7 +41354,7 @@ interface paths {
41270
41354
  "application/json": components["schemas"]["Error"];
41271
41355
  };
41272
41356
  };
41273
- /** @description Duplicate record */
41357
+ /** @description Duplicate record (`duplicate_record`), or the record changed while this update was applied (`record_conflict`; re-read and retry) */
41274
41358
  409: {
41275
41359
  headers: {
41276
41360
  [name: string]: unknown;
@@ -41297,6 +41381,15 @@ interface paths {
41297
41381
  "application/json": components["schemas"]["Error"];
41298
41382
  };
41299
41383
  };
41384
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
41385
+ 503: {
41386
+ headers: {
41387
+ [name: string]: unknown;
41388
+ };
41389
+ content: {
41390
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
41391
+ };
41392
+ };
41300
41393
  };
41301
41394
  };
41302
41395
  post?: never;
@@ -51195,6 +51288,16 @@ interface components {
51195
51288
  /** @enum {string} */
51196
51289
  status: "pending" | "applied" | "settled" | "not_applied";
51197
51290
  };
51291
+ CollectionLookupFailedError: {
51292
+ /** @enum {string} */
51293
+ code: "COLLECTION_LOOKUP_FAILED";
51294
+ /** @description The record type whose collection schema could not be loaded. */
51295
+ collection: string;
51296
+ /** @description Human-readable refusal; retry the request. */
51297
+ error: string;
51298
+ recordId?: string;
51299
+ recordName?: string;
51300
+ };
51198
51301
  ContextBlocks: {
51199
51302
  blocks: {
51200
51303
  /** @description The block text, scrubbed of secrets. */
@@ -53175,6 +53278,24 @@ interface components {
53175
53278
  valid: boolean;
53176
53279
  warnings: components["schemas"]["FlowValidationIssue"][];
53177
53280
  };
53281
+ IdentityAssertionJwks: {
53282
+ /** @description Every key that may have signed a live assertion: the active key first, then verify-only keys kept for rotation. */
53283
+ keys: components["schemas"]["IdentityAssertionPublicJwk"][];
53284
+ };
53285
+ IdentityAssertionPublicJwk: {
53286
+ /** @description Always `ES256`. */
53287
+ alg: string;
53288
+ /** @description Curve; always `P-256`. */
53289
+ crv: string;
53290
+ /** @description Key id, matched against the token header `kid`. */
53291
+ kid: string;
53292
+ /** @description Key type; always `EC`. */
53293
+ kty: string;
53294
+ /** @description Always `sig`. */
53295
+ use: string;
53296
+ x: string;
53297
+ y: string;
53298
+ };
53178
53299
  InputDeliveryReceipt: {
53179
53300
  deliveryId: string;
53180
53301
  executionId: string;
@@ -56708,8 +56829,23 @@ export interface RuntimeFlowToolConfig {
56708
56829
  export interface RuntimeCustomToolConfig {
56709
56830
  code: string;
56710
56831
  language?: 'javascript' | 'typescript' | 'python';
56711
- sandboxProvider?: 'quickjs' | 'daytona' | 'cloudflare-worker';
56832
+ sandboxProvider?: 'quickjs' | 'daytona' | 'cloudflare-worker' | 'runtype-sandbox';
56712
56833
  timeout?: number;
56834
+ /** Egress posture for the code. Omitted means `'off'`; prefer an `allowedHostnames` list. */
56835
+ networkAccess?: 'off' | 'on' | {
56836
+ allowedHostnames: string[];
56837
+ };
56838
+ /** Managed secrets the code may send, read as phantom tokens from `secrets.<key>`. Requires SECRETS:READ. */
56839
+ secrets?: RuntimeCustomToolSecret[];
56840
+ }
56841
+ /** One managed secret a custom tool may send; the egress proxy injects it only for the matching host and path. */
56842
+ export interface RuntimeCustomToolSecret {
56843
+ /** Bare managed secret name, e.g. `GITHUB_TOKEN`. */
56844
+ key: string;
56845
+ hostnamePattern: string;
56846
+ pathPattern?: string;
56847
+ injectionMode: 'bearer_header' | 'api_key_header' | 'query_param' | 'basic_auth';
56848
+ injectionConfig?: Record<string, JsonValue>;
56713
56849
  }
56714
56850
  export interface RuntimeExternalToolConfig {
56715
56851
  url: string;
@@ -62483,14 +62619,16 @@ interface ApiKeyRequestListParams {
62483
62619
  }
62484
62620
  //#endregion
62485
62621
  //#region src/generated-tool-gate.d.ts
62622
+ declare const CUSTOM_TOOL_SANDBOX_PROVIDERS: readonly ["quickjs", "daytona", "cloudflare-worker", "runtype-sandbox"];
62623
+ type GateSandboxProvider = (typeof CUSTOM_TOOL_SANDBOX_PROVIDERS)[number] | 'cloudflare-sandbox';
62486
62624
  interface GeneratedRuntimeToolGateOptions {
62487
62625
  /**
62488
62626
  * Allowed runtime tool types.
62489
62627
  * Defaults to ['custom'] because this gate is intended for generated code tools.
62490
62628
  */
62491
62629
  allowedToolTypes?: Array<'custom' | 'external' | 'flow' | 'local'>;
62492
- /** Allowed sandbox providers for generated custom tools. Defaults to ['quickjs', 'daytona', 'cloudflare-worker', 'cloudflare-sandbox']. */
62493
- allowedSandboxProviders?: Array<'quickjs' | 'daytona' | 'cloudflare-worker' | 'cloudflare-sandbox'>;
62630
+ /** Allowed sandbox providers for generated custom tools. Defaults to every provider, including runtype-sandbox and its cloudflare-sandbox alias. */
62631
+ allowedSandboxProviders?: GateSandboxProvider[];
62494
62632
  /** Allowed languages for generated custom tools. Defaults to JS/TS/Python. */
62495
62633
  allowedLanguages?: Array<'javascript' | 'typescript' | 'python'>;
62496
62634
  /** Maximum allowed code size in characters (default 12000). */
@@ -62506,6 +62644,15 @@ interface GeneratedRuntimeToolGateOptions {
62506
62644
  blockedCodePatterns?: RegExp[];
62507
62645
  /** Optional custom validator for additional policy checks. Return a violation message to reject. */
62508
62646
  customValidator?: (tool: RuntimeTool) => string | null;
62647
+ /**
62648
+ * Network egress a generated custom tool may request via `config.networkAccess`. Off by default:
62649
+ * a proposal asking for anything but `'off'` is rejected. `true` passes the requested posture
62650
+ * through; `{ allowedHostnames }` accepts only an allowlist within those hosts. A generated tool
62651
+ * can never declare `config.secrets`: managed credentials are always rejected by this gate.
62652
+ */
62653
+ allowNetworkAccess?: boolean | {
62654
+ allowedHostnames: string[];
62655
+ };
62509
62656
  }
62510
62657
  interface GeneratedRuntimeToolGateDecision {
62511
62658
  approved: boolean;
package/dist/index.d.ts CHANGED
@@ -117,6 +117,45 @@ interface ContextErrorHandling {
117
117
  * Do not make direct changes to the file.
118
118
  */
119
119
  interface paths {
120
+ "/.well-known/jwks.json": {
121
+ parameters: {
122
+ query?: never;
123
+ header?: never;
124
+ path?: never;
125
+ cookie?: never;
126
+ };
127
+ /**
128
+ * Identity assertion signing keys (JWKS)
129
+ * @description Public keys that verify the Runtype-signed `{{_identity.token}}` a tool call carries. Verify offline: check the ES256 signature against the key whose `kid` matches the token header, then `iss` (pin it to the one Runtype organization you trust: `<API origin>/orgs/<organizationId>`), `aud` (your host), `exp`, and the per-scope assurance in the `runtype` claim. Cache the response for up to five minutes; re-fetch when a token names an unknown `kid`.
130
+ */
131
+ get: {
132
+ parameters: {
133
+ query?: never;
134
+ header?: never;
135
+ path?: never;
136
+ cookie?: never;
137
+ };
138
+ requestBody?: never;
139
+ responses: {
140
+ /** @description The published key set. Empty when this environment has no signing key configured. */
141
+ 200: {
142
+ headers: {
143
+ [name: string]: unknown;
144
+ };
145
+ content: {
146
+ "application/json": components["schemas"]["IdentityAssertionJwks"];
147
+ };
148
+ };
149
+ };
150
+ };
151
+ put?: never;
152
+ post?: never;
153
+ delete?: never;
154
+ options?: never;
155
+ head?: never;
156
+ patch?: never;
157
+ trace?: never;
158
+ };
120
159
  "/v1/agent-aliases": {
121
160
  parameters: {
122
161
  query?: never;
@@ -11835,6 +11874,15 @@ interface paths {
11835
11874
  "application/json": components["schemas"]["Error"];
11836
11875
  };
11837
11876
  };
11877
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
11878
+ 503: {
11879
+ headers: {
11880
+ [name: string]: unknown;
11881
+ };
11882
+ content: {
11883
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
11884
+ };
11885
+ };
11838
11886
  };
11839
11887
  };
11840
11888
  delete?: never;
@@ -12072,6 +12120,15 @@ interface paths {
12072
12120
  "application/json": components["schemas"]["Error"];
12073
12121
  };
12074
12122
  };
12123
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
12124
+ 503: {
12125
+ headers: {
12126
+ [name: string]: unknown;
12127
+ };
12128
+ content: {
12129
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
12130
+ };
12131
+ };
12075
12132
  };
12076
12133
  };
12077
12134
  post?: never;
@@ -40343,6 +40400,15 @@ interface paths {
40343
40400
  "application/json": components["schemas"]["Error"];
40344
40401
  };
40345
40402
  };
40403
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
40404
+ 503: {
40405
+ headers: {
40406
+ [name: string]: unknown;
40407
+ };
40408
+ content: {
40409
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
40410
+ };
40411
+ };
40346
40412
  };
40347
40413
  };
40348
40414
  delete?: never;
@@ -40555,6 +40621,15 @@ interface paths {
40555
40621
  "application/json": components["schemas"]["Error"];
40556
40622
  };
40557
40623
  };
40624
+ /** @description A target record changed while the edit was applied (`record_conflict`); nothing was written, retry the edit */
40625
+ 409: {
40626
+ headers: {
40627
+ [name: string]: unknown;
40628
+ };
40629
+ content: {
40630
+ "application/json": components["schemas"]["Error"];
40631
+ };
40632
+ };
40558
40633
  /** @description A record's post-merge metadata violates its type's collection schema (enforce mode); the whole edit is rejected */
40559
40634
  422: {
40560
40635
  headers: {
@@ -40573,6 +40648,15 @@ interface paths {
40573
40648
  "application/json": components["schemas"]["Error"];
40574
40649
  };
40575
40650
  };
40651
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
40652
+ 503: {
40653
+ headers: {
40654
+ [name: string]: unknown;
40655
+ };
40656
+ content: {
40657
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
40658
+ };
40659
+ };
40576
40660
  };
40577
40661
  };
40578
40662
  delete?: never;
@@ -41179,7 +41263,7 @@ interface paths {
41179
41263
  /** @enum {string} */
41180
41264
  role: "user" | "assistant";
41181
41265
  }[] | null;
41182
- /** @default {} */
41266
+ /** @description Replaces the whole metadata object. Omit to leave metadata unchanged. */
41183
41267
  metadata?: {
41184
41268
  [key: string]: unknown;
41185
41269
  };
@@ -41270,7 +41354,7 @@ interface paths {
41270
41354
  "application/json": components["schemas"]["Error"];
41271
41355
  };
41272
41356
  };
41273
- /** @description Duplicate record */
41357
+ /** @description Duplicate record (`duplicate_record`), or the record changed while this update was applied (`record_conflict`; re-read and retry) */
41274
41358
  409: {
41275
41359
  headers: {
41276
41360
  [name: string]: unknown;
@@ -41297,6 +41381,15 @@ interface paths {
41297
41381
  "application/json": components["schemas"]["Error"];
41298
41382
  };
41299
41383
  };
41384
+ /** @description The type's collection schema could not be loaded, so the write was refused rather than left unvalidated; retry */
41385
+ 503: {
41386
+ headers: {
41387
+ [name: string]: unknown;
41388
+ };
41389
+ content: {
41390
+ "application/json": components["schemas"]["CollectionLookupFailedError"];
41391
+ };
41392
+ };
41300
41393
  };
41301
41394
  };
41302
41395
  post?: never;
@@ -51195,6 +51288,16 @@ interface components {
51195
51288
  /** @enum {string} */
51196
51289
  status: "pending" | "applied" | "settled" | "not_applied";
51197
51290
  };
51291
+ CollectionLookupFailedError: {
51292
+ /** @enum {string} */
51293
+ code: "COLLECTION_LOOKUP_FAILED";
51294
+ /** @description The record type whose collection schema could not be loaded. */
51295
+ collection: string;
51296
+ /** @description Human-readable refusal; retry the request. */
51297
+ error: string;
51298
+ recordId?: string;
51299
+ recordName?: string;
51300
+ };
51198
51301
  ContextBlocks: {
51199
51302
  blocks: {
51200
51303
  /** @description The block text, scrubbed of secrets. */
@@ -53175,6 +53278,24 @@ interface components {
53175
53278
  valid: boolean;
53176
53279
  warnings: components["schemas"]["FlowValidationIssue"][];
53177
53280
  };
53281
+ IdentityAssertionJwks: {
53282
+ /** @description Every key that may have signed a live assertion: the active key first, then verify-only keys kept for rotation. */
53283
+ keys: components["schemas"]["IdentityAssertionPublicJwk"][];
53284
+ };
53285
+ IdentityAssertionPublicJwk: {
53286
+ /** @description Always `ES256`. */
53287
+ alg: string;
53288
+ /** @description Curve; always `P-256`. */
53289
+ crv: string;
53290
+ /** @description Key id, matched against the token header `kid`. */
53291
+ kid: string;
53292
+ /** @description Key type; always `EC`. */
53293
+ kty: string;
53294
+ /** @description Always `sig`. */
53295
+ use: string;
53296
+ x: string;
53297
+ y: string;
53298
+ };
53178
53299
  InputDeliveryReceipt: {
53179
53300
  deliveryId: string;
53180
53301
  executionId: string;
@@ -56708,8 +56829,23 @@ export interface RuntimeFlowToolConfig {
56708
56829
  export interface RuntimeCustomToolConfig {
56709
56830
  code: string;
56710
56831
  language?: 'javascript' | 'typescript' | 'python';
56711
- sandboxProvider?: 'quickjs' | 'daytona' | 'cloudflare-worker';
56832
+ sandboxProvider?: 'quickjs' | 'daytona' | 'cloudflare-worker' | 'runtype-sandbox';
56712
56833
  timeout?: number;
56834
+ /** Egress posture for the code. Omitted means `'off'`; prefer an `allowedHostnames` list. */
56835
+ networkAccess?: 'off' | 'on' | {
56836
+ allowedHostnames: string[];
56837
+ };
56838
+ /** Managed secrets the code may send, read as phantom tokens from `secrets.<key>`. Requires SECRETS:READ. */
56839
+ secrets?: RuntimeCustomToolSecret[];
56840
+ }
56841
+ /** One managed secret a custom tool may send; the egress proxy injects it only for the matching host and path. */
56842
+ export interface RuntimeCustomToolSecret {
56843
+ /** Bare managed secret name, e.g. `GITHUB_TOKEN`. */
56844
+ key: string;
56845
+ hostnamePattern: string;
56846
+ pathPattern?: string;
56847
+ injectionMode: 'bearer_header' | 'api_key_header' | 'query_param' | 'basic_auth';
56848
+ injectionConfig?: Record<string, JsonValue>;
56713
56849
  }
56714
56850
  export interface RuntimeExternalToolConfig {
56715
56851
  url: string;
@@ -62483,14 +62619,16 @@ interface ApiKeyRequestListParams {
62483
62619
  }
62484
62620
  //#endregion
62485
62621
  //#region src/generated-tool-gate.d.ts
62622
+ declare const CUSTOM_TOOL_SANDBOX_PROVIDERS: readonly ["quickjs", "daytona", "cloudflare-worker", "runtype-sandbox"];
62623
+ type GateSandboxProvider = (typeof CUSTOM_TOOL_SANDBOX_PROVIDERS)[number] | 'cloudflare-sandbox';
62486
62624
  interface GeneratedRuntimeToolGateOptions {
62487
62625
  /**
62488
62626
  * Allowed runtime tool types.
62489
62627
  * Defaults to ['custom'] because this gate is intended for generated code tools.
62490
62628
  */
62491
62629
  allowedToolTypes?: Array<'custom' | 'external' | 'flow' | 'local'>;
62492
- /** Allowed sandbox providers for generated custom tools. Defaults to ['quickjs', 'daytona', 'cloudflare-worker', 'cloudflare-sandbox']. */
62493
- allowedSandboxProviders?: Array<'quickjs' | 'daytona' | 'cloudflare-worker' | 'cloudflare-sandbox'>;
62630
+ /** Allowed sandbox providers for generated custom tools. Defaults to every provider, including runtype-sandbox and its cloudflare-sandbox alias. */
62631
+ allowedSandboxProviders?: GateSandboxProvider[];
62494
62632
  /** Allowed languages for generated custom tools. Defaults to JS/TS/Python. */
62495
62633
  allowedLanguages?: Array<'javascript' | 'typescript' | 'python'>;
62496
62634
  /** Maximum allowed code size in characters (default 12000). */
@@ -62506,6 +62644,15 @@ interface GeneratedRuntimeToolGateOptions {
62506
62644
  blockedCodePatterns?: RegExp[];
62507
62645
  /** Optional custom validator for additional policy checks. Return a violation message to reject. */
62508
62646
  customValidator?: (tool: RuntimeTool) => string | null;
62647
+ /**
62648
+ * Network egress a generated custom tool may request via `config.networkAccess`. Off by default:
62649
+ * a proposal asking for anything but `'off'` is rejected. `true` passes the requested posture
62650
+ * through; `{ allowedHostnames }` accepts only an allowlist within those hosts. A generated tool
62651
+ * can never declare `config.secrets`: managed credentials are always rejected by this gate.
62652
+ */
62653
+ allowNetworkAccess?: boolean | {
62654
+ allowedHostnames: string[];
62655
+ };
62509
62656
  }
62510
62657
  interface GeneratedRuntimeToolGateDecision {
62511
62658
  approved: boolean;
package/dist/index.mjs CHANGED
@@ -2351,12 +2351,13 @@ const DEFAULT_BLOCKED_CODE_PATTERNS = [
2351
2351
  /\bsubprocess\b/i,
2352
2352
  /\bos\.system\s*\(/i
2353
2353
  ];
2354
- const DEFAULT_ALLOWED_SANDBOX_PROVIDERS = [
2354
+ const CUSTOM_TOOL_SANDBOX_PROVIDERS = [
2355
2355
  "quickjs",
2356
2356
  "daytona",
2357
2357
  "cloudflare-worker",
2358
- "cloudflare-sandbox"
2358
+ "runtype-sandbox"
2359
2359
  ];
2360
+ const DEFAULT_ALLOWED_SANDBOX_PROVIDERS = [...CUSTOM_TOOL_SANDBOX_PROVIDERS, "cloudflare-sandbox"];
2360
2361
  const DEFAULT_ALLOWED_LANGUAGES = [
2361
2362
  "javascript",
2362
2363
  "typescript",
@@ -2378,7 +2379,21 @@ function isLanguage(value) {
2378
2379
  return value === "javascript" || value === "typescript" || value === "python";
2379
2380
  }
2380
2381
  function isSandboxProvider(value) {
2381
- return value === "quickjs" || value === "daytona" || value === "cloudflare-worker";
2382
+ return CUSTOM_TOOL_SANDBOX_PROVIDERS.includes(value);
2383
+ }
2384
+ function isNetworkAccess(value) {
2385
+ if (value === "off" || value === "on") return true;
2386
+ if (!isObject(value) || !Array.isArray(value.allowedHostnames)) return false;
2387
+ const hosts = value.allowedHostnames;
2388
+ return hosts.length > 0 && hosts.every((host) => typeof host === "string" && host.length > 0);
2389
+ }
2390
+ /** Why the requested posture exceeds what the caller allowed, or null when it fits. */
2391
+ function networkAccessViolation(requested, allowed) {
2392
+ if (requested === void 0 || requested === "off" || allowed === true) return null;
2393
+ if (!allowed) return "Generated tool requests network access, which this gate does not allow";
2394
+ if (requested === "on") return "Generated tool requests unrestricted network access; only an allowedHostnames list is allowed";
2395
+ const outside = requested.allowedHostnames.filter((host) => !allowed.allowedHostnames.includes(host));
2396
+ return outside.length > 0 ? `Generated tool requests hosts outside the allowed list: ${outside.join(", ")}` : null;
2382
2397
  }
2383
2398
  function isJSONSchema(value) {
2384
2399
  if (!isObject(value)) return false;
@@ -2425,6 +2440,12 @@ function normalizeGeneratedProposal(proposal, violations) {
2425
2440
  const sandboxProviderRaw = config.sandboxProvider;
2426
2441
  const languageRaw = config.language;
2427
2442
  const timeoutRaw = config.timeout;
2443
+ const sandboxProvider = isSandboxProvider(sandboxProviderRaw) ? sandboxProviderRaw : "cloudflare-worker";
2444
+ const language = isLanguage(languageRaw) ? languageRaw : "javascript";
2445
+ const timeout = asNumber(timeoutRaw);
2446
+ if (Array.isArray(config.secrets) && config.secrets.length > 0) violations.push("Generated tools cannot declare config.secrets (managed credentials)");
2447
+ const networkAccess = config.networkAccess;
2448
+ if (networkAccess !== void 0 && !isNetworkAccess(networkAccess)) violations.push("config.networkAccess must be 'off', 'on', or { allowedHostnames: string[] }");
2428
2449
  return {
2429
2450
  name,
2430
2451
  description,
@@ -2432,9 +2453,10 @@ function normalizeGeneratedProposal(proposal, violations) {
2432
2453
  parametersSchema,
2433
2454
  config: {
2434
2455
  code,
2435
- sandboxProvider: isSandboxProvider(sandboxProviderRaw) ? sandboxProviderRaw : "cloudflare-worker",
2436
- language: isLanguage(languageRaw) ? languageRaw : "javascript",
2437
- timeout: asNumber(timeoutRaw)
2456
+ sandboxProvider,
2457
+ language,
2458
+ timeout,
2459
+ ...isNetworkAccess(networkAccess) ? { networkAccess } : {}
2438
2460
  }
2439
2461
  };
2440
2462
  }
@@ -2487,6 +2509,8 @@ function evaluateGeneratedRuntimeToolProposal(proposal, options = {}) {
2487
2509
  violations.push(`Generated code matched blocked pattern: ${pattern}`);
2488
2510
  break;
2489
2511
  }
2512
+ const networkViolation = networkAccessViolation(normalized.config.networkAccess, options.allowNetworkAccess);
2513
+ if (networkViolation) violations.push(networkViolation);
2490
2514
  }
2491
2515
  const tool = {
2492
2516
  name: normalized.name,
@@ -13456,7 +13480,7 @@ function transformQueryParams(params) {
13456
13480
  }
13457
13481
  //#endregion
13458
13482
  //#region src/version.ts
13459
- const SDK_VERSION = "10.5.2";
13483
+ const SDK_VERSION = "10.6.0";
13460
13484
  /**
13461
13485
  * Canonical client identity the API uses for attribution
13462
13486
  * (`detectActorSource` in apps/api/src/lib/audit-log.ts keys `'sdk'` off the
@@ -15387,6 +15411,10 @@ const STEP_FIELD_REGISTRY = {
15387
15411
  key: "maxRetries",
15388
15412
  format: "raw"
15389
15413
  },
15414
+ {
15415
+ key: "retryPost",
15416
+ format: "raw"
15417
+ },
15390
15418
  {
15391
15419
  key: "outputVariable",
15392
15420
  format: "json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runtypelabs/sdk",
3
- "version": "10.5.2",
3
+ "version": "10.6.0",
4
4
  "type": "module",
5
5
  "description": "TypeScript SDK for the Runtype API with fluent methods. Use it to quickly realize AI products, agents, and workflows.",
6
6
  "main": "dist/index.cjs",
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "dependencies": {},
26
26
  "devDependencies": {
27
- "@runtypelabs/shared": "3.65.0",
27
+ "@runtypelabs/shared": "3.67.0",
28
28
  "openapi-typescript": "^7.13.0",
29
29
  "tsdown": "^0.23.0",
30
30
  "typescript": "^6.0.3",