@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/PARITY.md +69 -3
- package/README.md +2 -1
- package/dist/cli.js +469 -284
- package/dist/index.cjs +462 -273
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +462 -273
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -455,11 +455,10 @@ function validateBasicStructure(flow, issues) {
|
|
|
455
455
|
// src/spec/aigentflow-spec.json
|
|
456
456
|
var aigentflow_spec_default = {
|
|
457
457
|
$comment: "Vendored enum surface mirrored from the AIgentFlow Go reference implementation. Regenerate / review on every flow-YAML schema change. See PARITY.md. Values here are public protocol/type names only.",
|
|
458
|
-
specVersion: "2.
|
|
458
|
+
specVersion: "2.833.0",
|
|
459
459
|
inputSchemaVersion: 1,
|
|
460
460
|
executorSchemes: [
|
|
461
461
|
"a2a",
|
|
462
|
-
"agent",
|
|
463
462
|
"ai",
|
|
464
463
|
"aiv",
|
|
465
464
|
"async",
|
|
@@ -473,7 +472,6 @@ var aigentflow_spec_default = {
|
|
|
473
472
|
"email",
|
|
474
473
|
"eurostat",
|
|
475
474
|
"eval",
|
|
476
|
-
"exons",
|
|
477
475
|
"flow",
|
|
478
476
|
"function",
|
|
479
477
|
"gdelt",
|
|
@@ -778,11 +776,36 @@ var aigentflow_spec_default = {
|
|
|
778
776
|
]
|
|
779
777
|
},
|
|
780
778
|
exons: {
|
|
781
|
-
$comment: "
|
|
782
|
-
executorPrefix: "exons://",
|
|
783
|
-
documentParam: "exons",
|
|
779
|
+
$comment: "The orchestrator's inline .exons document is still judged at the save door (orchestrator stays). A document opens with frontmatterDelimiter. Steps no longer carry inline .exons documents: the exons:// executor was removed (see removedAgentSurfaces).",
|
|
784
780
|
frontmatterDelimiter: "---"
|
|
785
781
|
},
|
|
782
|
+
removedAgentSurfaces: {
|
|
783
|
+
$comment: "AIgentFlow no longer runs agents of its own. executor_removed (ERROR): a step or loop sub-step whose executor scheme (text before '://', whitespace-trimmed, lower-cased) is in removedSchemes, or a top-level key in flowKeys (field = the key). agentic_param_removed (ERROR): an ai:// step or loop sub-step whose query carries ANY key of aiParams, on presence alone (null and false included); ONE finding per step, the keys sorted and joined by ', '. Only the paramScheme scheme is checked for params. A templated executor (containing templateActionOpen) is not judged. A step on a removed scheme yields ONLY executor_removed: no unknown_executor_scheme, executor-URL shape or inline-exons finding. Fields: steps.<id> and steps.<id>.loop.steps[<index>]. Not refused: aiv://, atlas://, ai:// tools / tool_choice / autofix / content_parts / stream, flow-level tool_discovery / discoverable_tools, the orchestrator block's own keys. Messages fill %s (the step id as written in the finding, then the scheme or the key list).",
|
|
784
|
+
removedSchemes: ["exons", "agent"],
|
|
785
|
+
paramScheme: "ai",
|
|
786
|
+
aiParams: [
|
|
787
|
+
"agentic",
|
|
788
|
+
"deny_tools",
|
|
789
|
+
"discoverable_tools",
|
|
790
|
+
"enable_signals",
|
|
791
|
+
"guardrails",
|
|
792
|
+
"max_tool_calls",
|
|
793
|
+
"max_tool_turns",
|
|
794
|
+
"mcp_server_url",
|
|
795
|
+
"parallel_tool_calls",
|
|
796
|
+
"require_confirmation",
|
|
797
|
+
"timeout_seconds",
|
|
798
|
+
"tool_auth_token",
|
|
799
|
+
"tool_discovery"
|
|
800
|
+
],
|
|
801
|
+
flowKeys: ["exons_uploads"],
|
|
802
|
+
executorRemovedCode: "executor_removed",
|
|
803
|
+
agenticParamRemovedCode: "agentic_param_removed",
|
|
804
|
+
schemeMessageFormat: "step %q uses %s://, which AIgentFlow no longer runs: its own agent chains were removed",
|
|
805
|
+
paramsMessageFormat: "step %q sets %s on ai://: AIgentFlow's own agent loop (agentic mode) was removed, so these parameters no longer exist",
|
|
806
|
+
flowKeyMessageFormat: "the flow-level key %q belonged to a removed agent surface and is no longer read",
|
|
807
|
+
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'
|
|
808
|
+
},
|
|
786
809
|
executorConfigEnvScopes: {
|
|
787
810
|
$comment: "executor_config may expand only the environment variables of the key it is written under. A value is a reference when it starts with referencePrefix and ends with referenceSuffix around a non-empty name. Checked fields: fields, plus every string value of extra (prefixed extraFieldPrefix in the message). A key absent from scopes has an EMPTY scope and refuses every reference. scopes is the reference's executorConfigEnvScope evaluated for every key with a non-empty scope. Reference: ValidateExecutorConfigEnvScopes (v2.597.0).",
|
|
788
811
|
referencePrefix: "${",
|
|
@@ -1008,12 +1031,12 @@ var aigentflow_spec_default = {
|
|
|
1008
1031
|
]
|
|
1009
1032
|
},
|
|
1010
1033
|
atlasExecutor: {
|
|
1011
|
-
$comment: "atlas://<provider>/<resource>: calls into the Atlas platform. Providers are agent (the one resource is run) and capability (the resource is a capability reference). All findings are ERRORS, field = the step (loop sub-steps use the composite step id and the sub-step path). Templated executors, unparsable URLs and other schemes are skipped. A literal agent and literal capabilities keep a step from being steered by data: query.agent and every string in query.capabilities may not contain templateActionOpen, while prompt, inputs and capability args may. A message format takes the quoted step id first.",
|
|
1034
|
+
$comment: "atlas://<provider>/<resource>: calls into the Atlas platform. Providers are agent (the one resource is run) and capability (the resource is a capability reference). All findings are ERRORS, field = the step (loop sub-steps use the composite step id and the sub-step path). Templated executors, unparsable URLs and other schemes are skipped. A literal agent and literal capabilities keep a step from being steered by data: query.agent and every string anywhere in query.capabilities and query.model may not contain templateActionOpen, while prompt, inputs and capability args may. agent, prompt and prompt_template count as present only when they are non-empty strings after trimming whitespace. A message format takes the quoted step id first. A URL the shared executor-URL shape refuses (a dot or colon in a reference, say) is still judged here, split at the first slash after atlas://.",
|
|
1012
1035
|
scheme: "atlas",
|
|
1013
1036
|
providerAgent: "agent",
|
|
1014
1037
|
providerCapability: "capability",
|
|
1015
1038
|
agentResource: "run",
|
|
1016
|
-
capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_
|
|
1039
|
+
capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$",
|
|
1017
1040
|
operationUnknown: {
|
|
1018
1041
|
code: "atlas_operation_unknown",
|
|
1019
1042
|
messageFormat: "step %s uses %s, which is not an Atlas operation. The providers are agent (resource run) and capability (resource: a capability reference).",
|
|
@@ -1021,7 +1044,7 @@ var aigentflow_spec_default = {
|
|
|
1021
1044
|
},
|
|
1022
1045
|
agentMissing: {
|
|
1023
1046
|
code: "atlas_agent_missing",
|
|
1024
|
-
messageFormat: "step %s runs an Atlas agent but query.agent is missing or
|
|
1047
|
+
messageFormat: "step %s runs an Atlas agent but query.agent is missing, empty or not a string.",
|
|
1025
1048
|
suggestion: "Set query.agent to the agent to run, written out as a literal such as @acme/reporter."
|
|
1026
1049
|
},
|
|
1027
1050
|
agentNotLiteral: {
|
|
@@ -1047,9 +1070,47 @@ var aigentflow_spec_default = {
|
|
|
1047
1070
|
capabilityRefInvalid: {
|
|
1048
1071
|
code: "atlas_capability_ref_invalid",
|
|
1049
1072
|
messageFormat: "step %s uses atlas://capability/%s, which is not a valid capability reference.",
|
|
1050
|
-
suggestion: "A capability reference starts with a letter or digit and continues with letters, digits
|
|
1073
|
+
suggestion: "A capability reference starts with a letter or digit and continues with letters, digits, _ and - up to 128 characters in all."
|
|
1074
|
+
},
|
|
1075
|
+
modelNotLiteral: {
|
|
1076
|
+
code: "atlas_model_not_literal",
|
|
1077
|
+
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.",
|
|
1078
|
+
suggestion: "Write the model choice out as literals. Data may go into the prompt or the inputs instead."
|
|
1079
|
+
},
|
|
1080
|
+
paramRefused: {
|
|
1081
|
+
code: "atlas_param_refused",
|
|
1082
|
+
messageFormat: "step %s sets %s under query. Atlas decides these itself, so a step may not set them.",
|
|
1083
|
+
suggestion: "Remove these keys from the query.",
|
|
1084
|
+
agentKeys: [
|
|
1085
|
+
"api_key",
|
|
1086
|
+
"attribution",
|
|
1087
|
+
"base_url",
|
|
1088
|
+
"host",
|
|
1089
|
+
"idempotency_key",
|
|
1090
|
+
"org_id",
|
|
1091
|
+
"person",
|
|
1092
|
+
"untrusted_input",
|
|
1093
|
+
"untrusted_input_override",
|
|
1094
|
+
"url",
|
|
1095
|
+
"user_id"
|
|
1096
|
+
],
|
|
1097
|
+
capabilityKeys: [
|
|
1098
|
+
"attribution",
|
|
1099
|
+
"idempotency_key",
|
|
1100
|
+
"untrusted_input",
|
|
1101
|
+
"untrusted_input_override"
|
|
1102
|
+
]
|
|
1051
1103
|
}
|
|
1052
1104
|
},
|
|
1105
|
+
reservedInputNames: {
|
|
1106
|
+
$comment: "reserved_input_name (ERROR): an input the flow declares under the top-level query: map, or as an input_schema field name, that starts with prefix. The platform keeps that namespace for values it writes itself (the acting person, the credential manifest, the untrusted-input marker); a value or default written under such a name is never delivered. Every name the platform reserves today starts with the prefix. Matching is exact and case-sensitive: one leading underscore is an ordinary name. Findings carry no step id. queryFieldFormat takes the input name; schemaFieldFormat takes the field name as written (a non-string name is skipped). Query names are reported sorted, then schema fields in file order.",
|
|
1107
|
+
prefix: "__",
|
|
1108
|
+
code: "reserved_input_name",
|
|
1109
|
+
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.",
|
|
1110
|
+
suggestion: 'Rename the input so it does not start with "__".',
|
|
1111
|
+
queryFieldFormat: "query.%s",
|
|
1112
|
+
schemaFieldFormat: "input_schema.fields.%s"
|
|
1113
|
+
},
|
|
1053
1114
|
flowDataReservedKeys: {
|
|
1054
1115
|
$comment: "flow_data_key_reserved (ERROR, no loop demotion): a key of the top-level data: map that names engine state. data: is seeded into the mission's .data namespace, where the engine keeps its own bookkeeping, so a flow declaring such a key would forge it. Matching is exact and case-sensitive. A key is reserved when it is one of exact (each with its reason), or starts with one of prefixes (checked in order, first wins; each with its reason). The finding's field is fieldFormat with the key; the message is messageFormat with the key (JSON-quoted, as Go's %q) then the reason; the suggestion is verbatim. Findings are sorted by key. Reference: FlowDataKeyReservation, validateFlowDataKeysAreNotReserved (aigentflow#247 review).",
|
|
1055
1116
|
code: "flow_data_key_reserved",
|
|
@@ -2073,13 +2134,22 @@ var ORCHESTRATOR_TOOL_ALLOW = {
|
|
|
2073
2134
|
campaignTools: aigentflow_spec_default.orchestratorToolAllow.campaignTools
|
|
2074
2135
|
};
|
|
2075
2136
|
var EXONS = {
|
|
2076
|
-
/** A step's document is judged only on an executor with this prefix. */
|
|
2077
|
-
executorPrefix: aigentflow_spec_default.exons.executorPrefix,
|
|
2078
|
-
/** The step `query` parameter that carries the document. */
|
|
2079
|
-
documentParam: aigentflow_spec_default.exons.documentParam,
|
|
2080
2137
|
/** The YAML frontmatter delimiter line. */
|
|
2081
2138
|
frontmatterDelimiter: aigentflow_spec_default.exons.frontmatterDelimiter
|
|
2082
2139
|
};
|
|
2140
|
+
var removed = aigentflow_spec_default.removedAgentSurfaces;
|
|
2141
|
+
var REMOVED_AGENT_SURFACES = {
|
|
2142
|
+
schemes: new Set(removed.removedSchemes),
|
|
2143
|
+
paramScheme: removed.paramScheme,
|
|
2144
|
+
aiParams: new Set(removed.aiParams),
|
|
2145
|
+
flowKeys: removed.flowKeys,
|
|
2146
|
+
executorRemovedCode: removed.executorRemovedCode,
|
|
2147
|
+
agenticParamRemovedCode: removed.agenticParamRemovedCode,
|
|
2148
|
+
schemeMessageFormat: removed.schemeMessageFormat,
|
|
2149
|
+
paramsMessageFormat: removed.paramsMessageFormat,
|
|
2150
|
+
flowKeyMessageFormat: removed.flowKeyMessageFormat,
|
|
2151
|
+
suggestion: removed.suggestion
|
|
2152
|
+
};
|
|
2083
2153
|
var EXECUTOR_CONFIG_ENV_SCOPES = {
|
|
2084
2154
|
referencePrefix: aigentflow_spec_default.executorConfigEnvScopes.referencePrefix,
|
|
2085
2155
|
referenceSuffix: aigentflow_spec_default.executorConfigEnvScopes.referenceSuffix,
|
|
@@ -2186,9 +2256,249 @@ var ATLAS_EXECUTOR = {
|
|
|
2186
2256
|
capabilitiesNotLiteral: atlas.capabilitiesNotLiteral,
|
|
2187
2257
|
promptMissing: atlas.promptMissing,
|
|
2188
2258
|
promptBoth: atlas.promptBoth,
|
|
2189
|
-
capabilityRefInvalid: atlas.capabilityRefInvalid
|
|
2259
|
+
capabilityRefInvalid: atlas.capabilityRefInvalid,
|
|
2260
|
+
modelNotLiteral: atlas.modelNotLiteral,
|
|
2261
|
+
paramRefused: {
|
|
2262
|
+
code: atlas.paramRefused.code,
|
|
2263
|
+
messageFormat: atlas.paramRefused.messageFormat,
|
|
2264
|
+
suggestion: atlas.paramRefused.suggestion,
|
|
2265
|
+
agentKeys: atlas.paramRefused.agentKeys,
|
|
2266
|
+
capabilityKeys: atlas.paramRefused.capabilityKeys
|
|
2267
|
+
}
|
|
2268
|
+
};
|
|
2269
|
+
var RESERVED_INPUT_NAMES = {
|
|
2270
|
+
prefix: aigentflow_spec_default.reservedInputNames.prefix,
|
|
2271
|
+
code: aigentflow_spec_default.reservedInputNames.code,
|
|
2272
|
+
messageFormat: aigentflow_spec_default.reservedInputNames.messageFormat,
|
|
2273
|
+
suggestion: aigentflow_spec_default.reservedInputNames.suggestion,
|
|
2274
|
+
queryFieldFormat: aigentflow_spec_default.reservedInputNames.queryFieldFormat,
|
|
2275
|
+
schemaFieldFormat: aigentflow_spec_default.reservedInputNames.schemaFieldFormat
|
|
2190
2276
|
};
|
|
2191
2277
|
|
|
2278
|
+
// src/validators/exons.ts
|
|
2279
|
+
import { isMap as isMap2, isScalar as isScalar2, isSeq as isSeq2, parseAllDocuments } from "yaml";
|
|
2280
|
+
var CODE_PARSE_FAILED = "orchestrator_exons_parse_failed";
|
|
2281
|
+
var CODE_NO_PROVIDER = "orchestrator_exons_no_provider";
|
|
2282
|
+
var CODE_RESOURCES = "exons_resources_unhonoured";
|
|
2283
|
+
var CODE_TOOL_WITHHELD = "orchestrator_tool_withheld";
|
|
2284
|
+
var EXONS_OPEN_DELIM = "{~";
|
|
2285
|
+
var EXONS_LEGACY_CONFIG_OPEN = "{~exons.config~}";
|
|
2286
|
+
var UTF8_BOM = "\uFEFF";
|
|
2287
|
+
var MAX_ALIAS_COUNT2 = 100;
|
|
2288
|
+
var UNREAD = {
|
|
2289
|
+
parseError: null,
|
|
2290
|
+
specRead: false,
|
|
2291
|
+
hasSpec: false,
|
|
2292
|
+
provider: "",
|
|
2293
|
+
toolsAllowDeclared: false,
|
|
2294
|
+
toolsAllow: [],
|
|
2295
|
+
resources: []
|
|
2296
|
+
};
|
|
2297
|
+
var GO_SPACE = "\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000";
|
|
2298
|
+
var GO_TRIM_SPACE = new RegExp(`^[${GO_SPACE}]+|[${GO_SPACE}]+$`, "g");
|
|
2299
|
+
function goTrimSpace(s) {
|
|
2300
|
+
return s.replace(GO_TRIM_SPACE, "");
|
|
2301
|
+
}
|
|
2302
|
+
function extractExonsFrontmatter(source) {
|
|
2303
|
+
const delim = EXONS.frontmatterDelimiter;
|
|
2304
|
+
let start = source.startsWith(UTF8_BOM) ? source.slice(UTF8_BOM.length) : source;
|
|
2305
|
+
start = start.replace(/^[ \t]+/, "");
|
|
2306
|
+
if (start.startsWith(EXONS_LEGACY_CONFIG_OPEN)) {
|
|
2307
|
+
return {
|
|
2308
|
+
frontmatter: "",
|
|
2309
|
+
hasFrontmatter: false,
|
|
2310
|
+
parseError: "legacy JSON config block detected; use YAML frontmatter"
|
|
2311
|
+
};
|
|
2312
|
+
}
|
|
2313
|
+
if (!start.startsWith(delim)) return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
2314
|
+
let rest = start.slice(delim.length);
|
|
2315
|
+
if (rest.startsWith("\n")) rest = rest.slice(1);
|
|
2316
|
+
else if (rest.startsWith("\r\n")) rest = rest.slice(2);
|
|
2317
|
+
else return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
2318
|
+
let pos = 0;
|
|
2319
|
+
while (pos <= rest.length) {
|
|
2320
|
+
const line = rest.slice(pos);
|
|
2321
|
+
if (line.startsWith(delim)) {
|
|
2322
|
+
const after = line.slice(delim.length);
|
|
2323
|
+
if (after === "" || after[0] === "\n" || after[0] === "\r") {
|
|
2324
|
+
return {
|
|
2325
|
+
frontmatter: goTrimSpace(rest.slice(0, pos)),
|
|
2326
|
+
hasFrontmatter: true,
|
|
2327
|
+
parseError: null
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
const nl = line.indexOf("\n");
|
|
2332
|
+
if (nl < 0) break;
|
|
2333
|
+
pos += nl + 1;
|
|
2334
|
+
}
|
|
2335
|
+
return {
|
|
2336
|
+
frontmatter: "",
|
|
2337
|
+
hasFrontmatter: true,
|
|
2338
|
+
parseError: "YAML frontmatter not properly closed"
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
function retagScalars(node) {
|
|
2342
|
+
if (isMap2(node)) {
|
|
2343
|
+
for (const pair of node.items) {
|
|
2344
|
+
retagScalars(pair.key);
|
|
2345
|
+
retagScalars(pair.value);
|
|
2346
|
+
}
|
|
2347
|
+
} else if (isSeq2(node)) {
|
|
2348
|
+
for (const item of node.items) retagScalars(item);
|
|
2349
|
+
} else if (isScalar2(node) && (typeof node.value === "number" || typeof node.value === "boolean") && typeof node.source === "string") {
|
|
2350
|
+
node.value = node.source;
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
var DecodeError = class extends Error {
|
|
2354
|
+
};
|
|
2355
|
+
function goString(v) {
|
|
2356
|
+
if (v === null || v === void 0) return "";
|
|
2357
|
+
if (isString(v)) return v;
|
|
2358
|
+
throw new DecodeError("not a string");
|
|
2359
|
+
}
|
|
2360
|
+
function goStringList(v) {
|
|
2361
|
+
if (v === null || v === void 0) return null;
|
|
2362
|
+
if (!isArray(v)) throw new DecodeError("not a list");
|
|
2363
|
+
return v.filter((item) => item !== null).map(goString);
|
|
2364
|
+
}
|
|
2365
|
+
function goStruct(v) {
|
|
2366
|
+
if (v === null || v === void 0) return null;
|
|
2367
|
+
if (!isRecord(v)) throw new DecodeError("not a mapping");
|
|
2368
|
+
return v;
|
|
2369
|
+
}
|
|
2370
|
+
function decodeSpecFields(frontmatter) {
|
|
2371
|
+
let value;
|
|
2372
|
+
try {
|
|
2373
|
+
const docs = parseAllDocuments(frontmatter, { merge: true });
|
|
2374
|
+
const doc = Array.isArray(docs) ? docs[0] : void 0;
|
|
2375
|
+
if (doc === void 0) {
|
|
2376
|
+
value = null;
|
|
2377
|
+
} else {
|
|
2378
|
+
if (doc.errors.length > 0) return null;
|
|
2379
|
+
retagScalars(doc.contents);
|
|
2380
|
+
value = doc.toJS({ maxAliasCount: MAX_ALIAS_COUNT2 });
|
|
2381
|
+
}
|
|
2382
|
+
} catch {
|
|
2383
|
+
return null;
|
|
2384
|
+
}
|
|
2385
|
+
try {
|
|
2386
|
+
const root = goStruct(value) ?? {};
|
|
2387
|
+
const execution = goStruct(root.execution);
|
|
2388
|
+
const tools = goStruct(root.tools);
|
|
2389
|
+
const requirements = goStruct(root.requirements);
|
|
2390
|
+
const allow = tools === null ? null : goStringList(tools.allow);
|
|
2391
|
+
let resources = [];
|
|
2392
|
+
if (requirements !== null) {
|
|
2393
|
+
const raw = requirements.resources;
|
|
2394
|
+
if (raw !== null && raw !== void 0) {
|
|
2395
|
+
if (!isArray(raw)) throw new DecodeError("not a list");
|
|
2396
|
+
resources = raw.filter((entry) => entry !== null).map((entry) => {
|
|
2397
|
+
const r = goStruct(entry) ?? {};
|
|
2398
|
+
return { ref: goString(r.ref), kind: goString(r.kind), scope: goString(r.scope) };
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
return {
|
|
2403
|
+
provider: execution === null ? "" : goString(execution.provider),
|
|
2404
|
+
toolsAllowDeclared: allow !== null,
|
|
2405
|
+
toolsAllow: allow ?? [],
|
|
2406
|
+
resources
|
|
2407
|
+
};
|
|
2408
|
+
} catch (e) {
|
|
2409
|
+
if (e instanceof DecodeError) return null;
|
|
2410
|
+
throw e;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
function inspectExonsFrontmatter(source) {
|
|
2414
|
+
const fm = extractExonsFrontmatter(source);
|
|
2415
|
+
if (fm.parseError !== null) return { ...UNREAD, parseError: fm.parseError };
|
|
2416
|
+
if (!fm.hasFrontmatter || fm.frontmatter === "") return { ...UNREAD, specRead: true };
|
|
2417
|
+
if (fm.frontmatter.includes(EXONS_OPEN_DELIM)) return { ...UNREAD };
|
|
2418
|
+
const fields = decodeSpecFields(fm.frontmatter);
|
|
2419
|
+
if (fields === null) return { ...UNREAD };
|
|
2420
|
+
return { parseError: null, specRead: true, hasSpec: true, ...fields };
|
|
2421
|
+
}
|
|
2422
|
+
function validateOrchestratorExons(flow, issues) {
|
|
2423
|
+
const orch = flow.orchestrator;
|
|
2424
|
+
if (!isRecord(orch)) return;
|
|
2425
|
+
const source = issues.stringOf(orch, "exons", "orchestrator");
|
|
2426
|
+
if (source === null || source === "") return;
|
|
2427
|
+
const field = "orchestrator.exons";
|
|
2428
|
+
const report = inspectExonsFrontmatter(source);
|
|
2429
|
+
if (report.parseError !== null) {
|
|
2430
|
+
issues.error({
|
|
2431
|
+
field,
|
|
2432
|
+
code: CODE_PARSE_FAILED,
|
|
2433
|
+
message: `orchestrator: failed to parse exons spec: ${report.parseError}`
|
|
2434
|
+
});
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
if (!report.specRead) return;
|
|
2438
|
+
if (!report.hasSpec) {
|
|
2439
|
+
issues.error({
|
|
2440
|
+
field,
|
|
2441
|
+
code: CODE_PARSE_FAILED,
|
|
2442
|
+
message: "orchestrator: failed to parse exons spec: the document has no frontmatter spec",
|
|
2443
|
+
suggestion: "Start the document with a --- frontmatter block that sets execution.provider"
|
|
2444
|
+
});
|
|
2445
|
+
return;
|
|
2446
|
+
}
|
|
2447
|
+
if (report.provider === "") {
|
|
2448
|
+
issues.error({
|
|
2449
|
+
field,
|
|
2450
|
+
code: CODE_NO_PROVIDER,
|
|
2451
|
+
message: "orchestrator: exons spec must have execution.provider set"
|
|
2452
|
+
});
|
|
2453
|
+
}
|
|
2454
|
+
if (report.resources.length > 0) {
|
|
2455
|
+
const refs = report.resources.map((r) => `${JSON.stringify(r.ref)} (kind ${r.kind})`);
|
|
2456
|
+
issues.error({
|
|
2457
|
+
field,
|
|
2458
|
+
code: CODE_RESOURCES,
|
|
2459
|
+
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("; "),
|
|
2460
|
+
suggestion: "Remove requirements.resources, and narrow the agent with tools.mcp_servers and tools.allow"
|
|
2461
|
+
});
|
|
2462
|
+
}
|
|
2463
|
+
warnOrchestratorToolWithheld(flow, orch, report, issues);
|
|
2464
|
+
}
|
|
2465
|
+
function warnOrchestratorToolWithheld(flow, orch, report, issues) {
|
|
2466
|
+
if (!report.toolsAllowDeclared) return;
|
|
2467
|
+
const cfg = ORCHESTRATOR_TOOL_ALLOW;
|
|
2468
|
+
const exempt = new Set(cfg.lifecycleTools);
|
|
2469
|
+
const signals = typeof orch.enable_signals === "boolean" ? orch.enable_signals : cfg.enableSignalsDefault;
|
|
2470
|
+
if (signals) for (const t of cfg.signalTools) exempt.add(t);
|
|
2471
|
+
const allow = new Set(report.toolsAllow);
|
|
2472
|
+
const withheld = (name) => !allow.has(name) && !exempt.has(name);
|
|
2473
|
+
const warn = (message) => issues.warn({ field: cfg.warningField, code: CODE_TOOL_WITHHELD, message });
|
|
2474
|
+
const named = [];
|
|
2475
|
+
if (isArray(orch.tools)) {
|
|
2476
|
+
orch.tools.forEach((raw, i) => {
|
|
2477
|
+
const name = issues.stringAt(raw, `orchestrator.tools[${i}]`);
|
|
2478
|
+
if (name !== null) named.push(name);
|
|
2479
|
+
});
|
|
2480
|
+
}
|
|
2481
|
+
if (named.length > 0) {
|
|
2482
|
+
for (const name of named) {
|
|
2483
|
+
if (!withheld(name)) continue;
|
|
2484
|
+
warn(
|
|
2485
|
+
`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.`
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2488
|
+
return;
|
|
2489
|
+
}
|
|
2490
|
+
if (withheld(cfg.askHumanTool)) {
|
|
2491
|
+
warn(
|
|
2492
|
+
`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.`
|
|
2493
|
+
);
|
|
2494
|
+
}
|
|
2495
|
+
if (isRecord(flow.campaign) && !cfg.campaignTools.some((name) => !withheld(name))) {
|
|
2496
|
+
warn(
|
|
2497
|
+
`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.`
|
|
2498
|
+
);
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2192
2502
|
// src/validators/executors.ts
|
|
2193
2503
|
var SCHEME_SEPARATOR = "://";
|
|
2194
2504
|
var UNKNOWN_SCHEME_BASE = (scheme) => `Unknown executor scheme '${scheme}'. It may be valid in a newer AIgentFlow release, or it could be a typo.`;
|
|
@@ -2251,12 +2561,64 @@ function checkExecutor(executor, field, stepID, issues) {
|
|
|
2251
2561
|
}
|
|
2252
2562
|
checkFunctionOperation(executor, field, stepID, templated, issues);
|
|
2253
2563
|
}
|
|
2564
|
+
function removedExecutorScheme(executor) {
|
|
2565
|
+
if (executor.includes(TEMPLATE_ACTION_OPEN)) return "";
|
|
2566
|
+
const trimmed = goTrimSpace(executor);
|
|
2567
|
+
const at = trimmed.indexOf(SCHEME_SEPARATOR);
|
|
2568
|
+
return at < 0 ? "" : trimmed.slice(0, at).toLowerCase();
|
|
2569
|
+
}
|
|
2570
|
+
function checkRemovedSurfaces(executor, query, field, stepID, issues) {
|
|
2571
|
+
const cfg = REMOVED_AGENT_SURFACES;
|
|
2572
|
+
const quoted = JSON.stringify(stepID);
|
|
2573
|
+
const scheme = removedExecutorScheme(executor);
|
|
2574
|
+
if (cfg.schemes.has(scheme)) {
|
|
2575
|
+
issues.error({
|
|
2576
|
+
field,
|
|
2577
|
+
message: fillRemovedMessage(cfg.schemeMessageFormat, quoted, scheme),
|
|
2578
|
+
code: cfg.executorRemovedCode,
|
|
2579
|
+
stepId: stepID,
|
|
2580
|
+
suggestion: cfg.suggestion
|
|
2581
|
+
});
|
|
2582
|
+
return true;
|
|
2583
|
+
}
|
|
2584
|
+
if (scheme !== cfg.paramScheme || !isRecord(query)) return false;
|
|
2585
|
+
const found = Object.keys(query).filter((key) => cfg.aiParams.has(key)).sort();
|
|
2586
|
+
if (found.length > 0) {
|
|
2587
|
+
issues.error({
|
|
2588
|
+
field,
|
|
2589
|
+
message: fillRemovedMessage(cfg.paramsMessageFormat, quoted, found.join(", ")),
|
|
2590
|
+
code: cfg.agenticParamRemovedCode,
|
|
2591
|
+
stepId: stepID,
|
|
2592
|
+
suggestion: cfg.suggestion
|
|
2593
|
+
});
|
|
2594
|
+
}
|
|
2595
|
+
return false;
|
|
2596
|
+
}
|
|
2597
|
+
function fillRemovedMessage(format, ...args) {
|
|
2598
|
+
let i = 0;
|
|
2599
|
+
return format.replace(/%[qs]/g, () => args[i++] ?? "");
|
|
2600
|
+
}
|
|
2601
|
+
function validateRemovedFlowKeys(flow, issues) {
|
|
2602
|
+
const cfg = REMOVED_AGENT_SURFACES;
|
|
2603
|
+
for (const key of cfg.flowKeys) {
|
|
2604
|
+
if (Object.prototype.hasOwnProperty.call(flow, key)) {
|
|
2605
|
+
issues.error({
|
|
2606
|
+
field: key,
|
|
2607
|
+
message: fillRemovedMessage(cfg.flowKeyMessageFormat, JSON.stringify(key)),
|
|
2608
|
+
code: cfg.executorRemovedCode,
|
|
2609
|
+
suggestion: cfg.suggestion
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2254
2614
|
function checkAtlasStep(executor, query, stepField, stepID, issues) {
|
|
2255
2615
|
if (executor.includes(TEMPLATE_ACTION_OPEN)) return;
|
|
2256
|
-
const
|
|
2257
|
-
if (
|
|
2258
|
-
const
|
|
2259
|
-
const
|
|
2616
|
+
const prefix = `${ATLAS_EXECUTOR.scheme}://`;
|
|
2617
|
+
if (!executor.startsWith(prefix)) return;
|
|
2618
|
+
const rest = executor.slice(prefix.length);
|
|
2619
|
+
const slash = rest.indexOf("/");
|
|
2620
|
+
const provider = slash < 0 ? rest : rest.slice(0, slash);
|
|
2621
|
+
const resource = slash < 0 ? "" : rest.slice(slash + 1);
|
|
2260
2622
|
const quoted = JSON.stringify(stepID);
|
|
2261
2623
|
const report = (rule, ...args) => {
|
|
2262
2624
|
let message = rule.messageFormat.replace("%s", () => quoted);
|
|
@@ -2270,31 +2632,41 @@ function checkAtlasStep(executor, query, stepField, stepID, issues) {
|
|
|
2270
2632
|
});
|
|
2271
2633
|
};
|
|
2272
2634
|
const q2 = isRecord(query) ? query : {};
|
|
2635
|
+
let refusedKeys = ATLAS_EXECUTOR.paramRefused.capabilityKeys;
|
|
2273
2636
|
if (provider === ATLAS_EXECUTOR.providerCapability) {
|
|
2274
2637
|
if (!ATLAS_EXECUTOR.capabilityRefPattern.test(resource)) {
|
|
2275
2638
|
report(ATLAS_EXECUTOR.capabilityRefInvalid, resource);
|
|
2276
2639
|
}
|
|
2277
2640
|
} else if (provider === ATLAS_EXECUTOR.providerAgent && resource === ATLAS_EXECUTOR.agentResource) {
|
|
2641
|
+
refusedKeys = ATLAS_EXECUTOR.paramRefused.agentKeys;
|
|
2278
2642
|
const agent = q2.agent;
|
|
2279
|
-
if (typeof agent !== "string" || agent === "") {
|
|
2643
|
+
if (typeof agent !== "string" || agent.trim() === "") {
|
|
2280
2644
|
report(ATLAS_EXECUTOR.agentMissing);
|
|
2281
2645
|
} else if (agent.includes(TEMPLATE_ACTION_OPEN)) {
|
|
2282
2646
|
report(ATLAS_EXECUTOR.agentNotLiteral);
|
|
2283
2647
|
}
|
|
2284
|
-
const
|
|
2285
|
-
const
|
|
2286
|
-
const hasPrompt = prompt !== void 0 && prompt !== null && prompt !== "";
|
|
2287
|
-
const hasTemplate = promptTemplate !== void 0 && promptTemplate !== null && promptTemplate !== "";
|
|
2648
|
+
const hasPrompt = atlasTextPresent(q2.prompt);
|
|
2649
|
+
const hasTemplate = atlasTextPresent(q2.prompt_template);
|
|
2288
2650
|
if (!hasPrompt && !hasTemplate) report(ATLAS_EXECUTOR.promptMissing);
|
|
2289
2651
|
else if (hasPrompt && hasTemplate) report(ATLAS_EXECUTOR.promptBoth);
|
|
2652
|
+
if (anyTemplate(q2.model)) report(ATLAS_EXECUTOR.modelNotLiteral);
|
|
2290
2653
|
} else {
|
|
2291
2654
|
report(ATLAS_EXECUTOR.operationUnknown, executor);
|
|
2292
2655
|
return;
|
|
2293
2656
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2657
|
+
if (anyTemplate(q2.capabilities)) report(ATLAS_EXECUTOR.capabilitiesNotLiteral);
|
|
2658
|
+
const refused = refusedKeys.filter((key) => Object.prototype.hasOwnProperty.call(q2, key)).sort();
|
|
2659
|
+
if (refused.length > 0) report(ATLAS_EXECUTOR.paramRefused, refused.join(", "));
|
|
2660
|
+
}
|
|
2661
|
+
function anyTemplate(v) {
|
|
2662
|
+
if (typeof v === "string") return v.includes(TEMPLATE_ACTION_OPEN);
|
|
2663
|
+
if (Array.isArray(v)) return v.some(anyTemplate);
|
|
2664
|
+
if (isRecord(v)) return Object.values(v).some(anyTemplate);
|
|
2665
|
+
return false;
|
|
2666
|
+
}
|
|
2667
|
+
function atlasTextPresent(v) {
|
|
2668
|
+
if (v === void 0 || v === null) return false;
|
|
2669
|
+
return typeof v !== "string" || v.trim() !== "";
|
|
2298
2670
|
}
|
|
2299
2671
|
function checkFunctionOperation(executor, field, stepID, templated, issues) {
|
|
2300
2672
|
if (templated) return;
|
|
@@ -2319,7 +2691,9 @@ function validateExecutors(flow, issues) {
|
|
|
2319
2691
|
const step = rawStep;
|
|
2320
2692
|
const executor = issues.stringOf(step, "executor", `steps.${stepID}`);
|
|
2321
2693
|
if (executor !== null && executor !== "") {
|
|
2322
|
-
|
|
2694
|
+
if (!checkRemovedSurfaces(executor, step.query, `steps.${stepID}`, stepID, issues)) {
|
|
2695
|
+
checkExecutor(executor, `steps.${stepID}.executor`, stepID, issues);
|
|
2696
|
+
}
|
|
2323
2697
|
checkAtlasStep(executor, step.query, `steps.${stepID}`, stepID, issues);
|
|
2324
2698
|
}
|
|
2325
2699
|
const loop = step.loop;
|
|
@@ -2331,12 +2705,14 @@ function validateExecutors(flow, issues) {
|
|
|
2331
2705
|
const subID = issues.stringOf(subStep, "id", subPath) ?? String(i);
|
|
2332
2706
|
const subExecutor = issues.stringOf(subStep, "executor", subPath);
|
|
2333
2707
|
if (subExecutor !== null && subExecutor !== "") {
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2708
|
+
if (!checkRemovedSurfaces(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues)) {
|
|
2709
|
+
checkExecutor(
|
|
2710
|
+
subExecutor,
|
|
2711
|
+
`steps.${stepID}.loop.steps[${i}].executor`,
|
|
2712
|
+
`${stepID}.${subID}`,
|
|
2713
|
+
issues
|
|
2714
|
+
);
|
|
2715
|
+
}
|
|
2340
2716
|
checkAtlasStep(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues);
|
|
2341
2717
|
}
|
|
2342
2718
|
});
|
|
@@ -3980,6 +4356,37 @@ function validateInputSchema(flow, issues) {
|
|
|
3980
4356
|
validateSchemaDefinition(flow.input_schema, "input_schema", issues);
|
|
3981
4357
|
}
|
|
3982
4358
|
|
|
4359
|
+
// src/validators/reservedInputs.ts
|
|
4360
|
+
function formatField(format, name) {
|
|
4361
|
+
return format.replace("%s", () => name);
|
|
4362
|
+
}
|
|
4363
|
+
function validateReservedInputNames(flow, issues) {
|
|
4364
|
+
const rule = RESERVED_INPUT_NAMES;
|
|
4365
|
+
const report = (name, fieldFormat) => {
|
|
4366
|
+
issues.error({
|
|
4367
|
+
field: formatField(fieldFormat, name),
|
|
4368
|
+
message: rule.messageFormat.replace("%s", () => JSON.stringify(name)),
|
|
4369
|
+
code: rule.code,
|
|
4370
|
+
suggestion: rule.suggestion
|
|
4371
|
+
});
|
|
4372
|
+
};
|
|
4373
|
+
const query = flow.query;
|
|
4374
|
+
if (isRecord(query)) {
|
|
4375
|
+
for (const name of Object.keys(query).sort()) {
|
|
4376
|
+
if (name.startsWith(rule.prefix)) report(name, rule.queryFieldFormat);
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
const schema = flow.input_schema;
|
|
4380
|
+
const fields = isRecord(schema) ? schema.fields : void 0;
|
|
4381
|
+
if (!Array.isArray(fields)) return;
|
|
4382
|
+
for (const f of fields) {
|
|
4383
|
+
if (!isRecord(f)) continue;
|
|
4384
|
+
if (typeof f.name === "string" && f.name.startsWith(rule.prefix)) {
|
|
4385
|
+
report(f.name, rule.schemaFieldFormat);
|
|
4386
|
+
}
|
|
4387
|
+
}
|
|
4388
|
+
}
|
|
4389
|
+
|
|
3983
4390
|
// src/validators/outputSchema.ts
|
|
3984
4391
|
function validateOutputSchemas(flow, issues) {
|
|
3985
4392
|
const steps = flow.steps;
|
|
@@ -5094,7 +5501,7 @@ var CODE2 = "server_owned_query_key";
|
|
|
5094
5501
|
var KEY_QUERY = "query";
|
|
5095
5502
|
var KEY_ID = "id";
|
|
5096
5503
|
var SERVER_OWNED = new Set(SERVER_OWNED_QUERY_KEYS.keys);
|
|
5097
|
-
function
|
|
5504
|
+
function formatField2(format, ...args) {
|
|
5098
5505
|
let i = 0;
|
|
5099
5506
|
return format.replace(/%s/g, () => args[i++] ?? "");
|
|
5100
5507
|
}
|
|
@@ -5112,7 +5519,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
|
|
|
5112
5519
|
issues,
|
|
5113
5520
|
stepID,
|
|
5114
5521
|
key,
|
|
5115
|
-
|
|
5522
|
+
formatField2(SERVER_OWNED_QUERY_KEYS.stepFieldFormat, stepID, key)
|
|
5116
5523
|
);
|
|
5117
5524
|
}
|
|
5118
5525
|
}
|
|
@@ -5126,7 +5533,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
|
|
|
5126
5533
|
issues,
|
|
5127
5534
|
stepID,
|
|
5128
5535
|
key,
|
|
5129
|
-
|
|
5536
|
+
formatField2(SERVER_OWNED_QUERY_KEYS.loopStepFieldFormat, stepID, subID, key)
|
|
5130
5537
|
);
|
|
5131
5538
|
}
|
|
5132
5539
|
}
|
|
@@ -5143,9 +5550,9 @@ function refuse(issues, stepId, key, field) {
|
|
|
5143
5550
|
}
|
|
5144
5551
|
|
|
5145
5552
|
// src/validators/goUrl.ts
|
|
5146
|
-
var
|
|
5147
|
-
var GO_TRIM_SPACE_RE = new RegExp(`^[${
|
|
5148
|
-
function
|
|
5553
|
+
var GO_SPACE2 = "\\t\\n\\v\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000";
|
|
5554
|
+
var GO_TRIM_SPACE_RE = new RegExp(`^[${GO_SPACE2}]+|[${GO_SPACE2}]+$`, "g");
|
|
5555
|
+
function goTrimSpace2(s) {
|
|
5149
5556
|
return s.replace(GO_TRIM_SPACE_RE, "");
|
|
5150
5557
|
}
|
|
5151
5558
|
function goToLower(s) {
|
|
@@ -5368,7 +5775,7 @@ function goQueryKeys(rawQuery) {
|
|
|
5368
5775
|
return keys;
|
|
5369
5776
|
}
|
|
5370
5777
|
function goEndpointOrigin(raw, defaultPorts, protocolSeparator) {
|
|
5371
|
-
const trimmed =
|
|
5778
|
+
const trimmed = goTrimSpace2(raw);
|
|
5372
5779
|
const u = goParseSchemeHost(trimmed);
|
|
5373
5780
|
if (u === null || u.scheme === "" || u.host === "") {
|
|
5374
5781
|
return goToLower(trimmed.replace(/\/+$/, ""));
|
|
@@ -5395,7 +5802,7 @@ function own(m, key) {
|
|
|
5395
5802
|
if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
|
|
5396
5803
|
return m[key];
|
|
5397
5804
|
}
|
|
5398
|
-
function
|
|
5805
|
+
function formatField3(format, ...args) {
|
|
5399
5806
|
let i = 0;
|
|
5400
5807
|
return format.replace(/%s/g, () => args[i++] ?? "");
|
|
5401
5808
|
}
|
|
@@ -5417,14 +5824,14 @@ function credentialEndpointSteps(flow, issues) {
|
|
|
5417
5824
|
out.push({
|
|
5418
5825
|
executor: issues.stringOf(step, KEY_EXECUTOR, `steps.${stepId}`) ?? "",
|
|
5419
5826
|
query: own(step, KEY_QUERY2),
|
|
5420
|
-
field: (key) =>
|
|
5827
|
+
field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.stepFieldFormat, stepId, key)
|
|
5421
5828
|
});
|
|
5422
5829
|
for (const sub of loopSubStepsOfStep(stepId, step)) {
|
|
5423
5830
|
const subId = issues.stringOf(sub.raw, KEY_ID2, sub.basePath) ?? "";
|
|
5424
5831
|
out.push({
|
|
5425
5832
|
executor: issues.stringOf(sub.raw, KEY_EXECUTOR, sub.basePath) ?? "",
|
|
5426
5833
|
query: own(sub.raw, KEY_QUERY2),
|
|
5427
|
-
field: (key) =>
|
|
5834
|
+
field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.loopStepFieldFormat, stepId, subId, key)
|
|
5428
5835
|
});
|
|
5429
5836
|
}
|
|
5430
5837
|
}
|
|
@@ -5488,7 +5895,7 @@ function validateAI(flow, steps, issues) {
|
|
|
5488
5895
|
if ((stepsUsing.get(provider) ?? 0) > 0 && (stepsWithoutOwnKey.get(provider) ?? 0) === 0) {
|
|
5489
5896
|
continue;
|
|
5490
5897
|
}
|
|
5491
|
-
warnStoredShape(issues,
|
|
5898
|
+
warnStoredShape(issues, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, provider), provider);
|
|
5492
5899
|
}
|
|
5493
5900
|
}
|
|
5494
5901
|
function warnStoredShape(issues, field, provider) {
|
|
@@ -5535,7 +5942,7 @@ function familySecret(flow, family, step, issues) {
|
|
|
5535
5942
|
if (apiKey !== "" && listHas(family.secretParams, family.configApiKeyParam)) {
|
|
5536
5943
|
return {
|
|
5537
5944
|
envName: serverEnvRef(family, apiKey),
|
|
5538
|
-
field:
|
|
5945
|
+
field: formatField3(
|
|
5539
5946
|
CREDENTIAL_ENDPOINT_PAIRING.executorConfigKeyFieldFormat,
|
|
5540
5947
|
configKey,
|
|
5541
5948
|
CREDENTIAL_ENDPOINT_PAIRING.executorConfigApiKeyField
|
|
@@ -5548,7 +5955,7 @@ function familySecret(flow, family, step, issues) {
|
|
|
5548
5955
|
if (v !== null) {
|
|
5549
5956
|
return {
|
|
5550
5957
|
envName: serverEnvRef(family, v),
|
|
5551
|
-
field:
|
|
5958
|
+
field: formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key)
|
|
5552
5959
|
};
|
|
5553
5960
|
}
|
|
5554
5961
|
}
|
|
@@ -5574,13 +5981,13 @@ function familyAuthorEndpoint(flow, family, step, issues) {
|
|
|
5574
5981
|
if (inst === null) continue;
|
|
5575
5982
|
const baseUrl = configStringField(inst, configKey, CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlField, issues);
|
|
5576
5983
|
if (baseUrl !== "" && listHas(family.endpointParams, family.configBaseUrlParam)) {
|
|
5577
|
-
return decide(baseUrl,
|
|
5984
|
+
return decide(baseUrl, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, configKey));
|
|
5578
5985
|
}
|
|
5579
5986
|
const extra = own(inst, EXECUTOR_CONFIG_ENV_SCOPES.extraKey);
|
|
5580
5987
|
for (const key of family.endpointParams) {
|
|
5581
5988
|
const v = nonEmptyEndpoint(extra, key);
|
|
5582
5989
|
if (v !== null)
|
|
5583
|
-
return decide(v,
|
|
5990
|
+
return decide(v, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key));
|
|
5584
5991
|
}
|
|
5585
5992
|
}
|
|
5586
5993
|
return null;
|
|
@@ -5603,230 +6010,6 @@ function validateFamilies(flow, steps, issues) {
|
|
|
5603
6010
|
}
|
|
5604
6011
|
}
|
|
5605
6012
|
|
|
5606
|
-
// src/validators/exons.ts
|
|
5607
|
-
import { isMap as isMap2, isScalar as isScalar2, isSeq as isSeq2, parseAllDocuments } from "yaml";
|
|
5608
|
-
var CODE_PARSE_FAILED = "orchestrator_exons_parse_failed";
|
|
5609
|
-
var CODE_NO_PROVIDER = "orchestrator_exons_no_provider";
|
|
5610
|
-
var CODE_RESOURCES = "exons_resources_unhonoured";
|
|
5611
|
-
var CODE_TOOL_WITHHELD = "orchestrator_tool_withheld";
|
|
5612
|
-
var EXONS_OPEN_DELIM = "{~";
|
|
5613
|
-
var EXONS_LEGACY_CONFIG_OPEN = "{~exons.config~}";
|
|
5614
|
-
var UTF8_BOM = "\uFEFF";
|
|
5615
|
-
var MAX_ALIAS_COUNT2 = 100;
|
|
5616
|
-
var UNREAD = {
|
|
5617
|
-
parseError: null,
|
|
5618
|
-
specRead: false,
|
|
5619
|
-
hasSpec: false,
|
|
5620
|
-
provider: "",
|
|
5621
|
-
toolsAllowDeclared: false,
|
|
5622
|
-
toolsAllow: [],
|
|
5623
|
-
resources: []
|
|
5624
|
-
};
|
|
5625
|
-
var GO_SPACE2 = "\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000";
|
|
5626
|
-
var GO_TRIM_SPACE = new RegExp(`^[${GO_SPACE2}]+|[${GO_SPACE2}]+$`, "g");
|
|
5627
|
-
function goTrimSpace2(s) {
|
|
5628
|
-
return s.replace(GO_TRIM_SPACE, "");
|
|
5629
|
-
}
|
|
5630
|
-
function extractExonsFrontmatter(source) {
|
|
5631
|
-
const delim = EXONS.frontmatterDelimiter;
|
|
5632
|
-
let start = source.startsWith(UTF8_BOM) ? source.slice(UTF8_BOM.length) : source;
|
|
5633
|
-
start = start.replace(/^[ \t]+/, "");
|
|
5634
|
-
if (start.startsWith(EXONS_LEGACY_CONFIG_OPEN)) {
|
|
5635
|
-
return {
|
|
5636
|
-
frontmatter: "",
|
|
5637
|
-
hasFrontmatter: false,
|
|
5638
|
-
parseError: "legacy JSON config block detected; use YAML frontmatter"
|
|
5639
|
-
};
|
|
5640
|
-
}
|
|
5641
|
-
if (!start.startsWith(delim)) return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
5642
|
-
let rest = start.slice(delim.length);
|
|
5643
|
-
if (rest.startsWith("\n")) rest = rest.slice(1);
|
|
5644
|
-
else if (rest.startsWith("\r\n")) rest = rest.slice(2);
|
|
5645
|
-
else return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
5646
|
-
let pos = 0;
|
|
5647
|
-
while (pos <= rest.length) {
|
|
5648
|
-
const line = rest.slice(pos);
|
|
5649
|
-
if (line.startsWith(delim)) {
|
|
5650
|
-
const after = line.slice(delim.length);
|
|
5651
|
-
if (after === "" || after[0] === "\n" || after[0] === "\r") {
|
|
5652
|
-
return {
|
|
5653
|
-
frontmatter: goTrimSpace2(rest.slice(0, pos)),
|
|
5654
|
-
hasFrontmatter: true,
|
|
5655
|
-
parseError: null
|
|
5656
|
-
};
|
|
5657
|
-
}
|
|
5658
|
-
}
|
|
5659
|
-
const nl = line.indexOf("\n");
|
|
5660
|
-
if (nl < 0) break;
|
|
5661
|
-
pos += nl + 1;
|
|
5662
|
-
}
|
|
5663
|
-
return {
|
|
5664
|
-
frontmatter: "",
|
|
5665
|
-
hasFrontmatter: true,
|
|
5666
|
-
parseError: "YAML frontmatter not properly closed"
|
|
5667
|
-
};
|
|
5668
|
-
}
|
|
5669
|
-
function retagScalars(node) {
|
|
5670
|
-
if (isMap2(node)) {
|
|
5671
|
-
for (const pair of node.items) {
|
|
5672
|
-
retagScalars(pair.key);
|
|
5673
|
-
retagScalars(pair.value);
|
|
5674
|
-
}
|
|
5675
|
-
} else if (isSeq2(node)) {
|
|
5676
|
-
for (const item of node.items) retagScalars(item);
|
|
5677
|
-
} else if (isScalar2(node) && (typeof node.value === "number" || typeof node.value === "boolean") && typeof node.source === "string") {
|
|
5678
|
-
node.value = node.source;
|
|
5679
|
-
}
|
|
5680
|
-
}
|
|
5681
|
-
var DecodeError = class extends Error {
|
|
5682
|
-
};
|
|
5683
|
-
function goString(v) {
|
|
5684
|
-
if (v === null || v === void 0) return "";
|
|
5685
|
-
if (isString(v)) return v;
|
|
5686
|
-
throw new DecodeError("not a string");
|
|
5687
|
-
}
|
|
5688
|
-
function goStringList(v) {
|
|
5689
|
-
if (v === null || v === void 0) return null;
|
|
5690
|
-
if (!isArray(v)) throw new DecodeError("not a list");
|
|
5691
|
-
return v.filter((item) => item !== null).map(goString);
|
|
5692
|
-
}
|
|
5693
|
-
function goStruct(v) {
|
|
5694
|
-
if (v === null || v === void 0) return null;
|
|
5695
|
-
if (!isRecord(v)) throw new DecodeError("not a mapping");
|
|
5696
|
-
return v;
|
|
5697
|
-
}
|
|
5698
|
-
function decodeSpecFields(frontmatter) {
|
|
5699
|
-
let value;
|
|
5700
|
-
try {
|
|
5701
|
-
const docs = parseAllDocuments(frontmatter, { merge: true });
|
|
5702
|
-
const doc = Array.isArray(docs) ? docs[0] : void 0;
|
|
5703
|
-
if (doc === void 0) {
|
|
5704
|
-
value = null;
|
|
5705
|
-
} else {
|
|
5706
|
-
if (doc.errors.length > 0) return null;
|
|
5707
|
-
retagScalars(doc.contents);
|
|
5708
|
-
value = doc.toJS({ maxAliasCount: MAX_ALIAS_COUNT2 });
|
|
5709
|
-
}
|
|
5710
|
-
} catch {
|
|
5711
|
-
return null;
|
|
5712
|
-
}
|
|
5713
|
-
try {
|
|
5714
|
-
const root = goStruct(value) ?? {};
|
|
5715
|
-
const execution = goStruct(root.execution);
|
|
5716
|
-
const tools = goStruct(root.tools);
|
|
5717
|
-
const requirements = goStruct(root.requirements);
|
|
5718
|
-
const allow = tools === null ? null : goStringList(tools.allow);
|
|
5719
|
-
let resources = [];
|
|
5720
|
-
if (requirements !== null) {
|
|
5721
|
-
const raw = requirements.resources;
|
|
5722
|
-
if (raw !== null && raw !== void 0) {
|
|
5723
|
-
if (!isArray(raw)) throw new DecodeError("not a list");
|
|
5724
|
-
resources = raw.filter((entry) => entry !== null).map((entry) => {
|
|
5725
|
-
const r = goStruct(entry) ?? {};
|
|
5726
|
-
return { ref: goString(r.ref), kind: goString(r.kind), scope: goString(r.scope) };
|
|
5727
|
-
});
|
|
5728
|
-
}
|
|
5729
|
-
}
|
|
5730
|
-
return {
|
|
5731
|
-
provider: execution === null ? "" : goString(execution.provider),
|
|
5732
|
-
toolsAllowDeclared: allow !== null,
|
|
5733
|
-
toolsAllow: allow ?? [],
|
|
5734
|
-
resources
|
|
5735
|
-
};
|
|
5736
|
-
} catch (e) {
|
|
5737
|
-
if (e instanceof DecodeError) return null;
|
|
5738
|
-
throw e;
|
|
5739
|
-
}
|
|
5740
|
-
}
|
|
5741
|
-
function inspectExonsFrontmatter(source) {
|
|
5742
|
-
const fm = extractExonsFrontmatter(source);
|
|
5743
|
-
if (fm.parseError !== null) return { ...UNREAD, parseError: fm.parseError };
|
|
5744
|
-
if (!fm.hasFrontmatter || fm.frontmatter === "") return { ...UNREAD, specRead: true };
|
|
5745
|
-
if (fm.frontmatter.includes(EXONS_OPEN_DELIM)) return { ...UNREAD };
|
|
5746
|
-
const fields = decodeSpecFields(fm.frontmatter);
|
|
5747
|
-
if (fields === null) return { ...UNREAD };
|
|
5748
|
-
return { parseError: null, specRead: true, hasSpec: true, ...fields };
|
|
5749
|
-
}
|
|
5750
|
-
function validateOrchestratorExons(flow, issues) {
|
|
5751
|
-
const orch = flow.orchestrator;
|
|
5752
|
-
if (!isRecord(orch)) return;
|
|
5753
|
-
const source = issues.stringOf(orch, "exons", "orchestrator");
|
|
5754
|
-
if (source === null || source === "") return;
|
|
5755
|
-
const field = "orchestrator.exons";
|
|
5756
|
-
const report = inspectExonsFrontmatter(source);
|
|
5757
|
-
if (report.parseError !== null) {
|
|
5758
|
-
issues.error({
|
|
5759
|
-
field,
|
|
5760
|
-
code: CODE_PARSE_FAILED,
|
|
5761
|
-
message: `orchestrator: failed to parse exons spec: ${report.parseError}`
|
|
5762
|
-
});
|
|
5763
|
-
return;
|
|
5764
|
-
}
|
|
5765
|
-
if (!report.specRead) return;
|
|
5766
|
-
if (!report.hasSpec) {
|
|
5767
|
-
issues.error({
|
|
5768
|
-
field,
|
|
5769
|
-
code: CODE_PARSE_FAILED,
|
|
5770
|
-
message: "orchestrator: failed to parse exons spec: the document has no frontmatter spec",
|
|
5771
|
-
suggestion: "Start the document with a --- frontmatter block that sets execution.provider"
|
|
5772
|
-
});
|
|
5773
|
-
return;
|
|
5774
|
-
}
|
|
5775
|
-
if (report.provider === "") {
|
|
5776
|
-
issues.error({
|
|
5777
|
-
field,
|
|
5778
|
-
code: CODE_NO_PROVIDER,
|
|
5779
|
-
message: "orchestrator: exons spec must have execution.provider set"
|
|
5780
|
-
});
|
|
5781
|
-
}
|
|
5782
|
-
if (report.resources.length > 0) {
|
|
5783
|
-
const refs = report.resources.map((r) => `${JSON.stringify(r.ref)} (kind ${r.kind})`);
|
|
5784
|
-
issues.error({
|
|
5785
|
-
field,
|
|
5786
|
-
code: CODE_RESOURCES,
|
|
5787
|
-
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("; "),
|
|
5788
|
-
suggestion: "Remove requirements.resources, and narrow the agent with tools.mcp_servers and tools.allow"
|
|
5789
|
-
});
|
|
5790
|
-
}
|
|
5791
|
-
warnOrchestratorToolWithheld(flow, orch, report, issues);
|
|
5792
|
-
}
|
|
5793
|
-
function warnOrchestratorToolWithheld(flow, orch, report, issues) {
|
|
5794
|
-
if (!report.toolsAllowDeclared) return;
|
|
5795
|
-
const cfg = ORCHESTRATOR_TOOL_ALLOW;
|
|
5796
|
-
const exempt = new Set(cfg.lifecycleTools);
|
|
5797
|
-
const signals = typeof orch.enable_signals === "boolean" ? orch.enable_signals : cfg.enableSignalsDefault;
|
|
5798
|
-
if (signals) for (const t of cfg.signalTools) exempt.add(t);
|
|
5799
|
-
const allow = new Set(report.toolsAllow);
|
|
5800
|
-
const withheld = (name) => !allow.has(name) && !exempt.has(name);
|
|
5801
|
-
const warn = (message) => issues.warn({ field: cfg.warningField, code: CODE_TOOL_WITHHELD, message });
|
|
5802
|
-
const named = [];
|
|
5803
|
-
if (isArray(orch.tools)) {
|
|
5804
|
-
orch.tools.forEach((raw, i) => {
|
|
5805
|
-
const name = issues.stringAt(raw, `orchestrator.tools[${i}]`);
|
|
5806
|
-
if (name !== null) named.push(name);
|
|
5807
|
-
});
|
|
5808
|
-
}
|
|
5809
|
-
if (named.length > 0) {
|
|
5810
|
-
for (const name of named) {
|
|
5811
|
-
if (!withheld(name)) continue;
|
|
5812
|
-
warn(
|
|
5813
|
-
`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.`
|
|
5814
|
-
);
|
|
5815
|
-
}
|
|
5816
|
-
return;
|
|
5817
|
-
}
|
|
5818
|
-
if (withheld(cfg.askHumanTool)) {
|
|
5819
|
-
warn(
|
|
5820
|
-
`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.`
|
|
5821
|
-
);
|
|
5822
|
-
}
|
|
5823
|
-
if (isRecord(flow.campaign) && !cfg.campaignTools.some((name) => !withheld(name))) {
|
|
5824
|
-
warn(
|
|
5825
|
-
`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.`
|
|
5826
|
-
);
|
|
5827
|
-
}
|
|
5828
|
-
}
|
|
5829
|
-
|
|
5830
6013
|
// src/validators/complianceResidency.ts
|
|
5831
6014
|
function own2(m, key) {
|
|
5832
6015
|
if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
|
|
@@ -5840,7 +6023,7 @@ function sprintf(format, ...args) {
|
|
|
5840
6023
|
});
|
|
5841
6024
|
}
|
|
5842
6025
|
function literalOrEmpty(s) {
|
|
5843
|
-
const t =
|
|
6026
|
+
const t = goTrimSpace(s);
|
|
5844
6027
|
return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
|
|
5845
6028
|
}
|
|
5846
6029
|
function euOnlyResidency(flow, issues) {
|
|
@@ -5855,7 +6038,7 @@ function euOnlyResidency(flow, issues) {
|
|
|
5855
6038
|
}
|
|
5856
6039
|
if (codes.length === 0) return null;
|
|
5857
6040
|
const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
|
|
5858
|
-
return codes.every((c) => eu.has(
|
|
6041
|
+
return codes.every((c) => eu.has(goTrimSpace(c).toUpperCase())) ? codes : null;
|
|
5859
6042
|
}
|
|
5860
6043
|
function aiProvider(executor) {
|
|
5861
6044
|
const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
|
|
@@ -5871,7 +6054,7 @@ function isRegionLane(provider) {
|
|
|
5871
6054
|
}
|
|
5872
6055
|
function nonBlankString(m, key) {
|
|
5873
6056
|
const v = own2(m, key);
|
|
5874
|
-
return typeof v === "string" &&
|
|
6057
|
+
return typeof v === "string" && goTrimSpace(v) !== "";
|
|
5875
6058
|
}
|
|
5876
6059
|
function queryEnforcesRegion(query) {
|
|
5877
6060
|
const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
|
|
@@ -5883,7 +6066,7 @@ function flowDirectsEndpoint(flow, provider, issues) {
|
|
|
5883
6066
|
const inst = own2(own2(flow, "executor_config"), key);
|
|
5884
6067
|
if (!isRecord(inst)) return false;
|
|
5885
6068
|
const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
|
|
5886
|
-
return baseUrl !== null &&
|
|
6069
|
+
return baseUrl !== null && goTrimSpace(baseUrl) !== "";
|
|
5887
6070
|
}
|
|
5888
6071
|
function callPinsEndpoint(flow, provider, query, issues) {
|
|
5889
6072
|
if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
|
|
@@ -5956,7 +6139,7 @@ function warnOrchestrator(flow, issues, warn) {
|
|
|
5956
6139
|
const provider = literalOrEmpty(report.provider);
|
|
5957
6140
|
if (!isRegionLane(provider)) return;
|
|
5958
6141
|
const region = issues.stringOf(orch, "region", "orchestrator");
|
|
5959
|
-
if (region !== null &&
|
|
6142
|
+
if (region !== null && goTrimSpace(region) !== "") return;
|
|
5960
6143
|
if (orch.enforce_region === true) return;
|
|
5961
6144
|
if (flowDirectsEndpoint(flow, provider, issues)) return;
|
|
5962
6145
|
warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
|
|
@@ -6122,7 +6305,7 @@ function asFileRef(v) {
|
|
|
6122
6305
|
};
|
|
6123
6306
|
}
|
|
6124
6307
|
function isTextualMediaType(mediaType) {
|
|
6125
|
-
const base = goToLower(
|
|
6308
|
+
const base = goToLower(goTrimSpace2((mediaType.split(";")[0] ?? "").toString()));
|
|
6126
6309
|
if (base.startsWith("text/")) return true;
|
|
6127
6310
|
if (base.endsWith("+json") || base.endsWith("+xml")) return true;
|
|
6128
6311
|
return TEXTUAL_MEDIA_BASES.has(base);
|
|
@@ -6226,7 +6409,7 @@ var Walker = class _Walker {
|
|
|
6226
6409
|
}
|
|
6227
6410
|
}
|
|
6228
6411
|
const title = this.s(ex, "title", path);
|
|
6229
|
-
if (
|
|
6412
|
+
if (goTrimSpace2(title) === "") {
|
|
6230
6413
|
this.err(
|
|
6231
6414
|
"example_title_missing",
|
|
6232
6415
|
`${path}.title`,
|
|
@@ -6243,7 +6426,7 @@ var Walker = class _Walker {
|
|
|
6243
6426
|
}
|
|
6244
6427
|
}
|
|
6245
6428
|
const guidance = this.s(ex, "guidance", path);
|
|
6246
|
-
if (
|
|
6429
|
+
if (goTrimSpace2(guidance) === "") {
|
|
6247
6430
|
this.warn(
|
|
6248
6431
|
"example_guidance_missing",
|
|
6249
6432
|
`${path}.guidance`,
|
|
@@ -6670,7 +6853,7 @@ var Walker = class _Walker {
|
|
|
6670
6853
|
}
|
|
6671
6854
|
const rubric = this.s(e, "rubric", path);
|
|
6672
6855
|
if (rubric !== "") {
|
|
6673
|
-
if (
|
|
6856
|
+
if (goTrimSpace2(rubric) === "") {
|
|
6674
6857
|
this.err(
|
|
6675
6858
|
"example_rubric_empty",
|
|
6676
6859
|
`${path}.rubric`,
|
|
@@ -6725,7 +6908,7 @@ var Walker = class _Walker {
|
|
|
6725
6908
|
this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
|
|
6726
6909
|
}
|
|
6727
6910
|
mustNot.forEach((item, j) => {
|
|
6728
|
-
if (
|
|
6911
|
+
if (goTrimSpace2(item) === "" || runeCount(item) > L.maxMustNotRunes) {
|
|
6729
6912
|
this.err("example_must_not_invalid", `${path}.must_not[${j}]`, mustNotMsg);
|
|
6730
6913
|
}
|
|
6731
6914
|
});
|
|
@@ -7280,6 +7463,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
7280
7463
|
const f = flow;
|
|
7281
7464
|
validateBasicStructure(f, issues);
|
|
7282
7465
|
validateRetiredKeys(f, issues);
|
|
7466
|
+
validateRemovedFlowKeys(f, issues);
|
|
7283
7467
|
validateExecutors(f, issues);
|
|
7284
7468
|
validateQuerySchema(f, issues);
|
|
7285
7469
|
validateResponseExpectations(f, issues);
|
|
@@ -7291,6 +7475,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
7291
7475
|
validateOrchestratorCampaign(f, issues, opts);
|
|
7292
7476
|
validateCredentialBindings(f, issues);
|
|
7293
7477
|
validateInputSchema(f, issues);
|
|
7478
|
+
validateReservedInputNames(f, issues);
|
|
7294
7479
|
validateOutputSchemas(f, issues);
|
|
7295
7480
|
validateQualityGates(f, issues);
|
|
7296
7481
|
validateProcessingOperations(f, issues);
|