@runtypelabs/cli 2.19.1 → 2.19.3

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 +3252 -26
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -15164,7 +15164,7 @@ var apiRoutingDocSchema = external_exports.object({
15164
15164
  path: ["api", "activeScript"]
15165
15165
  });
15166
15166
 
15167
- // ../shared/dist/chunk-R66POVE6.mjs
15167
+ // ../shared/dist/chunk-KR4LFVFE.mjs
15168
15168
  function getNestedValue(obj, path18) {
15169
15169
  let normalizedPath = path18;
15170
15170
  normalizedPath = normalizedPath.replace(/^\$\.?/, "");
@@ -15200,6 +15200,12 @@ function getNestedValue(obj, path18) {
15200
15200
  return current;
15201
15201
  }
15202
15202
  var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
15203
+ var MESSAGE_VARIABLES = /* @__PURE__ */ new Set([
15204
+ "messages",
15205
+ "userMessage",
15206
+ "lastMessage",
15207
+ "messageCount"
15208
+ ]);
15203
15209
  var SYSTEM_VARIABLES = /* @__PURE__ */ new Set([
15204
15210
  "_flow",
15205
15211
  "_user",
@@ -15207,10 +15213,15 @@ var SYSTEM_VARIABLES = /* @__PURE__ */ new Set([
15207
15213
  "_record",
15208
15214
  "_now",
15209
15215
  "_schedule",
15210
- "messages",
15211
- "userMessage",
15212
- "lastMessage",
15213
- "messageCount"
15216
+ // `_tools` is engine-populated, but LATER than the other system vars: it is
15217
+ // injected after tool resolution, just before dispatch (see
15218
+ // `injectToolsSystemVariable` in the api prompt-executor), so a prompt may
15219
+ // reference `{{_tools.interfaces}}` / `{{_tools.count}}` / `{{_tools.names}}`.
15220
+ // It belongs to the system namespace so the validator / FPO gate don't flag
15221
+ // it as undeclared and the executors don't report it as "unresolved" before
15222
+ // injection runs.
15223
+ "_tools",
15224
+ ...MESSAGE_VARIABLES
15214
15225
  ]);
15215
15226
  var SECRET_REF_PATTERN = /\{\{secret:([A-Z][A-Z0-9_]*[A-Z0-9])\}\}/g;
15216
15227
  var RUNTIME_PREFIXES = {
@@ -15355,6 +15366,18 @@ function stringifyValue(value) {
15355
15366
  if (typeof value === "object") return JSON.stringify(value);
15356
15367
  return String(value);
15357
15368
  }
15369
+ function extractTemplateExpressionPaths(expr) {
15370
+ let parsed;
15371
+ try {
15372
+ parsed = parseTemplateExpression(expr);
15373
+ } catch {
15374
+ return [];
15375
+ }
15376
+ if (parsed.kind === "legacy") {
15377
+ return parsed.variable ? [parsed.variable] : [];
15378
+ }
15379
+ return parsed.operands.filter((o) => o.kind === "path").map((o) => o.path);
15380
+ }
15358
15381
  var _SimpleTemplateEngine = class _SimpleTemplateEngine2 {
15359
15382
  substitute(template, context = {}) {
15360
15383
  const usedVariables = [];
@@ -15527,8 +15550,12 @@ function resolveFallback(parsed, context, tracking) {
15527
15550
  var templateEngine = new SimpleTemplateEngine();
15528
15551
 
15529
15552
  // ../shared/dist/index.mjs
15553
+ var FORMULA_TRIGGER = /^[=+\-@\t\r\n]/;
15554
+ var STRICT_NUMBER = /^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;
15530
15555
  function neutralizeCsvFormula(value) {
15531
- return /^[=+\-@\t\r\n]/.test(value) ? `'${value}` : value;
15556
+ if (!FORMULA_TRIGGER.test(value)) return value;
15557
+ if (STRICT_NUMBER.test(value)) return value;
15558
+ return `'${value}`;
15532
15559
  }
15533
15560
  var mediaAnnotationsSchema = external_exports.object({
15534
15561
  audience: external_exports.array(external_exports.enum(["user", "assistant"])).optional()
@@ -15986,7 +16013,15 @@ var stepCompleteEventSchema = external_exports.object({
15986
16013
  stopReason: wireStopReasonSchema.optional(),
15987
16014
  stepId: external_exports.string().optional(),
15988
16015
  stepName: external_exports.string().optional(),
15989
- toolContext: toolContextSchema.optional()
16016
+ toolContext: toolContextSchema.optional(),
16017
+ // Template variables that were still unresolved (`{{...}}` left intact) when
16018
+ // the prompt was dispatched to the model — the catch-all observability signal
16019
+ // for a surviving token (a missing flow input, an undeclared variable, or an
16020
+ // unknown-namespace typo). Only prompt steps populate it, and only when
16021
+ // non-empty; absence means every reference resolved. Non-fatal: the step still
16022
+ // ran. Sourced from the template engine's `missingVariables`, which already
16023
+ // includes unknown-namespace tokens (see `TemplateSubstitutionResult`).
16024
+ unresolvedVariables: external_exports.array(external_exports.string()).optional()
15990
16025
  });
15991
16026
  var stepErrorEventSchema = external_exports.object({
15992
16027
  ...baseFlowEvent,
@@ -16441,6 +16476,79 @@ var ExecuteToolSchema = external_exports.object({
16441
16476
  userId: external_exports.string()
16442
16477
  }).optional()
16443
16478
  });
16479
+ function parseToolInstanceId(toolId) {
16480
+ const hashIndex = toolId.indexOf("#");
16481
+ if (hashIndex === -1) {
16482
+ return { baseId: toolId, instanceId: "" };
16483
+ }
16484
+ return {
16485
+ baseId: toolId.substring(0, hashIndex),
16486
+ instanceId: toolId.substring(hashIndex + 1)
16487
+ };
16488
+ }
16489
+ function isBuiltInToolId(toolId) {
16490
+ return toolId.startsWith("builtin:");
16491
+ }
16492
+ function isPlatformToolId(toolId) {
16493
+ return toolId.startsWith("platform:");
16494
+ }
16495
+ var INTEGRATION_SERVER_IDS = /* @__PURE__ */ new Set(["slack", "google", "linear", "github", "telegram"]);
16496
+ function isBuiltInIntegrationToolId(toolId) {
16497
+ if (!toolId.startsWith("builtin:")) return false;
16498
+ const { baseId } = parseToolInstanceId(toolId);
16499
+ const parts = baseId.split(":");
16500
+ if (parts.length < 3) return false;
16501
+ return INTEGRATION_SERVER_IDS.has(parts[1]);
16502
+ }
16503
+ function isMCPToolId(toolId) {
16504
+ return toolId.startsWith("mcp:");
16505
+ }
16506
+ var NAMED_TOOL_REF_PREFIX = "tool:";
16507
+ function isNamedToolRef(toolId) {
16508
+ return toolId.startsWith(NAMED_TOOL_REF_PREFIX) && toolId.length > NAMED_TOOL_REF_PREFIX.length;
16509
+ }
16510
+ function parseNamedToolRef(toolId) {
16511
+ if (!isNamedToolRef(toolId)) return null;
16512
+ return { name: toolId.slice(NAMED_TOOL_REF_PREFIX.length) };
16513
+ }
16514
+ function separateToolIds(toolIds) {
16515
+ const builtInToolIds = [];
16516
+ const platformToolIds = [];
16517
+ const integrationToolIds = [];
16518
+ const mcpToolIds = [];
16519
+ const dataConnectionToolIds = [];
16520
+ const namedToolIds = [];
16521
+ const customToolIds = [];
16522
+ for (const toolId of toolIds) {
16523
+ if (isDataConnectionToolId(toolId)) {
16524
+ dataConnectionToolIds.push(toolId);
16525
+ } else if (isPlatformToolId(toolId)) {
16526
+ platformToolIds.push(toolId);
16527
+ } else if (isBuiltInIntegrationToolId(toolId)) {
16528
+ integrationToolIds.push(toolId);
16529
+ } else if (isBuiltInToolId(toolId)) {
16530
+ builtInToolIds.push(toolId);
16531
+ } else if (isMCPToolId(toolId)) {
16532
+ mcpToolIds.push(toolId);
16533
+ } else if (isNamedToolRef(toolId)) {
16534
+ namedToolIds.push(toolId);
16535
+ } else {
16536
+ customToolIds.push(toolId);
16537
+ }
16538
+ }
16539
+ return {
16540
+ builtInToolIds,
16541
+ platformToolIds,
16542
+ integrationToolIds,
16543
+ mcpToolIds,
16544
+ dataConnectionToolIds,
16545
+ namedToolIds,
16546
+ customToolIds
16547
+ };
16548
+ }
16549
+ function isDataConnectionToolId(toolId) {
16550
+ return toolId.startsWith("dc:");
16551
+ }
16444
16552
  var contextFallbackSchema = external_exports.union([
16445
16553
  external_exports.object({ type: external_exports.literal("retry"), delay: external_exports.number().optional() }),
16446
16554
  external_exports.object({
@@ -17247,6 +17355,1923 @@ var CONTEXT_STEP_TYPES = [
17247
17355
  "memory-summary"
17248
17356
  ];
17249
17357
  var FLOW_STEP_TYPES = ["prompt", ...CONTEXT_STEP_TYPES];
17358
+ var DEFAULT_MANAGED_SEND_FROM_DOMAIN = "runtype.email";
17359
+ var STAGING_MANAGED_SEND_FROM_DOMAIN = "runtype-staging.email";
17360
+ var MANAGED_SEND_FROM_DOMAINS = [
17361
+ DEFAULT_MANAGED_SEND_FROM_DOMAIN,
17362
+ STAGING_MANAGED_SEND_FROM_DOMAIN
17363
+ ];
17364
+ var MANAGED_TEMPLATE_SEND_FROM_ADDRESS_REGEX = /^{{\s*_flow\.id\s*}}@([^@\s]+)$/i;
17365
+ var LEGACY_MANAGED_SEND_FROM_ADDRESS_REGEX = /^[^@\s]+@messages\.runtype\.(com|ai)$/i;
17366
+ function normalizeFromAddress(configuredFrom) {
17367
+ return configuredFrom?.trim() ?? "";
17368
+ }
17369
+ function normalizeDomain(domain2) {
17370
+ return domain2?.trim().toLowerCase() ?? "";
17371
+ }
17372
+ function extractDomainFromAddress(fromAddress) {
17373
+ const normalizedFrom = normalizeFromAddress(fromAddress);
17374
+ const atIndex = normalizedFrom.lastIndexOf("@");
17375
+ if (atIndex === -1) {
17376
+ return void 0;
17377
+ }
17378
+ const domain2 = normalizedFrom.slice(atIndex + 1);
17379
+ return normalizeDomain(domain2) || void 0;
17380
+ }
17381
+ function getReservedManagedSendFromDomains(preferredManagedDomain) {
17382
+ const preferredDomain = normalizeDomain(preferredManagedDomain);
17383
+ const reservedDomains = preferredDomain ? [preferredDomain, ...MANAGED_SEND_FROM_DOMAINS] : [...MANAGED_SEND_FROM_DOMAINS];
17384
+ return Array.from(new Set(reservedDomains));
17385
+ }
17386
+ function isReservedManagedSendFromDomain(domain2, preferredManagedDomain) {
17387
+ const normalizedDomain = normalizeDomain(domain2);
17388
+ if (!normalizedDomain) {
17389
+ return false;
17390
+ }
17391
+ return getReservedManagedSendFromDomains(preferredManagedDomain).includes(normalizedDomain);
17392
+ }
17393
+ function extractManagedTemplateDomain(configuredFrom) {
17394
+ const normalizedFrom = normalizeFromAddress(configuredFrom);
17395
+ const managedTemplateMatch = normalizedFrom.match(MANAGED_TEMPLATE_SEND_FROM_ADDRESS_REGEX);
17396
+ return normalizeDomain(managedTemplateMatch?.[1]) || void 0;
17397
+ }
17398
+ function isManagedTemplateSendFromAddress(configuredFrom, preferredManagedDomain) {
17399
+ return isReservedManagedSendFromDomain(
17400
+ extractManagedTemplateDomain(configuredFrom),
17401
+ preferredManagedDomain
17402
+ );
17403
+ }
17404
+ function isLegacyManagedSendFromAddress(configuredFrom) {
17405
+ return LEGACY_MANAGED_SEND_FROM_ADDRESS_REGEX.test(normalizeFromAddress(configuredFrom));
17406
+ }
17407
+ function shouldUseManagedSendFromAddress(configuredFrom, preferredManagedDomain) {
17408
+ if (!normalizeFromAddress(configuredFrom)) {
17409
+ return true;
17410
+ }
17411
+ return isManagedTemplateSendFromAddress(configuredFrom, preferredManagedDomain) || isLegacyManagedSendFromAddress(configuredFrom);
17412
+ }
17413
+ function isCustomSendFromAddressOnManagedDomain(configuredFrom, preferredManagedDomain) {
17414
+ if (shouldUseManagedSendFromAddress(configuredFrom, preferredManagedDomain)) {
17415
+ return false;
17416
+ }
17417
+ return isReservedManagedSendFromDomain(
17418
+ extractDomainFromAddress(configuredFrom),
17419
+ preferredManagedDomain
17420
+ );
17421
+ }
17422
+ var NormalizationError = class extends Error {
17423
+ constructor(message, stepType, fieldName, expectedType, actualValue) {
17424
+ super(message);
17425
+ this.stepType = stepType;
17426
+ this.fieldName = fieldName;
17427
+ this.expectedType = expectedType;
17428
+ this.actualValue = actualValue;
17429
+ this.name = "NormalizationError";
17430
+ }
17431
+ };
17432
+ function validateRequired(value, fieldName, stepType) {
17433
+ if (value === null || value === void 0 || value === "") {
17434
+ throw new NormalizationError(
17435
+ `Missing required field '${fieldName}' for ${stepType} step`,
17436
+ stepType,
17437
+ fieldName,
17438
+ "non-null value",
17439
+ value
17440
+ );
17441
+ }
17442
+ }
17443
+ function validateString(value, fieldName, stepType, required2 = false) {
17444
+ if (required2) {
17445
+ validateRequired(value, fieldName, stepType);
17446
+ }
17447
+ if (value !== void 0 && value !== null && typeof value !== "string") {
17448
+ throw new NormalizationError(
17449
+ `Field '${fieldName}' must be a string for ${stepType} step`,
17450
+ stepType,
17451
+ fieldName,
17452
+ "string",
17453
+ typeof value
17454
+ );
17455
+ }
17456
+ }
17457
+ function validateNumber(value, fieldName, stepType, required2 = false) {
17458
+ if (required2) {
17459
+ validateRequired(value, fieldName, stepType);
17460
+ }
17461
+ if (value !== void 0 && value !== null) {
17462
+ const num = Number(value);
17463
+ if (isNaN(num)) {
17464
+ throw new NormalizationError(
17465
+ `Field '${fieldName}' must be a number for ${stepType} step`,
17466
+ stepType,
17467
+ fieldName,
17468
+ "number",
17469
+ typeof value
17470
+ );
17471
+ }
17472
+ }
17473
+ }
17474
+ function normalizeOptionalNumber(value) {
17475
+ if (value === void 0 || value === null) {
17476
+ return void 0;
17477
+ }
17478
+ return Number(value);
17479
+ }
17480
+ function validateBoolean(value, fieldName, stepType, required2 = false) {
17481
+ if (required2) {
17482
+ validateRequired(value, fieldName, stepType);
17483
+ }
17484
+ if (value !== void 0 && value !== null && typeof value !== "boolean") {
17485
+ throw new NormalizationError(
17486
+ `Field '${fieldName}' must be a boolean for ${stepType} step`,
17487
+ stepType,
17488
+ fieldName,
17489
+ "boolean",
17490
+ typeof value
17491
+ );
17492
+ }
17493
+ }
17494
+ function validateEnum(value, allowedValues, fieldName, stepType, required2 = false) {
17495
+ if (required2) {
17496
+ validateRequired(value, fieldName, stepType);
17497
+ }
17498
+ if (value !== void 0 && value !== null && !allowedValues.includes(value)) {
17499
+ throw new NormalizationError(
17500
+ `Field '${fieldName}' must be one of [${allowedValues.join(", ")}] for ${stepType} step, got: ${value}`,
17501
+ stepType,
17502
+ fieldName,
17503
+ `one of [${allowedValues.join(", ")}]`,
17504
+ value
17505
+ );
17506
+ }
17507
+ }
17508
+ function validateObject(value, fieldName, stepType, required2 = false) {
17509
+ if (required2) {
17510
+ validateRequired(value, fieldName, stepType);
17511
+ }
17512
+ if (value !== void 0 && value !== null) {
17513
+ if (typeof value !== "object" || Array.isArray(value)) {
17514
+ throw new NormalizationError(
17515
+ `Field '${fieldName}' must be an object for ${stepType} step`,
17516
+ stepType,
17517
+ fieldName,
17518
+ "object",
17519
+ Array.isArray(value) ? "array" : typeof value
17520
+ );
17521
+ }
17522
+ }
17523
+ }
17524
+ function validateArray(value, fieldName, stepType, required2 = false) {
17525
+ if (required2) {
17526
+ validateRequired(value, fieldName, stepType);
17527
+ }
17528
+ if (value !== void 0 && value !== null && !Array.isArray(value)) {
17529
+ throw new NormalizationError(
17530
+ `Field '${fieldName}' must be an array for ${stepType} step`,
17531
+ stepType,
17532
+ fieldName,
17533
+ "array",
17534
+ typeof value
17535
+ );
17536
+ }
17537
+ }
17538
+ function validateConfig(config3, stepType) {
17539
+ if (!config3 || typeof config3 !== "object" || Array.isArray(config3)) {
17540
+ throw new NormalizationError(
17541
+ `Config must be a valid object for ${stepType} step`,
17542
+ stepType,
17543
+ "config",
17544
+ "object",
17545
+ typeof config3
17546
+ );
17547
+ }
17548
+ }
17549
+ function normalizeErrorHandling(value) {
17550
+ if (!value) return void 0;
17551
+ if (typeof value === "object" && value !== null) {
17552
+ const objectValue = value;
17553
+ const onError = objectValue.onError || objectValue.on_error || "continue";
17554
+ return {
17555
+ onError: onError === "default" ? "continue" : onError,
17556
+ fallbacks: objectValue.fallbacks
17557
+ };
17558
+ }
17559
+ if (typeof value === "string") {
17560
+ const validModes = ["fail", "continue", "fallback", "default"];
17561
+ if (!validModes.includes(value)) {
17562
+ return { onError: "continue" };
17563
+ }
17564
+ return {
17565
+ onError: value === "default" ? "continue" : value
17566
+ };
17567
+ }
17568
+ return void 0;
17569
+ }
17570
+ function validateAndNormalizeErrorHandling(value, fieldName, stepType) {
17571
+ if (value === void 0 || value === null) return void 0;
17572
+ if (typeof value === "string") {
17573
+ const validModes = ["fail", "continue", "fallback", "default"];
17574
+ if (!validModes.includes(value)) {
17575
+ throw new NormalizationError(
17576
+ `Field '${fieldName}' must be one of [${validModes.join(", ")}] or an error handling object for ${stepType} step, got: ${value}`,
17577
+ stepType,
17578
+ fieldName,
17579
+ `one of [${validModes.join(", ")}] or object`,
17580
+ value
17581
+ );
17582
+ }
17583
+ }
17584
+ if (typeof value === "object" && value !== null) {
17585
+ const objectValue = value;
17586
+ const onError = objectValue.onError || objectValue.on_error;
17587
+ if (onError) {
17588
+ const validModes = ["fail", "continue", "fallback", "default"];
17589
+ if (!validModes.includes(onError)) {
17590
+ throw new NormalizationError(
17591
+ `Field '${fieldName}.onError' must be one of [${validModes.join(", ")}] for ${stepType} step, got: ${onError}`,
17592
+ stepType,
17593
+ `${fieldName}.onError`,
17594
+ `one of [${validModes.join(", ")}]`,
17595
+ onError
17596
+ );
17597
+ }
17598
+ }
17599
+ }
17600
+ return normalizeErrorHandling(value);
17601
+ }
17602
+ function normalizeContextStep(apiStep, options = {}) {
17603
+ if (!apiStep || typeof apiStep !== "object") {
17604
+ throw new NormalizationError(
17605
+ "Step must be a valid object",
17606
+ "unknown",
17607
+ "apiStep",
17608
+ "object",
17609
+ typeof apiStep
17610
+ );
17611
+ }
17612
+ validateRequired(apiStep.id, "id", apiStep.type || "unknown");
17613
+ validateRequired(apiStep.type, "type", "step");
17614
+ validateRequired(apiStep.name, "name", apiStep.type || "unknown");
17615
+ validateRequired(apiStep.order, "order", apiStep.type || "unknown");
17616
+ validateString(apiStep.id, "id", apiStep.type, true);
17617
+ validateString(apiStep.type, "type", "step", true);
17618
+ validateString(apiStep.name, "name", apiStep.type, true);
17619
+ validateNumber(apiStep.order, "order", apiStep.type, true);
17620
+ const validStepTypes = [
17621
+ "crawl",
17622
+ "fetch-url",
17623
+ "retrieve-record",
17624
+ "fetch-github",
17625
+ "api-call",
17626
+ "transform-data",
17627
+ "template",
17628
+ "conditional",
17629
+ "set-variable",
17630
+ "upsert-record",
17631
+ "send-email",
17632
+ "send-text",
17633
+ "send-event",
17634
+ "send-stream",
17635
+ "update-record",
17636
+ "search",
17637
+ "generate-embedding",
17638
+ "vector-search",
17639
+ "tool-call",
17640
+ "wait-until",
17641
+ "paginate-api",
17642
+ "store-vector",
17643
+ "execute-agent",
17644
+ "store-asset",
17645
+ "generate-pdf",
17646
+ "save-memory",
17647
+ "recall-memory",
17648
+ "memory-summary"
17649
+ ];
17650
+ if (!validStepTypes.includes(apiStep.type)) {
17651
+ throw new NormalizationError(
17652
+ `Unknown context step type: ${apiStep.type}. Must be one of: ${validStepTypes.join(", ")}`,
17653
+ apiStep.type,
17654
+ "type",
17655
+ `one of [${validStepTypes.join(", ")}]`,
17656
+ apiStep.type
17657
+ );
17658
+ }
17659
+ const baseStep = {
17660
+ id: apiStep.id,
17661
+ type: apiStep.type,
17662
+ name: apiStep.name,
17663
+ order: apiStep.order,
17664
+ enabled: apiStep.enabled ?? true
17665
+ };
17666
+ try {
17667
+ switch (apiStep.type) {
17668
+ case "crawl":
17669
+ return {
17670
+ ...baseStep,
17671
+ type: "crawl",
17672
+ config: normalizeCrawlConfig(apiStep.config)
17673
+ };
17674
+ case "fetch-url":
17675
+ return {
17676
+ ...baseStep,
17677
+ type: "fetch-url",
17678
+ config: normalizeFetchUrlConfig(apiStep.config)
17679
+ };
17680
+ case "retrieve-record":
17681
+ return {
17682
+ ...baseStep,
17683
+ type: "retrieve-record",
17684
+ config: normalizeRetrieveRecordConfig(apiStep.config)
17685
+ };
17686
+ case "fetch-github":
17687
+ return {
17688
+ ...baseStep,
17689
+ type: "fetch-github",
17690
+ config: normalizeFetchGithubConfig(apiStep.config)
17691
+ };
17692
+ case "api-call":
17693
+ return {
17694
+ ...baseStep,
17695
+ type: "api-call",
17696
+ config: normalizeApiCallConfig(apiStep.config)
17697
+ };
17698
+ case "transform-data":
17699
+ return {
17700
+ ...baseStep,
17701
+ type: "transform-data",
17702
+ config: normalizeTransformDataConfig(apiStep.config)
17703
+ };
17704
+ case "template":
17705
+ return {
17706
+ ...baseStep,
17707
+ type: "template",
17708
+ config: normalizeTemplateConfig(apiStep.config)
17709
+ };
17710
+ case "conditional":
17711
+ return {
17712
+ ...baseStep,
17713
+ type: "conditional",
17714
+ config: normalizeConditionalConfig(apiStep.config)
17715
+ };
17716
+ case "set-variable":
17717
+ return {
17718
+ ...baseStep,
17719
+ type: "set-variable",
17720
+ config: normalizeSetVariableConfig(apiStep.config)
17721
+ };
17722
+ case "upsert-record":
17723
+ return {
17724
+ ...baseStep,
17725
+ type: "upsert-record",
17726
+ config: normalizeUpsertRecordConfig(apiStep.config)
17727
+ };
17728
+ case "send-email":
17729
+ return {
17730
+ ...baseStep,
17731
+ type: "send-email",
17732
+ config: normalizeSendEmailConfig(apiStep.config, options)
17733
+ };
17734
+ case "send-text":
17735
+ return {
17736
+ ...baseStep,
17737
+ type: "send-text",
17738
+ config: normalizeSendTextConfig(apiStep.config)
17739
+ };
17740
+ case "send-event":
17741
+ return {
17742
+ ...baseStep,
17743
+ type: "send-event",
17744
+ config: normalizeSendEventConfig(apiStep.config)
17745
+ };
17746
+ case "send-stream":
17747
+ return {
17748
+ ...baseStep,
17749
+ type: "send-stream",
17750
+ config: normalizeSendStreamConfig(apiStep.config)
17751
+ };
17752
+ case "update-record":
17753
+ return {
17754
+ ...baseStep,
17755
+ type: "update-record",
17756
+ config: normalizeUpdateRecordConfig(apiStep.config)
17757
+ };
17758
+ case "search":
17759
+ return {
17760
+ ...baseStep,
17761
+ type: "search",
17762
+ config: normalizeSearchConfig(apiStep.config)
17763
+ };
17764
+ case "generate-embedding":
17765
+ return {
17766
+ ...baseStep,
17767
+ type: "generate-embedding",
17768
+ config: normalizeGenerateEmbeddingConfig(apiStep.config)
17769
+ };
17770
+ case "vector-search":
17771
+ return {
17772
+ ...baseStep,
17773
+ type: "vector-search",
17774
+ config: normalizeVectorSearchConfig(apiStep.config)
17775
+ };
17776
+ case "paginate-api":
17777
+ return {
17778
+ ...baseStep,
17779
+ type: "paginate-api",
17780
+ config: normalizePaginateApiConfig(apiStep.config)
17781
+ };
17782
+ case "store-vector":
17783
+ return {
17784
+ ...baseStep,
17785
+ type: "store-vector",
17786
+ config: normalizeStoreVectorConfig(apiStep.config)
17787
+ };
17788
+ case "tool-call":
17789
+ return {
17790
+ ...baseStep,
17791
+ type: "tool-call",
17792
+ config: normalizeToolCallConfig(apiStep.config)
17793
+ };
17794
+ case "wait-until":
17795
+ return {
17796
+ ...baseStep,
17797
+ type: "wait-until",
17798
+ config: normalizeWaitUntilConfig(apiStep.config)
17799
+ };
17800
+ case "execute-agent":
17801
+ return {
17802
+ ...baseStep,
17803
+ type: "execute-agent",
17804
+ config: normalizeExecuteAgentConfig(apiStep.config)
17805
+ };
17806
+ case "store-asset":
17807
+ return {
17808
+ ...baseStep,
17809
+ type: "store-asset",
17810
+ config: normalizeStoreAssetConfig(apiStep.config)
17811
+ };
17812
+ case "generate-pdf":
17813
+ return {
17814
+ ...baseStep,
17815
+ type: "generate-pdf",
17816
+ config: normalizeGeneratePdfConfig(apiStep.config)
17817
+ };
17818
+ case "save-memory":
17819
+ return {
17820
+ ...baseStep,
17821
+ type: "save-memory",
17822
+ config: normalizeSaveMemoryConfig(apiStep.config)
17823
+ };
17824
+ case "recall-memory":
17825
+ return {
17826
+ ...baseStep,
17827
+ type: "recall-memory",
17828
+ config: normalizeRecallMemoryConfig(apiStep.config)
17829
+ };
17830
+ case "memory-summary":
17831
+ return {
17832
+ ...baseStep,
17833
+ type: "memory-summary",
17834
+ config: normalizeMemorySummaryConfig(apiStep.config)
17835
+ };
17836
+ default:
17837
+ throw new NormalizationError(
17838
+ `Unknown context step type: ${apiStep.type}`,
17839
+ apiStep.type,
17840
+ "type",
17841
+ "valid step type",
17842
+ apiStep.type
17843
+ );
17844
+ }
17845
+ } catch (error51) {
17846
+ if (error51 instanceof NormalizationError) {
17847
+ throw error51;
17848
+ }
17849
+ throw new NormalizationError(
17850
+ `Failed to normalize ${apiStep.type} step: ${error51 instanceof Error ? error51.message : String(error51)}`,
17851
+ apiStep.type,
17852
+ void 0,
17853
+ void 0,
17854
+ error51
17855
+ );
17856
+ }
17857
+ }
17858
+ function normalizeHttpConfig(config3) {
17859
+ validateObject(config3, "http", "http-config", true);
17860
+ validateString(config3.url, "http.url", "http-config", true);
17861
+ if (config3.method) {
17862
+ validateEnum(
17863
+ config3.method,
17864
+ ["GET", "POST", "PUT", "DELETE", "PATCH"],
17865
+ "http.method",
17866
+ "http-config"
17867
+ );
17868
+ }
17869
+ if (config3.headers !== void 0 && config3.headers !== null) {
17870
+ validateObject(config3.headers, "http.headers", "http-config");
17871
+ }
17872
+ if (config3.timeout !== void 0 && config3.timeout !== null) {
17873
+ validateNumber(config3.timeout, "http.timeout", "http-config");
17874
+ }
17875
+ return {
17876
+ url: config3.url,
17877
+ method: config3.method,
17878
+ headers: config3.headers,
17879
+ // Preserve user headers as-is
17880
+ body: config3.body,
17881
+ timeout: config3.timeout
17882
+ };
17883
+ }
17884
+ function normalizeCrawlConfig(config3) {
17885
+ validateConfig(config3, "crawl");
17886
+ const url2 = config3.url;
17887
+ validateString(url2, "url", "crawl", true);
17888
+ validateString(config3.outputVariable ?? config3.output_variable, "outputVariable", "crawl", true);
17889
+ const limitRaw = config3.limit;
17890
+ const depthRaw = config3.depth;
17891
+ const maxAgeRaw = config3.maxAge ?? config3.max_age;
17892
+ const modifiedSince = config3.modifiedSince ?? config3.modified_since;
17893
+ const setExtraHTTPHeaders = config3.setExtraHTTPHeaders ?? config3.set_extra_http_headers;
17894
+ const gotoOptions = config3.gotoOptions ?? config3.goto_options;
17895
+ const waitForSelector = config3.waitForSelector ?? config3.wait_for_selector;
17896
+ const rejectResourceTypes = config3.rejectResourceTypes ?? config3.reject_resource_types;
17897
+ const rejectRequestPattern = config3.rejectRequestPattern ?? config3.reject_request_pattern;
17898
+ const userAgent = config3.userAgent ?? config3.user_agent;
17899
+ const jsonOptions = config3.jsonOptions ?? config3.json_options;
17900
+ const pollIntervalMsRaw = config3.pollIntervalMs ?? config3.poll_interval_ms;
17901
+ const completionTimeoutMsRaw = config3.completionTimeoutMs ?? config3.completion_timeout_ms;
17902
+ if (limitRaw !== void 0 && limitRaw !== null) validateNumber(limitRaw, "limit", "crawl");
17903
+ if (depthRaw !== void 0 && depthRaw !== null) validateNumber(depthRaw, "depth", "crawl");
17904
+ if (config3.source !== void 0) validateString(config3.source, "source", "crawl");
17905
+ if (config3.formats !== void 0) validateArray(config3.formats, "formats", "crawl");
17906
+ if (config3.render !== void 0) validateBoolean(config3.render, "render", "crawl");
17907
+ if (maxAgeRaw !== void 0 && maxAgeRaw !== null) validateNumber(maxAgeRaw, "maxAge", "crawl");
17908
+ if (modifiedSince !== void 0) validateString(modifiedSince, "modifiedSince", "crawl");
17909
+ if (config3.options !== void 0) validateObject(config3.options, "options", "crawl");
17910
+ if (config3.authenticate !== void 0) validateObject(config3.authenticate, "authenticate", "crawl");
17911
+ if (config3.cookies !== void 0) validateArray(config3.cookies, "cookies", "crawl");
17912
+ if (setExtraHTTPHeaders !== void 0) {
17913
+ validateObject(setExtraHTTPHeaders, "setExtraHTTPHeaders", "crawl");
17914
+ }
17915
+ if (gotoOptions !== void 0) validateObject(gotoOptions, "gotoOptions", "crawl");
17916
+ if (waitForSelector !== void 0) validateString(waitForSelector, "waitForSelector", "crawl");
17917
+ if (rejectResourceTypes !== void 0) {
17918
+ validateArray(rejectResourceTypes, "rejectResourceTypes", "crawl");
17919
+ }
17920
+ if (rejectRequestPattern !== void 0) {
17921
+ if (typeof rejectRequestPattern !== "string" && !Array.isArray(rejectRequestPattern)) {
17922
+ throw new NormalizationError(
17923
+ "Field 'rejectRequestPattern' must be a string or array for crawl step",
17924
+ "crawl",
17925
+ "rejectRequestPattern",
17926
+ "string | array",
17927
+ typeof rejectRequestPattern
17928
+ );
17929
+ }
17930
+ }
17931
+ if (userAgent !== void 0) validateString(userAgent, "userAgent", "crawl");
17932
+ if (jsonOptions !== void 0) validateObject(jsonOptions, "jsonOptions", "crawl");
17933
+ if (config3.streamOutput !== void 0) validateBoolean(config3.streamOutput, "streamOutput", "crawl");
17934
+ if (pollIntervalMsRaw !== void 0 && pollIntervalMsRaw !== null) {
17935
+ validateNumber(pollIntervalMsRaw, "pollIntervalMs", "crawl");
17936
+ }
17937
+ if (completionTimeoutMsRaw !== void 0 && completionTimeoutMsRaw !== null) {
17938
+ validateNumber(completionTimeoutMsRaw, "completionTimeoutMs", "crawl");
17939
+ }
17940
+ const errorHandling = validateAndNormalizeErrorHandling(
17941
+ config3.errorHandling ?? config3.error_handling,
17942
+ "errorHandling",
17943
+ "crawl"
17944
+ );
17945
+ const limit = normalizeOptionalNumber(limitRaw);
17946
+ const depth = normalizeOptionalNumber(depthRaw);
17947
+ const maxAge = normalizeOptionalNumber(maxAgeRaw);
17948
+ const pollIntervalMs = normalizeOptionalNumber(pollIntervalMsRaw);
17949
+ const completionTimeoutMs = normalizeOptionalNumber(completionTimeoutMsRaw);
17950
+ return {
17951
+ url: url2,
17952
+ limit,
17953
+ depth,
17954
+ source: config3.source,
17955
+ formats: config3.formats,
17956
+ render: config3.render,
17957
+ maxAge,
17958
+ modifiedSince,
17959
+ options: config3.options,
17960
+ authenticate: config3.authenticate,
17961
+ cookies: config3.cookies,
17962
+ setExtraHTTPHeaders,
17963
+ gotoOptions,
17964
+ waitForSelector,
17965
+ rejectResourceTypes,
17966
+ rejectRequestPattern,
17967
+ userAgent,
17968
+ jsonOptions,
17969
+ outputVariable: config3.outputVariable ?? config3.output_variable,
17970
+ streamOutput: config3.streamOutput ?? config3.stream_output,
17971
+ errorHandling,
17972
+ defaultValue: config3.defaultValue ?? config3.default_value,
17973
+ pollIntervalMs,
17974
+ completionTimeoutMs,
17975
+ asyncCrawl: config3.asyncCrawl
17976
+ };
17977
+ }
17978
+ function normalizeAuthConfig(config3) {
17979
+ if (!config3) return void 0;
17980
+ validateObject(config3, "auth", "auth-config", true);
17981
+ validateEnum(
17982
+ config3.type,
17983
+ ["none", "bearer", "basic", "api-key", "custom"],
17984
+ "auth.type",
17985
+ "auth-config",
17986
+ true
17987
+ );
17988
+ if (config3.token) validateString(config3.token, "auth.token", "auth-config");
17989
+ if (config3.username) validateString(config3.username, "auth.username", "auth-config");
17990
+ if (config3.password) validateString(config3.password, "auth.password", "auth-config");
17991
+ if (config3.apiKey) validateString(config3.apiKey, "auth.apiKey", "auth-config");
17992
+ if (config3.headerName) validateString(config3.headerName, "auth.headerName", "auth-config");
17993
+ if (config3.customHeaders !== void 0 && config3.customHeaders !== null) {
17994
+ validateObject(config3.customHeaders, "auth.customHeaders", "auth-config");
17995
+ }
17996
+ return {
17997
+ type: config3.type,
17998
+ token: config3.token,
17999
+ username: config3.username,
18000
+ password: config3.password,
18001
+ apiKey: config3.apiKey,
18002
+ headerName: config3.headerName,
18003
+ customHeaders: config3.customHeaders
18004
+ };
18005
+ }
18006
+ function normalizeFirecrawlConfig(config3) {
18007
+ if (!config3) return void 0;
18008
+ return {
18009
+ formats: config3.formats,
18010
+ actions: config3.actions,
18011
+ location: config3.location,
18012
+ maxAge: config3.maxAge,
18013
+ storeInCache: config3.storeInCache,
18014
+ onlyMainContent: config3.onlyMainContent,
18015
+ jsonSchema: config3.jsonSchema,
18016
+ jsonPrompt: config3.jsonPrompt
18017
+ };
18018
+ }
18019
+ function normalizeFetchUrlConfig(config3) {
18020
+ validateConfig(config3, "fetch-url");
18021
+ validateObject(config3.http, "http", "fetch-url", true);
18022
+ validateString(config3.outputVariable, "outputVariable", "fetch-url", true);
18023
+ if (config3.responseType) {
18024
+ validateEnum(config3.responseType, ["json", "text", "xml"], "responseType", "fetch-url");
18025
+ }
18026
+ if (config3.markdownIfAvailable !== void 0) {
18027
+ validateBoolean(config3.markdownIfAvailable, "markdownIfAvailable", "fetch-url");
18028
+ }
18029
+ const errorHandling = validateAndNormalizeErrorHandling(
18030
+ config3.errorHandling,
18031
+ "errorHandling",
18032
+ "fetch-url"
18033
+ );
18034
+ if (config3.fetchMethod) {
18035
+ validateEnum(config3.fetchMethod, ["standard", "firecrawl"], "fetchMethod", "fetch-url");
18036
+ }
18037
+ return {
18038
+ http: normalizeHttpConfig(config3.http),
18039
+ auth: normalizeAuthConfig(config3.auth),
18040
+ responseType: config3.responseType,
18041
+ markdownIfAvailable: config3.markdownIfAvailable,
18042
+ outputVariable: config3.outputVariable,
18043
+ streamOutput: config3.streamOutput,
18044
+ errorHandling,
18045
+ defaultValue: config3.defaultValue,
18046
+ fetchMethod: config3.fetchMethod,
18047
+ firecrawl: normalizeFirecrawlConfig(config3.firecrawl)
18048
+ };
18049
+ }
18050
+ function normalizeRetrieveRecordConfig(config3) {
18051
+ validateConfig(config3, "retrieve-record");
18052
+ const filter = config3.recordFilter;
18053
+ const hasFilter = filter && typeof filter === "object" && typeof filter.type === "string" && filter.type.length > 0;
18054
+ if (!config3.recordId && !config3.recordType && !config3.recordName && !hasFilter) {
18055
+ throw new NormalizationError(
18056
+ `retrieve-record step requires at least one of 'recordId', 'recordType', 'recordName', or 'recordFilter'`,
18057
+ "retrieve-record",
18058
+ "recordId/recordType/recordName/recordFilter",
18059
+ "at least one identification field",
18060
+ void 0
18061
+ );
18062
+ }
18063
+ validateString(config3.outputVariable, "outputVariable", "retrieve-record", true);
18064
+ if (config3.fieldsToInclude)
18065
+ validateString(config3.fieldsToInclude, "fieldsToInclude", "retrieve-record");
18066
+ if (config3.fieldsToExclude)
18067
+ validateString(config3.fieldsToExclude, "fieldsToExclude", "retrieve-record");
18068
+ if (config3.availableFields)
18069
+ validateArray(config3.availableFields, "availableFields", "retrieve-record");
18070
+ return {
18071
+ retrievalMode: config3.retrievalMode,
18072
+ recordType: config3.recordType,
18073
+ recordName: config3.recordName,
18074
+ recordId: config3.recordId,
18075
+ recordFilter: config3.recordFilter,
18076
+ fieldsToInclude: config3.fieldsToInclude,
18077
+ fieldsToExclude: config3.fieldsToExclude,
18078
+ availableFields: config3.availableFields,
18079
+ outputVariable: config3.outputVariable
18080
+ };
18081
+ }
18082
+ function normalizeFetchGithubConfig(config3) {
18083
+ validateConfig(config3, "fetch-github");
18084
+ validateString(config3.repository, "repository", "fetch-github", true);
18085
+ validateString(config3.outputVariable, "outputVariable", "fetch-github", true);
18086
+ if (config3.path) validateString(config3.path, "path", "fetch-github");
18087
+ if (config3.branch) validateString(config3.branch, "branch", "fetch-github");
18088
+ if (config3.token) validateString(config3.token, "token", "fetch-github");
18089
+ if (config3.contentType) {
18090
+ validateEnum(config3.contentType, ["raw", "metadata", "both"], "contentType", "fetch-github");
18091
+ }
18092
+ if (config3.includePatterns)
18093
+ validateArray(config3.includePatterns, "includePatterns", "fetch-github");
18094
+ if (config3.excludePatterns)
18095
+ validateArray(config3.excludePatterns, "excludePatterns", "fetch-github");
18096
+ if (config3.compress !== void 0 && config3.compress !== null) {
18097
+ validateBoolean(config3.compress, "compress", "fetch-github");
18098
+ }
18099
+ if (config3.style) {
18100
+ validateEnum(config3.style, ["xml", "json", "markdown"], "style", "fetch-github");
18101
+ }
18102
+ return {
18103
+ repository: config3.repository,
18104
+ path: config3.path,
18105
+ branch: config3.branch,
18106
+ token: config3.token,
18107
+ outputVariable: config3.outputVariable,
18108
+ contentType: config3.contentType,
18109
+ includePatterns: config3.includePatterns,
18110
+ excludePatterns: config3.excludePatterns,
18111
+ compress: config3.compress,
18112
+ style: config3.style
18113
+ };
18114
+ }
18115
+ function normalizeApiCallConfig(config3) {
18116
+ validateConfig(config3, "api-call");
18117
+ validateObject(config3.http, "http", "api-call", true);
18118
+ validateString(config3.outputVariable, "outputVariable", "api-call", true);
18119
+ if (config3.requestTemplate !== void 0 && config3.requestTemplate !== null) {
18120
+ validateString(config3.requestTemplate, "requestTemplate", "api-call");
18121
+ }
18122
+ if (config3.responseMapping !== void 0 && config3.responseMapping !== null) {
18123
+ validateObject(config3.responseMapping, "responseMapping", "api-call");
18124
+ }
18125
+ const errorHandling = validateAndNormalizeErrorHandling(
18126
+ config3.errorHandling,
18127
+ "errorHandling",
18128
+ "api-call"
18129
+ );
18130
+ return {
18131
+ http: normalizeHttpConfig(config3.http),
18132
+ auth: normalizeAuthConfig(config3.auth),
18133
+ requestTemplate: config3.requestTemplate,
18134
+ responseMapping: config3.responseMapping,
18135
+ // Preserve user mapping keys
18136
+ outputVariable: config3.outputVariable,
18137
+ errorHandling,
18138
+ defaultValue: config3.defaultValue
18139
+ };
18140
+ }
18141
+ function normalizeTransformDataConfig(config3) {
18142
+ validateConfig(config3, "transform-data");
18143
+ validateString(config3.script, "script", "transform-data", true);
18144
+ const outputVariable = config3.outputVariable ?? config3.output_variable;
18145
+ validateString(outputVariable, "outputVariable", "transform-data", true);
18146
+ if (config3.sandboxProvider) {
18147
+ validateEnum(
18148
+ config3.sandboxProvider,
18149
+ ["quickjs", "daytona", "cloudflare-worker", "runtype-sandbox", "cloudflare-sandbox"],
18150
+ "sandboxProvider",
18151
+ "transform-data"
18152
+ );
18153
+ if (config3.sandboxProvider === "cloudflare-sandbox") {
18154
+ config3.sandboxProvider = "runtype-sandbox";
18155
+ }
18156
+ }
18157
+ if (config3.language) {
18158
+ validateEnum(
18159
+ config3.language,
18160
+ ["javascript", "typescript", "python"],
18161
+ "language",
18162
+ "transform-data"
18163
+ );
18164
+ }
18165
+ if (config3.persistSandbox !== void 0 && typeof config3.persistSandbox !== "boolean") {
18166
+ throw new NormalizationError(
18167
+ "persistSandbox must be a boolean",
18168
+ "transform-data",
18169
+ "persistSandbox",
18170
+ "boolean",
18171
+ config3.persistSandbox
18172
+ );
18173
+ }
18174
+ if (config3.streamOutput !== void 0) {
18175
+ validateBoolean(config3.streamOutput, "streamOutput", "transform-data");
18176
+ }
18177
+ if (config3.reuseSandboxId !== void 0) {
18178
+ validateString(config3.reuseSandboxId, "reuseSandboxId", "transform-data", false);
18179
+ }
18180
+ if (config3.inputMode) {
18181
+ validateEnum(config3.inputMode, ["code", "variable"], "inputMode", "transform-data");
18182
+ }
18183
+ if (config3.packageJson && typeof config3.packageJson !== "string") {
18184
+ throw new NormalizationError("packageJson must be a string", "transform-data");
18185
+ }
18186
+ if (config3.networkAccess !== void 0) {
18187
+ if (config3.networkAccess !== "on" && config3.networkAccess !== "off") {
18188
+ if (typeof config3.networkAccess !== "object" || config3.networkAccess === null || !Array.isArray(config3.networkAccess.allowedHostnames)) {
18189
+ throw new NormalizationError(
18190
+ "networkAccess must be 'on', 'off', or { allowedHostnames: string[] }",
18191
+ "transform-data",
18192
+ "networkAccess"
18193
+ );
18194
+ }
18195
+ if (config3.networkAccess.allowedHostnames.length === 0) {
18196
+ throw new NormalizationError(
18197
+ "allowedHostnames must contain at least one entry",
18198
+ "transform-data",
18199
+ "networkAccess"
18200
+ );
18201
+ }
18202
+ for (const h2 of config3.networkAccess.allowedHostnames) {
18203
+ if (typeof h2 !== "string") {
18204
+ throw new NormalizationError(
18205
+ "allowedHostnames entries must be strings",
18206
+ "transform-data",
18207
+ "networkAccess"
18208
+ );
18209
+ }
18210
+ }
18211
+ }
18212
+ }
18213
+ const errorHandling = validateAndNormalizeErrorHandling(
18214
+ config3.errorHandling,
18215
+ "errorHandling",
18216
+ "transform-data"
18217
+ );
18218
+ return {
18219
+ script: config3.script,
18220
+ outputVariable,
18221
+ streamOutput: config3.streamOutput,
18222
+ sandboxProvider: config3.sandboxProvider,
18223
+ language: config3.language,
18224
+ inputMode: config3.inputMode,
18225
+ packageJson: config3.packageJson,
18226
+ persistSandbox: config3.persistSandbox,
18227
+ reuseSandboxId: config3.reuseSandboxId,
18228
+ networkAccess: config3.networkAccess,
18229
+ errorHandling,
18230
+ defaultValue: config3.defaultValue,
18231
+ ...config3.tools ? { tools: config3.tools } : {}
18232
+ };
18233
+ }
18234
+ function normalizeTemplateConfig(config3) {
18235
+ validateConfig(config3, "template");
18236
+ validateString(config3.template, "template", "template", true);
18237
+ validateString(config3.outputVariable, "outputVariable", "template", true);
18238
+ validateEnum(
18239
+ config3.outputFormat,
18240
+ ["html", "email-html", "markdown", "pdf", "text"],
18241
+ "outputFormat",
18242
+ "template"
18243
+ );
18244
+ if (config3.inputs !== void 0) {
18245
+ if (typeof config3.inputs !== "object" || config3.inputs === null || Array.isArray(config3.inputs)) {
18246
+ throw new NormalizationError("inputs must be an object", "template", "inputs");
18247
+ }
18248
+ for (const [key, value] of Object.entries(config3.inputs)) {
18249
+ if (typeof value !== "string") {
18250
+ throw new NormalizationError(
18251
+ `inputs.${key} must be a string expression`,
18252
+ "template",
18253
+ `inputs.${key}`
18254
+ );
18255
+ }
18256
+ }
18257
+ }
18258
+ if (config3.partials !== void 0) {
18259
+ if (typeof config3.partials !== "object" || config3.partials === null || Array.isArray(config3.partials)) {
18260
+ throw new NormalizationError("partials must be an object", "template", "partials");
18261
+ }
18262
+ for (const [key, value] of Object.entries(config3.partials)) {
18263
+ if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(key)) {
18264
+ throw new NormalizationError(
18265
+ `partials.${key} key must be a simple identifier`,
18266
+ "template",
18267
+ `partials.${key}`
18268
+ );
18269
+ }
18270
+ if (typeof value !== "string") {
18271
+ throw new NormalizationError(
18272
+ `partials.${key} must be a string template`,
18273
+ "template",
18274
+ `partials.${key}`
18275
+ );
18276
+ }
18277
+ }
18278
+ }
18279
+ if (config3.pdfOptions !== void 0 && config3.outputFormat !== "pdf") {
18280
+ throw new NormalizationError(
18281
+ 'pdfOptions is only allowed when outputFormat is "pdf"',
18282
+ "template",
18283
+ "pdfOptions"
18284
+ );
18285
+ }
18286
+ if (config3.asArtifact !== void 0 && typeof config3.asArtifact !== "boolean") {
18287
+ throw new NormalizationError("asArtifact must be a boolean", "template", "asArtifact");
18288
+ }
18289
+ if (config3.sampleData !== void 0) {
18290
+ validateArray(config3.sampleData, "sampleData", "template");
18291
+ for (const [i, scenario] of config3.sampleData.entries()) {
18292
+ if (typeof scenario !== "object" || scenario === null || Array.isArray(scenario)) {
18293
+ throw new NormalizationError(`sampleData[${i}] must be an object`, "template", `sampleData[${i}]`);
18294
+ }
18295
+ validateString(scenario.name, `sampleData[${i}].name`, "template", true);
18296
+ if (typeof scenario.data !== "object" || scenario.data === null || Array.isArray(scenario.data)) {
18297
+ throw new NormalizationError(`sampleData[${i}].data must be an object`, "template", `sampleData[${i}].data`);
18298
+ }
18299
+ }
18300
+ }
18301
+ const errorHandling = validateAndNormalizeErrorHandling(
18302
+ config3.errorHandling,
18303
+ "errorHandling",
18304
+ "template"
18305
+ );
18306
+ return {
18307
+ template: config3.template,
18308
+ inputs: config3.inputs,
18309
+ outputFormat: config3.outputFormat,
18310
+ outputVariable: config3.outputVariable,
18311
+ partials: config3.partials,
18312
+ pdfOptions: config3.pdfOptions,
18313
+ asArtifact: config3.asArtifact,
18314
+ streamOutput: config3.streamOutput,
18315
+ errorHandling,
18316
+ defaultValue: config3.defaultValue,
18317
+ sampleData: config3.sampleData
18318
+ };
18319
+ }
18320
+ function normalizeConditionalConfig(config3) {
18321
+ validateConfig(config3, "conditional");
18322
+ validateString(config3.condition, "condition", "conditional", true);
18323
+ const trueSteps = config3.trueSteps ?? config3.true_steps;
18324
+ const falseSteps = config3.falseSteps ?? config3.false_steps;
18325
+ if (trueSteps) {
18326
+ validateArray(trueSteps, "trueSteps", "conditional");
18327
+ }
18328
+ if (falseSteps) {
18329
+ validateArray(falseSteps, "falseSteps", "conditional");
18330
+ }
18331
+ const normalizeNestedSteps = (steps, parentStepId = "conditional") => {
18332
+ return steps.map((step, index) => {
18333
+ const stepWithDefaults = {
18334
+ ...step,
18335
+ id: step.id || `${parentStepId}-nested-${index}-${Date.now()}`,
18336
+ order: step.order ?? index
18337
+ };
18338
+ if (step.type === "prompt") {
18339
+ return stepWithDefaults;
18340
+ }
18341
+ return normalizeContextStep(stepWithDefaults);
18342
+ });
18343
+ };
18344
+ return {
18345
+ condition: config3.condition,
18346
+ trueSteps: trueSteps ? normalizeNestedSteps(trueSteps, "conditional-true") : [],
18347
+ falseSteps: falseSteps ? normalizeNestedSteps(falseSteps, "conditional-false") : void 0
18348
+ };
18349
+ }
18350
+ function normalizeSetVariableConfig(config3) {
18351
+ validateConfig(config3, "set-variable");
18352
+ const variableName = config3.variableName ?? config3.variable_name;
18353
+ validateString(variableName, "variableName", "set-variable", true);
18354
+ if (config3.value === void 0) {
18355
+ throw new NormalizationError(
18356
+ `Missing required field 'value' for set-variable step`,
18357
+ "set-variable",
18358
+ "value",
18359
+ "any value",
18360
+ void 0
18361
+ );
18362
+ }
18363
+ if (config3.valueTemplate !== void 0 && config3.valueTemplate !== null) {
18364
+ validateString(config3.valueTemplate, "valueTemplate", "set-variable");
18365
+ }
18366
+ return {
18367
+ variableName,
18368
+ value: config3.value,
18369
+ valueTemplate: config3.valueTemplate
18370
+ };
18371
+ }
18372
+ function normalizeUpsertRecordConfig(config3) {
18373
+ validateConfig(config3, "upsert-record");
18374
+ validateString(config3.recordType, "recordType", "upsert-record", true);
18375
+ validateString(config3.sourceVariable, "sourceVariable", "upsert-record", true);
18376
+ validateString(config3.outputVariable, "outputVariable", "upsert-record", true);
18377
+ if (config3.recordName !== void 0 && config3.recordName !== null) {
18378
+ validateString(config3.recordName, "recordName", "upsert-record");
18379
+ }
18380
+ if (config3.mergeStrategy) {
18381
+ validateEnum(config3.mergeStrategy, ["merge", "replace"], "mergeStrategy", "upsert-record");
18382
+ }
18383
+ const errorHandling = validateAndNormalizeErrorHandling(
18384
+ config3.errorHandling,
18385
+ "errorHandling",
18386
+ "upsert-record"
18387
+ );
18388
+ if (config3.inputMode) {
18389
+ validateEnum(config3.inputMode, ["single", "batch"], "inputMode", "upsert-record");
18390
+ }
18391
+ return {
18392
+ recordType: config3.recordType,
18393
+ recordName: config3.recordName,
18394
+ sourceVariable: config3.sourceVariable,
18395
+ outputVariable: config3.outputVariable,
18396
+ mergeStrategy: config3.mergeStrategy,
18397
+ errorHandling,
18398
+ defaultValue: config3.defaultValue,
18399
+ // Batch mode
18400
+ inputMode: config3.inputMode,
18401
+ inputVariable: config3.inputVariable,
18402
+ itemAlias: config3.itemAlias,
18403
+ metadataMapping: config3.metadataMapping,
18404
+ batchSize: config3.batchSize
18405
+ };
18406
+ }
18407
+ function normalizeSendEmailConfig(config3, options = {}) {
18408
+ validateConfig(config3, "send-email");
18409
+ validateString(config3.from, "from", "send-email");
18410
+ validateString(config3.to, "to", "send-email", true);
18411
+ validateString(config3.subject, "subject", "send-email", true);
18412
+ if (isCustomSendFromAddressOnManagedDomain(config3.from, options.managedSendFromDomain)) {
18413
+ throw new NormalizationError(
18414
+ "Field 'from' cannot use the platform-managed email domain for a custom sender",
18415
+ "send-email",
18416
+ "from",
18417
+ "custom email address on a non-managed domain",
18418
+ config3.from
18419
+ );
18420
+ }
18421
+ validateString(config3.outputVariable, "outputVariable", "send-email", true);
18422
+ if (config3.replyTo) validateString(config3.replyTo, "replyTo", "send-email");
18423
+ if (config3.cc) validateString(config3.cc, "cc", "send-email");
18424
+ if (config3.bcc) validateString(config3.bcc, "bcc", "send-email");
18425
+ if (config3.html) validateString(config3.html, "html", "send-email");
18426
+ if (config3.text) validateString(config3.text, "text", "send-email");
18427
+ if (config3.attachments) {
18428
+ validateArray(config3.attachments, "attachments", "send-email");
18429
+ }
18430
+ const errorHandling = validateAndNormalizeErrorHandling(
18431
+ config3.errorHandling,
18432
+ "errorHandling",
18433
+ "send-email"
18434
+ );
18435
+ return {
18436
+ from: config3.from,
18437
+ to: config3.to,
18438
+ subject: config3.subject,
18439
+ replyTo: config3.replyTo,
18440
+ cc: config3.cc,
18441
+ bcc: config3.bcc,
18442
+ html: config3.html,
18443
+ text: config3.text,
18444
+ attachments: config3.attachments,
18445
+ outputVariable: config3.outputVariable,
18446
+ errorHandling,
18447
+ defaultValue: config3.defaultValue
18448
+ };
18449
+ }
18450
+ function normalizeSendTextConfig(config3) {
18451
+ validateConfig(config3, "send-text");
18452
+ validateString(config3.from, "from", "send-text", true);
18453
+ validateString(config3.to, "to", "send-text", true);
18454
+ validateString(config3.message, "message", "send-text", true);
18455
+ validateString(config3.outputVariable, "outputVariable", "send-text", true);
18456
+ const errorHandling = validateAndNormalizeErrorHandling(
18457
+ config3.errorHandling,
18458
+ "errorHandling",
18459
+ "send-text"
18460
+ );
18461
+ return {
18462
+ from: config3.from,
18463
+ to: config3.to,
18464
+ message: config3.message,
18465
+ outputVariable: config3.outputVariable,
18466
+ errorHandling,
18467
+ defaultValue: config3.defaultValue
18468
+ };
18469
+ }
18470
+ function normalizeSendEventConfig(config3) {
18471
+ validateConfig(config3, "send-event");
18472
+ validateEnum(
18473
+ config3.provider,
18474
+ ["posthog", "google-analytics", "amplitude", "segment"],
18475
+ "provider",
18476
+ "send-event",
18477
+ true
18478
+ );
18479
+ validateString(config3.eventName, "eventName", "send-event", true);
18480
+ validateString(config3.outputVariable, "outputVariable", "send-event", true);
18481
+ if (config3.properties !== void 0 && config3.properties !== null) {
18482
+ validateObject(config3.properties, "properties", "send-event");
18483
+ }
18484
+ const errorHandling = validateAndNormalizeErrorHandling(
18485
+ config3.errorHandling,
18486
+ "errorHandling",
18487
+ "send-event"
18488
+ );
18489
+ return {
18490
+ provider: config3.provider,
18491
+ eventName: config3.eventName,
18492
+ properties: config3.properties,
18493
+ // Preserve user property keys as-is
18494
+ outputVariable: config3.outputVariable,
18495
+ errorHandling,
18496
+ defaultValue: config3.defaultValue
18497
+ };
18498
+ }
18499
+ function normalizeSendStreamConfig(config3) {
18500
+ validateConfig(config3, "send-stream");
18501
+ validateString(config3.message, "message", "send-stream", true);
18502
+ return {
18503
+ message: config3.message
18504
+ };
18505
+ }
18506
+ function normalizeUpdateRecordConfig(config3) {
18507
+ validateConfig(config3, "update-record");
18508
+ const filter = config3.recordFilter;
18509
+ const hasFilter = filter && typeof filter === "object" && typeof filter.type === "string" && filter.type.length > 0;
18510
+ if (!config3.recordId && !(config3.recordType && config3.recordName) && !hasFilter) {
18511
+ throw new NormalizationError(
18512
+ `update-record step requires either 'recordId', both 'recordType' and 'recordName', or 'recordFilter'`,
18513
+ "update-record",
18514
+ "recordId/recordType/recordName/recordFilter",
18515
+ "at least one identification method",
18516
+ void 0
18517
+ );
18518
+ }
18519
+ validateObject(config3.updates, "updates", "update-record", true);
18520
+ validateString(config3.outputVariable, "outputVariable", "update-record", true);
18521
+ validateEnum(
18522
+ config3.mergeStrategy,
18523
+ ["merge", "replace", "deep-merge"],
18524
+ "mergeStrategy",
18525
+ "update-record",
18526
+ true
18527
+ );
18528
+ if (config3.updatesTemplate !== void 0 && config3.updatesTemplate !== null) {
18529
+ validateString(config3.updatesTemplate, "updatesTemplate", "update-record");
18530
+ }
18531
+ if (config3.includeFullRecord !== void 0 && config3.includeFullRecord !== null) {
18532
+ validateBoolean(config3.includeFullRecord, "includeFullRecord", "update-record");
18533
+ }
18534
+ const errorHandling = validateAndNormalizeErrorHandling(
18535
+ config3.errorHandling,
18536
+ "errorHandling",
18537
+ "update-record"
18538
+ );
18539
+ return {
18540
+ recordId: config3.recordId,
18541
+ recordType: config3.recordType,
18542
+ recordName: config3.recordName,
18543
+ recordFilter: config3.recordFilter,
18544
+ updates: config3.updates,
18545
+ // Preserve user metadata keys as-is
18546
+ updatesTemplate: config3.updatesTemplate,
18547
+ mergeStrategy: config3.mergeStrategy,
18548
+ outputVariable: config3.outputVariable,
18549
+ includeFullRecord: config3.includeFullRecord,
18550
+ errorHandling,
18551
+ defaultValue: config3.defaultValue
18552
+ };
18553
+ }
18554
+ function normalizeSearchConfig(config3) {
18555
+ validateConfig(config3, "search");
18556
+ validateString(config3.provider, "provider", "search", true);
18557
+ validateString(config3.query, "query", "search", true);
18558
+ validateString(config3.outputVariable, "outputVariable", "search", true);
18559
+ if (config3.maxResults !== void 0 && config3.maxResults !== null) {
18560
+ validateNumber(config3.maxResults, "maxResults", "search");
18561
+ }
18562
+ if (config3.maxTokens !== void 0 && config3.maxTokens !== null) {
18563
+ validateNumber(config3.maxTokens, "maxTokens", "search");
18564
+ }
18565
+ if (config3.temperature !== void 0 && config3.temperature !== null) {
18566
+ validateNumber(config3.temperature, "temperature", "search");
18567
+ }
18568
+ if (config3.returnCitations !== void 0 && config3.returnCitations !== null) {
18569
+ validateBoolean(config3.returnCitations, "returnCitations", "search");
18570
+ }
18571
+ if (config3.allowedDomains) validateArray(config3.allowedDomains, "allowedDomains", "search");
18572
+ if (config3.blockedDomains) validateArray(config3.blockedDomains, "blockedDomains", "search");
18573
+ if (config3.sources) validateArray(config3.sources, "sources", "search");
18574
+ const errorHandling = validateAndNormalizeErrorHandling(
18575
+ config3.errorHandling,
18576
+ "errorHandling",
18577
+ "search"
18578
+ );
18579
+ return {
18580
+ provider: config3.provider,
18581
+ query: config3.query,
18582
+ maxResults: config3.maxResults,
18583
+ returnCitations: config3.returnCitations,
18584
+ dateRange: config3.dateRange,
18585
+ allowedDomains: config3.allowedDomains,
18586
+ blockedDomains: config3.blockedDomains,
18587
+ userLocation: config3.userLocation,
18588
+ sources: config3.sources,
18589
+ temperature: config3.temperature,
18590
+ maxTokens: config3.maxTokens,
18591
+ // Exa-specific options
18592
+ exaSearchType: config3.exaSearchType,
18593
+ exaContents: config3.exaContents,
18594
+ exaCategory: config3.exaCategory,
18595
+ outputVariable: config3.outputVariable,
18596
+ errorHandling,
18597
+ defaultValue: config3.defaultValue
18598
+ };
18599
+ }
18600
+ function normalizeGenerateEmbeddingConfig(config3) {
18601
+ validateConfig(config3, "generate-embedding");
18602
+ const isBatchMode = config3.inputMode === "batch";
18603
+ validateString(config3.outputVariable, "outputVariable", "generate-embedding", true);
18604
+ if (isBatchMode) {
18605
+ validateString(config3.inputVariable, "inputVariable", "generate-embedding", true);
18606
+ if (config3.textTemplate)
18607
+ validateString(config3.textTemplate, "textTemplate", "generate-embedding");
18608
+ if (config3.itemAlias) validateString(config3.itemAlias, "itemAlias", "generate-embedding");
18609
+ if (config3.batchSize !== void 0 && config3.batchSize !== null) {
18610
+ validateNumber(config3.batchSize, "batchSize", "generate-embedding");
18611
+ }
18612
+ } else {
18613
+ validateEnum(
18614
+ config3.inputSource,
18615
+ ["text", "variable", "record"],
18616
+ "inputSource",
18617
+ "generate-embedding",
18618
+ true
18619
+ );
18620
+ if (config3.inputSource === "text") {
18621
+ if (config3.text !== void 0 && config3.text !== null) {
18622
+ validateString(config3.text, "text", "generate-embedding");
18623
+ }
18624
+ } else if (config3.inputSource === "variable") {
18625
+ validateString(config3.variableName, "variableName", "generate-embedding", true);
18626
+ } else if (config3.inputSource === "record") {
18627
+ if (!config3.recordId && !(config3.recordType && config3.recordName)) {
18628
+ throw new NormalizationError(
18629
+ `generate-embedding step with inputSource='record' requires either 'recordId' or both 'recordType' and 'recordName'`,
18630
+ "generate-embedding",
18631
+ "recordId/recordType/recordName",
18632
+ "at least one identification method",
18633
+ void 0
18634
+ );
18635
+ }
18636
+ }
18637
+ }
18638
+ if (config3.embeddingModel)
18639
+ validateString(config3.embeddingModel, "embeddingModel", "generate-embedding");
18640
+ if (config3.textField) validateString(config3.textField, "textField", "generate-embedding");
18641
+ if (config3.maxLength !== void 0 && config3.maxLength !== null) {
18642
+ validateNumber(config3.maxLength, "maxLength", "generate-embedding");
18643
+ }
18644
+ if (config3.storeInRecord !== void 0 && config3.storeInRecord !== null) {
18645
+ validateBoolean(config3.storeInRecord, "storeInRecord", "generate-embedding");
18646
+ }
18647
+ return {
18648
+ inputSource: config3.inputSource,
18649
+ text: config3.text,
18650
+ variableName: config3.variableName,
18651
+ recordId: config3.recordId,
18652
+ recordType: config3.recordType,
18653
+ recordName: config3.recordName,
18654
+ textField: config3.textField,
18655
+ storeInRecord: config3.storeInRecord,
18656
+ embeddingModel: config3.embeddingModel,
18657
+ maxLength: config3.maxLength,
18658
+ outputVariable: config3.outputVariable,
18659
+ streamOutput: config3.streamOutput,
18660
+ // Batch mode fields
18661
+ inputMode: config3.inputMode,
18662
+ inputVariable: config3.inputVariable,
18663
+ textTemplate: config3.textTemplate,
18664
+ itemAlias: config3.itemAlias,
18665
+ batchSize: config3.batchSize
18666
+ };
18667
+ }
18668
+ function normalizeVectorSearchConfig(config3) {
18669
+ validateConfig(config3, "vector-search");
18670
+ validateString(config3.query, "query", "vector-search", true);
18671
+ validateString(config3.outputVariable, "outputVariable", "vector-search", true);
18672
+ if (config3.embeddingModel)
18673
+ validateString(config3.embeddingModel, "embeddingModel", "vector-search");
18674
+ if (config3.limit !== void 0 && config3.limit !== null) {
18675
+ validateNumber(config3.limit, "limit", "vector-search");
18676
+ }
18677
+ if (config3.threshold !== void 0 && config3.threshold !== null) {
18678
+ validateNumber(config3.threshold, "threshold", "vector-search");
18679
+ }
18680
+ if (config3.recordType) validateString(config3.recordType, "recordType", "vector-search");
18681
+ if (config3.metadataFilters !== void 0 && config3.metadataFilters !== null) {
18682
+ validateObject(config3.metadataFilters, "metadataFilters", "vector-search");
18683
+ }
18684
+ if (config3.includeEmbedding !== void 0 && config3.includeEmbedding !== null) {
18685
+ validateBoolean(config3.includeEmbedding, "includeEmbedding", "vector-search");
18686
+ }
18687
+ const providerInput = config3.provider || config3.vectorStore || "record";
18688
+ const vectorStore = providerInput === "record" ? "pgvector" : providerInput;
18689
+ const vectorizeConfig = config3.vectorizeConfigId || config3.vectorizeNamespace ? {
18690
+ configId: config3.vectorizeConfigId,
18691
+ namespace: config3.vectorizeNamespace
18692
+ } : void 0;
18693
+ const weaviateConfig = config3.weaviateClassName || config3.weaviateConfigId ? {
18694
+ configId: config3.weaviateConfigId,
18695
+ className: config3.weaviateClassName || ""
18696
+ } : void 0;
18697
+ return {
18698
+ query: config3.query,
18699
+ embeddingModel: config3.embeddingModel,
18700
+ limit: config3.limit,
18701
+ threshold: config3.threshold,
18702
+ recordType: config3.recordType,
18703
+ metadataFilters: config3.metadataFilters,
18704
+ // Preserve user filter keys
18705
+ outputVariable: config3.outputVariable,
18706
+ includeEmbedding: config3.includeEmbedding,
18707
+ streamOutput: config3.streamOutput,
18708
+ // Provider selection and provider-specific config (typed fields)
18709
+ vectorStore,
18710
+ vectorizeConfig,
18711
+ weaviateConfig,
18712
+ // Also pass through flat fields for executor compatibility
18713
+ // These are used by the executor which checks both patterns
18714
+ provider: providerInput,
18715
+ // Keep original for executor
18716
+ vectorizeConfigId: config3.vectorizeConfigId,
18717
+ vectorizeNamespace: config3.vectorizeNamespace,
18718
+ weaviateClassName: config3.weaviateClassName,
18719
+ hybridSearch: config3.hybridSearch,
18720
+ hybridAlpha: config3.hybridAlpha,
18721
+ weaviateProperties: config3.weaviateProperties
18722
+ };
18723
+ }
18724
+ function normalizePaginateApiConfig(config3) {
18725
+ validateConfig(config3, "paginate-api");
18726
+ const url2 = config3.http?.url || config3.url;
18727
+ validateString(url2, "url", "paginate-api", true);
18728
+ const method = config3.http?.method || config3.method || "GET";
18729
+ validateEnum(method, ["GET", "POST"], "method", "paginate-api");
18730
+ const headers = config3.http?.headers ?? config3.headers;
18731
+ if (headers !== void 0 && headers !== null) {
18732
+ validateObject(headers, "headers", "paginate-api");
18733
+ }
18734
+ const body = config3.http?.body ?? config3.body;
18735
+ if (body !== void 0 && body !== null) {
18736
+ validateString(body, "body", "paginate-api");
18737
+ }
18738
+ const paginationType = config3.paginationType || "offset";
18739
+ validateEnum(
18740
+ paginationType,
18741
+ ["cursor", "offset", "page", "link_header"],
18742
+ "paginationType",
18743
+ "paginate-api",
18744
+ true
18745
+ );
18746
+ const pageSizeRaw = config3.pageSize;
18747
+ const pageSize = pageSizeRaw !== void 0 && pageSizeRaw !== null ? Number(pageSizeRaw) : 100;
18748
+ if (pageSizeRaw !== void 0 && pageSizeRaw !== null) {
18749
+ validateNumber(pageSizeRaw, "pageSize", "paginate-api");
18750
+ }
18751
+ const paginationConfigInput = config3.paginationConfig || {};
18752
+ if (paginationConfigInput !== void 0 && paginationConfigInput !== null) {
18753
+ validateObject(paginationConfigInput, "paginationConfig", "paginate-api");
18754
+ }
18755
+ const paginationConfig = { ...paginationConfigInput };
18756
+ if (paginationType === "cursor") {
18757
+ paginationConfig.cursorParam = paginationConfig.cursorParam || config3.cursorParam || "cursor";
18758
+ paginationConfig.cursorPath = paginationConfig.cursorPath || config3.cursorPath;
18759
+ } else if (paginationType === "offset") {
18760
+ paginationConfig.offsetParam = paginationConfig.offsetParam || config3.offsetParam || "offset";
18761
+ paginationConfig.limitParam = paginationConfig.limitParam || config3.limitParam || "limit";
18762
+ paginationConfig.limit = paginationConfig.limit ?? pageSize;
18763
+ paginationConfig.totalPath = paginationConfig.totalPath || config3.totalPath;
18764
+ } else if (paginationType === "page") {
18765
+ paginationConfig.pageParam = paginationConfig.pageParam || config3.pageParam || "page";
18766
+ paginationConfig.perPageParam = paginationConfig.perPageParam || config3.perPageParam || "per_page";
18767
+ paginationConfig.perPage = paginationConfig.perPage ?? pageSize;
18768
+ paginationConfig.totalPagesPath = paginationConfig.totalPagesPath || config3.totalPagesPath;
18769
+ }
18770
+ const entitiesPath = config3.entitiesPath || config3.entityPath || "$[*]";
18771
+ validateString(entitiesPath, "entitiesPath", "paginate-api", true);
18772
+ const outputVariable = config3.outputVariable || "entities";
18773
+ validateString(outputVariable, "outputVariable", "paginate-api", true);
18774
+ if (config3.maxPages !== void 0 && config3.maxPages !== null) {
18775
+ validateNumber(config3.maxPages, "maxPages", "paginate-api");
18776
+ }
18777
+ if (config3.maxEntities !== void 0 && config3.maxEntities !== null) {
18778
+ validateNumber(config3.maxEntities, "maxEntities", "paginate-api");
18779
+ }
18780
+ if (config3.requestDelayMs !== void 0 && config3.requestDelayMs !== null) {
18781
+ validateNumber(config3.requestDelayMs, "requestDelayMs", "paginate-api");
18782
+ }
18783
+ if (config3.retryOnRateLimit !== void 0 && config3.retryOnRateLimit !== null) {
18784
+ validateBoolean(config3.retryOnRateLimit, "retryOnRateLimit", "paginate-api");
18785
+ }
18786
+ if (config3.maxRetries !== void 0 && config3.maxRetries !== null) {
18787
+ validateNumber(config3.maxRetries, "maxRetries", "paginate-api");
18788
+ }
18789
+ if (config3.includeMetadata !== void 0 && config3.includeMetadata !== null) {
18790
+ validateBoolean(config3.includeMetadata, "includeMetadata", "paginate-api");
18791
+ }
18792
+ if (config3.streamOutput !== void 0 && config3.streamOutput !== null) {
18793
+ validateBoolean(config3.streamOutput, "streamOutput", "paginate-api");
18794
+ }
18795
+ const errorHandling = validateAndNormalizeErrorHandling(
18796
+ config3.errorHandling,
18797
+ "errorHandling",
18798
+ "paginate-api"
18799
+ );
18800
+ return {
18801
+ url: url2,
18802
+ method,
18803
+ headers,
18804
+ body,
18805
+ authType: config3.authType || "none",
18806
+ authConfig: config3.authConfig,
18807
+ paginationType,
18808
+ paginationConfig,
18809
+ pageSize,
18810
+ maxPages: config3.maxPages,
18811
+ offsetParam: config3.offsetParam,
18812
+ limitParam: config3.limitParam,
18813
+ cursorParam: config3.cursorParam,
18814
+ cursorPath: config3.cursorPath,
18815
+ pageParam: config3.pageParam,
18816
+ startPage: config3.startPage,
18817
+ entitiesPath,
18818
+ entityPath: config3.entityPath,
18819
+ entityIdPath: config3.entityIdPath,
18820
+ maxEntities: config3.maxEntities,
18821
+ requestDelayMs: config3.requestDelayMs,
18822
+ retryOnRateLimit: config3.retryOnRateLimit,
18823
+ maxRetries: config3.maxRetries,
18824
+ outputVariable,
18825
+ includeMetadata: config3.includeMetadata,
18826
+ streamOutput: config3.streamOutput,
18827
+ errorHandling,
18828
+ defaultValue: config3.defaultValue
18829
+ };
18830
+ }
18831
+ function normalizeStoreVectorConfig(config3) {
18832
+ validateConfig(config3, "store-vector");
18833
+ const destination = config3.destination;
18834
+ validateEnum(
18835
+ destination,
18836
+ ["pgvector", "weaviate", "vectorize", "pinecone"],
18837
+ "destination",
18838
+ "store-vector",
18839
+ true
18840
+ );
18841
+ if (config3.vectorsSource) {
18842
+ validateString(config3.vectorsSource, "vectorsSource", "store-vector");
18843
+ }
18844
+ if (config3.inputMode) {
18845
+ validateEnum(config3.inputMode, ["single", "batch"], "inputMode", "store-vector");
18846
+ }
18847
+ if (config3.outputVariable) {
18848
+ validateString(config3.outputVariable, "outputVariable", "store-vector");
18849
+ }
18850
+ if (config3.streamOutput !== void 0 && config3.streamOutput !== null) {
18851
+ validateBoolean(config3.streamOutput, "streamOutput", "store-vector");
18852
+ }
18853
+ const errorHandling = validateAndNormalizeErrorHandling(
18854
+ config3.errorHandling,
18855
+ "errorHandling",
18856
+ "store-vector"
18857
+ );
18858
+ const idTemplate = config3.idTemplate;
18859
+ const metadata = config3.metadata;
18860
+ const weaviateConfigInput = config3.weaviateConfig;
18861
+ const vectorizeConfigInput = config3.vectorizeConfig;
18862
+ const pineconeConfig = config3.pineconeConfig;
18863
+ const weaviateConfigId = config3.weaviateConfigId;
18864
+ const weaviateClassName = config3.weaviateClassName;
18865
+ const vectorizeConfigId = config3.vectorizeConfigId;
18866
+ const vectorizeNamespace = config3.vectorizeNamespace;
18867
+ const normalizedWeaviateConfig = weaviateConfigInput || (weaviateConfigId || weaviateClassName || metadata || idTemplate ? {
18868
+ configId: weaviateConfigId,
18869
+ className: weaviateClassName,
18870
+ uuid: idTemplate,
18871
+ properties: metadata
18872
+ } : void 0);
18873
+ const normalizedVectorizeConfig = vectorizeConfigInput || (vectorizeConfigId || vectorizeNamespace || metadata || idTemplate ? {
18874
+ configId: vectorizeConfigId,
18875
+ id: idTemplate,
18876
+ namespace: vectorizeNamespace,
18877
+ metadata
18878
+ } : void 0);
18879
+ return {
18880
+ vectorsSource: config3.vectorsSource,
18881
+ inputMode: config3.inputMode,
18882
+ inputVariable: config3.inputVariable,
18883
+ itemAlias: config3.itemAlias,
18884
+ batchSize: config3.batchSize,
18885
+ destination,
18886
+ weaviateConfig: normalizedWeaviateConfig,
18887
+ vectorizeConfig: normalizedVectorizeConfig,
18888
+ pineconeConfig,
18889
+ weaviateConfigId,
18890
+ weaviateClassName,
18891
+ vectorizeConfigId,
18892
+ vectorizeNamespace,
18893
+ pineconeConfigId: config3.pineconeConfigId,
18894
+ pineconeNamespace: config3.pineconeNamespace,
18895
+ idTemplate,
18896
+ metadata,
18897
+ outputVariable: config3.outputVariable,
18898
+ streamOutput: config3.streamOutput,
18899
+ errorHandling,
18900
+ defaultValue: config3.defaultValue
18901
+ };
18902
+ }
18903
+ function normalizeToolCallConfig(config3) {
18904
+ validateConfig(config3, "tool-call");
18905
+ validateString(config3.toolId, "toolId", "tool-call", true);
18906
+ validateObject(config3.parameters, "parameters", "tool-call", true);
18907
+ validateString(config3.outputVariable, "outputVariable", "tool-call", true);
18908
+ if (config3.maxRetries !== void 0 && config3.maxRetries !== null) {
18909
+ validateNumber(config3.maxRetries, "maxRetries", "tool-call");
18910
+ }
18911
+ if (config3.timeout !== void 0 && config3.timeout !== null) {
18912
+ validateNumber(config3.timeout, "timeout", "tool-call");
18913
+ }
18914
+ if (config3.onError) {
18915
+ validateEnum(config3.onError, ["fail", "continue", "retry"], "onError", "tool-call");
18916
+ }
18917
+ return {
18918
+ toolId: config3.toolId,
18919
+ parameters: config3.parameters,
18920
+ // Preserve user parameter keys as-is
18921
+ outputVariable: config3.outputVariable,
18922
+ maxRetries: config3.maxRetries,
18923
+ timeout: config3.timeout,
18924
+ onError: config3.onError
18925
+ };
18926
+ }
18927
+ function normalizeSuccessCriteria(criteria) {
18928
+ if (!criteria) return void 0;
18929
+ validateObject(criteria, "poll.success", "wait-until", true);
18930
+ if (criteria.type) {
18931
+ validateEnum(
18932
+ criteria.type,
18933
+ ["status", "json_path", "body_contains", "expression"],
18934
+ "poll.success.type",
18935
+ "wait-until"
18936
+ );
18937
+ }
18938
+ if (criteria.status !== void 0 && criteria.status !== null) {
18939
+ validateNumber(criteria.status, "poll.success.status", "wait-until");
18940
+ }
18941
+ if (criteria.jsonPath) validateString(criteria.jsonPath, "poll.success.jsonPath", "wait-until");
18942
+ if (criteria.bodyContains)
18943
+ validateString(criteria.bodyContains, "poll.success.bodyContains", "wait-until");
18944
+ if (criteria.expression)
18945
+ validateString(criteria.expression, "poll.success.expression", "wait-until");
18946
+ return {
18947
+ type: criteria.type,
18948
+ status: criteria.status,
18949
+ jsonPath: criteria.jsonPath,
18950
+ expectedValue: criteria.expectedValue,
18951
+ operator: criteria.operator,
18952
+ bodyContains: criteria.bodyContains,
18953
+ expression: criteria.expression
18954
+ };
18955
+ }
18956
+ function normalizePollConfig(poll) {
18957
+ if (!poll) return void 0;
18958
+ validateObject(poll, "poll", "wait-until", true);
18959
+ if (poll.enabled === false) {
18960
+ const httpConfig = poll.http ? {
18961
+ url: poll.http.url || "",
18962
+ method: poll.http.method,
18963
+ headers: poll.http.headers,
18964
+ body: poll.http.body,
18965
+ timeout: poll.http.timeout
18966
+ } : { url: "" };
18967
+ return {
18968
+ enabled: false,
18969
+ http: httpConfig,
18970
+ auth: poll.auth ? normalizeAuthConfig(poll.auth) : void 0,
18971
+ intervalMs: poll.intervalMs,
18972
+ maxAttempts: poll.maxAttempts,
18973
+ responseType: poll.responseType,
18974
+ success: normalizeSuccessCriteria(poll.success)
18975
+ };
18976
+ }
18977
+ validateObject(poll.http, "poll.http", "wait-until", true);
18978
+ if (poll.intervalMs !== void 0 && poll.intervalMs !== null) {
18979
+ if (typeof poll.intervalMs !== "string") {
18980
+ validateNumber(poll.intervalMs, "poll.intervalMs", "wait-until");
18981
+ }
18982
+ }
18983
+ if (poll.maxAttempts !== void 0 && poll.maxAttempts !== null) {
18984
+ validateNumber(poll.maxAttempts, "poll.maxAttempts", "wait-until");
18985
+ }
18986
+ if (poll.responseType) {
18987
+ validateEnum(poll.responseType, ["json", "text"], "poll.responseType", "wait-until");
18988
+ }
18989
+ if (poll.enabled !== void 0 && poll.enabled !== null) {
18990
+ validateBoolean(poll.enabled, "poll.enabled", "wait-until");
18991
+ }
18992
+ return {
18993
+ enabled: poll.enabled,
18994
+ http: normalizeHttpConfig(poll.http),
18995
+ auth: normalizeAuthConfig(poll.auth),
18996
+ intervalMs: poll.intervalMs,
18997
+ maxAttempts: poll.maxAttempts,
18998
+ responseType: poll.responseType,
18999
+ success: normalizeSuccessCriteria(poll.success)
19000
+ };
19001
+ }
19002
+ function normalizeWaitUntilConfig(config3) {
19003
+ validateConfig(config3, "wait-until");
19004
+ validateString(config3.outputVariable, "outputVariable", "wait-until", true);
19005
+ if (config3.delayMs === void 0 && !config3.poll) {
19006
+ throw new NormalizationError(
19007
+ `wait-until step requires either 'delayMs' or 'poll' configuration`,
19008
+ "wait-until",
19009
+ "delayMs/poll",
19010
+ "at least one wait mechanism",
19011
+ void 0
19012
+ );
19013
+ }
19014
+ if (config3.delayMs !== void 0 && config3.delayMs !== null) {
19015
+ if (typeof config3.delayMs !== "string") {
19016
+ validateNumber(config3.delayMs, "delayMs", "wait-until");
19017
+ }
19018
+ }
19019
+ if (config3.continueOnTimeout !== void 0 && config3.continueOnTimeout !== null) {
19020
+ validateBoolean(config3.continueOnTimeout, "continueOnTimeout", "wait-until");
19021
+ }
19022
+ const errorHandling = validateAndNormalizeErrorHandling(
19023
+ config3.errorHandling,
19024
+ "errorHandling",
19025
+ "wait-until"
19026
+ );
19027
+ return {
19028
+ delayMs: config3.delayMs,
19029
+ poll: normalizePollConfig(config3.poll),
19030
+ continueOnTimeout: config3.continueOnTimeout,
19031
+ errorHandling,
19032
+ defaultValue: config3.defaultValue,
19033
+ outputVariable: config3.outputVariable
19034
+ };
19035
+ }
19036
+ function normalizeExecuteAgentConfig(config3) {
19037
+ validateConfig(config3, "execute-agent");
19038
+ const agentId = config3.agentId ?? config3.agent_id;
19039
+ validateString(agentId, "agentId", "execute-agent", true);
19040
+ const message = config3.message;
19041
+ validateString(message, "message", "execute-agent", true);
19042
+ const outputVariable = config3.outputVariable ?? config3.output_variable ?? "agent_response";
19043
+ validateString(outputVariable, "outputVariable", "execute-agent");
19044
+ const maxTurns = config3.maxTurns ?? config3.max_turns;
19045
+ if (maxTurns !== void 0 && maxTurns !== null) {
19046
+ validateNumber(maxTurns, "maxTurns", "execute-agent");
19047
+ }
19048
+ if (config3.timeout !== void 0 && config3.timeout !== null) {
19049
+ validateNumber(config3.timeout, "timeout", "execute-agent");
19050
+ }
19051
+ const errorHandling = validateAndNormalizeErrorHandling(
19052
+ config3.errorHandling ?? config3.error_handling,
19053
+ "errorHandling",
19054
+ "execute-agent"
19055
+ );
19056
+ return {
19057
+ agentId,
19058
+ message,
19059
+ outputVariable,
19060
+ variables: config3.variables,
19061
+ maxTurns,
19062
+ timeout: config3.timeout,
19063
+ errorHandling,
19064
+ defaultValue: config3.defaultValue ?? config3.default_value
19065
+ };
19066
+ }
19067
+ function normalizeStoreAssetConfig(config3) {
19068
+ validateConfig(config3, "store-asset");
19069
+ const url2 = config3.url;
19070
+ const content = config3.content;
19071
+ if ((url2 === void 0 || url2 === null) && (content === void 0 || content === null)) {
19072
+ throw new NormalizationError(
19073
+ 'store-asset requires either "url" or "content" (base64)',
19074
+ "store-asset",
19075
+ "url",
19076
+ "string",
19077
+ void 0
19078
+ );
19079
+ }
19080
+ if (url2 !== void 0 && url2 !== null && content !== void 0 && content !== null) {
19081
+ throw new NormalizationError(
19082
+ 'store-asset accepts exactly one of "url" or "content", not both',
19083
+ "store-asset",
19084
+ "url",
19085
+ "string",
19086
+ typeof url2
19087
+ );
19088
+ }
19089
+ if (url2 !== void 0 && url2 !== null) {
19090
+ validateString(url2, "url", "store-asset", true);
19091
+ }
19092
+ if (content !== void 0 && content !== null) {
19093
+ validateString(content, "content", "store-asset", true);
19094
+ }
19095
+ if (config3.filename !== void 0 && config3.filename !== null) {
19096
+ validateString(config3.filename, "filename", "store-asset");
19097
+ }
19098
+ if (config3.contentType !== void 0 && config3.contentType !== null) {
19099
+ validateString(config3.contentType, "contentType", "store-asset");
19100
+ }
19101
+ if (config3.visibility !== void 0 && config3.visibility !== null) {
19102
+ validateEnum(config3.visibility, ["public", "private"], "visibility", "store-asset");
19103
+ }
19104
+ validateString(config3.outputVariable, "outputVariable", "store-asset", true);
19105
+ const errorHandling = validateAndNormalizeErrorHandling(
19106
+ config3.errorHandling,
19107
+ "errorHandling",
19108
+ "store-asset"
19109
+ );
19110
+ return {
19111
+ url: url2,
19112
+ content,
19113
+ filename: config3.filename,
19114
+ contentType: config3.contentType,
19115
+ visibility: config3.visibility,
19116
+ outputVariable: config3.outputVariable,
19117
+ streamOutput: config3.streamOutput,
19118
+ errorHandling,
19119
+ defaultValue: config3.defaultValue
19120
+ };
19121
+ }
19122
+ function normalizeGeneratePdfConfig(config3) {
19123
+ validateConfig(config3, "generate-pdf");
19124
+ const html = config3.html;
19125
+ const markdown = config3.markdown;
19126
+ if ((html === void 0 || html === null) && (markdown === void 0 || markdown === null)) {
19127
+ throw new NormalizationError(
19128
+ 'generate-pdf requires either "html" or "markdown"',
19129
+ "generate-pdf",
19130
+ "html",
19131
+ "string",
19132
+ void 0
19133
+ );
19134
+ }
19135
+ if (html !== void 0 && html !== null && markdown !== void 0 && markdown !== null) {
19136
+ throw new NormalizationError(
19137
+ 'generate-pdf accepts exactly one of "html" or "markdown", not both',
19138
+ "generate-pdf",
19139
+ "html",
19140
+ "string",
19141
+ typeof html
19142
+ );
19143
+ }
19144
+ if (html !== void 0 && html !== null) {
19145
+ validateString(html, "html", "generate-pdf", true);
19146
+ }
19147
+ if (markdown !== void 0 && markdown !== null) {
19148
+ validateString(markdown, "markdown", "generate-pdf", true);
19149
+ }
19150
+ if (config3.filename !== void 0 && config3.filename !== null) {
19151
+ validateString(config3.filename, "filename", "generate-pdf");
19152
+ }
19153
+ if (config3.visibility !== void 0 && config3.visibility !== null) {
19154
+ validateEnum(config3.visibility, ["public", "private"], "visibility", "generate-pdf");
19155
+ }
19156
+ if (config3.pdfOptions !== void 0 && config3.pdfOptions !== null) {
19157
+ validateObject(config3.pdfOptions, "pdfOptions", "generate-pdf");
19158
+ const pdfOptions = config3.pdfOptions;
19159
+ if (pdfOptions.format !== void 0 && pdfOptions.format !== null) {
19160
+ validateEnum(pdfOptions.format, ["A4", "Letter"], "pdfOptions.format", "generate-pdf");
19161
+ }
19162
+ if (pdfOptions.landscape !== void 0 && pdfOptions.landscape !== null) {
19163
+ validateBoolean(pdfOptions.landscape, "pdfOptions.landscape", "generate-pdf");
19164
+ }
19165
+ }
19166
+ validateString(config3.outputVariable, "outputVariable", "generate-pdf", true);
19167
+ const errorHandling = validateAndNormalizeErrorHandling(
19168
+ config3.errorHandling,
19169
+ "errorHandling",
19170
+ "generate-pdf"
19171
+ );
19172
+ return {
19173
+ html,
19174
+ markdown,
19175
+ filename: config3.filename,
19176
+ visibility: config3.visibility,
19177
+ pdfOptions: config3.pdfOptions,
19178
+ outputVariable: config3.outputVariable,
19179
+ streamOutput: config3.streamOutput,
19180
+ errorHandling,
19181
+ defaultValue: config3.defaultValue
19182
+ };
19183
+ }
19184
+ function normalizeSaveMemoryConfig(config3) {
19185
+ validateConfig(config3, "save-memory");
19186
+ validateString(config3.profileTemplate, "profileTemplate", "save-memory", true);
19187
+ validateString(config3.contentVariable, "contentVariable", "save-memory", true);
19188
+ if (config3.sessionId !== void 0 && config3.sessionId !== null) {
19189
+ validateString(config3.sessionId, "sessionId", "save-memory");
19190
+ }
19191
+ if (config3.outputVariable !== void 0 && config3.outputVariable !== null) {
19192
+ validateString(config3.outputVariable, "outputVariable", "save-memory");
19193
+ }
19194
+ const errorHandling = validateAndNormalizeErrorHandling(
19195
+ config3.errorHandling ?? config3.error_handling,
19196
+ "errorHandling",
19197
+ "save-memory"
19198
+ );
19199
+ return {
19200
+ profileTemplate: config3.profileTemplate,
19201
+ contentVariable: config3.contentVariable,
19202
+ sessionId: config3.sessionId,
19203
+ outputVariable: config3.outputVariable,
19204
+ errorHandling,
19205
+ defaultValue: config3.defaultValue ?? config3.default_value
19206
+ };
19207
+ }
19208
+ function normalizeRecallMemoryConfig(config3) {
19209
+ validateConfig(config3, "recall-memory");
19210
+ validateString(config3.profileTemplate, "profileTemplate", "recall-memory", true);
19211
+ validateString(config3.queryTemplate, "queryTemplate", "recall-memory", true);
19212
+ validateString(config3.outputVariable, "outputVariable", "recall-memory", true);
19213
+ validateEnum(config3.thinkingLevel, ["low", "medium", "high"], "thinkingLevel", "recall-memory");
19214
+ validateEnum(
19215
+ config3.responseLength,
19216
+ ["short", "medium", "long"],
19217
+ "responseLength",
19218
+ "recall-memory"
19219
+ );
19220
+ const errorHandling = validateAndNormalizeErrorHandling(
19221
+ config3.errorHandling ?? config3.error_handling,
19222
+ "errorHandling",
19223
+ "recall-memory"
19224
+ );
19225
+ return {
19226
+ profileTemplate: config3.profileTemplate,
19227
+ queryTemplate: config3.queryTemplate,
19228
+ thinkingLevel: config3.thinkingLevel,
19229
+ responseLength: config3.responseLength,
19230
+ outputVariable: config3.outputVariable,
19231
+ errorHandling,
19232
+ defaultValue: config3.defaultValue ?? config3.default_value
19233
+ };
19234
+ }
19235
+ function normalizeMemorySummaryConfig(config3) {
19236
+ validateConfig(config3, "memory-summary");
19237
+ validateString(config3.profileTemplate, "profileTemplate", "memory-summary", true);
19238
+ validateString(config3.outputVariable, "outputVariable", "memory-summary", true);
19239
+ if (config3.sessionId !== void 0 && config3.sessionId !== null) {
19240
+ validateString(config3.sessionId, "sessionId", "memory-summary");
19241
+ }
19242
+ const errorHandling = validateAndNormalizeErrorHandling(
19243
+ config3.errorHandling ?? config3.error_handling,
19244
+ "errorHandling",
19245
+ "memory-summary"
19246
+ );
19247
+ return {
19248
+ profileTemplate: config3.profileTemplate,
19249
+ sessionId: config3.sessionId,
19250
+ outputVariable: config3.outputVariable,
19251
+ errorHandling,
19252
+ defaultValue: config3.defaultValue ?? config3.default_value
19253
+ };
19254
+ }
19255
+ var NAMED_AGENT_REF_PREFIX = "agent:";
19256
+ var NAMED_FLOW_REF_PREFIX = "flow:";
19257
+ function isNamedRef(value, prefix) {
19258
+ return value.startsWith(prefix) && value.length > prefix.length;
19259
+ }
19260
+ function parseNamedRef(value, prefix) {
19261
+ if (!isNamedRef(value, prefix)) return null;
19262
+ return { name: value.slice(prefix.length) };
19263
+ }
19264
+ function parseNamedAgentRef(value) {
19265
+ return parseNamedRef(value, NAMED_AGENT_REF_PREFIX);
19266
+ }
19267
+ function parseNamedFlowRef(value) {
19268
+ return parseNamedRef(value, NAMED_FLOW_REF_PREFIX);
19269
+ }
19270
+ function sanitizeCodeToolIdentifier(name) {
19271
+ let safe = name.replace(/[^a-zA-Z0-9_$]/g, "_");
19272
+ if (/^[0-9]/.test(safe)) safe = "_" + safe;
19273
+ return safe;
19274
+ }
17250
19275
  var flowStepValidationSchema = external_exports.object({
17251
19276
  // Optional stable client-supplied identifier. Preserved across saves so that
17252
19277
  // `flow_step_results.stepId` references stay valid and dashboard UI state
@@ -17306,6 +19331,1106 @@ var KNOWN_TOOL_KEYS = /* @__PURE__ */ new Set([
17306
19331
  ...Object.keys(CAMEL_CASE_TOOL_KEYS),
17307
19332
  ...Object.keys(SNAKE_CASE_TOOL_KEYS)
17308
19333
  ]);
19334
+ var LEGACY_TOOL_KEY_SUGGESTIONS = {
19335
+ builtinTools: "toolIds"
19336
+ };
19337
+ function isObjectRecord(value) {
19338
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19339
+ }
19340
+ var NETWORK_ISOLATED_SANDBOX_PROVIDERS = /* @__PURE__ */ new Set(["cloudflare-worker", "quickjs"]);
19341
+ var MAX_CONDITIONAL_NESTING_DEPTH = 10;
19342
+ var FETCH_CALL_PATTERN = /\bfetch\s*\(/;
19343
+ function validateSandboxNetworkAccess(config3, stepIndex, stepRef, buckets) {
19344
+ const rawProvider = typeof config3.sandboxProvider === "string" ? config3.sandboxProvider : "cloudflare-worker";
19345
+ if (!NETWORK_ISOLATED_SANDBOX_PROVIDERS.has(rawProvider)) {
19346
+ return;
19347
+ }
19348
+ const networkAccess = config3.networkAccess;
19349
+ if (networkAccess === "on") {
19350
+ return;
19351
+ }
19352
+ if (isObjectRecord(networkAccess) && Array.isArray(networkAccess.allowedHostnames) && networkAccess.allowedHostnames.length > 0) {
19353
+ return;
19354
+ }
19355
+ const code = typeof config3.script === "string" ? config3.script : "";
19356
+ if (!code || !FETCH_CALL_PATTERN.test(code)) {
19357
+ return;
19358
+ }
19359
+ addIssue(
19360
+ "warning",
19361
+ {
19362
+ code: "SANDBOX_NETWORK_ACCESS_DISABLED",
19363
+ message: "Step uses fetch() but network access is disabled for this sandbox; the request will be blocked at runtime. Set networkAccess to 'on' or an allowedHostnames allowlist, or use the daytona provider.",
19364
+ path: `flowSteps[${stepIndex}].config.networkAccess`,
19365
+ step: stepRef,
19366
+ details: {
19367
+ sandboxProvider: rawProvider,
19368
+ networkAccess: typeof networkAccess === "string" ? networkAccess : "off"
19369
+ }
19370
+ },
19371
+ buckets
19372
+ );
19373
+ }
19374
+ function validateCodeToolNameCollisions(toolNames, stepRef, code, preSeededCount = 0) {
19375
+ const seen = /* @__PURE__ */ new Map();
19376
+ for (const [i, tool] of toolNames.entries()) {
19377
+ const sanitized = sanitizeCodeToolIdentifier(tool.name);
19378
+ if (i < preSeededCount) {
19379
+ seen.set(sanitized, tool);
19380
+ continue;
19381
+ }
19382
+ const existing = seen.get(sanitized);
19383
+ if (existing) {
19384
+ return {
19385
+ code,
19386
+ message: `Tool names "${existing.name}" and "${tool.name}" both become "${sanitized}" in JavaScript. Rename or remove one before enabling code-mode execution.`,
19387
+ path: tool.path,
19388
+ step: stepRef,
19389
+ details: {
19390
+ firstPath: existing.path,
19391
+ secondPath: tool.path,
19392
+ sanitizedName: sanitized
19393
+ }
19394
+ };
19395
+ }
19396
+ seen.set(sanitized, tool);
19397
+ }
19398
+ return null;
19399
+ }
19400
+ function formatPath(path18) {
19401
+ return path18.reduce((acc, part) => {
19402
+ if (typeof part === "number") {
19403
+ return `${acc}[${part}]`;
19404
+ }
19405
+ const key = String(part);
19406
+ return acc ? `${acc}.${key}` : key;
19407
+ }, "");
19408
+ }
19409
+ function compareIssuePath(a, b) {
19410
+ if (!a && !b) return 0;
19411
+ if (!a) return 1;
19412
+ if (!b) return -1;
19413
+ return a.localeCompare(b);
19414
+ }
19415
+ function sortIssues(issues) {
19416
+ return [...issues].sort((a, b) => {
19417
+ const aStepIndex = a.step?.index ?? Number.MAX_SAFE_INTEGER;
19418
+ const bStepIndex = b.step?.index ?? Number.MAX_SAFE_INTEGER;
19419
+ if (aStepIndex !== bStepIndex) {
19420
+ return aStepIndex - bStepIndex;
19421
+ }
19422
+ const pathCompare = compareIssuePath(a.path, b.path);
19423
+ if (pathCompare !== 0) {
19424
+ return pathCompare;
19425
+ }
19426
+ const codeCompare = a.code.localeCompare(b.code);
19427
+ if (codeCompare !== 0) {
19428
+ return codeCompare;
19429
+ }
19430
+ return a.message.localeCompare(b.message);
19431
+ });
19432
+ }
19433
+ function addIssue(level, issue2, buckets) {
19434
+ switch (level) {
19435
+ case "error":
19436
+ buckets.errors.push(issue2);
19437
+ return;
19438
+ case "warning":
19439
+ buckets.warnings.push(issue2);
19440
+ return;
19441
+ default:
19442
+ buckets.recommendations.push(issue2);
19443
+ }
19444
+ }
19445
+ function buildIssueFromZod(issue2, resolvedPath, step) {
19446
+ return {
19447
+ code: "SCHEMA_VALIDATION_FAILED",
19448
+ message: issue2.message,
19449
+ path: resolvedPath,
19450
+ step,
19451
+ details: issue2
19452
+ };
19453
+ }
19454
+ function conditionalNestingDepth(config3) {
19455
+ let maxDepth = 0;
19456
+ const stack = [{ node: config3, depth: 1 }];
19457
+ while (stack.length > 0) {
19458
+ const { node, depth } = stack.pop();
19459
+ if (depth > maxDepth) maxDepth = depth;
19460
+ if (depth > MAX_CONDITIONAL_NESTING_DEPTH) break;
19461
+ if (!node || typeof node !== "object") continue;
19462
+ const cfg = node;
19463
+ for (const key of ["trueSteps", "falseSteps", "true_steps", "false_steps"]) {
19464
+ const branch = cfg[key];
19465
+ if (!Array.isArray(branch)) continue;
19466
+ for (const s of branch) {
19467
+ if (s && typeof s === "object" && s.type === "conditional") {
19468
+ const nestedCfg = s.config;
19469
+ if (nestedCfg && typeof nestedCfg === "object") {
19470
+ stack.push({ node: nestedCfg, depth: depth + 1 });
19471
+ }
19472
+ }
19473
+ }
19474
+ }
19475
+ }
19476
+ return maxDepth;
19477
+ }
19478
+ function registerReference(map2, id, reference) {
19479
+ const existing = map2.get(id) || [];
19480
+ existing.push(reference);
19481
+ map2.set(id, existing);
19482
+ }
19483
+ function collectRuntimeToolNameSelections(toolsConfig, stepIndex, selectedNames) {
19484
+ const runtimeTools = Array.isArray(toolsConfig.runtimeTools) ? toolsConfig.runtimeTools : [];
19485
+ const selections = [];
19486
+ for (const [runtimeToolIndex, runtimeTool] of runtimeTools.entries()) {
19487
+ if (!isObjectRecord(runtimeTool)) {
19488
+ continue;
19489
+ }
19490
+ const name = runtimeTool.name;
19491
+ if (typeof name !== "string") {
19492
+ continue;
19493
+ }
19494
+ if (selectedNames && !selectedNames.has(name)) {
19495
+ continue;
19496
+ }
19497
+ selections.push({
19498
+ name,
19499
+ path: `flowSteps[${stepIndex}].config.tools.runtimeTools[${runtimeToolIndex}].name`
19500
+ });
19501
+ }
19502
+ return selections;
19503
+ }
19504
+ function collectTransformDataCodeToolNameCheck(toolsConfig, stepIndex, stepRef, pendingChecks) {
19505
+ const toolIds = Array.isArray(toolsConfig.toolIds) ? toolsConfig.toolIds : [];
19506
+ const selectedToolIds = [];
19507
+ const selectedToolNames = [];
19508
+ for (const [toolIdIndex, toolId] of toolIds.entries()) {
19509
+ if (typeof toolId !== "string") {
19510
+ continue;
19511
+ }
19512
+ const path18 = `flowSteps[${stepIndex}].config.tools.toolIds[${toolIdIndex}]`;
19513
+ const named = parseNamedToolRef(toolId);
19514
+ if (named) {
19515
+ selectedToolNames.push({ name: named.name, path: path18 });
19516
+ continue;
19517
+ }
19518
+ const { customToolIds } = separateToolIds([toolId]);
19519
+ if (customToolIds.length === 0) {
19520
+ continue;
19521
+ }
19522
+ selectedToolIds.push({ toolId, path: path18 });
19523
+ }
19524
+ if (selectedToolIds.length > 0 || selectedToolNames.length > 0) {
19525
+ pendingChecks.hasAccountScopedReferences = true;
19526
+ pendingChecks.codeToolNameChecks.push({
19527
+ step: stepRef,
19528
+ collisionCode: "CODE_STEP_TOOL_NAME_COLLISION",
19529
+ runtimeToolNames: collectRuntimeToolNameSelections(toolsConfig, stepIndex),
19530
+ selectedToolIds,
19531
+ selectedToolNames
19532
+ });
19533
+ }
19534
+ }
19535
+ function collectCodeModeToolNameCheck(toolsConfig, stepIndex, stepRef, pendingChecks) {
19536
+ const codeModeConfig = toolsConfig.codeModeConfig;
19537
+ if (!isObjectRecord(codeModeConfig) || !Array.isArray(codeModeConfig.toolPool)) {
19538
+ return;
19539
+ }
19540
+ const runtimeTools = Array.isArray(toolsConfig.runtimeTools) ? toolsConfig.runtimeTools : [];
19541
+ const runtimeToolNames = /* @__PURE__ */ new Set();
19542
+ for (const runtimeTool of runtimeTools) {
19543
+ if (!isObjectRecord(runtimeTool) || typeof runtimeTool.name !== "string") {
19544
+ continue;
19545
+ }
19546
+ runtimeToolNames.add(runtimeTool.name);
19547
+ }
19548
+ const selectedRuntimeToolNames = /* @__PURE__ */ new Set();
19549
+ const selectedToolIds = [];
19550
+ const selectedToolNames = [];
19551
+ for (const [toolPoolIndex, entry] of codeModeConfig.toolPool.entries()) {
19552
+ if (typeof entry !== "string" || entry.length === 0 || entry.endsWith(":*")) {
19553
+ continue;
19554
+ }
19555
+ const path18 = `flowSteps[${stepIndex}].config.tools.codeModeConfig.toolPool[${toolPoolIndex}]`;
19556
+ const named = parseNamedToolRef(entry);
19557
+ if (named) {
19558
+ selectedToolNames.push({ name: named.name, path: path18 });
19559
+ continue;
19560
+ }
19561
+ if (runtimeToolNames.has(entry)) {
19562
+ selectedRuntimeToolNames.add(entry);
19563
+ continue;
19564
+ }
19565
+ const { customToolIds } = separateToolIds([entry]);
19566
+ if (customToolIds.length === 0) {
19567
+ continue;
19568
+ }
19569
+ selectedToolIds.push({ toolId: entry, path: path18 });
19570
+ }
19571
+ if (selectedToolIds.length > 0 || selectedToolNames.length > 0) {
19572
+ pendingChecks.hasAccountScopedReferences = true;
19573
+ pendingChecks.codeToolNameChecks.push({
19574
+ step: stepRef,
19575
+ collisionCode: "CODE_MODE_TOOL_NAME_COLLISION",
19576
+ runtimeToolNames: collectRuntimeToolNameSelections(
19577
+ toolsConfig,
19578
+ stepIndex,
19579
+ selectedRuntimeToolNames
19580
+ ),
19581
+ selectedToolIds,
19582
+ selectedToolNames
19583
+ });
19584
+ }
19585
+ }
19586
+ var SINGLE_BRACE_VARIABLE_PATTERN = /(?<!\{)\{([a-zA-Z_][a-zA-Z0-9_.]*)\}(?!\})/g;
19587
+ var DOUBLE_BRACE_VARIABLE_PATTERN = TEMPLATE_EXPRESSION_PATTERN;
19588
+ var TEMPLATE_STRING_FIELDS = /* @__PURE__ */ new Set([
19589
+ "text",
19590
+ "userPrompt",
19591
+ "systemPrompt",
19592
+ "url",
19593
+ "body",
19594
+ "query",
19595
+ "message",
19596
+ "valueTemplate",
19597
+ "value",
19598
+ "subject",
19599
+ "html",
19600
+ "from",
19601
+ "to",
19602
+ "cc",
19603
+ "bcc",
19604
+ "replyTo",
19605
+ "nameTemplate",
19606
+ "condition",
19607
+ "script",
19608
+ "requestTemplate"
19609
+ ]);
19610
+ var NON_FLOW_VARIABLE_SUBTREE_KEYS = /* @__PURE__ */ new Set(["tools"]);
19611
+ function extractTemplateStrings(config3, path18 = []) {
19612
+ const results = [];
19613
+ if (typeof config3 === "string") {
19614
+ const fieldName = path18[path18.length - 1];
19615
+ const parentFieldName = path18.length >= 2 ? path18[path18.length - 2] : void 0;
19616
+ if (fieldName && TEMPLATE_STRING_FIELDS.has(fieldName) || parentFieldName && TEMPLATE_STRING_FIELDS.has(parentFieldName)) {
19617
+ results.push({ value: config3, fieldPath: path18.join(".") });
19618
+ }
19619
+ return results;
19620
+ }
19621
+ if (Array.isArray(config3)) {
19622
+ for (const [index, item] of config3.entries()) {
19623
+ results.push(...extractTemplateStrings(item, [...path18, String(index)]));
19624
+ }
19625
+ return results;
19626
+ }
19627
+ if (isObjectRecord(config3)) {
19628
+ for (const [key, val] of Object.entries(config3)) {
19629
+ if (NON_FLOW_VARIABLE_SUBTREE_KEYS.has(key)) continue;
19630
+ if (typeof val === "string" && TEMPLATE_STRING_FIELDS.has(key)) {
19631
+ results.push({ value: val, fieldPath: [...path18, key].join(".") });
19632
+ } else if (typeof val === "object" && val !== null) {
19633
+ results.push(...extractTemplateStrings(val, [...path18, key]));
19634
+ }
19635
+ }
19636
+ }
19637
+ return results;
19638
+ }
19639
+ function detectMalformedVariableReferences(config3) {
19640
+ const malformed = [];
19641
+ const templateStrings = extractTemplateStrings(config3);
19642
+ for (const { value, fieldPath } of templateStrings) {
19643
+ let match;
19644
+ const pattern = new RegExp(SINGLE_BRACE_VARIABLE_PATTERN.source, "g");
19645
+ while ((match = pattern.exec(value)) !== null) {
19646
+ const varName = match[1];
19647
+ if (!varName) continue;
19648
+ const doublebraceForm = `{{${varName}}}`;
19649
+ if (value.includes(doublebraceForm)) continue;
19650
+ malformed.push({ variable: varName, fieldPath });
19651
+ }
19652
+ }
19653
+ return malformed;
19654
+ }
19655
+ function extractVariableReferences(config3) {
19656
+ const references = [];
19657
+ const templateStrings = extractTemplateStrings(config3);
19658
+ for (const { value, fieldPath } of templateStrings) {
19659
+ const pattern = new RegExp(DOUBLE_BRACE_VARIABLE_PATTERN.source, "g");
19660
+ let match;
19661
+ while ((match = pattern.exec(value)) !== null) {
19662
+ const expr = match[1];
19663
+ if (!expr) continue;
19664
+ for (const path18 of extractTemplateExpressionPaths(expr)) {
19665
+ references.push({ variable: path18, fieldPath });
19666
+ }
19667
+ }
19668
+ }
19669
+ return references;
19670
+ }
19671
+ function getStepOutputVariable(step) {
19672
+ if (!isObjectRecord(step.config)) return null;
19673
+ if (typeof step.config.outputVariable === "string" && step.config.outputVariable.length > 0) {
19674
+ return step.config.outputVariable;
19675
+ }
19676
+ if (step.type === "set-variable" && typeof step.config.variableName === "string" && step.config.variableName.length > 0) {
19677
+ return step.config.variableName;
19678
+ }
19679
+ return null;
19680
+ }
19681
+ function collectDeclaredFlowInputs(flowSteps, declaredFlowInputs) {
19682
+ const declared = /* @__PURE__ */ new Set();
19683
+ for (const key of declaredFlowInputs ?? []) {
19684
+ if (typeof key === "string" && key) declared.add(key);
19685
+ }
19686
+ for (const step of flowSteps) {
19687
+ const config3 = step.config;
19688
+ const inputVariables = config3?.inputVariables;
19689
+ if (Array.isArray(inputVariables)) {
19690
+ for (const name of inputVariables) {
19691
+ if (typeof name === "string" && name) declared.add(name);
19692
+ }
19693
+ }
19694
+ }
19695
+ return declared;
19696
+ }
19697
+ var NAMESPACE_VARIABLE_REFERENCE_CODES = [
19698
+ "UNDECLARED_VARIABLE_REFERENCE",
19699
+ "UNKNOWN_VARIABLE_NAMESPACE"
19700
+ ];
19701
+ function validateVariableReferences(flowSteps, buckets, skipStepIndices, declaredFlowInputs) {
19702
+ const declaredVariables = collectDeclaredFlowInputs(flowSteps, declaredFlowInputs);
19703
+ for (const [stepIndex, step] of flowSteps.entries()) {
19704
+ if (skipStepIndices?.has(stepIndex)) continue;
19705
+ const stepRef = {
19706
+ index: stepIndex,
19707
+ name: step.name,
19708
+ type: step.type
19709
+ };
19710
+ const malformed = detectMalformedVariableReferences(step.config);
19711
+ for (const { variable, fieldPath } of malformed) {
19712
+ addIssue(
19713
+ "warning",
19714
+ {
19715
+ code: "MALFORMED_VARIABLE_REFERENCE",
19716
+ message: `Possible malformed variable reference "{${variable}}" \u2014 use "{{${variable}}}" for template variable substitution.`,
19717
+ path: `flowSteps[${stepIndex}].config.${fieldPath}`,
19718
+ step: stepRef,
19719
+ details: { variable, suggestion: `{{${variable}}}` }
19720
+ },
19721
+ buckets
19722
+ );
19723
+ }
19724
+ const references = extractVariableReferences(step.config);
19725
+ for (const { variable, fieldPath } of references) {
19726
+ const classification = classifyVariableReference(variable);
19727
+ if (classification.namespace === "system" || classification.namespace === "secret") {
19728
+ continue;
19729
+ }
19730
+ if (classification.namespace === "unknown") {
19731
+ addIssue(
19732
+ "warning",
19733
+ {
19734
+ code: "UNKNOWN_VARIABLE_NAMESPACE",
19735
+ message: `Variable "{{${variable}}}" uses an unrecognized namespace prefix. Recognized prefixes are "flow:" (a flow input) and "secret:" (a configured secret). Use a known prefix or a plain variable name.`,
19736
+ path: `flowSteps[${stepIndex}].config.${fieldPath}`,
19737
+ step: stepRef,
19738
+ details: { variable }
19739
+ },
19740
+ buckets
19741
+ );
19742
+ continue;
19743
+ }
19744
+ const baseName = classification.baseName;
19745
+ const rootVariable = baseName.split(".")[0] || "";
19746
+ if (!declaredVariables.has(rootVariable) && !declaredVariables.has(baseName)) {
19747
+ addIssue(
19748
+ "warning",
19749
+ {
19750
+ code: "UNDECLARED_VARIABLE_REFERENCE",
19751
+ message: `Variable "{{${variable}}}" is referenced but no earlier step declares an output variable "${rootVariable}". Check that a previous step sets outputVariable to "${rootVariable}", or declare "${rootVariable}" as a flow input.`,
19752
+ path: `flowSteps[${stepIndex}].config.${fieldPath}`,
19753
+ step: stepRef,
19754
+ details: {
19755
+ variable,
19756
+ availableVariables: [...declaredVariables]
19757
+ }
19758
+ },
19759
+ buckets
19760
+ );
19761
+ }
19762
+ }
19763
+ if (step.enabled !== false) {
19764
+ const outputVar = getStepOutputVariable(step);
19765
+ if (outputVar) {
19766
+ declaredVariables.add(outputVar);
19767
+ }
19768
+ }
19769
+ }
19770
+ }
19771
+ function promptResponseFormatIsNonJson(responseFormat) {
19772
+ if (typeof responseFormat !== "string") return true;
19773
+ return responseFormat.trim().toLowerCase() !== "json";
19774
+ }
19775
+ function validateUpsertRecordSourceShape(flowSteps, buckets) {
19776
+ const stringPromptOutputs = /* @__PURE__ */ new Map();
19777
+ for (const [stepIndex, step] of flowSteps.entries()) {
19778
+ if (step.enabled === false) continue;
19779
+ if (!isObjectRecord(step.config)) continue;
19780
+ const config3 = step.config;
19781
+ if (step.type === "upsert-record") {
19782
+ const inputMode = typeof config3.inputMode === "string" ? config3.inputMode : "single";
19783
+ const sourceVariable = typeof config3.sourceVariable === "string" ? config3.sourceVariable : "";
19784
+ const hasContentField = typeof config3.contentField === "string" && config3.contentField.length > 0;
19785
+ if (inputMode !== "batch" && sourceVariable && !hasContentField) {
19786
+ const origin = stringPromptOutputs.get(sourceVariable);
19787
+ if (origin) {
19788
+ addIssue(
19789
+ "warning",
19790
+ {
19791
+ code: "UPSERT_RECORD_SOURCE_NOT_JSON",
19792
+ message: `Source variable "${sourceVariable}" is set by prompt step "${origin.name}" (responseFormat "${origin.responseFormat}"), which outputs a string, but the record metadata column requires a JSON object. This will fail at runtime. Either: (1) set that prompt's responseFormat to "json", (2) add a transform-data step to wrap the string, or (3) set contentField on this upsert-record step to auto-wrap the string as { [contentField]: content }.`,
19793
+ path: `flowSteps[${stepIndex}].config.sourceVariable`,
19794
+ step: { index: stepIndex, name: step.name, type: step.type },
19795
+ details: {
19796
+ sourceVariable,
19797
+ originStepIndex: origin.index,
19798
+ originStepName: origin.name,
19799
+ responseFormat: origin.responseFormat
19800
+ }
19801
+ },
19802
+ buckets
19803
+ );
19804
+ }
19805
+ }
19806
+ }
19807
+ const outputVar = getStepOutputVariable(step);
19808
+ if (outputVar) {
19809
+ if (step.type === "prompt" && promptResponseFormatIsNonJson(config3.responseFormat)) {
19810
+ const responseFormat = typeof config3.responseFormat === "string" ? config3.responseFormat : "default";
19811
+ stringPromptOutputs.set(outputVar, { index: stepIndex, name: step.name, responseFormat });
19812
+ } else {
19813
+ stringPromptOutputs.delete(outputVar);
19814
+ }
19815
+ }
19816
+ }
19817
+ }
19818
+ function collectAccountScopedReferences(step, stepIndex, pendingChecks) {
19819
+ const stepRef = {
19820
+ index: stepIndex,
19821
+ name: step.name,
19822
+ type: step.type
19823
+ };
19824
+ if (!isObjectRecord(step.config)) {
19825
+ return;
19826
+ }
19827
+ if (step.type === "execute-agent") {
19828
+ const agentId = step.config.agentId;
19829
+ if (typeof agentId === "string" && !agentId.includes("{{")) {
19830
+ const path18 = `flowSteps[${stepIndex}].config.agentId`;
19831
+ registerAgentReference(agentId, path18, stepRef, pendingChecks);
19832
+ }
19833
+ return;
19834
+ }
19835
+ if (step.type === "tool-call") {
19836
+ const toolId = step.config.toolId;
19837
+ if (typeof toolId === "string") {
19838
+ const path18 = `flowSteps[${stepIndex}].config.toolId`;
19839
+ const named = parseNamedToolRef(toolId);
19840
+ if (named) {
19841
+ pendingChecks.hasAccountScopedReferences = true;
19842
+ registerReference(pendingChecks.toolReferencesByName, named.name, { path: path18, step: stepRef });
19843
+ } else {
19844
+ const { customToolIds } = separateToolIds([toolId]);
19845
+ if (customToolIds.length > 0) {
19846
+ pendingChecks.hasAccountScopedReferences = true;
19847
+ registerReference(pendingChecks.toolReferencesById, toolId, { path: path18, step: stepRef });
19848
+ }
19849
+ }
19850
+ }
19851
+ return;
19852
+ }
19853
+ if (step.type !== "prompt" && step.type !== "transform-data") {
19854
+ return;
19855
+ }
19856
+ const toolsConfig = step.config.tools;
19857
+ if (!isObjectRecord(toolsConfig)) {
19858
+ return;
19859
+ }
19860
+ const toolIds = toolsConfig.toolIds;
19861
+ if (Array.isArray(toolIds)) {
19862
+ for (const [toolIdIndex, toolId] of toolIds.entries()) {
19863
+ if (typeof toolId !== "string") {
19864
+ continue;
19865
+ }
19866
+ const path18 = `flowSteps[${stepIndex}].config.tools.toolIds[${toolIdIndex}]`;
19867
+ const named = parseNamedToolRef(toolId);
19868
+ if (named) {
19869
+ pendingChecks.hasAccountScopedReferences = true;
19870
+ registerReference(pendingChecks.toolReferencesByName, named.name, { path: path18, step: stepRef });
19871
+ continue;
19872
+ }
19873
+ const { customToolIds } = separateToolIds([toolId]);
19874
+ if (customToolIds.length > 0) {
19875
+ pendingChecks.hasAccountScopedReferences = true;
19876
+ registerReference(pendingChecks.toolReferencesById, toolId, { path: path18, step: stepRef });
19877
+ }
19878
+ }
19879
+ }
19880
+ if (step.type === "transform-data") {
19881
+ collectTransformDataCodeToolNameCheck(toolsConfig, stepIndex, stepRef, pendingChecks);
19882
+ } else {
19883
+ collectCodeModeToolNameCheck(toolsConfig, stepIndex, stepRef, pendingChecks);
19884
+ }
19885
+ const runtimeTools = toolsConfig.runtimeTools;
19886
+ if (!Array.isArray(runtimeTools)) {
19887
+ return;
19888
+ }
19889
+ for (const [runtimeToolIndex, runtimeTool] of runtimeTools.entries()) {
19890
+ if (!isObjectRecord(runtimeTool)) {
19891
+ continue;
19892
+ }
19893
+ const runtimeConfig = runtimeTool.config;
19894
+ if (!isObjectRecord(runtimeConfig)) {
19895
+ continue;
19896
+ }
19897
+ const basePath = `flowSteps[${stepIndex}].config.tools.runtimeTools[${runtimeToolIndex}].config`;
19898
+ if (runtimeTool.toolType === "flow") {
19899
+ const flowId = runtimeConfig.flowId;
19900
+ if (typeof flowId === "string") {
19901
+ registerFlowReference(flowId, `${basePath}.flowId`, stepRef, pendingChecks);
19902
+ }
19903
+ continue;
19904
+ }
19905
+ if (runtimeTool.toolType === "subagent") {
19906
+ const agentId = runtimeConfig.agentId;
19907
+ if (typeof agentId === "string" && !agentId.includes("{{")) {
19908
+ registerAgentReference(agentId, `${basePath}.agentId`, stepRef, pendingChecks);
19909
+ }
19910
+ continue;
19911
+ }
19912
+ }
19913
+ }
19914
+ function registerAgentReference(agentId, path18, stepRef, pendingChecks) {
19915
+ const named = parseNamedAgentRef(agentId);
19916
+ pendingChecks.hasAccountScopedReferences = true;
19917
+ if (named) {
19918
+ registerReference(pendingChecks.agentReferencesByName, named.name, { path: path18, step: stepRef });
19919
+ } else {
19920
+ registerReference(pendingChecks.agentReferencesById, agentId, { path: path18, step: stepRef });
19921
+ }
19922
+ }
19923
+ function registerFlowReference(flowId, path18, stepRef, pendingChecks) {
19924
+ const named = parseNamedFlowRef(flowId);
19925
+ pendingChecks.hasAccountScopedReferences = true;
19926
+ if (named) {
19927
+ registerReference(pendingChecks.flowReferencesByName, named.name, { path: path18, step: stepRef });
19928
+ } else {
19929
+ registerReference(pendingChecks.flowReferencesById, flowId, { path: path18, step: stepRef });
19930
+ }
19931
+ }
19932
+ function validateSubagentConfig(value, stepTools, stepIndex, stepRef) {
19933
+ const basePath = `flowSteps[${stepIndex}].config.tools.subagentConfig`;
19934
+ if (!isObjectRecord(value)) {
19935
+ return {
19936
+ code: "SUBAGENT_CONFIG_INVALID",
19937
+ message: "subagentConfig must be an object.",
19938
+ path: basePath,
19939
+ step: stepRef
19940
+ };
19941
+ }
19942
+ const cfg = value;
19943
+ if (!Array.isArray(cfg.toolPool)) {
19944
+ return {
19945
+ code: "SUBAGENT_CONFIG_INVALID",
19946
+ message: "subagentConfig.toolPool must be an array of tool IDs (wildcards allowed).",
19947
+ path: `${basePath}.toolPool`,
19948
+ step: stepRef
19949
+ };
19950
+ }
19951
+ const parentToolIds = new Set(
19952
+ Array.isArray(stepTools.toolIds) ? stepTools.toolIds.filter((x2) => typeof x2 === "string") : []
19953
+ );
19954
+ const parentRuntimeToolNames = new Set(
19955
+ Array.isArray(stepTools.runtimeTools) ? stepTools.runtimeTools.map((t) => t.name).filter((n) => typeof n === "string") : []
19956
+ );
19957
+ for (const entry of cfg.toolPool) {
19958
+ if (typeof entry !== "string" || entry.length === 0) {
19959
+ return {
19960
+ code: "SUBAGENT_CONFIG_INVALID",
19961
+ message: "subagentConfig.toolPool entries must be non-empty strings.",
19962
+ path: `${basePath}.toolPool`,
19963
+ step: stepRef
19964
+ };
19965
+ }
19966
+ const isWildcard2 = entry.endsWith(":*");
19967
+ if (isWildcard2) continue;
19968
+ if (!parentToolIds.has(entry) && !parentRuntimeToolNames.has(entry)) {
19969
+ return {
19970
+ code: "SUBAGENT_CONFIG_ESCALATION",
19971
+ message: `subagentConfig.toolPool entry "${entry}" is not granted to the parent step. Every pool entry must be a wildcard (\`foo:*\`) or appear in the parent step's toolIds or runtimeTools \u2014 otherwise the spawned subagent cannot actually call it.`,
19972
+ path: `${basePath}.toolPool`,
19973
+ step: stepRef
19974
+ };
19975
+ }
19976
+ }
19977
+ if (cfg.defaultMaxTurns !== void 0) {
19978
+ const n = cfg.defaultMaxTurns;
19979
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
19980
+ return {
19981
+ code: "SUBAGENT_CONFIG_INVALID",
19982
+ message: "subagentConfig.defaultMaxTurns must be a positive integer.",
19983
+ path: `${basePath}.defaultMaxTurns`,
19984
+ step: stepRef
19985
+ };
19986
+ }
19987
+ }
19988
+ if (cfg.maxTurnsLimit !== void 0) {
19989
+ const n = cfg.maxTurnsLimit;
19990
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
19991
+ return {
19992
+ code: "SUBAGENT_CONFIG_INVALID",
19993
+ message: "subagentConfig.maxTurnsLimit must be a positive integer.",
19994
+ path: `${basePath}.maxTurnsLimit`,
19995
+ step: stepRef
19996
+ };
19997
+ }
19998
+ }
19999
+ if (cfg.maxSpawnsPerRun !== void 0) {
20000
+ const n = cfg.maxSpawnsPerRun;
20001
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
20002
+ return {
20003
+ code: "SUBAGENT_CONFIG_INVALID",
20004
+ message: "subagentConfig.maxSpawnsPerRun must be a positive integer.",
20005
+ path: `${basePath}.maxSpawnsPerRun`,
20006
+ step: stepRef
20007
+ };
20008
+ }
20009
+ }
20010
+ return null;
20011
+ }
20012
+ function validateCodeModeConfig(value, stepTools, stepIndex, stepRef) {
20013
+ const basePath = `flowSteps[${stepIndex}].config.tools.codeModeConfig`;
20014
+ if (!isObjectRecord(value)) {
20015
+ return {
20016
+ code: "CODE_MODE_CONFIG_INVALID",
20017
+ message: "codeModeConfig must be an object.",
20018
+ path: basePath,
20019
+ step: stepRef
20020
+ };
20021
+ }
20022
+ const cfg = value;
20023
+ if (!Array.isArray(cfg.toolPool)) {
20024
+ return {
20025
+ code: "CODE_MODE_CONFIG_INVALID",
20026
+ message: "codeModeConfig.toolPool must be an array of tool IDs (wildcards allowed).",
20027
+ path: `${basePath}.toolPool`,
20028
+ step: stepRef
20029
+ };
20030
+ }
20031
+ const parentToolIds = new Set(
20032
+ Array.isArray(stepTools.toolIds) ? stepTools.toolIds.filter((x2) => typeof x2 === "string") : []
20033
+ );
20034
+ const parentRuntimeTools = Array.isArray(stepTools.runtimeTools) ? stepTools.runtimeTools : [];
20035
+ const parentRuntimeToolNames = new Set(
20036
+ parentRuntimeTools.map((t) => t.name).filter((n) => typeof n === "string")
20037
+ );
20038
+ const runtimeToolByName = new Map(
20039
+ parentRuntimeTools.filter((t) => typeof t.name === "string").map((t) => [t.name, t])
20040
+ );
20041
+ const selectedRuntimeToolNames = [];
20042
+ for (const entry of cfg.toolPool) {
20043
+ if (typeof entry !== "string" || entry.length === 0) {
20044
+ return {
20045
+ code: "CODE_MODE_CONFIG_INVALID",
20046
+ message: "codeModeConfig.toolPool entries must be non-empty strings.",
20047
+ path: `${basePath}.toolPool`,
20048
+ step: stepRef
20049
+ };
20050
+ }
20051
+ const isWildcard2 = entry.endsWith(":*");
20052
+ if (isWildcard2) continue;
20053
+ const runtimeTool = runtimeToolByName.get(entry);
20054
+ if (runtimeTool) {
20055
+ if (runtimeTool.toolType === "local") {
20056
+ return {
20057
+ code: "CODE_MODE_CONFIG_INVALID",
20058
+ message: `codeModeConfig.toolPool entry "${entry}" is a local tool. Code mode cannot pause for client-side local tool callbacks.`,
20059
+ path: `${basePath}.toolPool`,
20060
+ step: stepRef
20061
+ };
20062
+ }
20063
+ selectedRuntimeToolNames.push({
20064
+ name: entry,
20065
+ path: `${basePath}.toolPool`
20066
+ });
20067
+ }
20068
+ if (!parentToolIds.has(entry) && !parentRuntimeToolNames.has(entry)) {
20069
+ return {
20070
+ code: "CODE_MODE_CONFIG_ESCALATION",
20071
+ message: `codeModeConfig.toolPool entry "${entry}" is not granted to the parent step. Every pool entry must be a wildcard (\`foo:*\`) or appear in the parent step's toolIds or runtimeTools \u2014 otherwise the sandbox code cannot actually call it.`,
20072
+ path: `${basePath}.toolPool`,
20073
+ step: stepRef
20074
+ };
20075
+ }
20076
+ }
20077
+ const collision = validateCodeToolNameCollisions(
20078
+ selectedRuntimeToolNames,
20079
+ stepRef,
20080
+ "CODE_MODE_TOOL_NAME_COLLISION"
20081
+ );
20082
+ if (collision) {
20083
+ return collision;
20084
+ }
20085
+ if (cfg.timeoutMs !== void 0) {
20086
+ const n = cfg.timeoutMs;
20087
+ if (typeof n !== "number" || !Number.isFinite(n) || n < 1e3 || n > 6e5) {
20088
+ return {
20089
+ code: "CODE_MODE_CONFIG_INVALID",
20090
+ message: "codeModeConfig.timeoutMs must be a number between 1000 and 600000.",
20091
+ path: `${basePath}.timeoutMs`,
20092
+ step: stepRef
20093
+ };
20094
+ }
20095
+ }
20096
+ return null;
20097
+ }
20098
+ function validateTransformDataCodeTools(toolsConfig, stepIndex, stepRef, buckets) {
20099
+ const runtimeTools = Array.isArray(toolsConfig.runtimeTools) ? toolsConfig.runtimeTools : [];
20100
+ const runtimeToolNames = [];
20101
+ for (const [runtimeToolIndex, runtimeTool] of runtimeTools.entries()) {
20102
+ if (!isObjectRecord(runtimeTool)) {
20103
+ continue;
20104
+ }
20105
+ const basePath = `flowSteps[${stepIndex}].config.tools.runtimeTools[${runtimeToolIndex}]`;
20106
+ const name = runtimeTool.name;
20107
+ if (typeof name === "string") {
20108
+ runtimeToolNames.push({ name, path: `${basePath}.name` });
20109
+ }
20110
+ if (runtimeTool.toolType === "local") {
20111
+ addIssue(
20112
+ "error",
20113
+ {
20114
+ code: "CODE_STEP_LOCAL_TOOL_UNSUPPORTED",
20115
+ message: "Transform-data code steps do not support local tools because code execution cannot pause for client-side callbacks.",
20116
+ path: `${basePath}.toolType`,
20117
+ step: stepRef
20118
+ },
20119
+ buckets
20120
+ );
20121
+ }
20122
+ }
20123
+ const collision = validateCodeToolNameCollisions(
20124
+ runtimeToolNames,
20125
+ stepRef,
20126
+ "CODE_STEP_TOOL_NAME_COLLISION"
20127
+ );
20128
+ if (collision) {
20129
+ addIssue("error", collision, buckets);
20130
+ }
20131
+ }
20132
+ function validateErrorHandlingTriggers(errorHandling, stepIndex, stepRef, buckets) {
20133
+ if (!isObjectRecord(errorHandling) || !Array.isArray(errorHandling.triggers)) {
20134
+ return;
20135
+ }
20136
+ for (const [triggerIndex, trigger] of errorHandling.triggers.entries()) {
20137
+ if (!isObjectRecord(trigger) || trigger.type !== "slow") continue;
20138
+ const afterMs = trigger.afterMs;
20139
+ if (typeof afterMs !== "number" || !Number.isFinite(afterMs) || afterMs <= 0) {
20140
+ addIssue(
20141
+ "error",
20142
+ {
20143
+ code: "SLOW_TRIGGER_INVALID_AFTER_MS",
20144
+ message: 'A "slow" fallback trigger requires a positive "afterMs" (the total-duration cap in milliseconds) before it can fire.',
20145
+ path: `flowSteps[${stepIndex}].config.errorHandling.triggers[${triggerIndex}].afterMs`,
20146
+ step: stepRef,
20147
+ details: { afterMs }
20148
+ },
20149
+ buckets
20150
+ );
20151
+ }
20152
+ }
20153
+ }
20154
+ function collectFlowStructureIssues(flowData, deps, buckets) {
20155
+ const pendingChecks = {
20156
+ hasAccountScopedReferences: false,
20157
+ toolReferencesById: /* @__PURE__ */ new Map(),
20158
+ toolReferencesByName: /* @__PURE__ */ new Map(),
20159
+ flowReferencesById: /* @__PURE__ */ new Map(),
20160
+ agentReferencesById: /* @__PURE__ */ new Map(),
20161
+ agentReferencesByName: /* @__PURE__ */ new Map(),
20162
+ flowReferencesByName: /* @__PURE__ */ new Map(),
20163
+ codeToolNameChecks: []
20164
+ };
20165
+ const orderToStepIndexes = /* @__PURE__ */ new Map();
20166
+ const normalizedOrders = flowData.flowSteps.map((step, index) => step.order ?? index);
20167
+ for (const [index, order] of normalizedOrders.entries()) {
20168
+ const existing = orderToStepIndexes.get(order) || [];
20169
+ existing.push(index);
20170
+ orderToStepIndexes.set(order, existing);
20171
+ }
20172
+ for (const [order, indexes] of orderToStepIndexes.entries()) {
20173
+ if (indexes.length <= 1) {
20174
+ continue;
20175
+ }
20176
+ addIssue(
20177
+ "warning",
20178
+ {
20179
+ code: "DUPLICATE_STEP_ORDER",
20180
+ message: `Multiple steps share order "${order}". Execution order may be ambiguous.`,
20181
+ details: { order, stepIndexes: indexes }
20182
+ },
20183
+ buckets
20184
+ );
20185
+ }
20186
+ const idToStepIndexes = /* @__PURE__ */ new Map();
20187
+ for (const [index, step] of flowData.flowSteps.entries()) {
20188
+ if (typeof step.id !== "string" || step.id.length === 0) continue;
20189
+ const existing = idToStepIndexes.get(step.id) || [];
20190
+ existing.push(index);
20191
+ idToStepIndexes.set(step.id, existing);
20192
+ }
20193
+ for (const [id, indexes] of idToStepIndexes.entries()) {
20194
+ if (indexes.length <= 1) continue;
20195
+ addIssue(
20196
+ "error",
20197
+ {
20198
+ code: "DUPLICATE_STEP_ID",
20199
+ message: `Multiple steps share id "${id}". Step ids must be unique within a flow.`,
20200
+ details: { id, stepIndexes: indexes }
20201
+ },
20202
+ buckets
20203
+ );
20204
+ }
20205
+ const enabledSteps = flowData.flowSteps.filter((step) => step.enabled !== false);
20206
+ if (enabledSteps.length === 0) {
20207
+ addIssue(
20208
+ "warning",
20209
+ {
20210
+ code: "NO_ENABLED_STEPS",
20211
+ message: "This flow has no enabled steps."
20212
+ },
20213
+ buckets
20214
+ );
20215
+ }
20216
+ if (!enabledSteps.some((step) => step.type === "prompt")) {
20217
+ addIssue(
20218
+ "recommendation",
20219
+ {
20220
+ code: "NO_PROMPT_STEPS",
20221
+ message: "No enabled prompt steps were found. Most flows require at least one prompt step."
20222
+ },
20223
+ buckets
20224
+ );
20225
+ }
20226
+ const conditionalStepsExceedingDepth = /* @__PURE__ */ new Set();
20227
+ const declaredVariables = /* @__PURE__ */ new Set();
20228
+ for (const [stepIndex, step] of flowData.flowSteps.entries()) {
20229
+ const stepRef = {
20230
+ index: stepIndex,
20231
+ name: step.name,
20232
+ type: step.type
20233
+ };
20234
+ if (step.type === "conditional" && conditionalNestingDepth(step.config) > MAX_CONDITIONAL_NESTING_DEPTH) {
20235
+ conditionalStepsExceedingDepth.add(stepIndex);
20236
+ addIssue(
20237
+ "error",
20238
+ {
20239
+ code: "CONDITIONAL_NESTING_TOO_DEEP",
20240
+ message: `Conditional steps may nest at most ${MAX_CONDITIONAL_NESTING_DEPTH} levels deep.`,
20241
+ path: `flowSteps[${stepIndex}].config`,
20242
+ step: stepRef
20243
+ },
20244
+ buckets
20245
+ );
20246
+ continue;
20247
+ }
20248
+ const configSchema = deps.configSchemas?.[step.type];
20249
+ if (configSchema) {
20250
+ const schemaResult = configSchema.safeParse(step.config);
20251
+ if (!schemaResult.success) {
20252
+ for (const issue2 of schemaResult.error.issues) {
20253
+ const issuePath = issue2.path.length > 0 ? `flowSteps[${stepIndex}].config.${formatPath(issue2.path)}` : `flowSteps[${stepIndex}].config`;
20254
+ addIssue("error", buildIssueFromZod(issue2, issuePath, stepRef), buckets);
20255
+ }
20256
+ }
20257
+ }
20258
+ if (isObjectRecord(step.config)) {
20259
+ validateErrorHandlingTriggers(step.config.errorHandling, stepIndex, stepRef, buckets);
20260
+ }
20261
+ if (isObjectRecord(step.config) && isObjectRecord(step.config.tools)) {
20262
+ for (const key of Object.keys(step.config.tools)) {
20263
+ if (KNOWN_TOOL_KEYS.has(key)) continue;
20264
+ const suggestion = LEGACY_TOOL_KEY_SUGGESTIONS[key];
20265
+ addIssue(
20266
+ "warning",
20267
+ {
20268
+ code: "UNKNOWN_PROMPT_TOOLS_FIELD",
20269
+ message: suggestion ? `Unknown field "${key}" under config.tools \u2014 did you mean "${suggestion}"? The runtime will ignore this value.` : `Unknown field "${key}" under config.tools \u2014 the runtime will ignore it. Expected keys: ${[...KNOWN_TOOL_KEYS].join(", ")}.`,
20270
+ path: `flowSteps[${stepIndex}].config.tools.${key}`,
20271
+ step: stepRef,
20272
+ details: suggestion ? { field: key, suggestion } : { field: key }
20273
+ },
20274
+ buckets
20275
+ );
20276
+ }
20277
+ if (deps.validateRuntimeTools) {
20278
+ const runtimeToolsValidation = deps.validateRuntimeTools(step.config.tools);
20279
+ if (!runtimeToolsValidation.valid) {
20280
+ addIssue(
20281
+ "error",
20282
+ {
20283
+ code: "RUNTIME_TOOLS_INVALID",
20284
+ message: runtimeToolsValidation.error || "Invalid runtime tools configuration",
20285
+ path: `flowSteps[${stepIndex}].config.tools`,
20286
+ step: stepRef
20287
+ },
20288
+ buckets
20289
+ );
20290
+ }
20291
+ }
20292
+ if (step.type === "transform-data") {
20293
+ validateTransformDataCodeTools(step.config.tools, stepIndex, stepRef, buckets);
20294
+ }
20295
+ const subagentCfg = step.config.tools.subagentConfig;
20296
+ if (subagentCfg !== void 0) {
20297
+ const issue2 = validateSubagentConfig(subagentCfg, step.config.tools, stepIndex, stepRef);
20298
+ if (issue2) addIssue("error", issue2, buckets);
20299
+ }
20300
+ const codeModeCfg = step.config.tools.codeModeConfig;
20301
+ if (codeModeCfg !== void 0) {
20302
+ const issue2 = validateCodeModeConfig(codeModeCfg, step.config.tools, stepIndex, stepRef);
20303
+ if (issue2) addIssue("error", issue2, buckets);
20304
+ }
20305
+ }
20306
+ if (step.type !== "prompt") {
20307
+ try {
20308
+ normalizeContextStep(
20309
+ {
20310
+ id: `step_validation_${stepIndex}`,
20311
+ type: step.type,
20312
+ name: step.name,
20313
+ order: step.order ?? stepIndex,
20314
+ enabled: step.enabled ?? true,
20315
+ config: step.config
20316
+ },
20317
+ {
20318
+ managedSendFromDomain: deps.managedSendFromDomain
20319
+ }
20320
+ );
20321
+ } catch (error51) {
20322
+ const normalizationError = error51 instanceof NormalizationError ? error51 : null;
20323
+ const fallbackMessage = error51 instanceof Error ? error51.message : String(error51);
20324
+ const fieldName = normalizationError?.fieldName;
20325
+ addIssue(
20326
+ "error",
20327
+ {
20328
+ code: "CONTEXT_STEP_INVALID",
20329
+ message: normalizationError?.message || fallbackMessage,
20330
+ path: fieldName ? `flowSteps[${stepIndex}].config.${fieldName}` : `flowSteps[${stepIndex}].config`,
20331
+ step: stepRef
20332
+ },
20333
+ buckets
20334
+ );
20335
+ }
20336
+ }
20337
+ if (step.type === "transform-data" && step.enabled !== false && isObjectRecord(step.config)) {
20338
+ const config3 = step.config;
20339
+ const sandboxProvider = config3.sandboxProvider || "cloudflare-worker";
20340
+ const resolvedProvider = sandboxProvider === "cloudflare-sandbox" ? "runtype-sandbox" : sandboxProvider;
20341
+ validateSandboxNetworkAccess(config3, stepIndex, stepRef, buckets);
20342
+ if (resolvedProvider === "runtype-sandbox" && !config3.language) {
20343
+ addIssue(
20344
+ "warning",
20345
+ {
20346
+ code: "MISSING_LANGUAGE",
20347
+ message: 'language is recommended when sandboxProvider is "runtype-sandbox" \u2014 defaults to "javascript" but you should specify "javascript", "typescript", or "python" explicitly',
20348
+ path: `flowSteps[${stepIndex}].config.language`,
20349
+ step: stepRef
20350
+ },
20351
+ buckets
20352
+ );
20353
+ }
20354
+ if (deps.validateScript && config3.inputMode !== "variable" && typeof config3.script === "string" && config3.script.trim()) {
20355
+ const codeResult = deps.validateScript(
20356
+ config3.script,
20357
+ {
20358
+ sandboxProvider,
20359
+ language: config3.language,
20360
+ availableVariables: [...declaredVariables]
20361
+ },
20362
+ { stepIndex }
20363
+ );
20364
+ for (const issue2 of codeResult.issues) {
20365
+ const location = issue2.line ? ` (line ${issue2.line}, column ${issue2.column})` : "";
20366
+ const issueCode = issue2.code === "SYNTAX_ERROR" ? "CODE_SYNTAX_ERROR" : `CODE_${issue2.code}`;
20367
+ addIssue(
20368
+ issue2.severity,
20369
+ {
20370
+ code: issueCode,
20371
+ message: `${issue2.message}${location}`,
20372
+ path: `flowSteps[${stepIndex}].config.script`,
20373
+ step: stepRef,
20374
+ details: {
20375
+ language: config3.language || "javascript",
20376
+ sandboxProvider,
20377
+ ...issue2.line !== void 0 ? { line: issue2.line } : {},
20378
+ ...issue2.column !== void 0 ? { column: issue2.column } : {}
20379
+ }
20380
+ },
20381
+ buckets
20382
+ );
20383
+ }
20384
+ }
20385
+ }
20386
+ collectAccountScopedReferences(step, stepIndex, pendingChecks);
20387
+ if (step.enabled !== false) {
20388
+ const outputVar = getStepOutputVariable(step);
20389
+ if (outputVar) declaredVariables.add(outputVar);
20390
+ }
20391
+ }
20392
+ validateVariableReferences(
20393
+ flowData.flowSteps,
20394
+ buckets,
20395
+ conditionalStepsExceedingDepth,
20396
+ deps.declaredFlowInputs
20397
+ );
20398
+ validateUpsertRecordSourceShape(flowData.flowSteps, buckets);
20399
+ return { pendingChecks };
20400
+ }
20401
+ function validateFlowStructure(flowData, deps = {}) {
20402
+ const buckets = { errors: [], warnings: [], recommendations: [] };
20403
+ collectFlowStructureIssues(flowData, deps, buckets);
20404
+ const errors = sortIssues(buckets.errors);
20405
+ return {
20406
+ valid: errors.length === 0,
20407
+ errors,
20408
+ warnings: sortIssues(buckets.warnings),
20409
+ recommendations: sortIssues(buckets.recommendations),
20410
+ context: {
20411
+ authenticated: false,
20412
+ accountChecksPerformed: false,
20413
+ accountChecksSkipped: false
20414
+ }
20415
+ };
20416
+ }
20417
+ function parseCreateFlowValidationInput(payload) {
20418
+ const parsed = createFlowValidationSchema.safeParse(payload);
20419
+ if (parsed.success) {
20420
+ return {
20421
+ success: true,
20422
+ data: parsed.data
20423
+ };
20424
+ }
20425
+ return {
20426
+ success: false,
20427
+ errors: sortIssues(
20428
+ parsed.error.issues.map(
20429
+ (issue2) => buildIssueFromZod(issue2, formatPath(issue2.path) || "root", void 0)
20430
+ )
20431
+ )
20432
+ };
20433
+ }
17309
20434
  var SERIALIZED_HELPERS_SOURCE = `
17310
20435
  // Transform helper functions (from packages/shared/src/transform-helpers.ts)
17311
20436
  const helpers = (function createHelpers() {
@@ -36737,6 +39862,7 @@ function mergeResults(...results) {
36737
39862
  merged.valid = merged.errors.length === 0;
36738
39863
  return merged;
36739
39864
  }
39865
+ var NAMESPACE_VARIABLE_CODES = new Set(NAMESPACE_VARIABLE_REFERENCE_CODES);
36740
39866
  function validateFlowDefinition(flow, capIndex, context) {
36741
39867
  const result = emptyResult();
36742
39868
  const base = `capabilities[${capIndex}].flow`;
@@ -36797,8 +39923,25 @@ function validateFlowDefinition(flow, capIndex, context) {
36797
39923
  }
36798
39924
  }
36799
39925
  }
39926
+ appendNamespaceVariableIssues(flow, base, result);
36800
39927
  return finalize2(result);
36801
39928
  }
39929
+ function reprefixCorePath(corePath, base) {
39930
+ if (!corePath) return `${base}.steps`;
39931
+ return corePath.replace(/^flowSteps\[/, `${base}.steps[`);
39932
+ }
39933
+ function appendNamespaceVariableIssues(flow, base, result) {
39934
+ const parsed = parseCreateFlowValidationInput({ name: flow.name, flowSteps: flow.steps });
39935
+ if (!parsed.success) return;
39936
+ const coreResult = validateFlowStructure(parsed.data);
39937
+ const push = (issue2, severity) => {
39938
+ if (!NAMESPACE_VARIABLE_CODES.has(issue2.code)) return;
39939
+ const bucket = severity === "error" ? result.errors : result.warnings;
39940
+ bucket.push(createIssue(severity, issue2.code, issue2.message, reprefixCorePath(issue2.path, base)));
39941
+ };
39942
+ for (const issue2 of coreResult.errors) push(issue2, "error");
39943
+ for (const issue2 of coreResult.warnings) push(issue2, "warning");
39944
+ }
36802
39945
  function finalize2(r) {
36803
39946
  r.valid = r.errors.length === 0;
36804
39947
  return r;
@@ -37426,8 +40569,10 @@ var fullProductObjectTemplateSchema = external_exports.object({
37426
40569
  });
37427
40570
  }
37428
40571
  });
37429
- var FLOW_PREFIX = "flow:";
37430
- var SECRET_PREFIX = "secret:";
40572
+ var FLOW_PREFIX = Object.values(RUNTIME_PREFIXES).find((spec) => spec.namespace === "flow").prefix;
40573
+ var SECRET_PREFIX = Object.values(RUNTIME_PREFIXES).find(
40574
+ (spec) => spec.namespace === "secret"
40575
+ ).prefix;
37431
40576
  function collectStringLeafPaths(value, path18 = []) {
37432
40577
  if (typeof value === "string") {
37433
40578
  return [{ path: path18, value }];
@@ -37458,12 +40603,16 @@ function extractTemplateReferences(value) {
37458
40603
  const inner = value.slice(start + 2, end);
37459
40604
  const separatorIndex = inner.indexOf("|");
37460
40605
  const key = (separatorIndex === -1 ? inner : inner.slice(0, separatorIndex)).trim();
37461
- if (key.length > 0 && !key.startsWith(SECRET_PREFIX) && !key.startsWith(FLOW_PREFIX)) {
37462
- references.push({
37463
- key,
37464
- defaultValue: separatorIndex === -1 ? void 0 : inner.slice(separatorIndex + 1).trim(),
37465
- raw
37466
- });
40606
+ if (key.length > 0) {
40607
+ const classification = classifyVariableReference(key);
40608
+ const ownedByRuntimeOrEngine = classification.namespace === "secret" || classification.namespace === "flow" || classification.namespace === "system";
40609
+ if (!ownedByRuntimeOrEngine) {
40610
+ references.push({
40611
+ key,
40612
+ defaultValue: separatorIndex === -1 ? void 0 : inner.slice(separatorIndex + 1).trim(),
40613
+ raw
40614
+ });
40615
+ }
37467
40616
  }
37468
40617
  cursor = end + 2;
37469
40618
  }
@@ -44280,26 +47429,26 @@ async function getCurrentAccountId() {
44280
47429
 
44281
47430
  // src/lib/quick-start-api.ts
44282
47431
  import { RuntypeApiError as RuntypeApiError2 } from "@runtypelabs/sdk";
44283
- function isObjectRecord(value) {
47432
+ function isObjectRecord2(value) {
44284
47433
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
44285
47434
  }
44286
47435
  function isQuickStartValidationResponse(value) {
44287
- if (!isObjectRecord(value) || typeof value.valid !== "boolean") {
47436
+ if (!isObjectRecord2(value) || typeof value.valid !== "boolean") {
44288
47437
  return false;
44289
47438
  }
44290
47439
  if (value.valid === false) {
44291
47440
  return typeof value.error === "string" && typeof value.code === "string";
44292
47441
  }
44293
- return typeof value.templateId === "string" && isObjectRecord(value.agentCard);
47442
+ return typeof value.templateId === "string" && isObjectRecord2(value.agentCard);
44294
47443
  }
44295
47444
  function isQuickStartCreateResponse(value) {
44296
- if (!isObjectRecord(value) || typeof value.success !== "boolean") {
47445
+ if (!isObjectRecord2(value) || typeof value.success !== "boolean") {
44297
47446
  return false;
44298
47447
  }
44299
47448
  if (value.success === false) {
44300
47449
  return typeof value.error === "string" && typeof value.code === "string";
44301
47450
  }
44302
- return isObjectRecord(value.product) && Array.isArray(value.capabilities) && typeof value.redirectUrl === "string";
47451
+ return isObjectRecord2(value.product) && Array.isArray(value.capabilities) && typeof value.redirectUrl === "string";
44303
47452
  }
44304
47453
  function getApiErrorData(error51) {
44305
47454
  return error51 instanceof RuntypeApiError2 ? error51.data : void 0;
@@ -56323,6 +59472,11 @@ function buildResumeHistoryWarning(state) {
56323
59472
  function canUseMarathonStartupShell(options) {
56324
59473
  return process.stdin.isTTY === true && process.stdout.isTTY === true && !options.json;
56325
59474
  }
59475
+ function formatBytes(bytes) {
59476
+ if (bytes < 1024) return `${bytes} B`;
59477
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
59478
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
59479
+ }
56326
59480
  function normalizeStartupModelOptionValue(value) {
56327
59481
  const trimmed = value?.trim().toLowerCase().replace(/^model\//, "") ?? "";
56328
59482
  if (!trimmed) return "";
@@ -56903,6 +60057,18 @@ async function taskAction(agent, options) {
56903
60057
  const sandboxWorkflowSelection = playbookWorkflow ? void 0 : resolveSandboxWorkflowSelection(baseMessage, parsedSandbox, resumeState);
56904
60058
  parsedSandbox = sandboxWorkflowSelection?.sandboxProvider ?? parsedSandbox;
56905
60059
  const resolvedWorkflow = playbookWorkflow ?? sandboxWorkflowSelection?.workflow;
60060
+ if (!resolvedWorkflow && !playbookWorkflow && !resumeState && !isDeployCapableSandbox(parsedSandbox) && (isGameIntent(baseMessage) || isDeployIntent(baseMessage))) {
60061
+ console.log(
60062
+ chalk23.yellow(
60063
+ "Hint: this goal looks like a build-and-deploy task, but no deploy-capable sandbox is enabled."
60064
+ )
60065
+ );
60066
+ console.log(
60067
+ chalk23.gray(
60068
+ " Re-run with --sandbox daytona to build and deploy to a live preview URL (enables the deploy_sandbox tool)."
60069
+ )
60070
+ );
60071
+ }
56906
60072
  const DEFAULT_MILESTONE_NAMES = ["research", "planning", "execution"];
56907
60073
  const EXTERNAL_MILESTONE_NAMES = ["research", "report"];
56908
60074
  const detectedVariant = resumeState?.workflowVariant ?? defaultWorkflow.classifyVariant?.(baseMessage);
@@ -57238,6 +60404,11 @@ Saving state... done. Session saved to ${filePath}`);
57238
60404
  let accumulatedCost = 0;
57239
60405
  let accumulatedTokens = { input: 0, output: 0 };
57240
60406
  let accumulatedToolCalls = 0;
60407
+ let indexedChunks = 0;
60408
+ let indexedBytes = 0;
60409
+ let indexingFailures = 0;
60410
+ let indexingFailureNoticed = false;
60411
+ const indexingRequests = [];
57241
60412
  let lastResult = null;
57242
60413
  let lastSessionMessages = [];
57243
60414
  let undeliveredSteering = [];
@@ -57409,12 +60580,35 @@ Saving state... done. Session saved to ${filePath}`);
57409
60580
  });
57410
60581
  if (chunks.length > 0) {
57411
60582
  const sessionIdx = currentSessionOffset + state.sessionCount - 1;
57412
- client.post("/session-context/index", {
60583
+ const payloadBytes = Buffer.byteLength(JSON.stringify(chunks), "utf-8");
60584
+ indexedChunks += chunks.length;
60585
+ indexedBytes += payloadBytes;
60586
+ const NOTICE_BYTES = 512 * 1024;
60587
+ if (payloadBytes >= NOTICE_BYTES) {
60588
+ reportContextNotice({
60589
+ kind: "session_indexed",
60590
+ message: `Session ${sessionIdx} indexed ${chunks.length.toLocaleString()} chunks (${formatBytes(payloadBytes)}) for semantic search.`,
60591
+ sessionIndex: sessionIdx,
60592
+ chunkCount: chunks.length,
60593
+ payloadBytes
60594
+ });
60595
+ }
60596
+ const indexingRequest = client.post("/session-context/index", {
57413
60597
  taskName,
57414
60598
  sessionIndex: sessionIdx,
57415
60599
  chunks
57416
- }).catch(() => {
60600
+ }).catch((error51) => {
60601
+ indexingFailures++;
60602
+ if (!indexingFailureNoticed) {
60603
+ indexingFailureNoticed = true;
60604
+ reportContextNotice({
60605
+ kind: "indexing_failed",
60606
+ message: `Session-search indexing failed; recall may be incomplete (${error51 instanceof Error ? error51.message : String(error51)}). Pass --no-session-search to disable indexing.`,
60607
+ sessionIndex: sessionIdx
60608
+ });
60609
+ }
57417
60610
  });
60611
+ indexingRequests.push(indexingRequest);
57418
60612
  }
57419
60613
  }
57420
60614
  }
@@ -57728,11 +60922,26 @@ Saving state... done. Session saved to ${filePath}`);
57728
60922
  saveState(filePath, finalState, { stripSnapshotEvents: !!eventLogWriter });
57729
60923
  await waitForUiExit?.();
57730
60924
  exitAltScreen();
60925
+ if (indexingRequests.length > 0) {
60926
+ const INDEXING_SETTLE_GRACE_MS = 5e3;
60927
+ await Promise.race([
60928
+ Promise.allSettled(indexingRequests),
60929
+ new Promise((resolve11) => {
60930
+ const timer = setTimeout(resolve11, INDEXING_SETTLE_GRACE_MS);
60931
+ timer.unref?.();
60932
+ })
60933
+ ]);
60934
+ }
57731
60935
  console.log();
57732
60936
  const statusColor = result.status === "complete" ? chalk23.green : result.status === "budget_exceeded" || result.status === "error" ? chalk23.red : chalk23.yellow;
57733
60937
  console.log(`Status: ${statusColor(result.status)}`);
57734
60938
  console.log(`Sessions: ${finalState.sessionCount}`);
57735
60939
  console.log(`Total cost: ${chalk23.yellow(`$${finalState.totalCost.toFixed(4)}`)}`);
60940
+ if (indexedChunks > 0 || indexingFailures > 0) {
60941
+ const indexedLine = `${indexedChunks.toLocaleString()} chunks (${formatBytes(indexedBytes)})`;
60942
+ const failureSuffix = indexingFailures > 0 ? chalk23.red(` \u2014 ${indexingFailures} indexing failure${indexingFailures === 1 ? "" : "s"}`) : "";
60943
+ console.log(`Indexed: ${chalk23.dim(indexedLine)}${failureSuffix}`);
60944
+ }
57736
60945
  console.log(`State: ${chalk23.gray(filePath)}`);
57737
60946
  if (typeof finalState.lastError === "string" && finalState.lastError.trim()) {
57738
60947
  console.log(`Last error: ${chalk23.red(finalState.lastError)}`);
@@ -57888,7 +61097,20 @@ ${details}`);
57888
61097
  }
57889
61098
  return resolved;
57890
61099
  }
57891
- function detectDeployWorkflow(_message, _sandboxProvider, resumeState) {
61100
+ function isDeployCapableSandbox(provider) {
61101
+ return provider === "daytona" || provider === "runtype-sandbox";
61102
+ }
61103
+ function isGameIntent(message) {
61104
+ const lower = message.toLowerCase();
61105
+ return /\b(game|gameplay|playable|racing|platformer|shooter|puzzle|arcade)\b/.test(lower) || /\b(three\.?js|webgl|phaser|babylon\.?js|pixi\.?js)\b/.test(lower);
61106
+ }
61107
+ function isDeployIntent(message) {
61108
+ const lower = message.toLowerCase();
61109
+ return /\b(deploy|deployed|deployment|publish|published|host|hosted|hosting|serve|served)\b/.test(
61110
+ lower
61111
+ ) || /\b(web ?app|web ?site|landing page|preview url|live url|public url)\b/.test(lower) || /\b(publicly|share with friends)\b/.test(lower);
61112
+ }
61113
+ function detectDeployWorkflow(message, sandboxProvider, resumeState) {
57892
61114
  if (resumeState?.workflowVariant === "game") return gameWorkflow;
57893
61115
  if (resumeState?.workflowPhase === "design" || resumeState?.workflowPhase === "build" || resumeState?.workflowPhase === "verify") {
57894
61116
  return gameWorkflow;
@@ -57897,10 +61119,14 @@ function detectDeployWorkflow(_message, _sandboxProvider, resumeState) {
57897
61119
  if (resumeState?.workflowPhase === "scaffold" || resumeState?.workflowPhase === "deploy") {
57898
61120
  return deployWorkflow;
57899
61121
  }
61122
+ if (isDeployCapableSandbox(sandboxProvider)) {
61123
+ if (isGameIntent(message)) return gameWorkflow;
61124
+ if (isDeployIntent(message)) return deployWorkflow;
61125
+ }
57900
61126
  return void 0;
57901
61127
  }
57902
61128
  function resolveSandboxWorkflowSelection(message, sandboxProvider, resumeState) {
57903
- if (sandboxProvider && sandboxProvider !== "daytona") {
61129
+ if (sandboxProvider && !isDeployCapableSandbox(sandboxProvider)) {
57904
61130
  return {
57905
61131
  workflow: void 0,
57906
61132
  sandboxProvider
@@ -60283,8 +63509,8 @@ import { execFileSync } from "child_process";
60283
63509
  // src/lib/persona-init.ts
60284
63510
  init_credential_store();
60285
63511
 
60286
- // ../../node_modules/.pnpm/@runtypelabs+persona@3.34.0/node_modules/@runtypelabs/persona/dist/codegen.js
60287
- var S = "3.34.0";
63512
+ // ../../node_modules/.pnpm/@runtypelabs+persona@3.34.1/node_modules/@runtypelabs/persona/dist/codegen.js
63513
+ var S = "3.34.1";
60288
63514
  var c = S;
60289
63515
  function u(e) {
60290
63516
  if (e !== void 0) return typeof e == "string" ? e : Array.isArray(e) ? `[${e.map((r) => r.toString()).join(", ")}]` : e.toString();