@vaudience/aigentflow-flow-validator 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -451,11 +451,10 @@ function validateBasicStructure(flow, issues) {
451
451
 
452
452
  // src/spec/aigentflow-spec.json
453
453
  var aigentflow_spec_default = {
454
- specVersion: "2.831.0",
454
+ specVersion: "2.833.0",
455
455
  inputSchemaVersion: 1,
456
456
  executorSchemes: [
457
457
  "a2a",
458
- "agent",
459
458
  "ai",
460
459
  "aiv",
461
460
  "async",
@@ -469,7 +468,6 @@ var aigentflow_spec_default = {
469
468
  "email",
470
469
  "eurostat",
471
470
  "eval",
472
- "exons",
473
471
  "flow",
474
472
  "function",
475
473
  "gdelt",
@@ -768,6 +766,32 @@ var aigentflow_spec_default = {
768
766
  exons: {
769
767
  frontmatterDelimiter: "---"
770
768
  },
769
+ removedAgentSurfaces: {
770
+ removedSchemes: ["exons", "agent"],
771
+ paramScheme: "ai",
772
+ aiParams: [
773
+ "agentic",
774
+ "deny_tools",
775
+ "discoverable_tools",
776
+ "enable_signals",
777
+ "guardrails",
778
+ "max_tool_calls",
779
+ "max_tool_turns",
780
+ "mcp_server_url",
781
+ "parallel_tool_calls",
782
+ "require_confirmation",
783
+ "timeout_seconds",
784
+ "tool_auth_token",
785
+ "tool_discovery"
786
+ ],
787
+ flowKeys: ["exons_uploads"],
788
+ executorRemovedCode: "executor_removed",
789
+ agenticParamRemovedCode: "agentic_param_removed",
790
+ schemeMessageFormat: "step %q uses %s://, which AIgentFlow no longer runs: its own agent chains were removed",
791
+ paramsMessageFormat: "step %q sets %s on ai://: AIgentFlow's own agent loop (agentic mode) was removed, so these parameters no longer exist",
792
+ flowKeyMessageFormat: "the flow-level key %q belonged to a removed agent surface and is no longer read",
793
+ suggestion: 'Rebuild the step: a tool-using agent becomes atlas://agent/run (agent: "@org/name", prompt, capabilities); one tool becomes atlas://capability/<ref>; a plain prompt becomes ai://<provider>/chat or a prompt-only aiv://<org>/<name>. A flow that cannot be converted (started by a webhook, a schedule, a share link, a campaign or a flow:// sub-flow, none of which has a person for atlas to act for; or one that needs an inline .exons spec, an arbitrary MCP server URL or signals) has no replacement here: start it from a person, or use a routine in atlas'
794
+ },
771
795
  executorConfigEnvScopes: {
772
796
  referencePrefix: "${",
773
797
  referenceSuffix: "}",
@@ -994,7 +1018,7 @@ var aigentflow_spec_default = {
994
1018
  providerAgent: "agent",
995
1019
  providerCapability: "capability",
996
1020
  agentResource: "run",
997
- capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$",
1021
+ capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$",
998
1022
  operationUnknown: {
999
1023
  code: "atlas_operation_unknown",
1000
1024
  messageFormat: "step %s uses %s, which is not an Atlas operation. The providers are agent (resource run) and capability (resource: a capability reference).",
@@ -1002,7 +1026,7 @@ var aigentflow_spec_default = {
1002
1026
  },
1003
1027
  agentMissing: {
1004
1028
  code: "atlas_agent_missing",
1005
- messageFormat: "step %s runs an Atlas agent but query.agent is missing or empty.",
1029
+ messageFormat: "step %s runs an Atlas agent but query.agent is missing, empty or not a string.",
1006
1030
  suggestion: "Set query.agent to the agent to run, written out as a literal such as @acme/reporter."
1007
1031
  },
1008
1032
  agentNotLiteral: {
@@ -1028,9 +1052,46 @@ var aigentflow_spec_default = {
1028
1052
  capabilityRefInvalid: {
1029
1053
  code: "atlas_capability_ref_invalid",
1030
1054
  messageFormat: "step %s uses atlas://capability/%s, which is not a valid capability reference.",
1031
- suggestion: "A capability reference starts with a letter or digit and continues with letters, digits and _ . : - up to 128 characters in all."
1055
+ suggestion: "A capability reference starts with a letter or digit and continues with letters, digits, _ and - up to 128 characters in all."
1056
+ },
1057
+ modelNotLiteral: {
1058
+ code: "atlas_model_not_literal",
1059
+ messageFormat: "step %s computes a value of query.model from a template. The provider, model and reasoning_effort must be fixed literals, never derived from input.",
1060
+ suggestion: "Write the model choice out as literals. Data may go into the prompt or the inputs instead."
1061
+ },
1062
+ paramRefused: {
1063
+ code: "atlas_param_refused",
1064
+ messageFormat: "step %s sets %s under query. Atlas decides these itself, so a step may not set them.",
1065
+ suggestion: "Remove these keys from the query.",
1066
+ agentKeys: [
1067
+ "api_key",
1068
+ "attribution",
1069
+ "base_url",
1070
+ "host",
1071
+ "idempotency_key",
1072
+ "org_id",
1073
+ "person",
1074
+ "untrusted_input",
1075
+ "untrusted_input_override",
1076
+ "url",
1077
+ "user_id"
1078
+ ],
1079
+ capabilityKeys: [
1080
+ "attribution",
1081
+ "idempotency_key",
1082
+ "untrusted_input",
1083
+ "untrusted_input_override"
1084
+ ]
1032
1085
  }
1033
1086
  },
1087
+ reservedInputNames: {
1088
+ prefix: "__",
1089
+ code: "reserved_input_name",
1090
+ messageFormat: "the input %s starts with two underscores. That namespace belongs to the platform (the acting person, the credential manifest, the untrusted-input marker): a flow cannot declare an input there, and a value or default written under such a name is never delivered.",
1091
+ suggestion: 'Rename the input so it does not start with "__".',
1092
+ queryFieldFormat: "query.%s",
1093
+ schemaFieldFormat: "input_schema.fields.%s"
1094
+ },
1034
1095
  flowDataReservedKeys: {
1035
1096
  code: "flow_data_key_reserved",
1036
1097
  fieldFormat: "data.%s",
@@ -1983,6 +2044,19 @@ var EXONS = {
1983
2044
  /** The YAML frontmatter delimiter line. */
1984
2045
  frontmatterDelimiter: aigentflow_spec_default.exons.frontmatterDelimiter
1985
2046
  };
2047
+ var removed = aigentflow_spec_default.removedAgentSurfaces;
2048
+ var REMOVED_AGENT_SURFACES = {
2049
+ schemes: new Set(removed.removedSchemes),
2050
+ paramScheme: removed.paramScheme,
2051
+ aiParams: new Set(removed.aiParams),
2052
+ flowKeys: removed.flowKeys,
2053
+ executorRemovedCode: removed.executorRemovedCode,
2054
+ agenticParamRemovedCode: removed.agenticParamRemovedCode,
2055
+ schemeMessageFormat: removed.schemeMessageFormat,
2056
+ paramsMessageFormat: removed.paramsMessageFormat,
2057
+ flowKeyMessageFormat: removed.flowKeyMessageFormat,
2058
+ suggestion: removed.suggestion
2059
+ };
1986
2060
  var EXECUTOR_CONFIG_ENV_SCOPES = {
1987
2061
  referencePrefix: aigentflow_spec_default.executorConfigEnvScopes.referencePrefix,
1988
2062
  referenceSuffix: aigentflow_spec_default.executorConfigEnvScopes.referenceSuffix,
@@ -2086,8 +2160,245 @@ var ATLAS_EXECUTOR = {
2086
2160
  capabilitiesNotLiteral: atlas.capabilitiesNotLiteral,
2087
2161
  promptMissing: atlas.promptMissing,
2088
2162
  promptBoth: atlas.promptBoth,
2089
- capabilityRefInvalid: atlas.capabilityRefInvalid
2163
+ capabilityRefInvalid: atlas.capabilityRefInvalid,
2164
+ modelNotLiteral: atlas.modelNotLiteral,
2165
+ paramRefused: {
2166
+ code: atlas.paramRefused.code,
2167
+ messageFormat: atlas.paramRefused.messageFormat,
2168
+ suggestion: atlas.paramRefused.suggestion,
2169
+ agentKeys: atlas.paramRefused.agentKeys,
2170
+ capabilityKeys: atlas.paramRefused.capabilityKeys
2171
+ }
2172
+ };
2173
+ var RESERVED_INPUT_NAMES = {
2174
+ prefix: aigentflow_spec_default.reservedInputNames.prefix,
2175
+ code: aigentflow_spec_default.reservedInputNames.code,
2176
+ messageFormat: aigentflow_spec_default.reservedInputNames.messageFormat,
2177
+ suggestion: aigentflow_spec_default.reservedInputNames.suggestion,
2178
+ queryFieldFormat: aigentflow_spec_default.reservedInputNames.queryFieldFormat,
2179
+ schemaFieldFormat: aigentflow_spec_default.reservedInputNames.schemaFieldFormat
2180
+ };
2181
+ var CODE_PARSE_FAILED = "orchestrator_exons_parse_failed";
2182
+ var CODE_NO_PROVIDER = "orchestrator_exons_no_provider";
2183
+ var CODE_RESOURCES = "exons_resources_unhonoured";
2184
+ var CODE_TOOL_WITHHELD = "orchestrator_tool_withheld";
2185
+ var EXONS_OPEN_DELIM = "{~";
2186
+ var EXONS_LEGACY_CONFIG_OPEN = "{~exons.config~}";
2187
+ var UTF8_BOM = "\uFEFF";
2188
+ var MAX_ALIAS_COUNT2 = 100;
2189
+ var UNREAD = {
2190
+ parseError: null,
2191
+ specRead: false,
2192
+ hasSpec: false,
2193
+ provider: "",
2194
+ toolsAllowDeclared: false,
2195
+ toolsAllow: [],
2196
+ resources: []
2197
+ };
2198
+ var GO_SPACE = "\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000";
2199
+ var GO_TRIM_SPACE = new RegExp(`^[${GO_SPACE}]+|[${GO_SPACE}]+$`, "g");
2200
+ function goTrimSpace(s) {
2201
+ return s.replace(GO_TRIM_SPACE, "");
2202
+ }
2203
+ function extractExonsFrontmatter(source) {
2204
+ const delim = EXONS.frontmatterDelimiter;
2205
+ let start = source.startsWith(UTF8_BOM) ? source.slice(UTF8_BOM.length) : source;
2206
+ start = start.replace(/^[ \t]+/, "");
2207
+ if (start.startsWith(EXONS_LEGACY_CONFIG_OPEN)) {
2208
+ return {
2209
+ frontmatter: "",
2210
+ hasFrontmatter: false,
2211
+ parseError: "legacy JSON config block detected; use YAML frontmatter"
2212
+ };
2213
+ }
2214
+ if (!start.startsWith(delim)) return { frontmatter: "", hasFrontmatter: false, parseError: null };
2215
+ let rest = start.slice(delim.length);
2216
+ if (rest.startsWith("\n")) rest = rest.slice(1);
2217
+ else if (rest.startsWith("\r\n")) rest = rest.slice(2);
2218
+ else return { frontmatter: "", hasFrontmatter: false, parseError: null };
2219
+ let pos = 0;
2220
+ while (pos <= rest.length) {
2221
+ const line = rest.slice(pos);
2222
+ if (line.startsWith(delim)) {
2223
+ const after = line.slice(delim.length);
2224
+ if (after === "" || after[0] === "\n" || after[0] === "\r") {
2225
+ return {
2226
+ frontmatter: goTrimSpace(rest.slice(0, pos)),
2227
+ hasFrontmatter: true,
2228
+ parseError: null
2229
+ };
2230
+ }
2231
+ }
2232
+ const nl = line.indexOf("\n");
2233
+ if (nl < 0) break;
2234
+ pos += nl + 1;
2235
+ }
2236
+ return {
2237
+ frontmatter: "",
2238
+ hasFrontmatter: true,
2239
+ parseError: "YAML frontmatter not properly closed"
2240
+ };
2241
+ }
2242
+ function retagScalars(node) {
2243
+ if (yaml.isMap(node)) {
2244
+ for (const pair of node.items) {
2245
+ retagScalars(pair.key);
2246
+ retagScalars(pair.value);
2247
+ }
2248
+ } else if (yaml.isSeq(node)) {
2249
+ for (const item of node.items) retagScalars(item);
2250
+ } else if (yaml.isScalar(node) && (typeof node.value === "number" || typeof node.value === "boolean") && typeof node.source === "string") {
2251
+ node.value = node.source;
2252
+ }
2253
+ }
2254
+ var DecodeError = class extends Error {
2090
2255
  };
2256
+ function goString(v) {
2257
+ if (v === null || v === void 0) return "";
2258
+ if (isString(v)) return v;
2259
+ throw new DecodeError("not a string");
2260
+ }
2261
+ function goStringList(v) {
2262
+ if (v === null || v === void 0) return null;
2263
+ if (!isArray(v)) throw new DecodeError("not a list");
2264
+ return v.filter((item) => item !== null).map(goString);
2265
+ }
2266
+ function goStruct(v) {
2267
+ if (v === null || v === void 0) return null;
2268
+ if (!isRecord(v)) throw new DecodeError("not a mapping");
2269
+ return v;
2270
+ }
2271
+ function decodeSpecFields(frontmatter) {
2272
+ let value;
2273
+ try {
2274
+ const docs = yaml.parseAllDocuments(frontmatter, { merge: true });
2275
+ const doc = Array.isArray(docs) ? docs[0] : void 0;
2276
+ if (doc === void 0) {
2277
+ value = null;
2278
+ } else {
2279
+ if (doc.errors.length > 0) return null;
2280
+ retagScalars(doc.contents);
2281
+ value = doc.toJS({ maxAliasCount: MAX_ALIAS_COUNT2 });
2282
+ }
2283
+ } catch {
2284
+ return null;
2285
+ }
2286
+ try {
2287
+ const root = goStruct(value) ?? {};
2288
+ const execution = goStruct(root.execution);
2289
+ const tools = goStruct(root.tools);
2290
+ const requirements = goStruct(root.requirements);
2291
+ const allow = tools === null ? null : goStringList(tools.allow);
2292
+ let resources = [];
2293
+ if (requirements !== null) {
2294
+ const raw = requirements.resources;
2295
+ if (raw !== null && raw !== void 0) {
2296
+ if (!isArray(raw)) throw new DecodeError("not a list");
2297
+ resources = raw.filter((entry) => entry !== null).map((entry) => {
2298
+ const r = goStruct(entry) ?? {};
2299
+ return { ref: goString(r.ref), kind: goString(r.kind), scope: goString(r.scope) };
2300
+ });
2301
+ }
2302
+ }
2303
+ return {
2304
+ provider: execution === null ? "" : goString(execution.provider),
2305
+ toolsAllowDeclared: allow !== null,
2306
+ toolsAllow: allow ?? [],
2307
+ resources
2308
+ };
2309
+ } catch (e) {
2310
+ if (e instanceof DecodeError) return null;
2311
+ throw e;
2312
+ }
2313
+ }
2314
+ function inspectExonsFrontmatter(source) {
2315
+ const fm = extractExonsFrontmatter(source);
2316
+ if (fm.parseError !== null) return { ...UNREAD, parseError: fm.parseError };
2317
+ if (!fm.hasFrontmatter || fm.frontmatter === "") return { ...UNREAD, specRead: true };
2318
+ if (fm.frontmatter.includes(EXONS_OPEN_DELIM)) return { ...UNREAD };
2319
+ const fields = decodeSpecFields(fm.frontmatter);
2320
+ if (fields === null) return { ...UNREAD };
2321
+ return { parseError: null, specRead: true, hasSpec: true, ...fields };
2322
+ }
2323
+ function validateOrchestratorExons(flow, issues) {
2324
+ const orch = flow.orchestrator;
2325
+ if (!isRecord(orch)) return;
2326
+ const source = issues.stringOf(orch, "exons", "orchestrator");
2327
+ if (source === null || source === "") return;
2328
+ const field = "orchestrator.exons";
2329
+ const report = inspectExonsFrontmatter(source);
2330
+ if (report.parseError !== null) {
2331
+ issues.error({
2332
+ field,
2333
+ code: CODE_PARSE_FAILED,
2334
+ message: `orchestrator: failed to parse exons spec: ${report.parseError}`
2335
+ });
2336
+ return;
2337
+ }
2338
+ if (!report.specRead) return;
2339
+ if (!report.hasSpec) {
2340
+ issues.error({
2341
+ field,
2342
+ code: CODE_PARSE_FAILED,
2343
+ message: "orchestrator: failed to parse exons spec: the document has no frontmatter spec",
2344
+ suggestion: "Start the document with a --- frontmatter block that sets execution.provider"
2345
+ });
2346
+ return;
2347
+ }
2348
+ if (report.provider === "") {
2349
+ issues.error({
2350
+ field,
2351
+ code: CODE_NO_PROVIDER,
2352
+ message: "orchestrator: exons spec must have execution.provider set"
2353
+ });
2354
+ }
2355
+ if (report.resources.length > 0) {
2356
+ const refs = report.resources.map((r) => `${JSON.stringify(r.ref)} (kind ${r.kind})`);
2357
+ issues.error({
2358
+ field,
2359
+ code: CODE_RESOURCES,
2360
+ message: "the orchestrator's exons spec declares requirements.resources that AIgentFlow cannot honour, so it is refused rather than run without the narrowing it asks for: " + refs.join("; "),
2361
+ suggestion: "Remove requirements.resources, and narrow the agent with tools.mcp_servers and tools.allow"
2362
+ });
2363
+ }
2364
+ warnOrchestratorToolWithheld(flow, orch, report, issues);
2365
+ }
2366
+ function warnOrchestratorToolWithheld(flow, orch, report, issues) {
2367
+ if (!report.toolsAllowDeclared) return;
2368
+ const cfg = ORCHESTRATOR_TOOL_ALLOW;
2369
+ const exempt = new Set(cfg.lifecycleTools);
2370
+ const signals = typeof orch.enable_signals === "boolean" ? orch.enable_signals : cfg.enableSignalsDefault;
2371
+ if (signals) for (const t of cfg.signalTools) exempt.add(t);
2372
+ const allow = new Set(report.toolsAllow);
2373
+ const withheld = (name) => !allow.has(name) && !exempt.has(name);
2374
+ const warn = (message) => issues.warn({ field: cfg.warningField, code: CODE_TOOL_WITHHELD, message });
2375
+ const named = [];
2376
+ if (isArray(orch.tools)) {
2377
+ orch.tools.forEach((raw, i) => {
2378
+ const name = issues.stringAt(raw, `orchestrator.tools[${i}]`);
2379
+ if (name !== null) named.push(name);
2380
+ });
2381
+ }
2382
+ if (named.length > 0) {
2383
+ for (const name of named) {
2384
+ if (!withheld(name)) continue;
2385
+ warn(
2386
+ `orchestrator tool '${name}' is named in orchestrator.tools but the orchestrator's exons definition's tools.allow does not name it, so it is never offered: a tool must pass both lists. Add '${name}' to tools.allow, or remove it from orchestrator.tools.`
2387
+ );
2388
+ }
2389
+ return;
2390
+ }
2391
+ if (withheld(cfg.askHumanTool)) {
2392
+ warn(
2393
+ `the orchestrator's exons definition has a tools.allow list that does not name ${cfg.askHumanTool}, so this orchestrator can never ask a person a question: human intervention is off. Add ${cfg.askHumanTool} to tools.allow if a human should be reachable, or ignore this if the orchestrator is meant to run unattended.`
2394
+ );
2395
+ }
2396
+ if (isRecord(flow.campaign) && !cfg.campaignTools.some((name) => !withheld(name))) {
2397
+ warn(
2398
+ `this flow declares a campaign, but the orchestrator's exons definition has a tools.allow list that names none of the campaign tools (${cfg.campaignTools.join(", ")}), so no child mission can be spawned or tracked. Add the campaign tools the orchestrator needs to tools.allow.`
2399
+ );
2400
+ }
2401
+ }
2091
2402
 
2092
2403
  // src/validators/executors.ts
2093
2404
  var SCHEME_SEPARATOR = "://";
@@ -2151,12 +2462,64 @@ function checkExecutor(executor, field, stepID, issues) {
2151
2462
  }
2152
2463
  checkFunctionOperation(executor, field, stepID, templated, issues);
2153
2464
  }
2465
+ function removedExecutorScheme(executor) {
2466
+ if (executor.includes(TEMPLATE_ACTION_OPEN)) return "";
2467
+ const trimmed = goTrimSpace(executor);
2468
+ const at = trimmed.indexOf(SCHEME_SEPARATOR);
2469
+ return at < 0 ? "" : trimmed.slice(0, at).toLowerCase();
2470
+ }
2471
+ function checkRemovedSurfaces(executor, query, field, stepID, issues) {
2472
+ const cfg = REMOVED_AGENT_SURFACES;
2473
+ const quoted = JSON.stringify(stepID);
2474
+ const scheme = removedExecutorScheme(executor);
2475
+ if (cfg.schemes.has(scheme)) {
2476
+ issues.error({
2477
+ field,
2478
+ message: fillRemovedMessage(cfg.schemeMessageFormat, quoted, scheme),
2479
+ code: cfg.executorRemovedCode,
2480
+ stepId: stepID,
2481
+ suggestion: cfg.suggestion
2482
+ });
2483
+ return true;
2484
+ }
2485
+ if (scheme !== cfg.paramScheme || !isRecord(query)) return false;
2486
+ const found = Object.keys(query).filter((key) => cfg.aiParams.has(key)).sort();
2487
+ if (found.length > 0) {
2488
+ issues.error({
2489
+ field,
2490
+ message: fillRemovedMessage(cfg.paramsMessageFormat, quoted, found.join(", ")),
2491
+ code: cfg.agenticParamRemovedCode,
2492
+ stepId: stepID,
2493
+ suggestion: cfg.suggestion
2494
+ });
2495
+ }
2496
+ return false;
2497
+ }
2498
+ function fillRemovedMessage(format, ...args) {
2499
+ let i = 0;
2500
+ return format.replace(/%[qs]/g, () => args[i++] ?? "");
2501
+ }
2502
+ function validateRemovedFlowKeys(flow, issues) {
2503
+ const cfg = REMOVED_AGENT_SURFACES;
2504
+ for (const key of cfg.flowKeys) {
2505
+ if (Object.prototype.hasOwnProperty.call(flow, key)) {
2506
+ issues.error({
2507
+ field: key,
2508
+ message: fillRemovedMessage(cfg.flowKeyMessageFormat, JSON.stringify(key)),
2509
+ code: cfg.executorRemovedCode,
2510
+ suggestion: cfg.suggestion
2511
+ });
2512
+ }
2513
+ }
2514
+ }
2154
2515
  function checkAtlasStep(executor, query, stepField, stepID, issues) {
2155
2516
  if (executor.includes(TEMPLATE_ACTION_OPEN)) return;
2156
- const m = EXECUTOR_URL_PATTERN.exec(executor);
2157
- if (m === null || m[1] !== ATLAS_EXECUTOR.scheme) return;
2158
- const provider = m[2];
2159
- const resource = m[3];
2517
+ const prefix = `${ATLAS_EXECUTOR.scheme}://`;
2518
+ if (!executor.startsWith(prefix)) return;
2519
+ const rest = executor.slice(prefix.length);
2520
+ const slash = rest.indexOf("/");
2521
+ const provider = slash < 0 ? rest : rest.slice(0, slash);
2522
+ const resource = slash < 0 ? "" : rest.slice(slash + 1);
2160
2523
  const quoted = JSON.stringify(stepID);
2161
2524
  const report = (rule, ...args) => {
2162
2525
  let message = rule.messageFormat.replace("%s", () => quoted);
@@ -2170,31 +2533,41 @@ function checkAtlasStep(executor, query, stepField, stepID, issues) {
2170
2533
  });
2171
2534
  };
2172
2535
  const q2 = isRecord(query) ? query : {};
2536
+ let refusedKeys = ATLAS_EXECUTOR.paramRefused.capabilityKeys;
2173
2537
  if (provider === ATLAS_EXECUTOR.providerCapability) {
2174
2538
  if (!ATLAS_EXECUTOR.capabilityRefPattern.test(resource)) {
2175
2539
  report(ATLAS_EXECUTOR.capabilityRefInvalid, resource);
2176
2540
  }
2177
2541
  } else if (provider === ATLAS_EXECUTOR.providerAgent && resource === ATLAS_EXECUTOR.agentResource) {
2542
+ refusedKeys = ATLAS_EXECUTOR.paramRefused.agentKeys;
2178
2543
  const agent = q2.agent;
2179
- if (typeof agent !== "string" || agent === "") {
2544
+ if (typeof agent !== "string" || agent.trim() === "") {
2180
2545
  report(ATLAS_EXECUTOR.agentMissing);
2181
2546
  } else if (agent.includes(TEMPLATE_ACTION_OPEN)) {
2182
2547
  report(ATLAS_EXECUTOR.agentNotLiteral);
2183
2548
  }
2184
- const prompt = q2.prompt;
2185
- const promptTemplate = q2.prompt_template;
2186
- const hasPrompt = prompt !== void 0 && prompt !== null && prompt !== "";
2187
- const hasTemplate = promptTemplate !== void 0 && promptTemplate !== null && promptTemplate !== "";
2549
+ const hasPrompt = atlasTextPresent(q2.prompt);
2550
+ const hasTemplate = atlasTextPresent(q2.prompt_template);
2188
2551
  if (!hasPrompt && !hasTemplate) report(ATLAS_EXECUTOR.promptMissing);
2189
2552
  else if (hasPrompt && hasTemplate) report(ATLAS_EXECUTOR.promptBoth);
2553
+ if (anyTemplate(q2.model)) report(ATLAS_EXECUTOR.modelNotLiteral);
2190
2554
  } else {
2191
2555
  report(ATLAS_EXECUTOR.operationUnknown, executor);
2192
2556
  return;
2193
2557
  }
2194
- const caps = q2.capabilities;
2195
- if (Array.isArray(caps) && caps.some((c) => typeof c === "string" && c.includes(TEMPLATE_ACTION_OPEN))) {
2196
- report(ATLAS_EXECUTOR.capabilitiesNotLiteral);
2197
- }
2558
+ if (anyTemplate(q2.capabilities)) report(ATLAS_EXECUTOR.capabilitiesNotLiteral);
2559
+ const refused = refusedKeys.filter((key) => Object.prototype.hasOwnProperty.call(q2, key)).sort();
2560
+ if (refused.length > 0) report(ATLAS_EXECUTOR.paramRefused, refused.join(", "));
2561
+ }
2562
+ function anyTemplate(v) {
2563
+ if (typeof v === "string") return v.includes(TEMPLATE_ACTION_OPEN);
2564
+ if (Array.isArray(v)) return v.some(anyTemplate);
2565
+ if (isRecord(v)) return Object.values(v).some(anyTemplate);
2566
+ return false;
2567
+ }
2568
+ function atlasTextPresent(v) {
2569
+ if (v === void 0 || v === null) return false;
2570
+ return typeof v !== "string" || v.trim() !== "";
2198
2571
  }
2199
2572
  function checkFunctionOperation(executor, field, stepID, templated, issues) {
2200
2573
  if (templated) return;
@@ -2219,7 +2592,9 @@ function validateExecutors(flow, issues) {
2219
2592
  const step = rawStep;
2220
2593
  const executor = issues.stringOf(step, "executor", `steps.${stepID}`);
2221
2594
  if (executor !== null && executor !== "") {
2222
- checkExecutor(executor, `steps.${stepID}.executor`, stepID, issues);
2595
+ if (!checkRemovedSurfaces(executor, step.query, `steps.${stepID}`, stepID, issues)) {
2596
+ checkExecutor(executor, `steps.${stepID}.executor`, stepID, issues);
2597
+ }
2223
2598
  checkAtlasStep(executor, step.query, `steps.${stepID}`, stepID, issues);
2224
2599
  }
2225
2600
  const loop = step.loop;
@@ -2231,12 +2606,14 @@ function validateExecutors(flow, issues) {
2231
2606
  const subID = issues.stringOf(subStep, "id", subPath) ?? String(i);
2232
2607
  const subExecutor = issues.stringOf(subStep, "executor", subPath);
2233
2608
  if (subExecutor !== null && subExecutor !== "") {
2234
- checkExecutor(
2235
- subExecutor,
2236
- `steps.${stepID}.loop.steps[${i}].executor`,
2237
- `${stepID}.${subID}`,
2238
- issues
2239
- );
2609
+ if (!checkRemovedSurfaces(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues)) {
2610
+ checkExecutor(
2611
+ subExecutor,
2612
+ `steps.${stepID}.loop.steps[${i}].executor`,
2613
+ `${stepID}.${subID}`,
2614
+ issues
2615
+ );
2616
+ }
2240
2617
  checkAtlasStep(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues);
2241
2618
  }
2242
2619
  });
@@ -3880,6 +4257,37 @@ function validateInputSchema(flow, issues) {
3880
4257
  validateSchemaDefinition(flow.input_schema, "input_schema", issues);
3881
4258
  }
3882
4259
 
4260
+ // src/validators/reservedInputs.ts
4261
+ function formatField(format, name) {
4262
+ return format.replace("%s", () => name);
4263
+ }
4264
+ function validateReservedInputNames(flow, issues) {
4265
+ const rule = RESERVED_INPUT_NAMES;
4266
+ const report = (name, fieldFormat) => {
4267
+ issues.error({
4268
+ field: formatField(fieldFormat, name),
4269
+ message: rule.messageFormat.replace("%s", () => JSON.stringify(name)),
4270
+ code: rule.code,
4271
+ suggestion: rule.suggestion
4272
+ });
4273
+ };
4274
+ const query = flow.query;
4275
+ if (isRecord(query)) {
4276
+ for (const name of Object.keys(query).sort()) {
4277
+ if (name.startsWith(rule.prefix)) report(name, rule.queryFieldFormat);
4278
+ }
4279
+ }
4280
+ const schema = flow.input_schema;
4281
+ const fields = isRecord(schema) ? schema.fields : void 0;
4282
+ if (!Array.isArray(fields)) return;
4283
+ for (const f of fields) {
4284
+ if (!isRecord(f)) continue;
4285
+ if (typeof f.name === "string" && f.name.startsWith(rule.prefix)) {
4286
+ report(f.name, rule.schemaFieldFormat);
4287
+ }
4288
+ }
4289
+ }
4290
+
3883
4291
  // src/validators/outputSchema.ts
3884
4292
  function validateOutputSchemas(flow, issues) {
3885
4293
  const steps = flow.steps;
@@ -4994,7 +5402,7 @@ var CODE2 = "server_owned_query_key";
4994
5402
  var KEY_QUERY = "query";
4995
5403
  var KEY_ID = "id";
4996
5404
  var SERVER_OWNED = new Set(SERVER_OWNED_QUERY_KEYS.keys);
4997
- function formatField(format, ...args) {
5405
+ function formatField2(format, ...args) {
4998
5406
  let i = 0;
4999
5407
  return format.replace(/%s/g, () => args[i++] ?? "");
5000
5408
  }
@@ -5012,7 +5420,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
5012
5420
  issues,
5013
5421
  stepID,
5014
5422
  key,
5015
- formatField(SERVER_OWNED_QUERY_KEYS.stepFieldFormat, stepID, key)
5423
+ formatField2(SERVER_OWNED_QUERY_KEYS.stepFieldFormat, stepID, key)
5016
5424
  );
5017
5425
  }
5018
5426
  }
@@ -5026,7 +5434,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
5026
5434
  issues,
5027
5435
  stepID,
5028
5436
  key,
5029
- formatField(SERVER_OWNED_QUERY_KEYS.loopStepFieldFormat, stepID, subID, key)
5437
+ formatField2(SERVER_OWNED_QUERY_KEYS.loopStepFieldFormat, stepID, subID, key)
5030
5438
  );
5031
5439
  }
5032
5440
  }
@@ -5043,9 +5451,9 @@ function refuse(issues, stepId, key, field) {
5043
5451
  }
5044
5452
 
5045
5453
  // src/validators/goUrl.ts
5046
- var GO_SPACE = "\\t\\n\\v\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000";
5047
- var GO_TRIM_SPACE_RE = new RegExp(`^[${GO_SPACE}]+|[${GO_SPACE}]+$`, "g");
5048
- function goTrimSpace(s) {
5454
+ var GO_SPACE2 = "\\t\\n\\v\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000";
5455
+ var GO_TRIM_SPACE_RE = new RegExp(`^[${GO_SPACE2}]+|[${GO_SPACE2}]+$`, "g");
5456
+ function goTrimSpace2(s) {
5049
5457
  return s.replace(GO_TRIM_SPACE_RE, "");
5050
5458
  }
5051
5459
  function goToLower(s) {
@@ -5266,7 +5674,7 @@ function goQueryKeys(rawQuery) {
5266
5674
  return keys;
5267
5675
  }
5268
5676
  function goEndpointOrigin(raw, defaultPorts, protocolSeparator) {
5269
- const trimmed = goTrimSpace(raw);
5677
+ const trimmed = goTrimSpace2(raw);
5270
5678
  const u = goParseSchemeHost(trimmed);
5271
5679
  if (u === null || u.scheme === "" || u.host === "") {
5272
5680
  return goToLower(trimmed.replace(/\/+$/, ""));
@@ -5293,7 +5701,7 @@ function own(m, key) {
5293
5701
  if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
5294
5702
  return m[key];
5295
5703
  }
5296
- function formatField2(format, ...args) {
5704
+ function formatField3(format, ...args) {
5297
5705
  let i = 0;
5298
5706
  return format.replace(/%s/g, () => args[i++] ?? "");
5299
5707
  }
@@ -5315,14 +5723,14 @@ function credentialEndpointSteps(flow, issues) {
5315
5723
  out.push({
5316
5724
  executor: issues.stringOf(step, KEY_EXECUTOR, `steps.${stepId}`) ?? "",
5317
5725
  query: own(step, KEY_QUERY2),
5318
- field: (key) => formatField2(CREDENTIAL_ENDPOINT_PAIRING.stepFieldFormat, stepId, key)
5726
+ field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.stepFieldFormat, stepId, key)
5319
5727
  });
5320
5728
  for (const sub of loopSubStepsOfStep(stepId, step)) {
5321
5729
  const subId = issues.stringOf(sub.raw, KEY_ID2, sub.basePath) ?? "";
5322
5730
  out.push({
5323
5731
  executor: issues.stringOf(sub.raw, KEY_EXECUTOR, sub.basePath) ?? "",
5324
5732
  query: own(sub.raw, KEY_QUERY2),
5325
- field: (key) => formatField2(CREDENTIAL_ENDPOINT_PAIRING.loopStepFieldFormat, stepId, subId, key)
5733
+ field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.loopStepFieldFormat, stepId, subId, key)
5326
5734
  });
5327
5735
  }
5328
5736
  }
@@ -5386,7 +5794,7 @@ function validateAI(flow, steps, issues) {
5386
5794
  if ((stepsUsing.get(provider) ?? 0) > 0 && (stepsWithoutOwnKey.get(provider) ?? 0) === 0) {
5387
5795
  continue;
5388
5796
  }
5389
- warnStoredShape(issues, formatField2(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, provider), provider);
5797
+ warnStoredShape(issues, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, provider), provider);
5390
5798
  }
5391
5799
  }
5392
5800
  function warnStoredShape(issues, field, provider) {
@@ -5433,7 +5841,7 @@ function familySecret(flow, family, step, issues) {
5433
5841
  if (apiKey !== "" && listHas(family.secretParams, family.configApiKeyParam)) {
5434
5842
  return {
5435
5843
  envName: serverEnvRef(family, apiKey),
5436
- field: formatField2(
5844
+ field: formatField3(
5437
5845
  CREDENTIAL_ENDPOINT_PAIRING.executorConfigKeyFieldFormat,
5438
5846
  configKey,
5439
5847
  CREDENTIAL_ENDPOINT_PAIRING.executorConfigApiKeyField
@@ -5446,7 +5854,7 @@ function familySecret(flow, family, step, issues) {
5446
5854
  if (v !== null) {
5447
5855
  return {
5448
5856
  envName: serverEnvRef(family, v),
5449
- field: formatField2(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key)
5857
+ field: formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key)
5450
5858
  };
5451
5859
  }
5452
5860
  }
@@ -5472,13 +5880,13 @@ function familyAuthorEndpoint(flow, family, step, issues) {
5472
5880
  if (inst === null) continue;
5473
5881
  const baseUrl = configStringField(inst, configKey, CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlField, issues);
5474
5882
  if (baseUrl !== "" && listHas(family.endpointParams, family.configBaseUrlParam)) {
5475
- return decide(baseUrl, formatField2(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, configKey));
5883
+ return decide(baseUrl, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, configKey));
5476
5884
  }
5477
5885
  const extra = own(inst, EXECUTOR_CONFIG_ENV_SCOPES.extraKey);
5478
5886
  for (const key of family.endpointParams) {
5479
5887
  const v = nonEmptyEndpoint(extra, key);
5480
5888
  if (v !== null)
5481
- return decide(v, formatField2(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key));
5889
+ return decide(v, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key));
5482
5890
  }
5483
5891
  }
5484
5892
  return null;
@@ -5500,227 +5908,6 @@ function validateFamilies(flow, steps, issues) {
5500
5908
  });
5501
5909
  }
5502
5910
  }
5503
- var CODE_PARSE_FAILED = "orchestrator_exons_parse_failed";
5504
- var CODE_NO_PROVIDER = "orchestrator_exons_no_provider";
5505
- var CODE_RESOURCES = "exons_resources_unhonoured";
5506
- var CODE_TOOL_WITHHELD = "orchestrator_tool_withheld";
5507
- var EXONS_OPEN_DELIM = "{~";
5508
- var EXONS_LEGACY_CONFIG_OPEN = "{~exons.config~}";
5509
- var UTF8_BOM = "\uFEFF";
5510
- var MAX_ALIAS_COUNT2 = 100;
5511
- var UNREAD = {
5512
- parseError: null,
5513
- specRead: false,
5514
- hasSpec: false,
5515
- provider: "",
5516
- toolsAllowDeclared: false,
5517
- toolsAllow: [],
5518
- resources: []
5519
- };
5520
- var GO_SPACE2 = "\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000";
5521
- var GO_TRIM_SPACE = new RegExp(`^[${GO_SPACE2}]+|[${GO_SPACE2}]+$`, "g");
5522
- function goTrimSpace2(s) {
5523
- return s.replace(GO_TRIM_SPACE, "");
5524
- }
5525
- function extractExonsFrontmatter(source) {
5526
- const delim = EXONS.frontmatterDelimiter;
5527
- let start = source.startsWith(UTF8_BOM) ? source.slice(UTF8_BOM.length) : source;
5528
- start = start.replace(/^[ \t]+/, "");
5529
- if (start.startsWith(EXONS_LEGACY_CONFIG_OPEN)) {
5530
- return {
5531
- frontmatter: "",
5532
- hasFrontmatter: false,
5533
- parseError: "legacy JSON config block detected; use YAML frontmatter"
5534
- };
5535
- }
5536
- if (!start.startsWith(delim)) return { frontmatter: "", hasFrontmatter: false, parseError: null };
5537
- let rest = start.slice(delim.length);
5538
- if (rest.startsWith("\n")) rest = rest.slice(1);
5539
- else if (rest.startsWith("\r\n")) rest = rest.slice(2);
5540
- else return { frontmatter: "", hasFrontmatter: false, parseError: null };
5541
- let pos = 0;
5542
- while (pos <= rest.length) {
5543
- const line = rest.slice(pos);
5544
- if (line.startsWith(delim)) {
5545
- const after = line.slice(delim.length);
5546
- if (after === "" || after[0] === "\n" || after[0] === "\r") {
5547
- return {
5548
- frontmatter: goTrimSpace2(rest.slice(0, pos)),
5549
- hasFrontmatter: true,
5550
- parseError: null
5551
- };
5552
- }
5553
- }
5554
- const nl = line.indexOf("\n");
5555
- if (nl < 0) break;
5556
- pos += nl + 1;
5557
- }
5558
- return {
5559
- frontmatter: "",
5560
- hasFrontmatter: true,
5561
- parseError: "YAML frontmatter not properly closed"
5562
- };
5563
- }
5564
- function retagScalars(node) {
5565
- if (yaml.isMap(node)) {
5566
- for (const pair of node.items) {
5567
- retagScalars(pair.key);
5568
- retagScalars(pair.value);
5569
- }
5570
- } else if (yaml.isSeq(node)) {
5571
- for (const item of node.items) retagScalars(item);
5572
- } else if (yaml.isScalar(node) && (typeof node.value === "number" || typeof node.value === "boolean") && typeof node.source === "string") {
5573
- node.value = node.source;
5574
- }
5575
- }
5576
- var DecodeError = class extends Error {
5577
- };
5578
- function goString(v) {
5579
- if (v === null || v === void 0) return "";
5580
- if (isString(v)) return v;
5581
- throw new DecodeError("not a string");
5582
- }
5583
- function goStringList(v) {
5584
- if (v === null || v === void 0) return null;
5585
- if (!isArray(v)) throw new DecodeError("not a list");
5586
- return v.filter((item) => item !== null).map(goString);
5587
- }
5588
- function goStruct(v) {
5589
- if (v === null || v === void 0) return null;
5590
- if (!isRecord(v)) throw new DecodeError("not a mapping");
5591
- return v;
5592
- }
5593
- function decodeSpecFields(frontmatter) {
5594
- let value;
5595
- try {
5596
- const docs = yaml.parseAllDocuments(frontmatter, { merge: true });
5597
- const doc = Array.isArray(docs) ? docs[0] : void 0;
5598
- if (doc === void 0) {
5599
- value = null;
5600
- } else {
5601
- if (doc.errors.length > 0) return null;
5602
- retagScalars(doc.contents);
5603
- value = doc.toJS({ maxAliasCount: MAX_ALIAS_COUNT2 });
5604
- }
5605
- } catch {
5606
- return null;
5607
- }
5608
- try {
5609
- const root = goStruct(value) ?? {};
5610
- const execution = goStruct(root.execution);
5611
- const tools = goStruct(root.tools);
5612
- const requirements = goStruct(root.requirements);
5613
- const allow = tools === null ? null : goStringList(tools.allow);
5614
- let resources = [];
5615
- if (requirements !== null) {
5616
- const raw = requirements.resources;
5617
- if (raw !== null && raw !== void 0) {
5618
- if (!isArray(raw)) throw new DecodeError("not a list");
5619
- resources = raw.filter((entry) => entry !== null).map((entry) => {
5620
- const r = goStruct(entry) ?? {};
5621
- return { ref: goString(r.ref), kind: goString(r.kind), scope: goString(r.scope) };
5622
- });
5623
- }
5624
- }
5625
- return {
5626
- provider: execution === null ? "" : goString(execution.provider),
5627
- toolsAllowDeclared: allow !== null,
5628
- toolsAllow: allow ?? [],
5629
- resources
5630
- };
5631
- } catch (e) {
5632
- if (e instanceof DecodeError) return null;
5633
- throw e;
5634
- }
5635
- }
5636
- function inspectExonsFrontmatter(source) {
5637
- const fm = extractExonsFrontmatter(source);
5638
- if (fm.parseError !== null) return { ...UNREAD, parseError: fm.parseError };
5639
- if (!fm.hasFrontmatter || fm.frontmatter === "") return { ...UNREAD, specRead: true };
5640
- if (fm.frontmatter.includes(EXONS_OPEN_DELIM)) return { ...UNREAD };
5641
- const fields = decodeSpecFields(fm.frontmatter);
5642
- if (fields === null) return { ...UNREAD };
5643
- return { parseError: null, specRead: true, hasSpec: true, ...fields };
5644
- }
5645
- function validateOrchestratorExons(flow, issues) {
5646
- const orch = flow.orchestrator;
5647
- if (!isRecord(orch)) return;
5648
- const source = issues.stringOf(orch, "exons", "orchestrator");
5649
- if (source === null || source === "") return;
5650
- const field = "orchestrator.exons";
5651
- const report = inspectExonsFrontmatter(source);
5652
- if (report.parseError !== null) {
5653
- issues.error({
5654
- field,
5655
- code: CODE_PARSE_FAILED,
5656
- message: `orchestrator: failed to parse exons spec: ${report.parseError}`
5657
- });
5658
- return;
5659
- }
5660
- if (!report.specRead) return;
5661
- if (!report.hasSpec) {
5662
- issues.error({
5663
- field,
5664
- code: CODE_PARSE_FAILED,
5665
- message: "orchestrator: failed to parse exons spec: the document has no frontmatter spec",
5666
- suggestion: "Start the document with a --- frontmatter block that sets execution.provider"
5667
- });
5668
- return;
5669
- }
5670
- if (report.provider === "") {
5671
- issues.error({
5672
- field,
5673
- code: CODE_NO_PROVIDER,
5674
- message: "orchestrator: exons spec must have execution.provider set"
5675
- });
5676
- }
5677
- if (report.resources.length > 0) {
5678
- const refs = report.resources.map((r) => `${JSON.stringify(r.ref)} (kind ${r.kind})`);
5679
- issues.error({
5680
- field,
5681
- code: CODE_RESOURCES,
5682
- message: "the orchestrator's exons spec declares requirements.resources that AIgentFlow cannot honour, so it is refused rather than run without the narrowing it asks for: " + refs.join("; "),
5683
- suggestion: "Remove requirements.resources, and narrow the agent with tools.mcp_servers and tools.allow"
5684
- });
5685
- }
5686
- warnOrchestratorToolWithheld(flow, orch, report, issues);
5687
- }
5688
- function warnOrchestratorToolWithheld(flow, orch, report, issues) {
5689
- if (!report.toolsAllowDeclared) return;
5690
- const cfg = ORCHESTRATOR_TOOL_ALLOW;
5691
- const exempt = new Set(cfg.lifecycleTools);
5692
- const signals = typeof orch.enable_signals === "boolean" ? orch.enable_signals : cfg.enableSignalsDefault;
5693
- if (signals) for (const t of cfg.signalTools) exempt.add(t);
5694
- const allow = new Set(report.toolsAllow);
5695
- const withheld = (name) => !allow.has(name) && !exempt.has(name);
5696
- const warn = (message) => issues.warn({ field: cfg.warningField, code: CODE_TOOL_WITHHELD, message });
5697
- const named = [];
5698
- if (isArray(orch.tools)) {
5699
- orch.tools.forEach((raw, i) => {
5700
- const name = issues.stringAt(raw, `orchestrator.tools[${i}]`);
5701
- if (name !== null) named.push(name);
5702
- });
5703
- }
5704
- if (named.length > 0) {
5705
- for (const name of named) {
5706
- if (!withheld(name)) continue;
5707
- warn(
5708
- `orchestrator tool '${name}' is named in orchestrator.tools but the orchestrator's exons definition's tools.allow does not name it, so it is never offered: a tool must pass both lists. Add '${name}' to tools.allow, or remove it from orchestrator.tools.`
5709
- );
5710
- }
5711
- return;
5712
- }
5713
- if (withheld(cfg.askHumanTool)) {
5714
- warn(
5715
- `the orchestrator's exons definition has a tools.allow list that does not name ${cfg.askHumanTool}, so this orchestrator can never ask a person a question: human intervention is off. Add ${cfg.askHumanTool} to tools.allow if a human should be reachable, or ignore this if the orchestrator is meant to run unattended.`
5716
- );
5717
- }
5718
- if (isRecord(flow.campaign) && !cfg.campaignTools.some((name) => !withheld(name))) {
5719
- warn(
5720
- `this flow declares a campaign, but the orchestrator's exons definition has a tools.allow list that names none of the campaign tools (${cfg.campaignTools.join(", ")}), so no child mission can be spawned or tracked. Add the campaign tools the orchestrator needs to tools.allow.`
5721
- );
5722
- }
5723
- }
5724
5911
 
5725
5912
  // src/validators/complianceResidency.ts
5726
5913
  function own2(m, key) {
@@ -5735,7 +5922,7 @@ function sprintf(format, ...args) {
5735
5922
  });
5736
5923
  }
5737
5924
  function literalOrEmpty(s) {
5738
- const t = goTrimSpace2(s);
5925
+ const t = goTrimSpace(s);
5739
5926
  return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
5740
5927
  }
5741
5928
  function euOnlyResidency(flow, issues) {
@@ -5750,7 +5937,7 @@ function euOnlyResidency(flow, issues) {
5750
5937
  }
5751
5938
  if (codes.length === 0) return null;
5752
5939
  const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
5753
- return codes.every((c) => eu.has(goTrimSpace2(c).toUpperCase())) ? codes : null;
5940
+ return codes.every((c) => eu.has(goTrimSpace(c).toUpperCase())) ? codes : null;
5754
5941
  }
5755
5942
  function aiProvider(executor) {
5756
5943
  const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
@@ -5766,7 +5953,7 @@ function isRegionLane(provider) {
5766
5953
  }
5767
5954
  function nonBlankString(m, key) {
5768
5955
  const v = own2(m, key);
5769
- return typeof v === "string" && goTrimSpace2(v) !== "";
5956
+ return typeof v === "string" && goTrimSpace(v) !== "";
5770
5957
  }
5771
5958
  function queryEnforcesRegion(query) {
5772
5959
  const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
@@ -5778,7 +5965,7 @@ function flowDirectsEndpoint(flow, provider, issues) {
5778
5965
  const inst = own2(own2(flow, "executor_config"), key);
5779
5966
  if (!isRecord(inst)) return false;
5780
5967
  const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
5781
- return baseUrl !== null && goTrimSpace2(baseUrl) !== "";
5968
+ return baseUrl !== null && goTrimSpace(baseUrl) !== "";
5782
5969
  }
5783
5970
  function callPinsEndpoint(flow, provider, query, issues) {
5784
5971
  if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
@@ -5851,7 +6038,7 @@ function warnOrchestrator(flow, issues, warn) {
5851
6038
  const provider = literalOrEmpty(report.provider);
5852
6039
  if (!isRegionLane(provider)) return;
5853
6040
  const region = issues.stringOf(orch, "region", "orchestrator");
5854
- if (region !== null && goTrimSpace2(region) !== "") return;
6041
+ if (region !== null && goTrimSpace(region) !== "") return;
5855
6042
  if (orch.enforce_region === true) return;
5856
6043
  if (flowDirectsEndpoint(flow, provider, issues)) return;
5857
6044
  warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
@@ -6017,7 +6204,7 @@ function asFileRef(v) {
6017
6204
  };
6018
6205
  }
6019
6206
  function isTextualMediaType(mediaType) {
6020
- const base = goToLower(goTrimSpace((mediaType.split(";")[0] ?? "").toString()));
6207
+ const base = goToLower(goTrimSpace2((mediaType.split(";")[0] ?? "").toString()));
6021
6208
  if (base.startsWith("text/")) return true;
6022
6209
  if (base.endsWith("+json") || base.endsWith("+xml")) return true;
6023
6210
  return TEXTUAL_MEDIA_BASES.has(base);
@@ -6121,7 +6308,7 @@ var Walker = class _Walker {
6121
6308
  }
6122
6309
  }
6123
6310
  const title = this.s(ex, "title", path);
6124
- if (goTrimSpace(title) === "") {
6311
+ if (goTrimSpace2(title) === "") {
6125
6312
  this.err(
6126
6313
  "example_title_missing",
6127
6314
  `${path}.title`,
@@ -6138,7 +6325,7 @@ var Walker = class _Walker {
6138
6325
  }
6139
6326
  }
6140
6327
  const guidance = this.s(ex, "guidance", path);
6141
- if (goTrimSpace(guidance) === "") {
6328
+ if (goTrimSpace2(guidance) === "") {
6142
6329
  this.warn(
6143
6330
  "example_guidance_missing",
6144
6331
  `${path}.guidance`,
@@ -6565,7 +6752,7 @@ var Walker = class _Walker {
6565
6752
  }
6566
6753
  const rubric = this.s(e, "rubric", path);
6567
6754
  if (rubric !== "") {
6568
- if (goTrimSpace(rubric) === "") {
6755
+ if (goTrimSpace2(rubric) === "") {
6569
6756
  this.err(
6570
6757
  "example_rubric_empty",
6571
6758
  `${path}.rubric`,
@@ -6620,7 +6807,7 @@ var Walker = class _Walker {
6620
6807
  this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
6621
6808
  }
6622
6809
  mustNot.forEach((item, j) => {
6623
- if (goTrimSpace(item) === "" || runeCount(item) > L.maxMustNotRunes) {
6810
+ if (goTrimSpace2(item) === "" || runeCount(item) > L.maxMustNotRunes) {
6624
6811
  this.err("example_must_not_invalid", `${path}.must_not[${j}]`, mustNotMsg);
6625
6812
  }
6626
6813
  });
@@ -7178,6 +7365,7 @@ function validateParsed(flow, opts, sources) {
7178
7365
  const f = flow;
7179
7366
  validateBasicStructure(f, issues);
7180
7367
  validateRetiredKeys(f, issues);
7368
+ validateRemovedFlowKeys(f, issues);
7181
7369
  validateExecutors(f, issues);
7182
7370
  validateQuerySchema(f, issues);
7183
7371
  validateResponseExpectations(f, issues);
@@ -7189,6 +7377,7 @@ function validateParsed(flow, opts, sources) {
7189
7377
  validateOrchestratorCampaign(f, issues, opts);
7190
7378
  validateCredentialBindings(f, issues);
7191
7379
  validateInputSchema(f, issues);
7380
+ validateReservedInputNames(f, issues);
7192
7381
  validateOutputSchemas(f, issues);
7193
7382
  validateQualityGates(f, issues);
7194
7383
  validateProcessingOperations(f, issues);