@runtypelabs/cli 2.24.0 → 2.25.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.
Files changed (2) hide show
  1. package/dist/index.js +955 -229
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -549,7 +549,7 @@ import { RuntypeApiError } from "@runtypelabs/sdk";
549
549
  // src/lib/sdk-client.ts
550
550
  import { createClient } from "@runtypelabs/sdk";
551
551
 
552
- // ../shared/dist/chunk-MYXAZOFG.mjs
552
+ // ../shared/dist/chunk-6FWWIIGE.mjs
553
553
  var travrseConfig = {
554
554
  name: "Travrse",
555
555
  nameLower: "travrse",
@@ -573,7 +573,7 @@ var runtypeConfig = {
573
573
  name: "Runtype",
574
574
  nameLower: "runtype",
575
575
  tagline: "Your AI Product Platform",
576
- description: "Build and deploy AI experiences faster than ever. Powerful API for developers, intuitive dashboard for teams.",
576
+ description: "The fastest way to ship agentic products. Prototype in minutes, prove it with evals, and ship to every surface on our cloud or yours.",
577
577
  url: "https://www.runtype.com",
578
578
  website: "https://runtype.com",
579
579
  domain: "runtype.com",
@@ -3060,9 +3060,9 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => {
3060
3060
  $ZodStringFormat.init(inst, def);
3061
3061
  inst._zod.check = (payload) => {
3062
3062
  try {
3063
- const trimmed = payload.value.trim();
3063
+ const trimmed2 = payload.value.trim();
3064
3064
  if (!def.normalize && def.protocol?.source === httpProtocol.source) {
3065
- if (!/^https?:\/\//i.test(trimmed)) {
3065
+ if (!/^https?:\/\//i.test(trimmed2)) {
3066
3066
  payload.issues.push({
3067
3067
  code: "invalid_format",
3068
3068
  format: "url",
@@ -3074,7 +3074,7 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => {
3074
3074
  return;
3075
3075
  }
3076
3076
  }
3077
- const url2 = new URL(trimmed);
3077
+ const url2 = new URL(trimmed2);
3078
3078
  if (def.hostname) {
3079
3079
  def.hostname.lastIndex = 0;
3080
3080
  if (!def.hostname.test(url2.hostname)) {
@@ -3106,7 +3106,7 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => {
3106
3106
  if (def.normalize) {
3107
3107
  payload.value = url2.href;
3108
3108
  } else {
3109
- payload.value = trimmed;
3109
+ payload.value = trimmed2;
3110
3110
  }
3111
3111
  return;
3112
3112
  } catch (_2) {
@@ -15181,7 +15181,7 @@ var edgeContextPayloadSchema = external_exports.object({
15181
15181
  exp: external_exports.number().int().positive()
15182
15182
  });
15183
15183
 
15184
- // ../shared/dist/chunk-3FPSMWBQ.mjs
15184
+ // ../shared/dist/chunk-OOL23ALD.mjs
15185
15185
  function getNestedValue(obj, path19) {
15186
15186
  let normalizedPath = path19;
15187
15187
  normalizedPath = normalizedPath.replace(/^\$\.?/, "");
@@ -15257,8 +15257,8 @@ var RUNTIME_PREFIXES = {
15257
15257
  };
15258
15258
  var PREFIX_PATTERN = /^([A-Za-z][A-Za-z0-9_-]*):(.*)$/s;
15259
15259
  function classifyVariableReference(token) {
15260
- const trimmed = token.trim();
15261
- const prefixMatch = PREFIX_PATTERN.exec(trimmed);
15260
+ const trimmed2 = token.trim();
15261
+ const prefixMatch = PREFIX_PATTERN.exec(trimmed2);
15262
15262
  if (prefixMatch) {
15263
15263
  const prefix = `${prefixMatch[1]}:`;
15264
15264
  const rest = prefixMatch[2] ?? "";
@@ -15266,12 +15266,12 @@ function classifyVariableReference(token) {
15266
15266
  if (spec) {
15267
15267
  return { namespace: spec.namespace, baseName: rest.trim() };
15268
15268
  }
15269
- return { namespace: "unknown", raw: trimmed };
15269
+ return { namespace: "unknown", raw: trimmed2 };
15270
15270
  }
15271
- if (isSystemVariable(trimmed)) {
15272
- return { namespace: "system", baseName: trimmed };
15271
+ if (isSystemVariable(trimmed2)) {
15272
+ return { namespace: "system", baseName: trimmed2 };
15273
15273
  }
15274
- return { namespace: "plain", baseName: trimmed };
15274
+ return { namespace: "plain", baseName: trimmed2 };
15275
15275
  }
15276
15276
  function isSystemVariable(varName) {
15277
15277
  const rootSegment = varName.split(".")[0] || "";
@@ -15287,15 +15287,15 @@ function parseTemplateExpression(expr) {
15287
15287
  operands: tokens.rawOperands.map(parseOperand)
15288
15288
  };
15289
15289
  }
15290
- const trimmed = expr.trim();
15291
- const pipeIndex = trimmed.indexOf("|");
15290
+ const trimmed2 = expr.trim();
15291
+ const pipeIndex = trimmed2.indexOf("|");
15292
15292
  if (pipeIndex === -1) {
15293
- return { kind: "legacy", variable: trimmed };
15293
+ return { kind: "legacy", variable: trimmed2 };
15294
15294
  }
15295
15295
  return {
15296
15296
  kind: "legacy",
15297
- variable: trimmed.slice(0, pipeIndex).trim(),
15298
- defaultValue: trimmed.slice(pipeIndex + 1).trim()
15297
+ variable: trimmed2.slice(0, pipeIndex).trim(),
15298
+ defaultValue: trimmed2.slice(pipeIndex + 1).trim()
15299
15299
  };
15300
15300
  }
15301
15301
  function tokenizeFallbackExpression(expr) {
@@ -15566,7 +15566,7 @@ function resolveFallback(parsed, context, tracking) {
15566
15566
  }
15567
15567
  var templateEngine = new SimpleTemplateEngine();
15568
15568
 
15569
- // ../shared/dist/chunk-MMDRPM6Q.mjs
15569
+ // ../shared/dist/chunk-CNO2UJFO.mjs
15570
15570
  var tokensSchema = external_exports.object({ input: external_exports.number(), output: external_exports.number() });
15571
15571
  var wireStopReasonSchema = external_exports.enum([
15572
15572
  "end_turn",
@@ -15641,7 +15641,13 @@ var unifiedExecutionErrorEventSchema = external_exports.object({
15641
15641
  error: unifiedErrorPayloadSchema,
15642
15642
  completedAt: external_exports.string().optional(),
15643
15643
  code: external_exports.string().optional(),
15644
- upgradeUrl: external_exports.string().optional()
15644
+ upgradeUrl: external_exports.string().optional(),
15645
+ // Structured discriminant for a platform-key spend block (credit_exhausted |
15646
+ // trial_expired | auto_topup_failed) so the dashboard paywall can render
15647
+ // differentiated copy. The `PlatformKeyBlockReason` union lives in
15648
+ // `@runtypelabs/model-execution`, which `shared` cannot import — typed as a
15649
+ // string to mirror the sibling `code` / `upgradeUrl` fields.
15650
+ blockReason: external_exports.string().optional()
15645
15651
  });
15646
15652
  var unifiedTurnStartEventSchema = external_exports.object({
15647
15653
  ...unifiedBase,
@@ -15867,7 +15873,11 @@ var unifiedToolCompleteEventSchema = external_exports.object({
15867
15873
  });
15868
15874
  var unifiedSubagentAttributionSchema = external_exports.object({
15869
15875
  toolName: external_exports.string(),
15870
- agentName: external_exports.string().optional()
15876
+ agentName: external_exports.string().optional(),
15877
+ // Parent-stream correlation id: the subagent tool bubble the client already
15878
+ // saw (the approval's own `toolCallId` is the muted child's never-streamed
15879
+ // tool_use id).
15880
+ parentToolCallId: external_exports.string().optional()
15871
15881
  });
15872
15882
  var unifiedApprovalStartEventSchema = external_exports.object({
15873
15883
  ...unifiedBase,
@@ -15904,7 +15914,17 @@ var unifiedAwaitEventSchema = external_exports.object({
15904
15914
  parameters: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
15905
15915
  awaitedAt: external_exports.string().optional(),
15906
15916
  origin: external_exports.enum(["webmcp", "sdk"]).optional(),
15907
- pageOrigin: external_exports.string().optional()
15917
+ pageOrigin: external_exports.string().optional(),
15918
+ // Discriminates an AUTO-RESUMING durable pause (`crawl_pending` /
15919
+ // `durable_poll`, resumed server-side by the crawl / wait-until
15920
+ // Workflow) from a CLIENT-RESOLVABLE local-tool / WebMCP await (absent), so a
15921
+ // streaming consumer does not render a "resume" prompt for a pause that
15922
+ // resumes itself. Mirrors the JSON `pausedReason` discriminator
15923
+ // (execution-pipeline.ts); the server-resumed pauses carry `crawlId` /
15924
+ // `stepId` instead of the tool fields. UX context; never a control signal.
15925
+ awaitReason: external_exports.string().optional(),
15926
+ crawlId: external_exports.string().optional(),
15927
+ stepId: external_exports.string().optional()
15908
15928
  });
15909
15929
  var unifiedErrorEventSchema = external_exports.object({
15910
15930
  ...unifiedBase,
@@ -16024,7 +16044,8 @@ var externalAgentContextSchema = external_exports.object({
16024
16044
  });
16025
16045
  var subagentAttributionSchema = external_exports.object({
16026
16046
  toolName: external_exports.string(),
16027
- agentName: external_exports.string().optional()
16047
+ agentName: external_exports.string().optional(),
16048
+ parentToolCallId: external_exports.string().optional()
16028
16049
  });
16029
16050
  var tokensSchema2 = external_exports.object({ input: external_exports.number(), output: external_exports.number() });
16030
16051
  var wireStopReasonSchema2 = external_exports.enum([
@@ -16383,6 +16404,11 @@ var flowErrorEventSchema = external_exports.object({
16383
16404
  // Spread only on platform-key spend errors (api raw-write).
16384
16405
  code: external_exports.string().optional(),
16385
16406
  upgradeUrl: external_exports.string().optional(),
16407
+ // Structured discriminant for a platform-key spend block (credit_exhausted |
16408
+ // trial_expired | auto_topup_failed). Typed as a string here because the
16409
+ // `PlatformKeyBlockReason` union lives in `@runtypelabs/model-execution`,
16410
+ // which `shared` cannot import — mirrors the sibling `code` / `upgradeUrl`.
16411
+ blockReason: external_exports.string().optional(),
16386
16412
  timestamp: external_exports.string().optional(),
16387
16413
  flowId: external_exports.string().optional(),
16388
16414
  toolContext: toolContextSchema.optional()
@@ -16400,7 +16426,23 @@ var flowAwaitEventSchema = external_exports.object({
16400
16426
  parameters: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
16401
16427
  awaitedAt: external_exports.string(),
16402
16428
  origin: external_exports.enum(["webmcp", "sdk"]).optional(),
16403
- pageOrigin: external_exports.string().optional()
16429
+ pageOrigin: external_exports.string().optional(),
16430
+ // Discriminates an AUTO-RESUMING durable pause (`crawl_pending` /
16431
+ // `durable_poll`, resumed server-side by the crawl / wait-until
16432
+ // Workflow) from a CLIENT-RESOLVABLE local-tool / WebMCP await (absent). The
16433
+ // server-resumed pauses carry `crawlId` / `stepId` instead of the tool fields.
16434
+ // Open `z.string()` (not an enum) for forward-compat — kept in lockstep with
16435
+ // the JSON `pausedReason` discriminator in execution-pipeline.ts. UX context;
16436
+ // never a control signal.
16437
+ awaitReason: external_exports.string().optional(),
16438
+ crawlId: external_exports.string().optional(),
16439
+ stepId: external_exports.string().optional(),
16440
+ // Approval pauses (`awaitReason: 'approval_required'`) carry the approval
16441
+ // handle + configured timeout (ms). The flow→agent bridges and the unified
16442
+ // translator key on `approvalId` to surface the pause as an approval event
16443
+ // instead of a local-tool await.
16444
+ approvalId: external_exports.string().optional(),
16445
+ timeout: external_exports.number().optional()
16404
16446
  });
16405
16447
  var stepStartEventSchema = external_exports.object({
16406
16448
  ...baseFlowEvent,
@@ -16691,6 +16733,7 @@ var AGENT_CONTENT_CONFIG_KEYS = {
16691
16733
  errorHandling: true,
16692
16734
  artifacts: true,
16693
16735
  loggingPolicy: true,
16736
+ piiRedaction: true,
16694
16737
  temporal: true,
16695
16738
  memory: true,
16696
16739
  sandbox: true,
@@ -17604,6 +17647,51 @@ var retrieveRecordConfigSchema = external_exports.object({
17604
17647
  includeMetadata: external_exports.boolean().optional(),
17605
17648
  streamOutput: external_exports.boolean().optional()
17606
17649
  });
17650
+ var LIST_RECORDS_MAX_LIMIT = 1e3;
17651
+ var hasNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
17652
+ var getRecordConfigSchema = external_exports.object({
17653
+ recordId: external_exports.string().optional(),
17654
+ recordType: external_exports.string().optional(),
17655
+ recordName: external_exports.string().optional(),
17656
+ recordFilter: recordFilterSchema.optional(),
17657
+ fieldsToInclude: external_exports.string().optional(),
17658
+ fieldsToExclude: external_exports.string().optional(),
17659
+ availableFields: external_exports.array(external_exports.string()).optional(),
17660
+ includeMetadata: external_exports.boolean().optional(),
17661
+ streamOutput: external_exports.boolean().optional(),
17662
+ outputVariable: external_exports.string().min(1, "Output variable is required")
17663
+ }).superRefine((config3, ctx) => {
17664
+ const hasFilterType = hasNonEmptyString(config3.recordFilter?.type);
17665
+ if (!hasNonEmptyString(config3.recordId) && !hasNonEmptyString(config3.recordType) && !hasNonEmptyString(config3.recordName) && !hasFilterType) {
17666
+ ctx.addIssue({
17667
+ code: "custom",
17668
+ path: ["recordId"],
17669
+ message: "get-record step requires at least one of 'recordId', 'recordType', 'recordName', or 'recordFilter'"
17670
+ });
17671
+ }
17672
+ });
17673
+ var listRecordsConfigSchema = external_exports.object({
17674
+ recordType: external_exports.string().optional(),
17675
+ recordName: external_exports.string().optional(),
17676
+ recordFilter: recordFilterSchema.optional(),
17677
+ limit: external_exports.number().int().min(1).max(LIST_RECORDS_MAX_LIMIT).optional(),
17678
+ onEmpty: external_exports.enum(["succeed", "fail"]).optional(),
17679
+ fieldsToInclude: external_exports.string().optional(),
17680
+ fieldsToExclude: external_exports.string().optional(),
17681
+ availableFields: external_exports.array(external_exports.string()).optional(),
17682
+ includeMetadata: external_exports.boolean().optional(),
17683
+ streamOutput: external_exports.boolean().optional(),
17684
+ outputVariable: external_exports.string().min(1, "Output variable is required")
17685
+ }).superRefine((config3, ctx) => {
17686
+ const hasFilterType = hasNonEmptyString(config3.recordFilter?.type);
17687
+ if (!hasNonEmptyString(config3.recordType) && !hasNonEmptyString(config3.recordName) && !hasFilterType) {
17688
+ ctx.addIssue({
17689
+ code: "custom",
17690
+ path: ["recordType"],
17691
+ message: "list-records step requires at least one of 'recordType', 'recordName', or 'recordFilter'"
17692
+ });
17693
+ }
17694
+ });
17607
17695
  var updateRecordConfigSchema = external_exports.object({
17608
17696
  recordId: external_exports.string().optional(),
17609
17697
  recordType: external_exports.string().optional(),
@@ -17832,6 +17920,8 @@ var sharedStepConfigSchemas = {
17832
17920
  "send-email": sendEmailConfigSchema,
17833
17921
  "paginate-api": paginateApiConfigSchema,
17834
17922
  "retrieve-record": retrieveRecordConfigSchema,
17923
+ "get-record": getRecordConfigSchema,
17924
+ "list-records": listRecordsConfigSchema,
17835
17925
  "update-record": updateRecordConfigSchema,
17836
17926
  "transform-data": transformDataConfigSchema,
17837
17927
  prompt: promptConfigSchema,
@@ -17859,6 +17949,8 @@ var CONTEXT_STEP_TYPES = [
17859
17949
  "crawl",
17860
17950
  "fetch-url",
17861
17951
  "retrieve-record",
17952
+ "get-record",
17953
+ "list-records",
17862
17954
  "fetch-github",
17863
17955
  "api-call",
17864
17956
  "transform-data",
@@ -17950,6 +18042,52 @@ function isCustomSendFromAddressOnManagedDomain(configuredFrom, preferredManaged
17950
18042
  preferredManagedDomain
17951
18043
  );
17952
18044
  }
18045
+ function isPlainObject9(value) {
18046
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18047
+ }
18048
+ function trimmed(value) {
18049
+ return typeof value === "string" ? value.trim() : "";
18050
+ }
18051
+ function retrieveRecordProducesArray(config3) {
18052
+ const recordId = trimmed(config3.recordId);
18053
+ if (recordId) return false;
18054
+ if (config3.retrievalMode && config3.retrievalMode !== "query") return false;
18055
+ const recordType = trimmed(config3.recordType);
18056
+ const recordName = trimmed(config3.recordName);
18057
+ const filter = config3.recordFilter;
18058
+ const filterType = isPlainObject9(filter) ? trimmed(filter.type) : "";
18059
+ return !!(recordType || recordName || filterType);
18060
+ }
18061
+ function resolveRetrieveRecordAlias(config3) {
18062
+ const common = {
18063
+ recordType: config3.recordType,
18064
+ recordName: config3.recordName,
18065
+ recordFilter: config3.recordFilter,
18066
+ fieldsToInclude: config3.fieldsToInclude,
18067
+ fieldsToExclude: config3.fieldsToExclude,
18068
+ availableFields: config3.availableFields,
18069
+ includeMetadata: config3.includeMetadata,
18070
+ streamOutput: config3.streamOutput,
18071
+ outputVariable: config3.outputVariable
18072
+ };
18073
+ if (retrieveRecordProducesArray(config3)) {
18074
+ return {
18075
+ type: "list-records",
18076
+ config: {
18077
+ ...common,
18078
+ limit: LIST_RECORDS_MAX_LIMIT,
18079
+ onEmpty: "fail"
18080
+ }
18081
+ };
18082
+ }
18083
+ return {
18084
+ type: "get-record",
18085
+ config: {
18086
+ recordId: config3.recordId,
18087
+ ...common
18088
+ }
18089
+ };
18090
+ }
17953
18091
  var NormalizationError = class extends Error {
17954
18092
  constructor(message, stepType, fieldName, expectedType, actualValue) {
17955
18093
  super(message);
@@ -18152,6 +18290,8 @@ function normalizeContextStep(apiStep, options = {}) {
18152
18290
  "crawl",
18153
18291
  "fetch-url",
18154
18292
  "retrieve-record",
18293
+ "get-record",
18294
+ "list-records",
18155
18295
  "fetch-github",
18156
18296
  "api-call",
18157
18297
  "transform-data",
@@ -18208,11 +18348,26 @@ function normalizeContextStep(apiStep, options = {}) {
18208
18348
  type: "fetch-url",
18209
18349
  config: normalizeFetchUrlConfig(apiStep.config)
18210
18350
  };
18211
- case "retrieve-record":
18351
+ case "retrieve-record": {
18352
+ const legacyConfig = normalizeRetrieveRecordConfig(apiStep.config);
18353
+ const aliased = resolveRetrieveRecordAlias(legacyConfig);
18354
+ return {
18355
+ ...baseStep,
18356
+ type: aliased.type,
18357
+ config: aliased.config
18358
+ };
18359
+ }
18360
+ case "get-record":
18212
18361
  return {
18213
18362
  ...baseStep,
18214
- type: "retrieve-record",
18215
- config: normalizeRetrieveRecordConfig(apiStep.config)
18363
+ type: "get-record",
18364
+ config: normalizeGetRecordConfig(apiStep.config)
18365
+ };
18366
+ case "list-records":
18367
+ return {
18368
+ ...baseStep,
18369
+ type: "list-records",
18370
+ config: normalizeListRecordsConfig(apiStep.config)
18216
18371
  };
18217
18372
  case "fetch-github":
18218
18373
  return {
@@ -18612,6 +18767,84 @@ function normalizeRetrieveRecordConfig(config3) {
18612
18767
  outputVariable: config3.outputVariable
18613
18768
  };
18614
18769
  }
18770
+ function normalizeGetRecordConfig(config3) {
18771
+ validateConfig(config3, "get-record");
18772
+ const filter = config3.recordFilter;
18773
+ const hasFilter = filter && typeof filter === "object" && typeof filter.type === "string" && filter.type.length > 0;
18774
+ if (!config3.recordId && !config3.recordType && !config3.recordName && !hasFilter) {
18775
+ throw new NormalizationError(
18776
+ `get-record step requires at least one of 'recordId', 'recordType', 'recordName', or 'recordFilter'`,
18777
+ "get-record",
18778
+ "recordId/recordType/recordName/recordFilter",
18779
+ "at least one identification field",
18780
+ void 0
18781
+ );
18782
+ }
18783
+ validateString(config3.outputVariable, "outputVariable", "get-record", true);
18784
+ if (config3.fieldsToInclude)
18785
+ validateString(config3.fieldsToInclude, "fieldsToInclude", "get-record");
18786
+ if (config3.fieldsToExclude)
18787
+ validateString(config3.fieldsToExclude, "fieldsToExclude", "get-record");
18788
+ if (config3.availableFields)
18789
+ validateArray(config3.availableFields, "availableFields", "get-record");
18790
+ if (config3.includeMetadata !== void 0)
18791
+ validateBoolean(config3.includeMetadata, "includeMetadata", "get-record");
18792
+ if (config3.streamOutput !== void 0)
18793
+ validateBoolean(config3.streamOutput, "streamOutput", "get-record");
18794
+ return {
18795
+ recordId: config3.recordId,
18796
+ recordType: config3.recordType,
18797
+ recordName: config3.recordName,
18798
+ recordFilter: config3.recordFilter,
18799
+ fieldsToInclude: config3.fieldsToInclude,
18800
+ fieldsToExclude: config3.fieldsToExclude,
18801
+ availableFields: config3.availableFields,
18802
+ includeMetadata: config3.includeMetadata,
18803
+ streamOutput: config3.streamOutput,
18804
+ outputVariable: config3.outputVariable
18805
+ };
18806
+ }
18807
+ function normalizeListRecordsConfig(config3) {
18808
+ validateConfig(config3, "list-records");
18809
+ const filter = config3.recordFilter;
18810
+ const hasFilter = filter && typeof filter === "object" && typeof filter.type === "string" && filter.type.length > 0;
18811
+ if (!config3.recordType && !config3.recordName && !hasFilter) {
18812
+ throw new NormalizationError(
18813
+ `list-records step requires at least one of 'recordType', 'recordName', or 'recordFilter'`,
18814
+ "list-records",
18815
+ "recordType/recordName/recordFilter",
18816
+ "at least one query field",
18817
+ void 0
18818
+ );
18819
+ }
18820
+ validateString(config3.outputVariable, "outputVariable", "list-records", true);
18821
+ if (config3.limit !== void 0) validateNumber(config3.limit, "limit", "list-records");
18822
+ if (config3.onEmpty !== void 0)
18823
+ validateEnum(config3.onEmpty, ["succeed", "fail"], "onEmpty", "list-records");
18824
+ if (config3.fieldsToInclude)
18825
+ validateString(config3.fieldsToInclude, "fieldsToInclude", "list-records");
18826
+ if (config3.fieldsToExclude)
18827
+ validateString(config3.fieldsToExclude, "fieldsToExclude", "list-records");
18828
+ if (config3.availableFields)
18829
+ validateArray(config3.availableFields, "availableFields", "list-records");
18830
+ if (config3.includeMetadata !== void 0)
18831
+ validateBoolean(config3.includeMetadata, "includeMetadata", "list-records");
18832
+ if (config3.streamOutput !== void 0)
18833
+ validateBoolean(config3.streamOutput, "streamOutput", "list-records");
18834
+ return {
18835
+ recordType: config3.recordType,
18836
+ recordName: config3.recordName,
18837
+ recordFilter: config3.recordFilter,
18838
+ limit: normalizeOptionalNumber(config3.limit),
18839
+ onEmpty: config3.onEmpty,
18840
+ fieldsToInclude: config3.fieldsToInclude,
18841
+ fieldsToExclude: config3.fieldsToExclude,
18842
+ availableFields: config3.availableFields,
18843
+ includeMetadata: config3.includeMetadata,
18844
+ streamOutput: config3.streamOutput,
18845
+ outputVariable: config3.outputVariable
18846
+ };
18847
+ }
18615
18848
  function normalizeFetchGithubConfig(config3) {
18616
18849
  validateConfig(config3, "fetch-github");
18617
18850
  validateString(config3.repository, "repository", "fetch-github", true);
@@ -19842,6 +20075,7 @@ function sanitizeCodeToolIdentifier(name) {
19842
20075
  if (/^[0-9]/.test(safe)) safe = "_" + safe;
19843
20076
  return safe;
19844
20077
  }
20078
+ var MAX_DURABLE_POLL_ATTEMPTS = 1e3;
19845
20079
  var flowStepValidationSchema = external_exports.object({
19846
20080
  // Optional stable client-supplied identifier. Preserved across saves so that
19847
20081
  // `flow_step_results.stepId` references stay valid and dashboard UI state
@@ -19907,7 +20141,12 @@ var LEGACY_TOOL_KEY_SUGGESTIONS = {
19907
20141
  function isObjectRecord(value) {
19908
20142
  return typeof value === "object" && value !== null && !Array.isArray(value);
19909
20143
  }
19910
- var NETWORK_ISOLATED_SANDBOX_PROVIDERS = /* @__PURE__ */ new Set(["cloudflare-worker", "quickjs"]);
20144
+ var NETWORK_ISOLATED_SANDBOX_PROVIDERS = /* @__PURE__ */ new Set([
20145
+ "cloudflare-worker",
20146
+ "quickjs",
20147
+ "runtype-sandbox",
20148
+ "cloudflare-sandbox"
20149
+ ]);
19911
20150
  var MAX_CONDITIONAL_NESTING_DEPTH = 10;
19912
20151
  var FETCH_CALL_PATTERN = /\bfetch\s*\(/;
19913
20152
  function validateSandboxNetworkAccess(config3, stepIndex, stepRef, buckets) {
@@ -20515,6 +20754,134 @@ function validateConditionExpressions(flowSteps, buckets, conditionalStepsExceed
20515
20754
  walkStepConditionExpressions(step, `flowSteps[${stepIndex}]`, stepRef, buckets, 1);
20516
20755
  }
20517
20756
  }
20757
+ var TOOL_STRATEGY_REQUIRED_MULTISTEP_CODE = "TOOL_STRATEGY_REQUIRED_MULTISTEP";
20758
+ function isRequiredMultiStepFootgun(input) {
20759
+ if (input.toolCallStrategy !== "required") return false;
20760
+ if (typeof input.maxTurns === "number" && input.maxTurns > 1) return true;
20761
+ return input.maxToolCalls !== 1;
20762
+ }
20763
+ function toolStrategyRequiredMultiStepMessage() {
20764
+ return 'Tool call strategy "required" forces the model to call a tool on every step. Unless the turn is capped to a single tool call (maxToolCalls of 1), the model can never return a final text answer and the output comes back empty \u2014 the runtime default allows multiple tool calls, so leaving maxToolCalls unset (or above 1), or running a multi-turn loop, triggers this. Use "auto" (recommended) so the model decides when to call tools and can finish with text, or keep "required" only for a single forced tool call (maxToolCalls of 1, no loop).';
20765
+ }
20766
+ function validateToolCallStrategyMultiStep(flowSteps, buckets) {
20767
+ for (const [stepIndex, step] of flowSteps.entries()) {
20768
+ if (step.enabled === false) continue;
20769
+ if (step.type !== "prompt") continue;
20770
+ if (!isObjectRecord(step.config)) continue;
20771
+ const tools = step.config.tools;
20772
+ if (!isObjectRecord(tools)) continue;
20773
+ const toolCallStrategy = tools.toolCallStrategy ?? tools.tool_call_strategy;
20774
+ const maxToolCallsRaw = tools.maxToolCalls ?? tools.max_tool_calls;
20775
+ const maxToolCalls = typeof maxToolCallsRaw === "number" ? maxToolCallsRaw : void 0;
20776
+ if (isRequiredMultiStepFootgun({ toolCallStrategy, maxToolCalls })) {
20777
+ addIssue(
20778
+ "warning",
20779
+ {
20780
+ code: TOOL_STRATEGY_REQUIRED_MULTISTEP_CODE,
20781
+ message: toolStrategyRequiredMultiStepMessage(),
20782
+ path: `flowSteps[${stepIndex}].config.tools`,
20783
+ step: { index: stepIndex, name: step.name, type: step.type },
20784
+ details: { toolCallStrategy: "required", maxToolCalls }
20785
+ },
20786
+ buckets
20787
+ );
20788
+ }
20789
+ }
20790
+ }
20791
+ var WAIT_UNTIL_MAX_ATTEMPTS_CLAMPED_CODE = "WAIT_UNTIL_MAX_ATTEMPTS_CLAMPED";
20792
+ function validateWaitUntilPollBudget(flowSteps, buckets) {
20793
+ for (const [stepIndex, step] of flowSteps.entries()) {
20794
+ if (step.enabled === false) continue;
20795
+ if (step.type !== "wait-until") continue;
20796
+ if (!isObjectRecord(step.config)) continue;
20797
+ const poll = step.config.poll;
20798
+ if (!isObjectRecord(poll)) continue;
20799
+ const maxAttempts = poll.maxAttempts;
20800
+ if (typeof maxAttempts !== "number" || maxAttempts <= MAX_DURABLE_POLL_ATTEMPTS) continue;
20801
+ addIssue(
20802
+ "warning",
20803
+ {
20804
+ code: WAIT_UNTIL_MAX_ATTEMPTS_CLAMPED_CODE,
20805
+ message: `poll.maxAttempts (${maxAttempts}) exceeds the durable poll budget of ${MAX_DURABLE_POLL_ATTEMPTS} attempts; when this step runs as a durable Workflow poll the attempt count is clamped to ${MAX_DURABLE_POLL_ATTEMPTS}. To cover the same wall-clock window, increase poll.intervalMs instead of adding attempts.`,
20806
+ path: `flowSteps[${stepIndex}].config.poll.maxAttempts`,
20807
+ step: { index: stepIndex, name: step.name, type: step.type },
20808
+ details: { maxAttempts, maxDurablePollAttempts: MAX_DURABLE_POLL_ATTEMPTS }
20809
+ },
20810
+ buckets
20811
+ );
20812
+ }
20813
+ }
20814
+ var LIST_RECORDS_OBJECT_ACCESS_CODE = "LIST_RECORDS_OBJECT_ACCESS";
20815
+ var DEPRECATED_STEP_TYPE_CODE = "DEPRECATED_STEP_TYPE";
20816
+ function stepProducesRecordArray(type, config3) {
20817
+ if (type === "list-records") return true;
20818
+ if (type === "retrieve-record") {
20819
+ return resolveRetrieveRecordAlias(config3).type === "list-records";
20820
+ }
20821
+ return false;
20822
+ }
20823
+ function validateListRecordsArrayAccess(flowSteps, buckets) {
20824
+ const arrayOutputs = /* @__PURE__ */ new Map();
20825
+ for (const [stepIndex, step] of flowSteps.entries()) {
20826
+ if (step.enabled === false) continue;
20827
+ if (!isObjectRecord(step.config)) continue;
20828
+ const config3 = step.config;
20829
+ for (const { variable, fieldPath } of extractVariableReferences(config3)) {
20830
+ const classification = classifyVariableReference(variable);
20831
+ if (classification.namespace !== "plain" && classification.namespace !== "flow") continue;
20832
+ const segments = classification.baseName.split(".");
20833
+ const root = segments[0] || "";
20834
+ const origin = arrayOutputs.get(root);
20835
+ if (!origin) continue;
20836
+ if (segments.length < 2) continue;
20837
+ const field = segments[1] || "";
20838
+ if (/^\d+$/.test(field) || field === "length") continue;
20839
+ addIssue(
20840
+ "warning",
20841
+ {
20842
+ code: LIST_RECORDS_OBJECT_ACCESS_CODE,
20843
+ message: `Variable "{{${variable}}}" reads field "${field}" on "${root}", but step "${origin.name}" returns an ARRAY of records (even when a single record matches). Object-style access resolves to undefined at runtime. Index into the array first \u2014 e.g. "{{${root}.0.${field}}}" for the first record \u2014 or loop over "${root}". To get a single record object, use a get-record step.`,
20844
+ path: `flowSteps[${stepIndex}].config.${fieldPath}`,
20845
+ step: { index: stepIndex, name: step.name, type: step.type },
20846
+ details: {
20847
+ variable,
20848
+ rootVariable: root,
20849
+ field,
20850
+ originStepIndex: origin.index,
20851
+ originStepName: origin.name
20852
+ }
20853
+ },
20854
+ buckets
20855
+ );
20856
+ }
20857
+ const outputVar = getStepOutputVariable(step);
20858
+ if (outputVar) {
20859
+ if (stepProducesRecordArray(step.type, config3)) {
20860
+ arrayOutputs.set(outputVar, { index: stepIndex, name: step.name });
20861
+ } else {
20862
+ arrayOutputs.delete(outputVar);
20863
+ }
20864
+ }
20865
+ }
20866
+ }
20867
+ function validateDeprecatedStepTypes(flowSteps, buckets) {
20868
+ for (const [stepIndex, step] of flowSteps.entries()) {
20869
+ if (step.type !== "retrieve-record") continue;
20870
+ const config3 = isObjectRecord(step.config) ? step.config : {};
20871
+ const resolvedType = resolveRetrieveRecordAlias(config3).type;
20872
+ addIssue(
20873
+ "warning",
20874
+ {
20875
+ code: DEPRECATED_STEP_TYPE_CODE,
20876
+ message: `The "retrieve-record" step is deprecated. Use "get-record" (returns a single record object) or "list-records" (returns an array of records) instead \u2014 this config resolves to "${resolvedType}".`,
20877
+ path: `flowSteps[${stepIndex}].type`,
20878
+ step: { index: stepIndex, name: step.name, type: step.type },
20879
+ details: { deprecatedType: "retrieve-record", resolvedType }
20880
+ },
20881
+ buckets
20882
+ );
20883
+ }
20884
+ }
20518
20885
  function collectAccountScopedReferences(step, stepIndex, pendingChecks) {
20519
20886
  const stepRef = {
20520
20887
  index: stepIndex,
@@ -21098,6 +21465,10 @@ function collectFlowStructureIssues(flowData, deps, buckets) {
21098
21465
  validateUpsertRecordSourceShape(flowData.flowSteps, buckets);
21099
21466
  validateStoreVectorSource(flowData.flowSteps, buckets, deps.declaredFlowInputs);
21100
21467
  validateConditionExpressions(flowData.flowSteps, buckets, conditionalStepsExceedingDepth);
21468
+ validateToolCallStrategyMultiStep(flowData.flowSteps, buckets);
21469
+ validateListRecordsArrayAccess(flowData.flowSteps, buckets);
21470
+ validateWaitUntilPollBudget(flowData.flowSteps, buckets);
21471
+ validateDeprecatedStepTypes(flowData.flowSteps, buckets);
21101
21472
  return { pendingChecks };
21102
21473
  }
21103
21474
  function validateFlowStructure(flowData, deps = {}) {
@@ -33327,7 +33698,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
33327
33698
  {
33328
33699
  id: "exa",
33329
33700
  name: "Exa",
33330
- description: "Search the web using neural and keyword algorithms. Returns relevant content with optional summaries, highlights, and full text.",
33701
+ description: "Search the web using neural and keyword algorithms. Returns relevant content with optional summaries, highlights, and full text. Tuned for retrieval and not blocked by anti-bot defenses, so prefer this over the raw fetch-url/crawl flow steps for research against sites that block datacenter traffic.",
33331
33702
  category: BuiltInToolCategory.WEB_SEARCH,
33332
33703
  providers: [BuiltInToolProvider.MULTI],
33333
33704
  parametersSchema: {
@@ -33402,7 +33773,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
33402
33773
  {
33403
33774
  id: "firecrawl",
33404
33775
  name: "Firecrawl",
33405
- description: "Scrape and extract content from a URL as markdown. Provide a url and optional formats array.",
33776
+ description: "Scrape and extract content from a URL as markdown. Provide a url and optional formats array. Handles rendering and anti-bot measures, so prefer this over a raw HTTP fetch when a site blocks, rate-limits, or challenges datacenter (non-human) traffic.",
33406
33777
  category: BuiltInToolCategory.WEB_SCRAPING,
33407
33778
  providers: [BuiltInToolProvider.MULTI],
33408
33779
  parametersSchema: {
@@ -37589,7 +37960,11 @@ var BUILT_IN_GRADER_IDS = [
37589
37960
  "followsInstructions",
37590
37961
  "grounded",
37591
37962
  "rightTone",
37592
- "safeToSend"
37963
+ "safeToSend",
37964
+ "staysOnTask",
37965
+ "sameLanguage",
37966
+ "refusesWhenItShould",
37967
+ "noPersonalData"
37593
37968
  ];
37594
37969
  var graderSeveritySchema = external_exports.enum(["gate", "soft"]);
37595
37970
  var severityFields = { severity: graderSeveritySchema.optional() };
@@ -37695,39 +38070,137 @@ var caseExpectedSchema = external_exports.object({
37695
38070
  });
37696
38071
  var DEFAULT_MODELS_FOR_NEW_ACCOUNTS = [
37697
38072
  // Mixlayer models
37698
- { provider: "runtype", modelId: "qwen/qwen3.6-27b", isDefault: false },
37699
- { provider: "runtype", modelId: "qwen3.6-plus", isDefault: false },
37700
- // General Compute (platform key) - explicit provider prefix, single-provider model
37701
- { provider: "runtype", modelId: "general-compute/minimax-m2.7", isDefault: false },
38073
+ {
38074
+ provider: "runtype",
38075
+ modelId: "qwen/qwen3.6-27b",
38076
+ isDefault: false,
38077
+ strengths: "Fast, low-cost open-weight workhorse with reasoning, tool-use, and vision \u2014 good for high-volume extraction, classification, and simple transforms.",
38078
+ bestFor: ["fast-cheap", "vision"]
38079
+ },
37702
38080
  // Routed models - benefit from automatic provider optimization
37703
38081
  // OpenAI models (routed via OpenAI direct, with Vercel fallback)
37704
- { provider: "runtype", modelId: "gpt-5.5", isDefault: false },
37705
- { provider: "runtype", modelId: "gpt-5.4-mini", isDefault: false },
37706
- { provider: "runtype", modelId: "gpt-5.4-nano", isDefault: false },
38082
+ {
38083
+ provider: "runtype",
38084
+ modelId: "gpt-5.5",
38085
+ isDefault: false,
38086
+ strengths: "Top-tier general reasoning and tool-use with excellent structured-output reliability, vision, and a 1M context \u2014 a strong pick for complex, correctness-sensitive steps.",
38087
+ bestFor: ["default", "deep-reasoning", "agentic-tools", "vision", "long-context"]
38088
+ },
38089
+ {
38090
+ provider: "runtype",
38091
+ modelId: "gpt-5.4-mini",
38092
+ isDefault: false,
38093
+ strengths: "Fast and affordable with dependable JSON formatting \u2014 a good fit for mid-complexity task steps.",
38094
+ bestFor: ["fast-cheap", "default"]
38095
+ },
38096
+ {
38097
+ provider: "runtype",
38098
+ modelId: "gpt-5.4-nano",
38099
+ isDefault: false,
38100
+ strengths: "Cheapest and fastest GPT-5 tier \u2014 reserve for trivial deterministic transforms, routing, and classification, not complex authoring.",
38101
+ bestFor: ["fast-cheap"]
38102
+ },
37707
38103
  // Anthropic models (routed via Anthropic direct, with Vertex/Bedrock fallback)
37708
- { provider: "runtype", modelId: "claude-haiku-4-5", isDefault: false },
37709
- { provider: "runtype", modelId: "claude-sonnet-4-6", isDefault: false },
37710
- { provider: "runtype", modelId: "claude-opus-4-8", isDefault: false },
38104
+ {
38105
+ provider: "runtype",
38106
+ modelId: "claude-haiku-4-5",
38107
+ isDefault: false,
38108
+ strengths: "Fast and inexpensive while retaining real reasoning, tool-use, and vision \u2014 great for high-volume task steps that still need some judgment.",
38109
+ bestFor: ["fast-cheap", "agentic-tools", "vision"]
38110
+ },
38111
+ {
38112
+ provider: "runtype",
38113
+ modelId: "claude-sonnet-5",
38114
+ isDefault: false,
38115
+ strengths: "Balanced all-rounder: strong reasoning, very reliable multi-round tool loops, vision, and a 1M context \u2014 an excellent choice for agentic and structured work.",
38116
+ bestFor: ["default", "agentic-tools", "vision", "long-context"]
38117
+ },
38118
+ {
38119
+ provider: "runtype",
38120
+ modelId: "claude-opus-4-8",
38121
+ isDefault: false,
38122
+ strengths: "Deepest reasoning and planning for hard analysis and multi-constraint synthesis, with vision and a 1M context \u2014 premium-priced, so reserve for genuinely difficult steps.",
38123
+ bestFor: ["deep-reasoning", "vision", "long-context"]
38124
+ },
37711
38125
  // Google models (routed via Google direct, with Vertex/Vercel fallback)
37712
- { provider: "runtype", modelId: "gemini-3-1-flash-lite", isDefault: false },
37713
- { provider: "runtype", modelId: "gemini-3.5-flash", isDefault: false },
37714
- { provider: "runtype", modelId: "gemini-3-1-flash-image", isDefault: false },
37715
- { provider: "runtype", modelId: "gemini-3.1-pro", isDefault: false },
38126
+ {
38127
+ provider: "runtype",
38128
+ modelId: "gemini-3-1-flash-lite",
38129
+ isDefault: false,
38130
+ strengths: "Very fast and very cheap with full multimodal input (vision and audio), good structured output, and a 1M context \u2014 ideal for high-volume, simple steps.",
38131
+ bestFor: ["fast-cheap", "vision", "long-context"]
38132
+ },
38133
+ {
38134
+ provider: "runtype",
38135
+ modelId: "gemini-3.5-flash",
38136
+ isDefault: false,
38137
+ strengths: "Fast, low-cost, and natively multimodal with good reasoning, tool-use, and a 1M context \u2014 a strong choice for vision and high-throughput steps.",
38138
+ bestFor: ["default", "vision", "fast-cheap", "agentic-tools", "long-context"]
38139
+ },
38140
+ {
38141
+ provider: "runtype",
38142
+ modelId: "gemini-3-1-flash-image",
38143
+ isDefault: false,
38144
+ strengths: "Specialised for image generation and editing (image output) \u2014 use for steps that produce images, not text reasoning.",
38145
+ bestFor: ["image-generation"]
38146
+ },
38147
+ {
38148
+ provider: "runtype",
38149
+ modelId: "gemini-3.1-pro",
38150
+ isDefault: false,
38151
+ strengths: "Google's frontier tier: strong reasoning, a 1M context, and multimodal input \u2014 for complex analytical or long-document steps.",
38152
+ bestFor: ["deep-reasoning", "vision", "long-context"]
38153
+ },
37716
38154
  // Inception models (routed via Vercel)
37717
- { provider: "runtype", modelId: "mercury-2", isDefault: false },
38155
+ {
38156
+ provider: "runtype",
38157
+ modelId: "mercury-2",
38158
+ isDefault: false,
38159
+ strengths: "Diffusion-based LLM optimised for very low latency \u2014 good when speed matters more than deep reasoning.",
38160
+ bestFor: ["fast-cheap"]
38161
+ },
37718
38162
  // Moonshot models (routed via Vercel)
37719
38163
  // Kimi K2.6 is the default model: a reasoning + tool-use + vision model
37720
38164
  // already trusted as the product-generator default.
37721
- { provider: "runtype", modelId: "kimi-k2.6", isDefault: true },
38165
+ {
38166
+ provider: "runtype",
38167
+ modelId: "kimi-k2.6",
38168
+ isDefault: true,
38169
+ strengths: "Capable open agentic model with reasoning, tool-use, and vision at strong value \u2014 the current account default and a dependable general workhorse.",
38170
+ bestFor: ["default", "agentic-tools", "vision"]
38171
+ },
37722
38172
  // NVIDIA Nemotron Ultra (reasoning + tool-use flagship, routed via Vercel)
37723
- { provider: "runtype", modelId: "nemotron-3-ultra-550b-a55b", isDefault: false },
38173
+ {
38174
+ provider: "runtype",
38175
+ modelId: "nemotron-3-ultra-550b-a55b",
38176
+ isDefault: false,
38177
+ strengths: "Large open-weight reasoning and tool-use flagship with a 1M context at a low price \u2014 strong analytical depth where an open model is preferred.",
38178
+ bestFor: ["deep-reasoning", "agentic-tools", "long-context"]
38179
+ },
37724
38180
  // Google models (routed via Cloudflare Workers AI)
37725
- { provider: "runtype", modelId: "gemma-4-26b-a4b-it", isDefault: false },
38181
+ {
38182
+ provider: "runtype",
38183
+ modelId: "gemma-4-26b-a4b-it",
38184
+ isDefault: false,
38185
+ strengths: "Lightweight open-weight instruct model served free on Workers AI \u2014 fine for straightforward general tasks at zero cost.",
38186
+ bestFor: ["fast-cheap"]
38187
+ },
37726
38188
  // Z.ai GLM-5.2 (agentic coding flagship, routed via Cloudflare Workers AI,
37727
38189
  // Vercel fallback). The bare routed name resolves to `@cf/zai-org/glm-5.2`.
37728
- { provider: "runtype", modelId: "glm-5.2", isDefault: false }
38190
+ {
38191
+ provider: "runtype",
38192
+ modelId: "glm-5.2",
38193
+ isDefault: false,
38194
+ strengths: "Agentic flagship \u2014 best-in-class at long, multi-round tool-call loops and coding/agent workflows, with a 1M context; well suited to tool-heavy agent steps.",
38195
+ bestFor: ["agentic-tools", "default", "deep-reasoning", "long-context"]
38196
+ }
37729
38197
  ];
37730
38198
  var DEFAULT_MODEL_ID = DEFAULT_MODELS_FOR_NEW_ACCOUNTS.find((m2) => m2.isDefault)?.modelId ?? "kimi-k2.6";
38199
+ function renderDefaultModelStrengthsGuide() {
38200
+ return DEFAULT_MODELS_FOR_NEW_ACCOUNTS.map(
38201
+ (m2) => `- \`${m2.modelId}\`${m2.isDefault ? " (account default)" : ""} \u2014 ${m2.strengths}`
38202
+ ).join("\n");
38203
+ }
37731
38204
  var userProfileFeaturesSchema = external_exports.object({
37732
38205
  enableAgentSkills: external_exports.boolean(),
37733
38206
  // Gates the WebMCP-powered dashboard assistant (copilot panel + chat
@@ -37748,9 +38221,21 @@ var userProfileFeaturesSchema = external_exports.object({
37748
38221
  // `POST /v1/skills/scan` verdict UI). Driven by the `enable-skill-scanner`
37749
38222
  // boolean flag (fail-closed until a rule enables it). The scan ROUTE stays
37750
38223
  // reachable; this only hides the UI while the scanner rollout completes.
37751
- enableSkillScanner: external_exports.boolean()
38224
+ enableSkillScanner: external_exports.boolean(),
38225
+ // Gates the usage-based-pricing dashboard surfaces (card-centric paywall /
38226
+ // slow-mode copy, trial-expired alerts, CTAs to the credit-card entry page).
38227
+ // Driven by the `usage-based-pricing` boolean flag (fail-closed in
38228
+ // production until Lane 1 is live and a rule ramps a cohort). Off renders
38229
+ // today's UI byte-identically.
38230
+ usageBasedPricing: external_exports.boolean()
37752
38231
  });
37753
38232
  var MODEL_FAMILY_PROVIDER_IDS = {
38233
+ "arrow-1-1": {
38234
+ "vercel": "quiverai/arrow-1.1"
38235
+ },
38236
+ "arrow-1.1": {
38237
+ "vercel": "quiverai/arrow-1.1"
38238
+ },
37754
38239
  "claude-fable-5": {
37755
38240
  "anthropic": "claude-fable-5"
37756
38241
  },
@@ -37842,6 +38327,10 @@ var MODEL_FAMILY_PROVIDER_IDS = {
37842
38327
  "claude-sonnet-4.6": {
37843
38328
  "vercel": "anthropic/claude-sonnet-4.6"
37844
38329
  },
38330
+ "claude-sonnet-5": {
38331
+ "anthropic": "claude-sonnet-5",
38332
+ "vercel": "anthropic/claude-sonnet-5"
38333
+ },
37845
38334
  "codestral": {
37846
38335
  "vercel": "mistral/codestral"
37847
38336
  },
@@ -38026,6 +38515,9 @@ var MODEL_FAMILY_PROVIDER_IDS = {
38026
38515
  "google": "gemini-3.1-flash-lite",
38027
38516
  "vercel": "google/gemini-3.1-flash-lite"
38028
38517
  },
38518
+ "gemini-3-1-flash-lite-image": {
38519
+ "vercel": "google/gemini-3.1-flash-lite-image"
38520
+ },
38029
38521
  "gemini-3-1-pro": {
38030
38522
  "google": "gemini-3.1-pro-preview",
38031
38523
  "vercel": "google/gemini-3.1-pro-preview"
@@ -38058,6 +38550,9 @@ var MODEL_FAMILY_PROVIDER_IDS = {
38058
38550
  "google": "gemini-3.1-flash-lite",
38059
38551
  "vercel": "google/gemini-3.1-flash-lite"
38060
38552
  },
38553
+ "gemini-3.1-flash-lite-image": {
38554
+ "vercel": "google/gemini-3.1-flash-lite-image"
38555
+ },
38061
38556
  "gemini-3.1-pro-preview": {
38062
38557
  "google": "gemini-3.1-pro-preview",
38063
38558
  "vercel": "google/gemini-3.1-pro-preview"
@@ -38085,89 +38580,19 @@ var MODEL_FAMILY_PROVIDER_IDS = {
38085
38580
  "togetherai": "togetherai/pearl-ai/gemma-4-31b-it",
38086
38581
  "vercel": "google/gemma-4-31b-it"
38087
38582
  },
38088
- "glm-4-5": {
38089
- "vercel": "zai/glm-4.5"
38090
- },
38091
- "glm-4-5-air": {
38092
- "vercel": "zai/glm-4.5-air"
38093
- },
38094
- "glm-4-5v": {
38095
- "vercel": "zai/glm-4.5v"
38096
- },
38097
- "glm-4-6": {
38098
- "vercel": "zai/glm-4.6"
38099
- },
38100
- "glm-4-6v": {
38101
- "vercel": "zai/glm-4.6v"
38102
- },
38103
- "glm-4-6v-flash": {
38104
- "vercel": "zai/glm-4.6v-flash"
38105
- },
38106
- "glm-4-7": {
38107
- "vercel": "zai/glm-4.7"
38108
- },
38109
- "glm-4-7-flash": {
38110
- "vercel": "zai/glm-4.7-flash"
38111
- },
38112
- "glm-4-7-flashx": {
38113
- "vercel": "zai/glm-4.7-flashx"
38114
- },
38115
- "glm-4.5": {
38116
- "vercel": "zai/glm-4.5"
38117
- },
38118
- "glm-4.5-air": {
38119
- "vercel": "zai/glm-4.5-air"
38120
- },
38121
- "glm-4.5v": {
38122
- "vercel": "zai/glm-4.5v"
38123
- },
38124
- "glm-4.6": {
38125
- "vercel": "zai/glm-4.6"
38126
- },
38127
- "glm-4.6v": {
38128
- "vercel": "zai/glm-4.6v"
38129
- },
38130
- "glm-4.6v-flash": {
38131
- "vercel": "zai/glm-4.6v-flash"
38132
- },
38133
- "glm-4.7": {
38134
- "vercel": "zai/glm-4.7"
38135
- },
38136
- "glm-4.7-flash": {
38137
- "vercel": "zai/glm-4.7-flash"
38138
- },
38139
- "glm-4.7-flashx": {
38140
- "vercel": "zai/glm-4.7-flashx"
38141
- },
38142
- "glm-5": {
38143
- "togetherai": "togetherai/zai-org/GLM-5",
38144
- "vercel": "zai/glm-5"
38145
- },
38146
- "glm-5-1": {
38147
- "togetherai": "togetherai/zai-org/GLM-5.1",
38148
- "vercel": "zai/glm-5.1"
38149
- },
38150
38583
  "glm-5-2": {
38584
+ "togetherai": "togetherai/zai-org/GLM-5.2",
38151
38585
  "vercel": "zai/glm-5.2"
38152
38586
  },
38153
38587
  "glm-5-2-fast": {
38154
38588
  "vercel": "zai/glm-5.2-fast"
38155
38589
  },
38156
- "glm-5-turbo": {
38157
- "vercel": "zai/glm-5-turbo"
38158
- },
38159
- "glm-5.1": {
38160
- "vercel": "zai/glm-5.1"
38161
- },
38162
38590
  "glm-5.2": {
38163
38591
  "vercel": "zai/glm-5.2"
38164
38592
  },
38165
38593
  "glm-5.2-fast": {
38166
38594
  "vercel": "zai/glm-5.2-fast"
38167
38595
  },
38168
- "glm-5v-turbo": {
38169
- "vercel": "zai/glm-5v-turbo"
38170
- },
38171
38596
  "google/gemma-4-31B-it": {
38172
38597
  "togetherai": "togetherai/google/gemma-4-31B-it"
38173
38598
  },
@@ -38499,6 +38924,9 @@ var MODEL_FAMILY_PROVIDER_IDS = {
38499
38924
  "grok-imagine-video-1-5": {
38500
38925
  "vercel": "xai/grok-imagine-video-1.5-preview"
38501
38926
  },
38927
+ "grok-imagine-video-1.5": {
38928
+ "vercel": "xai/grok-imagine-video-1.5"
38929
+ },
38502
38930
  "grok-imagine-video-1.5-preview": {
38503
38931
  "vercel": "xai/grok-imagine-video-1.5-preview"
38504
38932
  },
@@ -38715,22 +39143,6 @@ var MODEL_FAMILY_PROVIDER_IDS = {
38715
39143
  "mimo-v2.5-pro": {
38716
39144
  "vercel": "xiaomi/mimo-v2.5-pro"
38717
39145
  },
38718
- "minimax-m2": {
38719
- "vercel": "minimax/minimax-m2"
38720
- },
38721
- "minimax-m2-1": {
38722
- "vercel": "minimax/minimax-m2.1"
38723
- },
38724
- "minimax-m2-1-lightning": {
38725
- "vercel": "minimax/minimax-m2.1-lightning"
38726
- },
38727
- "minimax-m2-5": {
38728
- "togetherai": "togetherai/MiniMaxAI/MiniMax-M2.5",
38729
- "vercel": "minimax/minimax-m2.5"
38730
- },
38731
- "minimax-m2-5-highspeed": {
38732
- "vercel": "minimax/minimax-m2.5-highspeed"
38733
- },
38734
39146
  "minimax-m2-7": {
38735
39147
  "general-compute": "general-compute/minimax-m2.7",
38736
39148
  "togetherai": "togetherai/MiniMaxAI/MiniMax-M2.7",
@@ -38739,18 +39151,6 @@ var MODEL_FAMILY_PROVIDER_IDS = {
38739
39151
  "minimax-m2-7-highspeed": {
38740
39152
  "vercel": "minimax/minimax-m2.7-highspeed"
38741
39153
  },
38742
- "minimax-m2.1": {
38743
- "vercel": "minimax/minimax-m2.1"
38744
- },
38745
- "minimax-m2.1-lightning": {
38746
- "vercel": "minimax/minimax-m2.1-lightning"
38747
- },
38748
- "minimax-m2.5": {
38749
- "vercel": "minimax/minimax-m2.5"
38750
- },
38751
- "minimax-m2.5-highspeed": {
38752
- "vercel": "minimax/minimax-m2.5-highspeed"
38753
- },
38754
39154
  "minimax-m2.7": {
38755
39155
  "general-compute": "general-compute/minimax-m2.7",
38756
39156
  "vercel": "minimax/minimax-m2.7"
@@ -38762,9 +39162,6 @@ var MODEL_FAMILY_PROVIDER_IDS = {
38762
39162
  "togetherai": "togetherai/MiniMaxAI/MiniMax-M3",
38763
39163
  "vercel": "minimax/minimax-m3"
38764
39164
  },
38765
- "MiniMaxAI/MiniMax-M2.5": {
38766
- "togetherai": "togetherai/MiniMaxAI/MiniMax-M2.5"
38767
- },
38768
39165
  "MiniMaxAI/MiniMax-M2.7": {
38769
39166
  "togetherai": "togetherai/MiniMaxAI/MiniMax-M2.7"
38770
39167
  },
@@ -39352,11 +39749,8 @@ var MODEL_FAMILY_PROVIDER_IDS = {
39352
39749
  "whisper-1": {
39353
39750
  "vercel": "openai/whisper-1"
39354
39751
  },
39355
- "zai-org/GLM-5": {
39356
- "togetherai": "togetherai/zai-org/GLM-5"
39357
- },
39358
- "zai-org/GLM-5.1": {
39359
- "togetherai": "togetherai/zai-org/GLM-5.1"
39752
+ "zai-org/GLM-5.2": {
39753
+ "togetherai": "togetherai/zai-org/GLM-5.2"
39360
39754
  }
39361
39755
  };
39362
39756
  var PLATFORM_KEY_PROVIDER_MAP = {
@@ -40342,10 +40736,12 @@ var sandboxConfigSchema = external_exports.object({
40342
40736
  instanceType: external_exports.enum(["standard-1", "standard-2", "standard-3", "standard-4"]).optional(),
40343
40737
  networkAccess: sandboxNetworkAccessSchema.optional(),
40344
40738
  ttl: external_exports.enum(["5m", "1h", "24h", "unlimited"]).optional(),
40345
- sleepAfter: external_exports.enum(["5m", "15m", "30m", "1h"]).optional(),
40346
- // Opt-in approval gate on `bash`. Default false; wiring lands in Phase 3. The
40347
- // approval decision is on tool name + params only — never the agent's reason.
40348
- requireApprovalForBash: external_exports.boolean().optional()
40739
+ sleepAfter: external_exports.enum(["5m", "15m", "30m", "1h"]).optional()
40740
+ // NOTE: a `requireApprovalForBash` knob was forward-declared here for Phase 3
40741
+ // but never wired to any runtime gate, so it was REMOVED from the public
40742
+ // schema rather than ship a misleading, inert control (post-Fable handoff 05,
40743
+ // F3). To gate `bash` today use the generic `tools.approval` config, which
40744
+ // matches the tool by name. Re-add the dedicated knob only with its wiring.
40349
40745
  });
40350
40746
  var agentRuntimeConfigSchema = external_exports.object({
40351
40747
  model: external_exports.string().optional(),
@@ -40474,6 +40870,10 @@ var agentRuntimeConfigSchema = external_exports.object({
40474
40870
  }).optional(),
40475
40871
  errorHandling: errorHandlingSchema,
40476
40872
  loggingPolicy: external_exports.enum(["default", "on", "off"]).optional(),
40873
+ // Opt-in PII redaction for tail-log and telemetry payloads. `'default'`
40874
+ // defers to a lower layer (surface/product) or the resolver default (off).
40875
+ // Mirrors `loggingPolicy`.
40876
+ piiRedaction: external_exports.enum(["default", "off", "redact"]).optional(),
40477
40877
  // Opt-in temporal awareness. `injectElapsed` turns on the automatic
40478
40878
  // "time has passed" decorator (a `<temporal_context>` block prepended to
40479
40879
  // the user turn at dispatch, gated on turn ≥ 2 and a gap ≥
@@ -40499,6 +40899,142 @@ var agentRuntimeConfigSchema = external_exports.object({
40499
40899
  // `./tenancy-strategy`; the expansion + gate logic lives in apps/api.
40500
40900
  tenancyStrategy: tenancyStrategySchema.optional()
40501
40901
  });
40902
+ var identityAdapterKindSchema = external_exports.enum(["oidc-jwt", "session", "custom"]);
40903
+ var ASYMMETRIC_JWT_ALGORITHMS = [
40904
+ "RS256",
40905
+ "RS384",
40906
+ "RS512",
40907
+ "PS256",
40908
+ "PS384",
40909
+ "PS512",
40910
+ "ES256",
40911
+ "ES384",
40912
+ "ES512",
40913
+ "EdDSA"
40914
+ ];
40915
+ var asymmetricAlgorithmSchema = external_exports.enum(ASYMMETRIC_JWT_ALGORITHMS);
40916
+ var httpsUrlSchema = external_exports.string().url().refine((value) => value.startsWith("https://"), {
40917
+ message: "must be an https:// URL (plaintext http is not accepted)."
40918
+ });
40919
+ var claimMapSchema = external_exports.object({
40920
+ /** JSON path (dot notation) to the end-user id, e.g. `sub`. */
40921
+ subject: external_exports.string().min(1),
40922
+ /** JSON path to the tenant id, e.g. `org_id` / `o.id` / `organizationId`. Optional. */
40923
+ tenant: external_exports.string().min(1).optional(),
40924
+ /** JSON path to the end-user email. Optional. */
40925
+ email: external_exports.string().min(1).optional(),
40926
+ /** JSON path to a roles claim. Optional, display/authz context only. */
40927
+ roles: external_exports.string().min(1).optional(),
40928
+ /** JSON path to a permissions claim. Optional. */
40929
+ permissions: external_exports.string().min(1).optional()
40930
+ });
40931
+ var oboModeSchema = external_exports.enum([
40932
+ "token-exchange-8693",
40933
+ // Okta / Auth0 Custom Token Exchange (RFC 8693)
40934
+ "federated-token-vault",
40935
+ // Auth0 Token Vault, WorkOS Pipes, Clerk OAuth tokens
40936
+ "customer-endpoint"
40937
+ // Better Auth / custom escape hatch
40938
+ ]);
40939
+ var baseDescriptorShape = {
40940
+ /** Stable integration id (surface-scoped). Also the isolation namespace (C1). */
40941
+ id: external_exports.string().min(1),
40942
+ kind: identityAdapterKindSchema,
40943
+ claimMap: claimMapSchema,
40944
+ /**
40945
+ * The strongest assurance this integration may confer. Bounded ABOVE by the
40946
+ * kind ceiling ({@link assuranceCeilingForKind}) — may only lower it, never
40947
+ * raise it. A `custom`/`session` descriptor cannot declare `verified`.
40948
+ */
40949
+ maxAssurance: tenancyAssuranceLevelSchema.optional(),
40950
+ capabilities: external_exports.object({
40951
+ obo: external_exports.boolean().default(false),
40952
+ oboMode: oboModeSchema.optional()
40953
+ }).default({ obo: false })
40954
+ };
40955
+ var verifiableDescriptorShape = {
40956
+ /** Expected `iss`. REQUIRED, non-empty, non-wildcard. */
40957
+ issuer: httpsUrlSchema,
40958
+ /** JWKS endpoint for the issuer's public keys. REQUIRED. */
40959
+ jwksUri: httpsUrlSchema,
40960
+ /** Expected `aud`. REQUIRED, non-empty, non-wildcard (see refinement). */
40961
+ audience: external_exports.union([external_exports.string().min(1), external_exports.array(external_exports.string().min(1)).nonempty()]),
40962
+ /** Non-empty subset of {@link ASYMMETRIC_JWT_ALGORITHMS}. */
40963
+ allowedAlgorithms: external_exports.array(asymmetricAlgorithmSchema).nonempty(),
40964
+ clockSkewSec: external_exports.number().int().min(0).max(120).optional()
40965
+ };
40966
+ var identityAdapterDescriptorSchema = external_exports.discriminatedUnion("kind", [
40967
+ external_exports.object({
40968
+ ...baseDescriptorShape,
40969
+ ...verifiableDescriptorShape,
40970
+ kind: external_exports.literal("oidc-jwt"),
40971
+ /** `azp` allowlist (Clerk CSRF/origin guard, Auth0 authorized party). */
40972
+ authorizedParties: external_exports.array(external_exports.string().min(1)).optional(),
40973
+ /** Provider-specific post-verify policy toggles. */
40974
+ claimPolicy: external_exports.object({
40975
+ rejectImpersonation: external_exports.boolean().optional(),
40976
+ // Clerk `act`
40977
+ rejectPendingOrg: external_exports.boolean().optional(),
40978
+ // Clerk `sts:pending`
40979
+ rejectAudienceEqualsAzp: external_exports.boolean().optional(),
40980
+ // Auth0 ID-vs-access-token
40981
+ requireIssuerPathSegment: external_exports.string().min(1).optional()
40982
+ // Okta `/oauth2/{id}`
40983
+ }).optional()
40984
+ }),
40985
+ external_exports.object({
40986
+ ...baseDescriptorShape,
40987
+ ...verifiableDescriptorShape,
40988
+ kind: external_exports.literal("session")
40989
+ }),
40990
+ external_exports.object({
40991
+ ...baseDescriptorShape,
40992
+ kind: external_exports.literal("custom"),
40993
+ /** The customer verify endpoint (HTTPS). Egress is SSRF-guarded at call time. */
40994
+ verifyEndpoint: httpsUrlSchema
40995
+ })
40996
+ ]).superRefine((descriptor, ctx) => {
40997
+ if (descriptor.kind === "oidc-jwt" || descriptor.kind === "session") {
40998
+ const auds = Array.isArray(descriptor.audience) ? descriptor.audience : [descriptor.audience];
40999
+ if (auds.some((a) => a.trim() === "*" || a.trim() === "")) {
41000
+ ctx.addIssue({
41001
+ code: external_exports.ZodIssueCode.custom,
41002
+ path: ["audience"],
41003
+ message: "audience must name a specific relying party (no wildcard / empty value)."
41004
+ });
41005
+ }
41006
+ }
41007
+ if (descriptor.maxAssurance) {
41008
+ const ceiling = assuranceCeilingForKind(descriptor.kind);
41009
+ if (assuranceRank(descriptor.maxAssurance) === 0) {
41010
+ ctx.addIssue({
41011
+ code: external_exports.ZodIssueCode.custom,
41012
+ path: ["maxAssurance"],
41013
+ message: "maxAssurance cannot be 'anonymous' \u2014 it is a ceiling; omit the field or use 'asserted' / 'verified'."
41014
+ });
41015
+ } else if (assuranceRank(descriptor.maxAssurance) > assuranceRank(ceiling)) {
41016
+ ctx.addIssue({
41017
+ code: external_exports.ZodIssueCode.custom,
41018
+ path: ["maxAssurance"],
41019
+ message: `maxAssurance '${descriptor.maxAssurance}' exceeds the '${descriptor.kind}' kind ceiling '${ceiling}'.`
41020
+ });
41021
+ }
41022
+ }
41023
+ });
41024
+ function assuranceRank(level) {
41025
+ return level === "verified" ? 2 : level === "asserted" ? 1 : 0;
41026
+ }
41027
+ function assuranceCeilingForKind(kind) {
41028
+ return kind === "oidc-jwt" ? "verified" : "asserted";
41029
+ }
41030
+ var identityProofSchema = external_exports.object({
41031
+ /** Which configured integration the token claims to come from (hint only). */
41032
+ provider: external_exports.string().min(1).max(64),
41033
+ /** The customer-native proof (JWT / opaque session token). */
41034
+ token: external_exports.string().min(1).max(8192)
41035
+ }).describe(
41036
+ "Customer-native auth proof for the Identity Exchange. When present and the surface has a matching integration, the verified tenant/end-user replace any body-asserted tenant/endUser (which are never trusted for web-embedded callers). Ignored until the Identity Exchange admission upgrade ships."
41037
+ );
40502
41038
  function extractSecretReferences(template) {
40503
41039
  const keys = /* @__PURE__ */ new Set();
40504
41040
  let match;
@@ -42074,10 +42610,22 @@ var FLOW_STEP_TYPE_METADATA = {
42074
42610
  configHints: "http, auth, requestTemplate, responseMapping, outputVariable"
42075
42611
  },
42076
42612
  "retrieve-record": {
42077
- description: "Load records from the Runtype record store by ID, by type+name, or by a chip-style recordFilter (metadata + top-level columns: id, name, createdAt, updatedAt).",
42613
+ description: "DEPRECATED \u2014 use get-record (single object) or list-records (array) instead. Loads records from the Runtype record store; its return shape is inferred from the lookup method (an id lookup returns one object, a type/name/filter query returns an array even for a single match), which is the ambiguity the successor step types remove.",
42078
42614
  category: "data",
42079
42615
  isPrompt: false,
42080
- configHints: "recordType, recordName, recordFilter ({ type, where: { field, op, value } }), outputVariable"
42616
+ configHints: "DEPRECATED. Prefer get-record / list-records. recordType, recordName, recordFilter ({ type, where: { field, op, value } }), outputVariable"
42617
+ },
42618
+ "get-record": {
42619
+ description: "Load a SINGLE record object from the Runtype record store by ID, by type+name, or by a chip-style recordFilter (first match, ordered by updated_at desc). Access fields directly in templates ({{var.field}}). Fails if no record matches.",
42620
+ category: "data",
42621
+ isPrompt: false,
42622
+ configHints: "recordId, recordType, recordName, recordFilter ({ type, where: { field, op, value } }), outputVariable (returns one object \u2014 access as {{var.field}})"
42623
+ },
42624
+ "list-records": {
42625
+ description: "Load an ARRAY of records from the Runtype record store by type, name, or a chip-style recordFilter (metadata + top-level columns: id, name, createdAt, updatedAt), ordered by updated_at desc. Always returns an array \u2014 even for a single match \u2014 so index it in templates ({{var.0.field}}). Default limit 50 (max 1000).",
42626
+ category: "data",
42627
+ isPrompt: false,
42628
+ configHints: "recordType, recordName, recordFilter ({ type, where: { field, op, value } }), limit (default 50, max 1000), onEmpty (succeed|fail), outputVariable (returns an array \u2014 index as {{var.0.field}})"
42081
42629
  },
42082
42630
  "upsert-record": {
42083
42631
  description: "Create or update a record. The sourceVariable must point to a JSON object.",
@@ -42146,10 +42694,10 @@ var FLOW_STEP_TYPE_METADATA = {
42146
42694
  configHints: "vectorsSource, destination, idTemplate, outputVariable"
42147
42695
  },
42148
42696
  crawl: {
42149
- description: "Crawl a website and extract content from pages.",
42697
+ description: "Crawl a website with Cloudflare Browser Rendering and extract page content as markdown. Renders the SEED page fully; at depth >= 1 it enumerates child links WITHOUT rendering them (1 rendered seed record + N empty-markdown child records) and follows only ABSOLUTE link hrefs (relative links like item?id= are never followed). Writes { crawlId, status, result, resultPages[] } to outputVariable \u2014 flatten resultPages[].records[] (each { url, status, markdown?, metadata? }) to read every page. GOTCHA: the URL query string is DROPPED (https://site/item?id=42 crawls https://site/item) \u2014 for query-string URLs, JSON APIs, SPAs, or single detail/comment pages use fetch-url or the builtin:firecrawl scrape tool instead (firecrawl preserves query strings). ASYNC by default: with no streaming consumer (MCP run_flow/dispatch) the flow durably PAUSES while a Workflow polls; if the crawl exceeds completionTimeoutMs (default 120000 = 2 min) the step SILENTLY resumes with output = null. For real crawls raise completionTimeoutMs (e.g. 600000) and set pollIntervalMs (e.g. 5000), or set asyncCrawl:false to poll inline within the request (good for smoke tests).",
42150
42698
  category: "integration",
42151
42699
  isPrompt: false,
42152
- configHints: "url, limit, depth, outputVariable"
42700
+ configHints: 'url (required; query string is dropped), outputVariable (required), depth (0 = seed-only render, recommended), limit, formats (e.g. ["markdown"]), render, options ({ includePatterns, excludePatterns, allowSubdomains, allowExternalLinks, ignoreSitemap, sitemapOnly }), waitForSelector, completionTimeoutMs (default 120000; raise for slow crawls), pollIntervalMs, asyncCrawl (false = synchronous inline polling), errorHandling ({ onError: "continue"|"fail" } OBJECT, not a bare string), defaultValue. Pattern for "index + detail/comment pages": crawl the index with depth 0, transform-data to extract the links/ids from result markdown, then an agent prompt step (mode: "agent") with tools.toolIds ["builtin:firecrawl"] to fetch each query-string detail URL.'
42153
42701
  },
42154
42702
  "paginate-api": {
42155
42703
  description: "Fetch paginated data from an API endpoint across multiple pages.",
@@ -42782,7 +43330,8 @@ ${lines.join("\n")}`;
42782
43330
  var PLATFORM_FEATURES_SUMMARY = (() => {
42783
43331
  const integrations = PLATFORM_CATALOG.availableIntegrations.map((i) => i.provider).join(", ");
42784
43332
  const stepTypes = FLOW_STEP_TYPES.filter((t) => t !== "prompt").join(", ");
42785
- const models = DEFAULT_MODELS_FOR_NEW_ACCOUNTS.map((m2) => m2.modelId).join(", ");
43333
+ const models = `use ONLY these routed IDs (never dated/legacy IDs like gpt-4.1 or gpt-4o), matched to the work:
43334
+ ${renderDefaultModelStrengthsGuide()}`;
42786
43335
  return `## Available Platform Features
42787
43336
 
42788
43337
  - **Built-in tools**: GPT Image 2 image generation, provider-native web search (OpenAI web search, Anthropic web search/fetch, xAI Live Search for Grok-3 series, xAI X Search / Web Search agentic tools for Grok-4 series), Exa (AI search), Firecrawl (simple web scraping), Browser Run tools (rendered markdown, HTML, screenshots, snapshots, selector scraping, JSON extraction, link harvesting \u2014 stateless), Browser Session tools (persistent interactive browsing: open, navigate, click, type, scroll, screenshot, evaluate, close), Browser Agent (autonomous higher-level alternative \u2014 give a natural-language goal plus a startUrl or sessionId and the agent navigates/clicks/extracts on its own), Store Asset (host any file from a URL or base64 inline content \u2014 returns a permanent public or signed private URL, downloads as attachment), Publish Page (host HTML that renders inline in the browser at a shareable 7-day /preview/ URL under a locked-down CSP), vector search, UCP commerce tools (discovery, catalog, cart, checkout, orders for any UCP-enabled merchant)
@@ -42792,6 +43341,113 @@ var PLATFORM_FEATURES_SUMMARY = (() => {
42792
43341
  - **Available models**: ${models}
42793
43342
  - **Surface types**: ${PLATFORM_CATALOG.availableSurfaceTypes.join(", ")}`;
42794
43343
  })();
43344
+ var FLOW_GENERATION_GUIDE = `## Flow Generation Guide
43345
+
43346
+ ### Step Types
43347
+
43348
+ - **prompt**: AI model call. Config: model, systemPrompt, userPrompt, responseFormat (text|json), outputVariable, tools
43349
+ - **transform-data**: Code execution in a sandboxed environment. **Use sparingly** \u2014 most agent-built flows over-use transform-data for work the platform already does natively. Before adding one, check the Transform-Data Anti-Patterns section: leading "Parse Input" steps duplicate the surface's \`parametersSchema\`; trailing "Final Output" reshapers add a dead hop; pre-cleaning data before a prompt step does the prompt's job in the wrong place; \`map().join()\` to format prompt input ignores that \`{{variable}}\` auto-stringifies; retrieving then plucking the first record ignores that \`recordFilter\` + \`{{records[0]}}\` work. Reach for transform-data only when the work is genuinely deterministic (record-name templating, JSON-shape coercion, math). Config: script, outputVariable, sandboxProvider (optional, default \`cloudflare-worker\`), language (required when sandboxProvider is \`runtype-sandbox\`). Sandbox providers: \`cloudflare-worker\` (default, JS only, strict mode ES module), \`runtype-sandbox\` (full container \u2014 supports \`javascript\`, \`typescript\`, and \`python\` via the \`language\` field), \`daytona\` (remote VM). For the default \`cloudflare-worker\` sandbox: always declare variables with const/let, access context variables via the \`input\` object (e.g., \`input.varName\`), use \`return { key: value }\` pattern. For \`runtype-sandbox\`: JS/TS use the same return pattern; Python uses \`print(json.dumps(...))\` to emit JSON output. Parameters are injected as a \`parameters\` object in all languages
43350
+ - **template**: Render a Liquid template into HTML, email-html, markdown, PDF, or text. **Prefer this over a prompt step when the output is a structured document** (invoice, receipt, email body, report) \u2014 keeps the LLM focused on producing data, not authoring HTML.
43351
+
43352
+ **Config fields:**
43353
+ - \`template\` (required): Liquid template body
43354
+ - \`outputFormat\` (required): \`html\` | \`email-html\` | \`markdown\` | \`pdf\` | \`text\`
43355
+ - \`outputVariable\` (required): variable name to store the rendered output
43356
+ - \`inputs\` (optional): map of logical name \u2192 expression resolving against flow context. If omitted, the entire flow context is available as template variables
43357
+ - \`partials\` (optional): named partial templates referenceable via \`{% include 'name' %}\`
43358
+ - \`pdfOptions\` (optional, pdf only): \`{ format?: 'A4' | 'Letter', landscape?: boolean, margin?: { top, bottom, left, right } }\`. PDF output returns \`{ contentType, bytes (base64), byteLength }\`
43359
+ - \`asArtifact\` (optional): emit a Persona artifact event for chat surfaces \u2014 renders inline in the conversation
43360
+ - \`streamOutput\` (optional): stream the rendered output via SSE
43361
+ - \`sampleData\` (optional): array of \`{ name, data }\` scenarios for the dashboard template editor preview
43362
+
43363
+ **Liquid syntax quick reference:**
43364
+ - Variables: \`{{ name }}\`, \`{{ object.field }}\`, \`{{ array[0] }}\`
43365
+ - Filters: \`{{ name | upcase }}\`, \`{{ price | round: 2 }}\`, \`{{ title | default: "Untitled" }}\`
43366
+ - Loops: \`{% for item in items %} ... {% endfor %}\`
43367
+ - Conditionals: \`{% if condition %} ... {% elsif other %} ... {% else %} ... {% endif %}\`
43368
+ - Partials: \`{% include 'partial_name' %}\` (references \`partials\` map keys)
43369
+ - Assignment: \`{% assign total = 0 %}\`, \`{% capture greeting %}Hello {{ name }}{% endcapture %}\`
43370
+ - Common filters: upcase, downcase, capitalize, strip, truncate, replace, split, join, size, round, date, default, escape, url_encode, newline_to_br
43371
+
43372
+ **Output format notes:**
43373
+ - \`html\` / \`email-html\`: Raw HTML string. \`email-html\` is identical today but semantically marks output destined for send-email steps
43374
+ - \`markdown\`: Plain markdown text
43375
+ - \`pdf\`: Renders the Liquid body as HTML, then converts to PDF. Result is \`{ contentType: "application/pdf", bytes: "<base64>", byteLength: N }\`
43376
+ - \`text\`: Plain text, no HTML processing
43377
+
43378
+ **Inputs map vs. full context:**
43379
+ - With \`inputs\`: only the declared names are available inside the template. Example: \`inputs: { "customer": "{{order_data}}" }\` exposes \`order_data\` as \`{{ customer }}\` in the template. Preferred for clarity and safety
43380
+ - Without \`inputs\`: the entire flow variable scope is available. Convenient for simple templates but risks name collisions
43381
+
43382
+ **Example \u2014 prompt produces JSON, template renders HTML:**
43383
+ \`\`\`
43384
+ Step 1 (prompt): model: "claude-sonnet-4-6", responseFormat: "json", outputVariable: "invoice"
43385
+ \u2192 AI generates { "company": "Acme", "items": [{...}], "total": "1,234.56" }
43386
+ Step 2 (template):
43387
+ template: "<h1>Invoice for {{ data.company }}</h1>{% for item in data.items %}<p>{{ item.desc }}: \${{ item.price }}</p>{% endfor %}<p>Total: \${{ data.total }}</p>"
43388
+ inputs: { "data": "{{invoice}}" }
43389
+ outputFormat: "html"
43390
+ outputVariable: "invoice_html"
43391
+ \`\`\`
43392
+ - **conditional**: Branch logic. Either the binary shape (condition (JS expression), trueSteps, falseSteps) or N-way named branches (branches: [{ id, name, condition, steps }], evaluated first-match-wins, with otherwiseSteps as the fallback). Set outputVariable to merge whichever branch ran into one named result.
43393
+ - **fetch-url**: HTTP request. Config: http (url, method, headers, body), responseType, outputVariable
43394
+ - **api-call**: Structured API call. Config: http, auth, requestTemplate, responseMapping, outputVariable
43395
+ - **get-record**: Load a SINGLE record OBJECT. Config: recordId, OR recordType + recordName, OR recordFilter ({ type, where: { field, op, value } }) for richer metadata-aware queries; outputVariable. Reachable filter columns include id, name, createdAt, updatedAt plus any metadata key. Returns one object \u2014 access fields directly in templates (\`{{record.field}}\`). On multiple matches the first by updated_at desc wins; fails if none match.
43396
+ - **list-records**: Load an ARRAY of records. Config: recordType, recordName, OR recordFilter ({ type, where: { field, op, value } }); limit (default 50, max 1000), onEmpty (succeed|fail, default succeed), outputVariable. Ordered by updated_at desc. Always writes an array \u2014 even for a single match \u2014 so index it in templates (\`{{records.0.field}}\` or \`{{records[0].field}}\`); object-style access (\`{{records.field}}\`) on the array resolves to undefined.
43397
+ - **retrieve-record**: DEPRECATED \u2014 use get-record (single object) or list-records (array). Still accepted at write and aliased at execution onto one of them; its return shape is inferred from the lookup method (recordId \u2192 object, type/name/filter \u2192 array), which is the ambiguity the successors remove.
43398
+ - **upsert-record**: Create/update a record keyed by \`(recordType, recordName)\` per owner. Config: recordType, **recordName** (REQUIRED for upsert semantics \u2014 without it each run creates a fresh \`\${recordType}-\${Date.now()}\` record), sourceVariable (the JSON metadata payload only \u2014 do NOT wrap as \`{ name, type, metadata }\`; the wrapper gets stored verbatim), outputVariable. See "Record-Keyed Upsert Patterns" in the build-product instructions for the full anti-pattern list (silent timestamped fallback, wrapped-source footgun, JSONB-blob aggregate races).
43399
+ - **update-record**: Update record fields. Config: recordId, OR recordFilter ({ type, where }) for first-match-wins by predicate; updates, mergeStrategy (merge|replace|deep-merge), outputVariable.
43400
+ - **set-variable**: Set a variable. Config: variableName, value
43401
+ - **send-email**: Send email. Config: from, to, subject, html, outputVariable
43402
+ - **send-text**: Send SMS. Config: from, to, message, outputVariable
43403
+ - **search**: Web/AI search. Config: provider, query, maxResults, outputVariable
43404
+ - **generate-embedding**: Create vector embedding. Config: inputSource, text, embeddingModel, outputVariable
43405
+ - **vector-search**: Search vectors. Config: query, limit, threshold, outputVariable
43406
+ - **crawl**: Multi-page web crawl via Cloudflare Browser Rendering \u2192 markdown. Config: url (required; **query string is DROPPED** \u2014 \`item?id=42\` crawls \`/item\`), outputVariable (required), depth (0 = render seed only, recommended), limit, completionTimeoutMs (default 120000; a slower crawl SILENTLY resumes with output **null** \u2014 raise to e.g. 600000 + set pollIntervalMs), asyncCrawl (false = inline polling for smoke tests), errorHandling ({ onError } OBJECT, not a bare string). Output: \`{ crawlId, status, result, resultPages[] }\` \u2014 flatten \`resultPages[].records[]\` (each \`{ url, status, markdown? }\`). Renders the seed fully but at depth \u2265 1 enumerates child links WITHOUT rendering them and follows only ABSOLUTE hrefs. For query-string URLs / single detail or comment pages use **fetch-url** or **builtin:firecrawl** (preserves query strings) instead.
43407
+ - **paginate-api**: Paginated API fetch. Config: url, paginationType, entityPath, outputVariable
43408
+ - **store-vector**: Store embeddings. Config: vectorsSource, destination, outputVariable
43409
+ - **execute-agent**: Run an existing agent. Config: agentId, message, outputVariable
43410
+ - **save-memory**: Persist a fact or observation to Cloudflare Agent Memory. Config: profileTemplate (e.g. \`{{_user.id}}\`), contentVariable, sessionId?, outputVariable?
43411
+ - **recall-memory**: Query long-term memory for a synthesized answer. Config: profileTemplate, queryTemplate, thinkingLevel? (low|medium|high), responseLength? (short|medium|long), outputVariable
43412
+ - **memory-summary**: Fetch a Markdown summary of what the agent has stored. Config: profileTemplate, sessionId?, outputVariable
43413
+
43414
+ > **Subagent tools** are not flow step types \u2014 they are runtime tools attached to prompt steps via \`tools.runtimeTools[]\` with \`toolType: 'subagent'\`. Use them when an agent should delegate focused sub-tasks with tool subsetting and context isolation. See the Subagent Delegation Guide.
43415
+
43416
+ > **Agent-level memory shortcut:** if the memory belongs to an agent (not a standalone flow), prefer the agent's \`memory: { enabled: true }\` config over threading the three steps through a flow. The agent gets the same three operations as tools (\`save_memory\`, \`recall_memory\`, \`memory_summary\`) and auto-ingests each exchange. Use the flow steps only when the memory operation must run deterministically at a fixed point in the flow.
43417
+
43418
+ ### Tool Usage Best Practice
43419
+
43420
+ Prefer registering tools on **prompt** or **execute-agent** steps via \`tools: { toolIds: [...] }\` rather than using standalone \`tool-call\` steps. When tools are registered on a prompt step, the AI model autonomously decides when and how to invoke them, producing more natural and adaptive flows.
43421
+
43422
+ Only use a \`tool-call\` step when the tool must run deterministically at a fixed point in the flow (e.g., always store an asset, always send a notification) regardless of model judgment.
43423
+
43424
+ > **Platform limits:** max 50 runtime tools per dispatch request, 30s tool timeout cap, and tool search auto-activates at 20+ tools (deferred tools become search-loaded). Fetch the \`limits\` documentation topic for the full list.
43425
+
43426
+ ### Variable System
43427
+
43428
+ - System variables (read-only): \`{{_flow.id}}\`, \`{{_flow.name}}\`, \`{{_user.id}}\`, \`{{_organization.id}}\`, \`{{_agent.id}}\`, \`{{_execution.id}}\`, \`{{_execution.conversationId}}\`
43429
+ - Temporal: \`{{_now.date}}\` (YYYY-MM-DD), \`{{_now.time}}\` (HH:mm:ss), \`{{_now.weekday}}\`, \`{{_now.iso}}\`, \`{{_now.year|month|day|unix|timezone}}\` \u2014 rendered in the schedule's tz on schedule-fired runs, UTC otherwise
43430
+ - End-user variables (populated when the caller passes \`endUser\` on dispatch \u2014 Persona widget, SDK \`executeAgent\`, or top-level \`endUser: { id, email?, ... }\` on the dispatch body): \`{{_endUser.id}}\`, \`{{_endUser.email}}\`, plus any additional fields the caller provides under \`_endUser.*\`. Use these for memory sharding in SaaS products where your customer's users are not Runtype account holders.
43431
+ - Product Tenant variables (populated when the caller passes \`tenant\` on dispatch or \`agents/:id/execute\` \u2014 top-level \`tenant: { id, ... }\` on the body): \`{{_tenant.id}}\`, plus any additional fields under \`_tenant.*\`. The Product Tenant is the builder's customer/account *inside* a Product (nested under the Builder Org \`_user\` and above the individual End User \`_endUser\`). Use \`{{_tenant.id}}\` to address account-level scope shared by all of a tenant's end-users (e.g. shard shared memory by \`{{_tenant.id}}\` while sharding per-user memory by \`{{_endUser.id}}\`).
43432
+ - Record variables: \`{{_record.id}}\`, \`{{_record.name}}\`, \`{{_record.type}}\`, \`{{_record.metadata.field}}\`
43433
+ - Schedule (schedule-fired runs only): \`{{_schedule.id}}\`, \`{{_schedule.name}}\`, \`{{_schedule.cron}}\`, \`{{_schedule.timezone}}\`, \`{{_schedule.lastRunAt}}\`, \`{{_schedule.nextRunAt}}\` \u2014 useful for incremental-window patterns: \`{{_schedule.lastRunAt || "24h ago"}}\`
43434
+ - Message variables: \`{{messages}}\`, \`{{userMessage}}\`, \`{{lastMessage}}\`, \`{{messageCount}}\`
43435
+ - Step outputs: Use the outputVariable name from previous steps, e.g., \`{{result}}\`, \`{{analysis}}\`
43436
+ - **One distinct \`outputVariable\` per step \u2014 never share one across \`when\`-guarded steps.** A \`when\`-skipped step does not no-op; the engine writes \`null\` to its \`outputVariable\`. With last-writer-wins, if several steps point at the SAME output name (e.g. five HTTP-method steps all writing \`response\`), the skipped ones null out the value the one that ran produced, and every downstream read sees \`null\`. Give each step its own name (\`response_get\`, \`response_post\`, \u2026) and coalesce them in a final step (\`{{response_get || response_post || ...}}\`, or a transform-data returning the first non-null).
43437
+ - Custom inputs: \`{{input_name}}\` \u2014 top-level variables passed via dispatch inputs
43438
+ - Defaults & fallbacks:
43439
+ - Legacy literal default: \`{{name|Anonymous}}\` \u2014 uses \`Anonymous\` if \`name\` is unset
43440
+ - Truthy fallback: \`{{primary || fallback}}\` \u2014 first truthy operand wins (skips empty strings, 0, false)
43441
+ - Nullish fallback: \`{{count ?? 0}}\` \u2014 keeps 0 / "" / false (only null/undefined fall through)
43442
+ - Chains: \`{{a || b || "default"}}\` \u2014 supports paths and string/number/boolean/null literals; do NOT mix \`||\` and \`??\` in one expression
43443
+
43444
+ ### Model Selection
43445
+
43446
+ Use ONLY routed model IDs from the list below (platform-key compatible). Never
43447
+ emit dated or legacy IDs (e.g. \`gpt-4.1\`, \`gpt-4o\`, \`claude-sonnet-4\`) \u2014 they
43448
+ are not enabled for new accounts. Match the model to the step's actual work:
43449
+
43450
+ ${renderDefaultModelStrengthsGuide()}`;
42795
43451
  var CATEGORY_DISPLAY_NAMES = {
42796
43452
  [BuiltInToolCategory.IMAGE_GENERATION]: "Image Generation",
42797
43453
  [BuiltInToolCategory.WEB_SEARCH]: "Web Search",
@@ -42867,6 +43523,7 @@ ${orthogonalLines.join("\n")}
42867
43523
  - **Web search (provider-native, inline citations)** \u2192 see Provider-Native Search section above
42868
43524
  - **Web search (standalone, AI-powered)** \u2192 \`builtin:exa\`
42869
43525
  - **Simple web scraping to markdown** \u2192 \`builtin:firecrawl\`
43526
+ - **Research/scraping a site that blocks bots** \u2192 prefer \`builtin:firecrawl\` or \`builtin:exa\` over the raw \`fetch-url\`/\`crawl\` flow steps. Those steps request from datacenter IPs flagged as non-human traffic, so sites behind a WAF/anti-bot service often return a 403, CAPTCHA, or empty body. A mixed approach (fetch first, fall back to Firecrawl/Exa on a block) is the most reliable.
42870
43527
  - **Rendered web pages, screenshots, structured extraction, or link harvesting** \u2192 \`builtin:browser:markdown\`, \`builtin:browser:snapshot\`, \`builtin:browser:json\`, \`builtin:browser:scrape\`, \`builtin:browser:links\` (stateless, one-shot \u2014 cheap, no session overhead)
42871
43528
  - **Autonomous browsing (just want the outcome \u2014 extract data, complete a form, find info on a page)** \u2192 \`builtin:browser:agent\` with a natural-language \`goal\` plus \`startUrl\` (fresh browser) or \`sessionId\` (continue an existing session). Stagehand handles observe/act/extract; you get back text or, with an \`outputSchema\`, structured JSON. Try this BEFORE reaching for the manual session tools below.
42872
43529
  - **Interactive browsing (precise control over individual actions)** \u2192 \`builtin:browser:open\` to start a session, then \`builtin:browser:click\`, \`builtin:browser:type\`, \`builtin:browser:scroll\`, \`builtin:browser:session-screenshot\`, \`builtin:browser:evaluate\`, \`builtin:browser:navigate\`, and \`builtin:browser:close\` when done. Session tools maintain cookies and page state across calls but cost more than stateless tools \u2014 prefer stateless tools when a single page read suffices.
@@ -42932,6 +43589,7 @@ Tools are added to prompt steps via \`tools: { toolIds: ["<id>"] }\`. The AI mod
42932
43589
  - **Web search (provider-native, inline citations)** \u2192 see the Provider-Native Search section
42933
43590
  - **Web search (standalone, AI-powered)** \u2192 \`builtin:exa\`
42934
43591
  - **Simple web scraping to markdown** \u2192 \`builtin:firecrawl\`
43592
+ - **Research/scraping a site that blocks bots** \u2192 prefer \`builtin:firecrawl\` or \`builtin:exa\` over the raw \`fetch-url\`/\`crawl\` flow steps. Those steps request from datacenter IPs flagged as non-human traffic, so sites behind a WAF/anti-bot service often return a 403, CAPTCHA, or empty body. A mixed approach (fetch first, fall back to Firecrawl/Exa on a block) is the most reliable.
42935
43593
  - **Rendered web pages, screenshots, structured extraction, or link harvesting** \u2192 \`builtin:browser:markdown\`, \`builtin:browser:snapshot\`, \`builtin:browser:json\`, \`builtin:browser:scrape\`, \`builtin:browser:links\` (stateless, one-shot)
42936
43594
  - **Autonomous browsing (just want the outcome)** \u2192 \`builtin:browser:agent\` with a natural-language \`goal\` plus \`startUrl\` or \`sessionId\` \u2014 try this BEFORE the manual session tools
42937
43595
  - **Interactive browsing (precise control)** \u2192 \`builtin:browser:open\`, then \`builtin:browser:click\` / \`type\` / \`scroll\` / \`session-screenshot\` / \`evaluate\` / \`navigate\`, and \`builtin:browser:close\` when done
@@ -43606,6 +44264,22 @@ function selectAccountId(params) {
43606
44264
  if (isValidAccountId(params.userId)) return params.userId;
43607
44265
  return void 0;
43608
44266
  }
44267
+ function flattenTextContent(content) {
44268
+ if (typeof content === "string") return content;
44269
+ return content.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
44270
+ }
44271
+ function hasUsableClaudeManagedSeed(messages) {
44272
+ let lastUserIndex = -1;
44273
+ for (let i = messages.length - 1; i >= 0; i--) {
44274
+ if (messages[i]?.role === "user") {
44275
+ lastUserIndex = i;
44276
+ break;
44277
+ }
44278
+ }
44279
+ if (lastUserIndex === -1) return false;
44280
+ if (lastUserIndex > 0) return true;
44281
+ return flattenTextContent(messages[lastUserIndex].content).length > 0;
44282
+ }
43609
44283
  var RecordInputSchema = external_exports.object({
43610
44284
  id: external_exports.string().min(1).optional(),
43611
44285
  name: external_exports.string().min(1).optional(),
@@ -43866,6 +44540,12 @@ var DispatchRequestSchema = external_exports.object({
43866
44540
  tenant: external_exports.object({
43867
44541
  id: external_exports.string().min(1)
43868
44542
  }).passthrough().optional(),
44543
+ // Identity Exchange proof (design §4.1): a customer-native auth token the
44544
+ // broker will verify server-side and admit as `verified` tenant/end-user.
44545
+ // Wire contract only for now — parsed here, consumed by NOTHING until the
44546
+ // admission slice wires verification into the tenancy seam. The token is a
44547
+ // live credential: never log or persist it (see identityProofSchema docs).
44548
+ identityProof: identityProofSchema.optional(),
43869
44549
  options: external_exports.object({
43870
44550
  streamResponse: external_exports.boolean().optional().default(true),
43871
44551
  modelOverride: external_exports.string().optional(),
@@ -43901,6 +44581,15 @@ var DispatchRequestSchema = external_exports.object({
43901
44581
  })
43902
44582
  }).refine((data) => data.flow || data.agent, {
43903
44583
  message: "Either 'flow' or 'agent' configuration must be provided"
44584
+ }).superRefine((data, ctx) => {
44585
+ if (data.agent?.agentType !== "claude_managed") return;
44586
+ if (!hasUsableClaudeManagedSeed(data.messages ?? [])) {
44587
+ ctx.addIssue({
44588
+ code: "custom",
44589
+ path: ["messages"],
44590
+ message: "messages with a non-empty user message is required for Claude Managed agents"
44591
+ });
44592
+ }
43904
44593
  });
43905
44594
  var RunFlowOptionsSchema = external_exports.object({
43906
44595
  recordId: external_exports.string().optional(),
@@ -43952,6 +44641,15 @@ var RuntimeProxyToolConfigSchema = external_exports.object({
43952
44641
  toolCallStrategy: external_exports.enum(["auto", "required", "none"]).optional(),
43953
44642
  onToolError: external_exports.enum(["fail", "continue", "retry"]).optional()
43954
44643
  });
44644
+ var RuntimeProxyProviderTransportSchema = external_exports.object({
44645
+ mixlayer: external_exports.object({
44646
+ modelApi: external_exports.enum(["chat", "responses"]).optional(),
44647
+ responsesTransport: external_exports.enum(["http", "websocket"]).optional()
44648
+ }).optional(),
44649
+ openai: external_exports.object({
44650
+ responsesTransport: external_exports.enum(["http", "websocket"]).optional()
44651
+ }).optional()
44652
+ });
43955
44653
  var RuntimeProxyRequestSchema = external_exports.object({
43956
44654
  model: external_exports.string().min(1),
43957
44655
  prompt: external_exports.string().default(""),
@@ -43968,6 +44666,7 @@ var RuntimeProxyRequestSchema = external_exports.object({
43968
44666
  seed: external_exports.number().int().optional(),
43969
44667
  tools: external_exports.array(RuntimeProxyToolSchema).optional(),
43970
44668
  providerTools: external_exports.array(RuntimeProxyProviderToolSchema).optional(),
44669
+ providerTransport: RuntimeProxyProviderTransportSchema.optional(),
43971
44670
  toolConfiguration: RuntimeProxyToolConfigSchema.optional()
43972
44671
  }).optional().default({})
43973
44672
  });
@@ -44952,11 +45651,11 @@ async function promptConfirm(message, options) {
44952
45651
  return new Promise((resolve12) => {
44953
45652
  rl.question(chalk3.cyan(`${message} (${hint}): `), (answer) => {
44954
45653
  rl.close();
44955
- const trimmed = answer.trim().toLowerCase();
44956
- if (trimmed === "") {
45654
+ const trimmed2 = answer.trim().toLowerCase();
45655
+ if (trimmed2 === "") {
44957
45656
  resolve12(defaultYes);
44958
45657
  } else {
44959
- resolve12(trimmed === "y" || trimmed === "yes");
45658
+ resolve12(trimmed2 === "y" || trimmed2 === "yes");
44960
45659
  }
44961
45660
  });
44962
45661
  });
@@ -47338,7 +48037,13 @@ secretsCommand.command("get <id>").description("Get secret metadata (value is ne
47338
48037
  const { waitUntilExit } = render6(React6.createElement(App));
47339
48038
  await waitUntilExit();
47340
48039
  });
47341
- secretsCommand.command("create").description("Create a new secret (provide the value via --value or stdin)").requiredOption("-k, --key <key>", "Secret key (alphanumeric/underscore, starts with a letter)").option("--value <value>", "Secret value (omit to read from stdin without echo)").option("-d, --description <text>", "Secret description").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(
48040
+ secretsCommand.command("create").description("Create a new secret (provide the value via --value or stdin)").requiredOption("-k, --key <key>", "Secret key (alphanumeric/underscore, starts with a letter)").option("--value <value>", "Secret value (omit to read from stdin without echo)").option("-d, --description <text>", "Secret description").option(
48041
+ "--product-tenant-id <id>",
48042
+ "Scope the secret to a Product Tenant (tnt_*). Omit for an org-level secret; a scoped secret requires a value."
48043
+ ).option(
48044
+ "--end-user-id <id>",
48045
+ "Scope the secret to an End User (eu_*); its enclosing tenant is derived server-side. Omit for an org-level secret; a scoped secret requires a value."
48046
+ ).option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(
47342
48047
  async (options) => {
47343
48048
  const apiKey = await ensureAuth();
47344
48049
  if (!apiKey) return;
@@ -47358,6 +48063,8 @@ secretsCommand.command("create").description("Create a new secret (provide the v
47358
48063
  description: options.description
47359
48064
  };
47360
48065
  if (value !== void 0) body.value = value;
48066
+ if (options.productTenantId !== void 0) body.productTenantId = options.productTenantId;
48067
+ if (options.endUserId !== void 0) body.endUserId = options.endUserId;
47361
48068
  if (!isTTY(options) || options.json) {
47362
48069
  try {
47363
48070
  const data = await client.post("/secrets", body);
@@ -50469,9 +51176,9 @@ ${delta}` : `${content}${delta}`;
50469
51176
  }
50470
51177
  function getVisibleReasoningLines(reasoning, maxLines) {
50471
51178
  if (maxLines <= 0) return [];
50472
- const trimmed = reasoning.trimEnd();
50473
- if (!trimmed) return [];
50474
- return trimmed.split("\n").slice(-maxLines);
51179
+ const trimmed2 = reasoning.trimEnd();
51180
+ if (!trimmed2) return [];
51181
+ return trimmed2.split("\n").slice(-maxLines);
50475
51182
  }
50476
51183
 
50477
51184
  // src/ink/marathon/useMarathonStream.ts
@@ -52874,12 +53581,12 @@ function parseSandboxTimeout(value, provider) {
52874
53581
  }
52875
53582
  function parseDaytonaExecutionResult(value) {
52876
53583
  if (typeof value !== "string") return value;
52877
- const trimmed = value.trim();
52878
- if (!trimmed) return "";
53584
+ const trimmed2 = value.trim();
53585
+ if (!trimmed2) return "";
52879
53586
  try {
52880
- return JSON.parse(trimmed);
53587
+ return JSON.parse(trimmed2);
52881
53588
  } catch {
52882
- const lines = trimmed.split("\n").map((line) => line.trim()).filter(Boolean);
53589
+ const lines = trimmed2.split("\n").map((line) => line.trim()).filter(Boolean);
52883
53590
  const lastLine = lines[lines.length - 1];
52884
53591
  if (!lastLine) return value;
52885
53592
  try {
@@ -54998,9 +55705,9 @@ function CheckpointPrompt({
54998
55705
  onSubmit
54999
55706
  ]);
55000
55707
  const handleSubmit = (text) => {
55001
- const trimmed = text.trim();
55002
- const modelArg = trimmed.startsWith("/model") ? trimmed.slice("/model".length).trim() : "";
55003
- if (trimmed.startsWith("/model")) {
55708
+ const trimmed2 = text.trim();
55709
+ const modelArg = trimmed2.startsWith("/model") ? trimmed2.slice("/model".length).trim() : "";
55710
+ if (trimmed2.startsWith("/model")) {
55004
55711
  clearInputDraft();
55005
55712
  if (modelArg) {
55006
55713
  setPendingModel(modelArg);
@@ -55009,53 +55716,53 @@ function CheckpointPrompt({
55009
55716
  }
55010
55717
  return;
55011
55718
  }
55012
- if (trimmed.startsWith("/reflect")) {
55719
+ if (trimmed2.startsWith("/reflect")) {
55013
55720
  setShowReflectEditor(true);
55014
55721
  clearInputDraft();
55015
55722
  return;
55016
55723
  }
55017
- if (trimmed === "/tree") {
55724
+ if (trimmed2 === "/tree") {
55018
55725
  setTreePanelRows(onLoadTreeView?.() ?? []);
55019
55726
  clearInputDraft();
55020
55727
  return;
55021
55728
  }
55022
- if (trimmed === "/fork") {
55729
+ if (trimmed2 === "/fork") {
55023
55730
  setForkCandidates(onLoadForkCandidates?.() ?? []);
55024
55731
  clearInputDraft();
55025
55732
  return;
55026
55733
  }
55027
- if (trimmed === "/copy") {
55734
+ if (trimmed2 === "/copy") {
55028
55735
  onCopySession?.();
55029
55736
  clearInputDraft();
55030
55737
  return;
55031
55738
  }
55032
- if (trimmed === "/copy-trimmed") {
55739
+ if (trimmed2 === "/copy-trimmed") {
55033
55740
  onCopySessionTrimmed?.();
55034
55741
  clearInputDraft();
55035
55742
  return;
55036
55743
  }
55037
- if (trimmed === "/open") {
55744
+ if (trimmed2 === "/open") {
55038
55745
  onOpenStateFile?.();
55039
55746
  clearInputDraft();
55040
55747
  return;
55041
55748
  }
55042
- if (trimmed.startsWith("/help")) {
55749
+ if (trimmed2.startsWith("/help")) {
55043
55750
  onToggleHelp();
55044
55751
  clearInputDraft();
55045
55752
  return;
55046
55753
  }
55047
- if (trimmed.startsWith("/tools")) {
55754
+ if (trimmed2.startsWith("/tools")) {
55048
55755
  setPendingToolsToggle((prev) => !prev);
55049
55756
  clearInputDraft();
55050
55757
  return;
55051
55758
  }
55052
- if (trimmed.startsWith("/sandbox")) {
55053
- const arg = trimmed.slice("/sandbox".length).trim();
55759
+ if (trimmed2.startsWith("/sandbox")) {
55760
+ const arg = trimmed2.slice("/sandbox".length).trim();
55054
55761
  setPendingSandbox(arg ? arg : false);
55055
55762
  clearInputDraft();
55056
55763
  return;
55057
55764
  }
55058
- if (trimmed.startsWith("/stop")) {
55765
+ if (trimmed2.startsWith("/stop")) {
55059
55766
  setPendingStop((prev) => !prev);
55060
55767
  clearInputDraft();
55061
55768
  return;
@@ -55064,11 +55771,11 @@ function CheckpointPrompt({
55064
55771
  submitStagedResult("stop");
55065
55772
  return;
55066
55773
  }
55067
- if (trimmed === "") {
55774
+ if (trimmed2 === "") {
55068
55775
  submitStagedResult("continue");
55069
55776
  return;
55070
55777
  }
55071
- submitStagedResult("steer", trimmed);
55778
+ submitStagedResult("steer", trimmed2);
55072
55779
  };
55073
55780
  const handleModelSelect = (model) => {
55074
55781
  setShowModelPicker(false);
@@ -55079,11 +55786,11 @@ function CheckpointPrompt({
55079
55786
  };
55080
55787
  const handleReflectSubmit = (message) => {
55081
55788
  setShowReflectEditor(false);
55082
- const trimmed = message.trim();
55083
- if (trimmed) {
55789
+ const trimmed2 = message.trim();
55790
+ if (trimmed2) {
55084
55791
  setValue((prev) => prev.trim() ? `${prev}
55085
55792
 
55086
- ${trimmed}` : trimmed);
55793
+ ${trimmed2}` : trimmed2);
55087
55794
  setIsTyping(true);
55088
55795
  }
55089
55796
  };
@@ -55219,12 +55926,12 @@ function SteerComposer({ initialDraft = "", onSubmit, onCancel }) {
55219
55926
  }
55220
55927
  });
55221
55928
  const handleSubmit = (text) => {
55222
- const trimmed = text.trim();
55223
- if (!trimmed) {
55929
+ const trimmed2 = text.trim();
55930
+ if (!trimmed2) {
55224
55931
  onCancel("");
55225
55932
  return;
55226
55933
  }
55227
- onSubmit(trimmed, kind);
55934
+ onSubmit(trimmed2, kind);
55228
55935
  };
55229
55936
  const kindLabel = kind === "steer" ? "deliver: next turn" : "deliver: after all work";
55230
55937
  return /* @__PURE__ */ jsxs23(
@@ -57229,8 +57936,8 @@ function MarathonApp({
57229
57936
  adjustedContentHeight - reasoningHintRows - reasoningBodyRows - reasoningLiveRows - thinkingRows - compactionIndicatorRows
57230
57937
  );
57231
57938
  const reasoningDetailLineCount = useMemo11(() => {
57232
- const trimmed = displayedReasoning.trimEnd();
57233
- return trimmed ? getReasoningLines(trimmed, terminalWidth).length : 0;
57939
+ const trimmed2 = displayedReasoning.trimEnd();
57940
+ return trimmed2 ? getReasoningLines(trimmed2, terminalWidth).length : 0;
57234
57941
  }, [displayedReasoning, terminalWidth]);
57235
57942
  const fileDetailRenderedLineCount = useMemo11(
57236
57943
  () => detailFile && detailFileContent ? getFileRenderedLineCount(detailFile.path, detailFileContent, terminalWidth) : 0,
@@ -58462,10 +59169,10 @@ var ALLOWED_VERIFICATION_COMMANDS = [
58462
59169
  /^(?:make|just)\s+(?:test|lint|build|check|typecheck)\b/i
58463
59170
  ];
58464
59171
  function isSafeVerificationCommand(command) {
58465
- const trimmed = command.trim();
58466
- if (!trimmed) return false;
58467
- if (BLOCKED_VERIFICATION_PATTERNS.some((pattern) => pattern.test(trimmed))) return false;
58468
- return ALLOWED_VERIFICATION_COMMANDS.some((pattern) => pattern.test(trimmed));
59172
+ const trimmed2 = command.trim();
59173
+ if (!trimmed2) return false;
59174
+ if (BLOCKED_VERIFICATION_PATTERNS.some((pattern) => pattern.test(trimmed2))) return false;
59175
+ return ALLOWED_VERIFICATION_COMMANDS.some((pattern) => pattern.test(trimmed2));
58469
59176
  }
58470
59177
  var SCRIPT_COMMAND_PATTERNS = [
58471
59178
  {
@@ -58482,9 +59189,9 @@ var SCRIPT_COMMAND_PATTERNS = [
58482
59189
  }
58483
59190
  ];
58484
59191
  function getScriptConfigFiles(command) {
58485
- const trimmed = command.trim();
59192
+ const trimmed2 = command.trim();
58486
59193
  for (const { pattern, files } of SCRIPT_COMMAND_PATTERNS) {
58487
- if (pattern.test(trimmed)) return files;
59194
+ if (pattern.test(trimmed2)) return files;
58488
59195
  }
58489
59196
  return [];
58490
59197
  }
@@ -60480,12 +61187,12 @@ function resolveModelContextLength(modelId, configuredModels, availableModels) {
60480
61187
  }
60481
61188
  function resolveAutoCompactTokenThreshold(modelContextLength, rawThreshold, strategy = "summary_fallback") {
60482
61189
  const effectiveBudget = resolveEffectiveInputBudgetTokens(modelContextLength);
60483
- const trimmed = rawThreshold?.trim();
60484
- if (!trimmed) {
61190
+ const trimmed2 = rawThreshold?.trim();
61191
+ if (!trimmed2) {
60485
61192
  const ratio = strategy === "provider_native" ? DEFAULT_PROVIDER_NATIVE_COMPACT_THRESHOLD_RATIO : DEFAULT_AUTO_COMPACT_THRESHOLD_RATIO;
60486
61193
  return typeof effectiveBudget === "number" && effectiveBudget > 0 ? Math.max(1, Math.floor(effectiveBudget * ratio)) : void 0;
60487
61194
  }
60488
- const percentMatch = trimmed.match(/^(\d+(?:\.\d+)?)%$/);
61195
+ const percentMatch = trimmed2.match(/^(\d+(?:\.\d+)?)%$/);
60489
61196
  if (percentMatch) {
60490
61197
  const percentValue = Number(percentMatch[1]);
60491
61198
  if (!Number.isFinite(percentValue) || percentValue <= 0 || percentValue > 100) {
@@ -60495,7 +61202,7 @@ function resolveAutoCompactTokenThreshold(modelContextLength, rawThreshold, stra
60495
61202
  }
60496
61203
  return typeof effectiveBudget === "number" && effectiveBudget > 0 ? Math.max(1, Math.floor(effectiveBudget * (percentValue / 100))) : void 0;
60497
61204
  }
60498
- const numericValue = Number(trimmed);
61205
+ const numericValue = Number(trimmed2);
60499
61206
  if (!Number.isFinite(numericValue) || numericValue <= 0) {
60500
61207
  throw new Error(
60501
61208
  `Invalid --compact-threshold value "${rawThreshold}". Use a percentage (e.g. 80%) or absolute token count (e.g. 120000).`
@@ -60965,9 +61672,9 @@ function formatBytes(bytes) {
60965
61672
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
60966
61673
  }
60967
61674
  function normalizeStartupModelOptionValue(value) {
60968
- const trimmed = value?.trim().toLowerCase().replace(/^model\//, "") ?? "";
60969
- if (!trimmed) return "";
60970
- const withoutProvider = trimmed.includes(":") ? trimmed.split(":").slice(1).join(":") : trimmed;
61675
+ const trimmed2 = value?.trim().toLowerCase().replace(/^model\//, "") ?? "";
61676
+ if (!trimmed2) return "";
61677
+ const withoutProvider = trimmed2.includes(":") ? trimmed2.split(":").slice(1).join(":") : trimmed2;
60971
61678
  if (withoutProvider.includes("/")) {
60972
61679
  return withoutProvider.split("/").pop() ?? withoutProvider;
60973
61680
  }
@@ -61049,8 +61756,8 @@ function buildMarathonClientHeaders(devPlanOverride) {
61049
61756
  };
61050
61757
  }
61051
61758
  function normalizeMarathonAgentArgument(agent) {
61052
- const trimmed = agent.trim();
61053
- if (trimmed.length < 2) return trimmed;
61759
+ const trimmed2 = agent.trim();
61760
+ if (trimmed2.length < 2) return trimmed2;
61054
61761
  const matchingQuotePairs = [
61055
61762
  ['"', '"'],
61056
61763
  ["'", "'"],
@@ -61058,12 +61765,12 @@ function normalizeMarathonAgentArgument(agent) {
61058
61765
  ["\u2018", "\u2019"]
61059
61766
  ];
61060
61767
  for (const [openQuote, closeQuote] of matchingQuotePairs) {
61061
- if (trimmed.startsWith(openQuote) && trimmed.endsWith(closeQuote)) {
61062
- const unwrapped = trimmed.slice(openQuote.length, trimmed.length - closeQuote.length).trim();
61063
- return unwrapped || trimmed;
61768
+ if (trimmed2.startsWith(openQuote) && trimmed2.endsWith(closeQuote)) {
61769
+ const unwrapped = trimmed2.slice(openQuote.length, trimmed2.length - closeQuote.length).trim();
61770
+ return unwrapped || trimmed2;
61064
61771
  }
61065
61772
  }
61066
- return trimmed;
61773
+ return trimmed2;
61067
61774
  }
61068
61775
  function buildMarathonAutoCreatedAgentBootstrap(agentName, options = {}) {
61069
61776
  const normalizedModel = options.model?.trim();
@@ -64325,7 +65032,10 @@ function printSuiteResult(rootDir, outcome) {
64325
65032
  const rel = relative6(rootDir, outcome.file) || outcome.file;
64326
65033
  const badge = result.passed ? chalk27.green("PASS") : chalk27.red("FAIL");
64327
65034
  const score = `${result.passedCases}/${result.totalCases}`;
64328
- console.log(`${badge} ${chalk27.bold(definition.name)} ${chalk27.gray(`(${score} cases \xB7 ${rel})`)}`);
65035
+ const runRef = result.runId ? ` \xB7 run ${result.runId}` : "";
65036
+ console.log(
65037
+ `${badge} ${chalk27.bold(definition.name)} ${chalk27.gray(`(${score} cases \xB7 ${rel}${runRef})`)}`
65038
+ );
64329
65039
  for (const testCase of result.cases) {
64330
65040
  const caseBadge = testCase.passed ? chalk27.green(" \u2713") : chalk27.red(" \u2717");
64331
65041
  console.log(`${caseBadge} ${testCase.name}`);
@@ -66545,11 +67255,11 @@ async function promptLine(rl, question, defaultValue) {
66545
67255
  const answer = await new Promise((resolve12) => {
66546
67256
  rl.question(`${question}${hint}: `, resolve12);
66547
67257
  });
66548
- const trimmed = answer.trim();
66549
- if (!trimmed && defaultValue !== void 0) {
67258
+ const trimmed2 = answer.trim();
67259
+ if (!trimmed2 && defaultValue !== void 0) {
66550
67260
  return defaultValue;
66551
67261
  }
66552
- return trimmed;
67262
+ return trimmed2;
66553
67263
  }
66554
67264
  async function promptConfirm2(rl, message, defaultYes = false) {
66555
67265
  const hint = defaultYes ? chalk30.dim(" (Y/n)") : chalk30.dim(" (y/N)");
@@ -68334,9 +69044,9 @@ async function readInput(input) {
68334
69044
  if (!input || input === "-") {
68335
69045
  return await readStdin();
68336
69046
  }
68337
- const trimmed = input.trim();
68338
- if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
68339
- return trimmed;
69047
+ const trimmed2 = input.trim();
69048
+ if (trimmed2.startsWith("{") || trimmed2.startsWith("[")) {
69049
+ return trimmed2;
68340
69050
  }
68341
69051
  return readFileSync18(input, "utf-8");
68342
69052
  }
@@ -70255,6 +70965,19 @@ function maybeNotifyAboutCliUpdate(args, options = {}) {
70255
70965
  void refreshCliUpdateMetadata(options);
70256
70966
  }
70257
70967
 
70968
+ // src/lib/global-option-forwarding.ts
70969
+ function registerGlobalOptionForwarding(program2) {
70970
+ program2.hook("preAction", (_thisCommand, actionCommand) => {
70971
+ const globals = program2.opts();
70972
+ if (typeof globals.apiUrl === "string" && globals.apiUrl.length > 0) {
70973
+ process.env.RUNTYPE_API_URL = globals.apiUrl;
70974
+ }
70975
+ if (globals.json === true && actionCommand.getOptionValue("json") === void 0) {
70976
+ actionCommand.setOptionValue("json", true);
70977
+ }
70978
+ });
70979
+ }
70980
+
70258
70981
  // src/index.ts
70259
70982
  loadEnv();
70260
70983
  setCliTitle();
@@ -70293,6 +71016,7 @@ program.addCommand(validateProductCommand);
70293
71016
  program.addCommand(deployCommand);
70294
71017
  program.addCommand(skillsCommand);
70295
71018
  program.addCommand(appsCommand);
71019
+ registerGlobalOptionForwarding(program);
70296
71020
  program.exitOverride();
70297
71021
  async function run() {
70298
71022
  const userArgs = process.argv.slice(2);
@@ -70315,7 +71039,9 @@ run().catch((error51) => {
70315
71039
  } else if (commanderError.code === "commander.unknownOption") {
70316
71040
  console.error(chalk42.red(`Error: ${commanderError.message}`));
70317
71041
  process.exit(1);
70318
- } else if (commanderError.code === "commander.help" || commanderError.code === "commander.version") {
71042
+ } else if (commanderError.code === "commander.unknownCommand") {
71043
+ process.exit(1);
71044
+ } else if (commanderError.code === "commander.help" || commanderError.code === "commander.helpDisplayed" || commanderError.code === "commander.version") {
70319
71045
  process.exit(0);
70320
71046
  } else {
70321
71047
  console.error(chalk42.red("An unexpected error occurred:"));