@vaudience/aigentflow-flow-validator 0.26.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 +33 -4
- package/README.md +2 -1
- package/dist/cli.js +342 -255
- package/dist/index.cjs +337 -245
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +337 -245
- 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: "${",
|
|
@@ -2111,13 +2134,22 @@ var ORCHESTRATOR_TOOL_ALLOW = {
|
|
|
2111
2134
|
campaignTools: aigentflow_spec_default.orchestratorToolAllow.campaignTools
|
|
2112
2135
|
};
|
|
2113
2136
|
var EXONS = {
|
|
2114
|
-
/** A step's document is judged only on an executor with this prefix. */
|
|
2115
|
-
executorPrefix: aigentflow_spec_default.exons.executorPrefix,
|
|
2116
|
-
/** The step `query` parameter that carries the document. */
|
|
2117
|
-
documentParam: aigentflow_spec_default.exons.documentParam,
|
|
2118
2137
|
/** The YAML frontmatter delimiter line. */
|
|
2119
2138
|
frontmatterDelimiter: aigentflow_spec_default.exons.frontmatterDelimiter
|
|
2120
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
|
+
};
|
|
2121
2153
|
var EXECUTOR_CONFIG_ENV_SCOPES = {
|
|
2122
2154
|
referencePrefix: aigentflow_spec_default.executorConfigEnvScopes.referencePrefix,
|
|
2123
2155
|
referenceSuffix: aigentflow_spec_default.executorConfigEnvScopes.referenceSuffix,
|
|
@@ -2243,6 +2275,230 @@ var RESERVED_INPUT_NAMES = {
|
|
|
2243
2275
|
schemaFieldFormat: aigentflow_spec_default.reservedInputNames.schemaFieldFormat
|
|
2244
2276
|
};
|
|
2245
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
|
+
|
|
2246
2502
|
// src/validators/executors.ts
|
|
2247
2503
|
var SCHEME_SEPARATOR = "://";
|
|
2248
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.`;
|
|
@@ -2305,6 +2561,56 @@ function checkExecutor(executor, field, stepID, issues) {
|
|
|
2305
2561
|
}
|
|
2306
2562
|
checkFunctionOperation(executor, field, stepID, templated, issues);
|
|
2307
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
|
+
}
|
|
2308
2614
|
function checkAtlasStep(executor, query, stepField, stepID, issues) {
|
|
2309
2615
|
if (executor.includes(TEMPLATE_ACTION_OPEN)) return;
|
|
2310
2616
|
const prefix = `${ATLAS_EXECUTOR.scheme}://`;
|
|
@@ -2385,7 +2691,9 @@ function validateExecutors(flow, issues) {
|
|
|
2385
2691
|
const step = rawStep;
|
|
2386
2692
|
const executor = issues.stringOf(step, "executor", `steps.${stepID}`);
|
|
2387
2693
|
if (executor !== null && executor !== "") {
|
|
2388
|
-
|
|
2694
|
+
if (!checkRemovedSurfaces(executor, step.query, `steps.${stepID}`, stepID, issues)) {
|
|
2695
|
+
checkExecutor(executor, `steps.${stepID}.executor`, stepID, issues);
|
|
2696
|
+
}
|
|
2389
2697
|
checkAtlasStep(executor, step.query, `steps.${stepID}`, stepID, issues);
|
|
2390
2698
|
}
|
|
2391
2699
|
const loop = step.loop;
|
|
@@ -2397,12 +2705,14 @@ function validateExecutors(flow, issues) {
|
|
|
2397
2705
|
const subID = issues.stringOf(subStep, "id", subPath) ?? String(i);
|
|
2398
2706
|
const subExecutor = issues.stringOf(subStep, "executor", subPath);
|
|
2399
2707
|
if (subExecutor !== null && subExecutor !== "") {
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
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
|
+
}
|
|
2406
2716
|
checkAtlasStep(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues);
|
|
2407
2717
|
}
|
|
2408
2718
|
});
|
|
@@ -5240,9 +5550,9 @@ function refuse(issues, stepId, key, field) {
|
|
|
5240
5550
|
}
|
|
5241
5551
|
|
|
5242
5552
|
// src/validators/goUrl.ts
|
|
5243
|
-
var
|
|
5244
|
-
var GO_TRIM_SPACE_RE = new RegExp(`^[${
|
|
5245
|
-
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) {
|
|
5246
5556
|
return s.replace(GO_TRIM_SPACE_RE, "");
|
|
5247
5557
|
}
|
|
5248
5558
|
function goToLower(s) {
|
|
@@ -5465,7 +5775,7 @@ function goQueryKeys(rawQuery) {
|
|
|
5465
5775
|
return keys;
|
|
5466
5776
|
}
|
|
5467
5777
|
function goEndpointOrigin(raw, defaultPorts, protocolSeparator) {
|
|
5468
|
-
const trimmed =
|
|
5778
|
+
const trimmed = goTrimSpace2(raw);
|
|
5469
5779
|
const u = goParseSchemeHost(trimmed);
|
|
5470
5780
|
if (u === null || u.scheme === "" || u.host === "") {
|
|
5471
5781
|
return goToLower(trimmed.replace(/\/+$/, ""));
|
|
@@ -5700,230 +6010,6 @@ function validateFamilies(flow, steps, issues) {
|
|
|
5700
6010
|
}
|
|
5701
6011
|
}
|
|
5702
6012
|
|
|
5703
|
-
// src/validators/exons.ts
|
|
5704
|
-
import { isMap as isMap2, isScalar as isScalar2, isSeq as isSeq2, parseAllDocuments } from "yaml";
|
|
5705
|
-
var CODE_PARSE_FAILED = "orchestrator_exons_parse_failed";
|
|
5706
|
-
var CODE_NO_PROVIDER = "orchestrator_exons_no_provider";
|
|
5707
|
-
var CODE_RESOURCES = "exons_resources_unhonoured";
|
|
5708
|
-
var CODE_TOOL_WITHHELD = "orchestrator_tool_withheld";
|
|
5709
|
-
var EXONS_OPEN_DELIM = "{~";
|
|
5710
|
-
var EXONS_LEGACY_CONFIG_OPEN = "{~exons.config~}";
|
|
5711
|
-
var UTF8_BOM = "\uFEFF";
|
|
5712
|
-
var MAX_ALIAS_COUNT2 = 100;
|
|
5713
|
-
var UNREAD = {
|
|
5714
|
-
parseError: null,
|
|
5715
|
-
specRead: false,
|
|
5716
|
-
hasSpec: false,
|
|
5717
|
-
provider: "",
|
|
5718
|
-
toolsAllowDeclared: false,
|
|
5719
|
-
toolsAllow: [],
|
|
5720
|
-
resources: []
|
|
5721
|
-
};
|
|
5722
|
-
var GO_SPACE2 = "\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000";
|
|
5723
|
-
var GO_TRIM_SPACE = new RegExp(`^[${GO_SPACE2}]+|[${GO_SPACE2}]+$`, "g");
|
|
5724
|
-
function goTrimSpace2(s) {
|
|
5725
|
-
return s.replace(GO_TRIM_SPACE, "");
|
|
5726
|
-
}
|
|
5727
|
-
function extractExonsFrontmatter(source) {
|
|
5728
|
-
const delim = EXONS.frontmatterDelimiter;
|
|
5729
|
-
let start = source.startsWith(UTF8_BOM) ? source.slice(UTF8_BOM.length) : source;
|
|
5730
|
-
start = start.replace(/^[ \t]+/, "");
|
|
5731
|
-
if (start.startsWith(EXONS_LEGACY_CONFIG_OPEN)) {
|
|
5732
|
-
return {
|
|
5733
|
-
frontmatter: "",
|
|
5734
|
-
hasFrontmatter: false,
|
|
5735
|
-
parseError: "legacy JSON config block detected; use YAML frontmatter"
|
|
5736
|
-
};
|
|
5737
|
-
}
|
|
5738
|
-
if (!start.startsWith(delim)) return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
5739
|
-
let rest = start.slice(delim.length);
|
|
5740
|
-
if (rest.startsWith("\n")) rest = rest.slice(1);
|
|
5741
|
-
else if (rest.startsWith("\r\n")) rest = rest.slice(2);
|
|
5742
|
-
else return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
5743
|
-
let pos = 0;
|
|
5744
|
-
while (pos <= rest.length) {
|
|
5745
|
-
const line = rest.slice(pos);
|
|
5746
|
-
if (line.startsWith(delim)) {
|
|
5747
|
-
const after = line.slice(delim.length);
|
|
5748
|
-
if (after === "" || after[0] === "\n" || after[0] === "\r") {
|
|
5749
|
-
return {
|
|
5750
|
-
frontmatter: goTrimSpace2(rest.slice(0, pos)),
|
|
5751
|
-
hasFrontmatter: true,
|
|
5752
|
-
parseError: null
|
|
5753
|
-
};
|
|
5754
|
-
}
|
|
5755
|
-
}
|
|
5756
|
-
const nl = line.indexOf("\n");
|
|
5757
|
-
if (nl < 0) break;
|
|
5758
|
-
pos += nl + 1;
|
|
5759
|
-
}
|
|
5760
|
-
return {
|
|
5761
|
-
frontmatter: "",
|
|
5762
|
-
hasFrontmatter: true,
|
|
5763
|
-
parseError: "YAML frontmatter not properly closed"
|
|
5764
|
-
};
|
|
5765
|
-
}
|
|
5766
|
-
function retagScalars(node) {
|
|
5767
|
-
if (isMap2(node)) {
|
|
5768
|
-
for (const pair of node.items) {
|
|
5769
|
-
retagScalars(pair.key);
|
|
5770
|
-
retagScalars(pair.value);
|
|
5771
|
-
}
|
|
5772
|
-
} else if (isSeq2(node)) {
|
|
5773
|
-
for (const item of node.items) retagScalars(item);
|
|
5774
|
-
} else if (isScalar2(node) && (typeof node.value === "number" || typeof node.value === "boolean") && typeof node.source === "string") {
|
|
5775
|
-
node.value = node.source;
|
|
5776
|
-
}
|
|
5777
|
-
}
|
|
5778
|
-
var DecodeError = class extends Error {
|
|
5779
|
-
};
|
|
5780
|
-
function goString(v) {
|
|
5781
|
-
if (v === null || v === void 0) return "";
|
|
5782
|
-
if (isString(v)) return v;
|
|
5783
|
-
throw new DecodeError("not a string");
|
|
5784
|
-
}
|
|
5785
|
-
function goStringList(v) {
|
|
5786
|
-
if (v === null || v === void 0) return null;
|
|
5787
|
-
if (!isArray(v)) throw new DecodeError("not a list");
|
|
5788
|
-
return v.filter((item) => item !== null).map(goString);
|
|
5789
|
-
}
|
|
5790
|
-
function goStruct(v) {
|
|
5791
|
-
if (v === null || v === void 0) return null;
|
|
5792
|
-
if (!isRecord(v)) throw new DecodeError("not a mapping");
|
|
5793
|
-
return v;
|
|
5794
|
-
}
|
|
5795
|
-
function decodeSpecFields(frontmatter) {
|
|
5796
|
-
let value;
|
|
5797
|
-
try {
|
|
5798
|
-
const docs = parseAllDocuments(frontmatter, { merge: true });
|
|
5799
|
-
const doc = Array.isArray(docs) ? docs[0] : void 0;
|
|
5800
|
-
if (doc === void 0) {
|
|
5801
|
-
value = null;
|
|
5802
|
-
} else {
|
|
5803
|
-
if (doc.errors.length > 0) return null;
|
|
5804
|
-
retagScalars(doc.contents);
|
|
5805
|
-
value = doc.toJS({ maxAliasCount: MAX_ALIAS_COUNT2 });
|
|
5806
|
-
}
|
|
5807
|
-
} catch {
|
|
5808
|
-
return null;
|
|
5809
|
-
}
|
|
5810
|
-
try {
|
|
5811
|
-
const root = goStruct(value) ?? {};
|
|
5812
|
-
const execution = goStruct(root.execution);
|
|
5813
|
-
const tools = goStruct(root.tools);
|
|
5814
|
-
const requirements = goStruct(root.requirements);
|
|
5815
|
-
const allow = tools === null ? null : goStringList(tools.allow);
|
|
5816
|
-
let resources = [];
|
|
5817
|
-
if (requirements !== null) {
|
|
5818
|
-
const raw = requirements.resources;
|
|
5819
|
-
if (raw !== null && raw !== void 0) {
|
|
5820
|
-
if (!isArray(raw)) throw new DecodeError("not a list");
|
|
5821
|
-
resources = raw.filter((entry) => entry !== null).map((entry) => {
|
|
5822
|
-
const r = goStruct(entry) ?? {};
|
|
5823
|
-
return { ref: goString(r.ref), kind: goString(r.kind), scope: goString(r.scope) };
|
|
5824
|
-
});
|
|
5825
|
-
}
|
|
5826
|
-
}
|
|
5827
|
-
return {
|
|
5828
|
-
provider: execution === null ? "" : goString(execution.provider),
|
|
5829
|
-
toolsAllowDeclared: allow !== null,
|
|
5830
|
-
toolsAllow: allow ?? [],
|
|
5831
|
-
resources
|
|
5832
|
-
};
|
|
5833
|
-
} catch (e) {
|
|
5834
|
-
if (e instanceof DecodeError) return null;
|
|
5835
|
-
throw e;
|
|
5836
|
-
}
|
|
5837
|
-
}
|
|
5838
|
-
function inspectExonsFrontmatter(source) {
|
|
5839
|
-
const fm = extractExonsFrontmatter(source);
|
|
5840
|
-
if (fm.parseError !== null) return { ...UNREAD, parseError: fm.parseError };
|
|
5841
|
-
if (!fm.hasFrontmatter || fm.frontmatter === "") return { ...UNREAD, specRead: true };
|
|
5842
|
-
if (fm.frontmatter.includes(EXONS_OPEN_DELIM)) return { ...UNREAD };
|
|
5843
|
-
const fields = decodeSpecFields(fm.frontmatter);
|
|
5844
|
-
if (fields === null) return { ...UNREAD };
|
|
5845
|
-
return { parseError: null, specRead: true, hasSpec: true, ...fields };
|
|
5846
|
-
}
|
|
5847
|
-
function validateOrchestratorExons(flow, issues) {
|
|
5848
|
-
const orch = flow.orchestrator;
|
|
5849
|
-
if (!isRecord(orch)) return;
|
|
5850
|
-
const source = issues.stringOf(orch, "exons", "orchestrator");
|
|
5851
|
-
if (source === null || source === "") return;
|
|
5852
|
-
const field = "orchestrator.exons";
|
|
5853
|
-
const report = inspectExonsFrontmatter(source);
|
|
5854
|
-
if (report.parseError !== null) {
|
|
5855
|
-
issues.error({
|
|
5856
|
-
field,
|
|
5857
|
-
code: CODE_PARSE_FAILED,
|
|
5858
|
-
message: `orchestrator: failed to parse exons spec: ${report.parseError}`
|
|
5859
|
-
});
|
|
5860
|
-
return;
|
|
5861
|
-
}
|
|
5862
|
-
if (!report.specRead) return;
|
|
5863
|
-
if (!report.hasSpec) {
|
|
5864
|
-
issues.error({
|
|
5865
|
-
field,
|
|
5866
|
-
code: CODE_PARSE_FAILED,
|
|
5867
|
-
message: "orchestrator: failed to parse exons spec: the document has no frontmatter spec",
|
|
5868
|
-
suggestion: "Start the document with a --- frontmatter block that sets execution.provider"
|
|
5869
|
-
});
|
|
5870
|
-
return;
|
|
5871
|
-
}
|
|
5872
|
-
if (report.provider === "") {
|
|
5873
|
-
issues.error({
|
|
5874
|
-
field,
|
|
5875
|
-
code: CODE_NO_PROVIDER,
|
|
5876
|
-
message: "orchestrator: exons spec must have execution.provider set"
|
|
5877
|
-
});
|
|
5878
|
-
}
|
|
5879
|
-
if (report.resources.length > 0) {
|
|
5880
|
-
const refs = report.resources.map((r) => `${JSON.stringify(r.ref)} (kind ${r.kind})`);
|
|
5881
|
-
issues.error({
|
|
5882
|
-
field,
|
|
5883
|
-
code: CODE_RESOURCES,
|
|
5884
|
-
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("; "),
|
|
5885
|
-
suggestion: "Remove requirements.resources, and narrow the agent with tools.mcp_servers and tools.allow"
|
|
5886
|
-
});
|
|
5887
|
-
}
|
|
5888
|
-
warnOrchestratorToolWithheld(flow, orch, report, issues);
|
|
5889
|
-
}
|
|
5890
|
-
function warnOrchestratorToolWithheld(flow, orch, report, issues) {
|
|
5891
|
-
if (!report.toolsAllowDeclared) return;
|
|
5892
|
-
const cfg = ORCHESTRATOR_TOOL_ALLOW;
|
|
5893
|
-
const exempt = new Set(cfg.lifecycleTools);
|
|
5894
|
-
const signals = typeof orch.enable_signals === "boolean" ? orch.enable_signals : cfg.enableSignalsDefault;
|
|
5895
|
-
if (signals) for (const t of cfg.signalTools) exempt.add(t);
|
|
5896
|
-
const allow = new Set(report.toolsAllow);
|
|
5897
|
-
const withheld = (name) => !allow.has(name) && !exempt.has(name);
|
|
5898
|
-
const warn = (message) => issues.warn({ field: cfg.warningField, code: CODE_TOOL_WITHHELD, message });
|
|
5899
|
-
const named = [];
|
|
5900
|
-
if (isArray(orch.tools)) {
|
|
5901
|
-
orch.tools.forEach((raw, i) => {
|
|
5902
|
-
const name = issues.stringAt(raw, `orchestrator.tools[${i}]`);
|
|
5903
|
-
if (name !== null) named.push(name);
|
|
5904
|
-
});
|
|
5905
|
-
}
|
|
5906
|
-
if (named.length > 0) {
|
|
5907
|
-
for (const name of named) {
|
|
5908
|
-
if (!withheld(name)) continue;
|
|
5909
|
-
warn(
|
|
5910
|
-
`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.`
|
|
5911
|
-
);
|
|
5912
|
-
}
|
|
5913
|
-
return;
|
|
5914
|
-
}
|
|
5915
|
-
if (withheld(cfg.askHumanTool)) {
|
|
5916
|
-
warn(
|
|
5917
|
-
`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.`
|
|
5918
|
-
);
|
|
5919
|
-
}
|
|
5920
|
-
if (isRecord(flow.campaign) && !cfg.campaignTools.some((name) => !withheld(name))) {
|
|
5921
|
-
warn(
|
|
5922
|
-
`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.`
|
|
5923
|
-
);
|
|
5924
|
-
}
|
|
5925
|
-
}
|
|
5926
|
-
|
|
5927
6013
|
// src/validators/complianceResidency.ts
|
|
5928
6014
|
function own2(m, key) {
|
|
5929
6015
|
if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
|
|
@@ -5937,7 +6023,7 @@ function sprintf(format, ...args) {
|
|
|
5937
6023
|
});
|
|
5938
6024
|
}
|
|
5939
6025
|
function literalOrEmpty(s) {
|
|
5940
|
-
const t =
|
|
6026
|
+
const t = goTrimSpace(s);
|
|
5941
6027
|
return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
|
|
5942
6028
|
}
|
|
5943
6029
|
function euOnlyResidency(flow, issues) {
|
|
@@ -5952,7 +6038,7 @@ function euOnlyResidency(flow, issues) {
|
|
|
5952
6038
|
}
|
|
5953
6039
|
if (codes.length === 0) return null;
|
|
5954
6040
|
const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
|
|
5955
|
-
return codes.every((c) => eu.has(
|
|
6041
|
+
return codes.every((c) => eu.has(goTrimSpace(c).toUpperCase())) ? codes : null;
|
|
5956
6042
|
}
|
|
5957
6043
|
function aiProvider(executor) {
|
|
5958
6044
|
const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
|
|
@@ -5968,7 +6054,7 @@ function isRegionLane(provider) {
|
|
|
5968
6054
|
}
|
|
5969
6055
|
function nonBlankString(m, key) {
|
|
5970
6056
|
const v = own2(m, key);
|
|
5971
|
-
return typeof v === "string" &&
|
|
6057
|
+
return typeof v === "string" && goTrimSpace(v) !== "";
|
|
5972
6058
|
}
|
|
5973
6059
|
function queryEnforcesRegion(query) {
|
|
5974
6060
|
const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
|
|
@@ -5980,7 +6066,7 @@ function flowDirectsEndpoint(flow, provider, issues) {
|
|
|
5980
6066
|
const inst = own2(own2(flow, "executor_config"), key);
|
|
5981
6067
|
if (!isRecord(inst)) return false;
|
|
5982
6068
|
const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
|
|
5983
|
-
return baseUrl !== null &&
|
|
6069
|
+
return baseUrl !== null && goTrimSpace(baseUrl) !== "";
|
|
5984
6070
|
}
|
|
5985
6071
|
function callPinsEndpoint(flow, provider, query, issues) {
|
|
5986
6072
|
if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
|
|
@@ -6053,7 +6139,7 @@ function warnOrchestrator(flow, issues, warn) {
|
|
|
6053
6139
|
const provider = literalOrEmpty(report.provider);
|
|
6054
6140
|
if (!isRegionLane(provider)) return;
|
|
6055
6141
|
const region = issues.stringOf(orch, "region", "orchestrator");
|
|
6056
|
-
if (region !== null &&
|
|
6142
|
+
if (region !== null && goTrimSpace(region) !== "") return;
|
|
6057
6143
|
if (orch.enforce_region === true) return;
|
|
6058
6144
|
if (flowDirectsEndpoint(flow, provider, issues)) return;
|
|
6059
6145
|
warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
|
|
@@ -6219,7 +6305,7 @@ function asFileRef(v) {
|
|
|
6219
6305
|
};
|
|
6220
6306
|
}
|
|
6221
6307
|
function isTextualMediaType(mediaType) {
|
|
6222
|
-
const base = goToLower(
|
|
6308
|
+
const base = goToLower(goTrimSpace2((mediaType.split(";")[0] ?? "").toString()));
|
|
6223
6309
|
if (base.startsWith("text/")) return true;
|
|
6224
6310
|
if (base.endsWith("+json") || base.endsWith("+xml")) return true;
|
|
6225
6311
|
return TEXTUAL_MEDIA_BASES.has(base);
|
|
@@ -6323,7 +6409,7 @@ var Walker = class _Walker {
|
|
|
6323
6409
|
}
|
|
6324
6410
|
}
|
|
6325
6411
|
const title = this.s(ex, "title", path);
|
|
6326
|
-
if (
|
|
6412
|
+
if (goTrimSpace2(title) === "") {
|
|
6327
6413
|
this.err(
|
|
6328
6414
|
"example_title_missing",
|
|
6329
6415
|
`${path}.title`,
|
|
@@ -6340,7 +6426,7 @@ var Walker = class _Walker {
|
|
|
6340
6426
|
}
|
|
6341
6427
|
}
|
|
6342
6428
|
const guidance = this.s(ex, "guidance", path);
|
|
6343
|
-
if (
|
|
6429
|
+
if (goTrimSpace2(guidance) === "") {
|
|
6344
6430
|
this.warn(
|
|
6345
6431
|
"example_guidance_missing",
|
|
6346
6432
|
`${path}.guidance`,
|
|
@@ -6767,7 +6853,7 @@ var Walker = class _Walker {
|
|
|
6767
6853
|
}
|
|
6768
6854
|
const rubric = this.s(e, "rubric", path);
|
|
6769
6855
|
if (rubric !== "") {
|
|
6770
|
-
if (
|
|
6856
|
+
if (goTrimSpace2(rubric) === "") {
|
|
6771
6857
|
this.err(
|
|
6772
6858
|
"example_rubric_empty",
|
|
6773
6859
|
`${path}.rubric`,
|
|
@@ -6822,7 +6908,7 @@ var Walker = class _Walker {
|
|
|
6822
6908
|
this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
|
|
6823
6909
|
}
|
|
6824
6910
|
mustNot.forEach((item, j) => {
|
|
6825
|
-
if (
|
|
6911
|
+
if (goTrimSpace2(item) === "" || runeCount(item) > L.maxMustNotRunes) {
|
|
6826
6912
|
this.err("example_must_not_invalid", `${path}.must_not[${j}]`, mustNotMsg);
|
|
6827
6913
|
}
|
|
6828
6914
|
});
|
|
@@ -7377,6 +7463,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
7377
7463
|
const f = flow;
|
|
7378
7464
|
validateBasicStructure(f, issues);
|
|
7379
7465
|
validateRetiredKeys(f, issues);
|
|
7466
|
+
validateRemovedFlowKeys(f, issues);
|
|
7380
7467
|
validateExecutors(f, issues);
|
|
7381
7468
|
validateQuerySchema(f, issues);
|
|
7382
7469
|
validateResponseExpectations(f, issues);
|