@vaudience/aigentflow-flow-validator 0.19.0 → 0.21.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 +114 -35
- package/README.md +3 -3
- package/dist/cli.js +413 -73
- package/dist/index.cjs +409 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +409 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -307,6 +307,17 @@ function isValidGoDuration(input) {
|
|
|
307
307
|
var RESERVED_STEP_ID_CHAR = ".";
|
|
308
308
|
var RESERVED_STEP_ID_ORCHESTRATOR = "orchestrator";
|
|
309
309
|
var DISPLAY_NAME_MAX_LEN = 80;
|
|
310
|
+
var YAML11_BOOL_WORDS = new Set(
|
|
311
|
+
["y", "yes", "on", "n", "no", "off"].flatMap((w) => [
|
|
312
|
+
w,
|
|
313
|
+
w.toUpperCase(),
|
|
314
|
+
w[0].toUpperCase() + w.slice(1)
|
|
315
|
+
])
|
|
316
|
+
);
|
|
317
|
+
function isBoolLike(v) {
|
|
318
|
+
if (v === null || typeof v === "boolean") return true;
|
|
319
|
+
return typeof v === "string" && YAML11_BOOL_WORDS.has(v);
|
|
320
|
+
}
|
|
310
321
|
function validateBasicStructure(flow, issues) {
|
|
311
322
|
if (!issues.nonEmptyStringOf(flow, "aigentflow_version", "")) {
|
|
312
323
|
issues.error({
|
|
@@ -336,6 +347,14 @@ function validateBasicStructure(flow, issues) {
|
|
|
336
347
|
});
|
|
337
348
|
}
|
|
338
349
|
}
|
|
350
|
+
if (flow.strict_templates !== void 0 && !isBoolLike(flow.strict_templates)) {
|
|
351
|
+
issues.error({
|
|
352
|
+
field: "strict_templates",
|
|
353
|
+
message: "strict_templates must be a boolean (true or false)",
|
|
354
|
+
code: "invalid_type",
|
|
355
|
+
suggestion: "Write 'strict_templates: true' or remove the key"
|
|
356
|
+
});
|
|
357
|
+
}
|
|
339
358
|
const start = issues.stringOf(flow, "start", "");
|
|
340
359
|
if (start === null || start === "") {
|
|
341
360
|
issues.error({
|
|
@@ -436,7 +455,7 @@ function validateBasicStructure(flow, issues) {
|
|
|
436
455
|
// src/spec/aigentflow-spec.json
|
|
437
456
|
var aigentflow_spec_default = {
|
|
438
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.",
|
|
439
|
-
specVersion: "2.
|
|
458
|
+
specVersion: "2.827.0",
|
|
440
459
|
inputSchemaVersion: 1,
|
|
441
460
|
executorSchemes: [
|
|
442
461
|
"a2a",
|
|
@@ -460,6 +479,7 @@ var aigentflow_spec_default = {
|
|
|
460
479
|
"geocoding",
|
|
461
480
|
"geovisualize",
|
|
462
481
|
"getmd",
|
|
482
|
+
"here",
|
|
463
483
|
"homeassistant",
|
|
464
484
|
"hosting",
|
|
465
485
|
"http",
|
|
@@ -1275,6 +1295,42 @@ var aigentflow_spec_default = {
|
|
|
1275
1295
|
}
|
|
1276
1296
|
}
|
|
1277
1297
|
},
|
|
1298
|
+
templateDefaultPiped: {
|
|
1299
|
+
$comment: "template_default_piped (ERROR at the top level, WARNING inside a loop body, like template_syntax_error). The template function `default` takes the value FIRST; a pipeline that passes a value into it as a non-first command hands the piped value as the LAST argument, so the fallback is always the result. Flagged: any pipeline (in any action, including if / else if / range / with / template / block conditions, parenthesised sub-pipelines and variable declarations) in which a command whose first word is the bare identifier `default` is not the FIRST command. Never flagged: a field, a variable, a string literal, a comment, `default` as the first command. The message fills %s with the pipeline.",
|
|
1300
|
+
code: "template_default_piped",
|
|
1301
|
+
function: "default",
|
|
1302
|
+
messageFormat: "`default` takes the value FIRST, and a pipe passes the piped value LAST: `%s` is `default <fallback> <value>`, so the fallback is always the result",
|
|
1303
|
+
suggestion: 'write the value first and the fallback second, as a call: `{{ default .x "fallback" }}`'
|
|
1304
|
+
},
|
|
1305
|
+
complianceResidency: {
|
|
1306
|
+
$comment: "compliance_residency_unenforced (WARNING, never an error; needs no catalogue). When compliance.residency is non-empty and every code (trimmed, upper-cased) is in euResidencyCodes, each top-level step and loop sub-step whose executor starts with aiProtocol+protocolSeparator, then the orchestrator (provider = its exons execution.provider), warns when its provider (literal, lower-cased; skipped when empty or containing templateActionOpen) is in regionLaneProviders and the call is not pinned. Pinned = query region (orchestrator.region) a non-empty string after trimming; OR enforce_region true (query: bool true or the strings in enforceRegionTrueStrings; orchestrator: bool true); OR the author named the endpoint: query <provider>+baseUrlParamSuffix a non-empty string after trimming, or executor_config.<provider>.base_url non-empty after trimming. The provider segment of ai://<provider>/<operation> exists only when a slash follows it. regionLaneProviders is the set of providers whose adapter routes on `region`; a provider outside it has no region lane and is never warned. Message, suggestion and site formats fill %s and %q (a Go-quoted string) in order; the message's last placeholder is the residency list as written, printed [A B]. Reference: validateResidencyEnforcement (validation.residency.go).",
|
|
1307
|
+
code: "compliance_residency_unenforced",
|
|
1308
|
+
euResidencyCodes: ["EU", "DE", "FR", "IE", "NL", "IT", "ES"],
|
|
1309
|
+
regionLaneProviders: [
|
|
1310
|
+
"bedrock",
|
|
1311
|
+
"google",
|
|
1312
|
+
"azure",
|
|
1313
|
+
"openai",
|
|
1314
|
+
"assemblyai",
|
|
1315
|
+
"speechmatics",
|
|
1316
|
+
"deepgram",
|
|
1317
|
+
"mistral"
|
|
1318
|
+
],
|
|
1319
|
+
aiProtocol: "ai",
|
|
1320
|
+
protocolSeparator: "://",
|
|
1321
|
+
regionParam: "region",
|
|
1322
|
+
enforceRegionParam: "enforce_region",
|
|
1323
|
+
baseUrlParamSuffix: "_base_url",
|
|
1324
|
+
enforceRegionTrueStrings: ["true", "1", "yes"],
|
|
1325
|
+
stepFieldFormat: "steps.%s.executor",
|
|
1326
|
+
loopStepFieldFormat: "steps.%s.loop.steps.%s.executor",
|
|
1327
|
+
orchestratorField: "orchestrator.exons",
|
|
1328
|
+
siteStepFormat: "step %q",
|
|
1329
|
+
siteLoopStepFormat: "loop sub-step %q of step %q",
|
|
1330
|
+
siteOrchestrator: "the orchestrator",
|
|
1331
|
+
messageFormat: "%s calls provider %q, whose default endpoint commits to no jurisdiction, but sets neither region nor enforce_region, so nothing pins it to the declared residency %v. compliance.residency is a catalogue eligibility check, not endpoint evidence",
|
|
1332
|
+
suggestion: "Add `region: eu` and `enforce_region: true` to the call (an orchestrator: the same two keys on the orchestrator block). Prove it afterwards: the step record's diagnostics.region is stamped from the host actually dialled."
|
|
1333
|
+
},
|
|
1278
1334
|
examples: {
|
|
1279
1335
|
$comment: "The examples: block. Derived from the reference's constants, never hand-typed: limits, vocabularies, the credential-shaped-literal pattern set and each code's severity. example_ref_blocked_host is listed for completeness but is raised by the reference implementation only; the ports never raise it. See PARITY.md, 'The examples block'.",
|
|
1280
1336
|
limits: {
|
|
@@ -1609,6 +1665,7 @@ var aigentflow_spec_default = {
|
|
|
1609
1665
|
rate_limit: "FlowRateLimitConfig",
|
|
1610
1666
|
start: "scalar",
|
|
1611
1667
|
steps: "map<StepDefinition>",
|
|
1668
|
+
strict_templates: "scalar",
|
|
1612
1669
|
tags: "list<scalar>",
|
|
1613
1670
|
template: "FlowTemplateMetadata",
|
|
1614
1671
|
tool_discovery: "scalar",
|
|
@@ -1943,6 +2000,25 @@ var CREDENTIAL_ENDPOINT_PAIRING = {
|
|
|
1943
2000
|
familyKeySeparator: aigentflow_spec_default.credentialEndpointPairing.familyKeySeparator,
|
|
1944
2001
|
families: aigentflow_spec_default.credentialEndpointPairing.families
|
|
1945
2002
|
};
|
|
2003
|
+
var COMPLIANCE_RESIDENCY = {
|
|
2004
|
+
code: aigentflow_spec_default.complianceResidency.code,
|
|
2005
|
+
euResidencyCodes: aigentflow_spec_default.complianceResidency.euResidencyCodes,
|
|
2006
|
+
regionLaneProviders: aigentflow_spec_default.complianceResidency.regionLaneProviders,
|
|
2007
|
+
aiProtocol: aigentflow_spec_default.complianceResidency.aiProtocol,
|
|
2008
|
+
protocolSeparator: aigentflow_spec_default.complianceResidency.protocolSeparator,
|
|
2009
|
+
regionParam: aigentflow_spec_default.complianceResidency.regionParam,
|
|
2010
|
+
enforceRegionParam: aigentflow_spec_default.complianceResidency.enforceRegionParam,
|
|
2011
|
+
baseUrlParamSuffix: aigentflow_spec_default.complianceResidency.baseUrlParamSuffix,
|
|
2012
|
+
enforceRegionTrueStrings: aigentflow_spec_default.complianceResidency.enforceRegionTrueStrings,
|
|
2013
|
+
stepFieldFormat: aigentflow_spec_default.complianceResidency.stepFieldFormat,
|
|
2014
|
+
loopStepFieldFormat: aigentflow_spec_default.complianceResidency.loopStepFieldFormat,
|
|
2015
|
+
orchestratorField: aigentflow_spec_default.complianceResidency.orchestratorField,
|
|
2016
|
+
siteStepFormat: aigentflow_spec_default.complianceResidency.siteStepFormat,
|
|
2017
|
+
siteLoopStepFormat: aigentflow_spec_default.complianceResidency.siteLoopStepFormat,
|
|
2018
|
+
siteOrchestrator: aigentflow_spec_default.complianceResidency.siteOrchestrator,
|
|
2019
|
+
messageFormat: aigentflow_spec_default.complianceResidency.messageFormat,
|
|
2020
|
+
suggestion: aigentflow_spec_default.complianceResidency.suggestion
|
|
2021
|
+
};
|
|
1946
2022
|
var EXAMPLES = {
|
|
1947
2023
|
limits: aigentflow_spec_default.examples.limits,
|
|
1948
2024
|
idPattern: new RegExp(aigentflow_spec_default.examples.idPattern),
|
|
@@ -1962,6 +2038,12 @@ var EXAMPLES = {
|
|
|
1962
2038
|
})),
|
|
1963
2039
|
codes: aigentflow_spec_default.examples.codes
|
|
1964
2040
|
};
|
|
2041
|
+
var TEMPLATE_DEFAULT_PIPED = {
|
|
2042
|
+
code: aigentflow_spec_default.templateDefaultPiped.code,
|
|
2043
|
+
function: aigentflow_spec_default.templateDefaultPiped.function,
|
|
2044
|
+
messageFormat: aigentflow_spec_default.templateDefaultPiped.messageFormat,
|
|
2045
|
+
suggestion: aigentflow_spec_default.templateDefaultPiped.suggestion
|
|
2046
|
+
};
|
|
1965
2047
|
|
|
1966
2048
|
// src/validators/executors.ts
|
|
1967
2049
|
var SCHEME_SEPARATOR = "://";
|
|
@@ -3925,6 +4007,117 @@ function splitPipeline(body) {
|
|
|
3925
4007
|
return stages;
|
|
3926
4008
|
}
|
|
3927
4009
|
|
|
4010
|
+
// src/template/gotmpl-default.ts
|
|
4011
|
+
var FUNCTION_NAME = "default";
|
|
4012
|
+
var PIPE = "|";
|
|
4013
|
+
var OPEN_PAREN = "(";
|
|
4014
|
+
var CLOSE_PAREN = ")";
|
|
4015
|
+
var MAX_NESTING_DEPTH = 100;
|
|
4016
|
+
var PIPELINE_KEYWORDS = /^(?:else\s+if|else\s+with|if|range|with|template|block)(?![\w$.])/;
|
|
4017
|
+
var NO_PIPELINE = /^(?:define|else|end|break|continue)(?![\w$.])/;
|
|
4018
|
+
var DECLARATION = /^\$\w*(?:\s*,\s*\$\w*)*\s*:?=/;
|
|
4019
|
+
function pipedDefaultPipelines(src) {
|
|
4020
|
+
const { actions, fatal } = lexActions(src);
|
|
4021
|
+
if (fatal) return [];
|
|
4022
|
+
const found = /* @__PURE__ */ new Set();
|
|
4023
|
+
try {
|
|
4024
|
+
for (const action of actions) {
|
|
4025
|
+
if (action.isComment || action.body === "") continue;
|
|
4026
|
+
scanAction(action.body, found);
|
|
4027
|
+
}
|
|
4028
|
+
} catch (err) {
|
|
4029
|
+
if (!(err instanceof RangeError)) throw err;
|
|
4030
|
+
return [];
|
|
4031
|
+
}
|
|
4032
|
+
return [...found].sort();
|
|
4033
|
+
}
|
|
4034
|
+
function scanAction(body, found) {
|
|
4035
|
+
let rest = body;
|
|
4036
|
+
const kw = PIPELINE_KEYWORDS.exec(rest);
|
|
4037
|
+
if (!kw && NO_PIPELINE.test(rest)) return;
|
|
4038
|
+
if (kw) {
|
|
4039
|
+
rest = rest.slice(kw[0].length).trimStart();
|
|
4040
|
+
const keyword = kw[0].replace(/\s+/g, " ");
|
|
4041
|
+
if (keyword === "template" || keyword === "block") {
|
|
4042
|
+
const q2 = rest[0];
|
|
4043
|
+
if (q2 === '"' || q2 === "`") {
|
|
4044
|
+
const end = scanString(rest, 0, q2);
|
|
4045
|
+
if (end === -1) return;
|
|
4046
|
+
rest = rest.slice(end + 1).trimStart();
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
if (rest === "") return;
|
|
4051
|
+
parsePipeline(rest, 0, false, found, 0);
|
|
4052
|
+
}
|
|
4053
|
+
function parsePipeline(src, start, nested, found, depth) {
|
|
4054
|
+
if (depth > MAX_NESTING_DEPTH) return { text: src.slice(start), end: src.length };
|
|
4055
|
+
let i = start;
|
|
4056
|
+
const n = src.length;
|
|
4057
|
+
let decl = "";
|
|
4058
|
+
const decMatch = DECLARATION.exec(src.slice(i));
|
|
4059
|
+
if (decMatch) {
|
|
4060
|
+
decl = decMatch[0].replace(/\s+/g, " ") + " ";
|
|
4061
|
+
i += decMatch[0].length;
|
|
4062
|
+
}
|
|
4063
|
+
const commands = [];
|
|
4064
|
+
let current = [];
|
|
4065
|
+
let firstWords = [];
|
|
4066
|
+
let pipedDefault = false;
|
|
4067
|
+
const pushCommand = () => {
|
|
4068
|
+
if (current.length > 0) {
|
|
4069
|
+
commands.push(current);
|
|
4070
|
+
firstWords.push(current[0]);
|
|
4071
|
+
}
|
|
4072
|
+
current = [];
|
|
4073
|
+
};
|
|
4074
|
+
while (i < n) {
|
|
4075
|
+
const c = src[i];
|
|
4076
|
+
if (c === " " || c === " " || c === "\n" || c === "\r") {
|
|
4077
|
+
i += 1;
|
|
4078
|
+
continue;
|
|
4079
|
+
}
|
|
4080
|
+
if (c === '"' || c === "`" || c === "'") {
|
|
4081
|
+
const end = scanString(src, i, c);
|
|
4082
|
+
const stop = end === -1 ? n - 1 : end;
|
|
4083
|
+
current.push(src.slice(i, stop + 1));
|
|
4084
|
+
i = stop + 1;
|
|
4085
|
+
continue;
|
|
4086
|
+
}
|
|
4087
|
+
if (c === OPEN_PAREN) {
|
|
4088
|
+
const inner = parsePipeline(src, i + 1, true, found, depth + 1);
|
|
4089
|
+
current.push(`(${inner.text})`);
|
|
4090
|
+
i = inner.end;
|
|
4091
|
+
continue;
|
|
4092
|
+
}
|
|
4093
|
+
if (c === CLOSE_PAREN) {
|
|
4094
|
+
if (nested) {
|
|
4095
|
+
i += 1;
|
|
4096
|
+
break;
|
|
4097
|
+
}
|
|
4098
|
+
i += 1;
|
|
4099
|
+
continue;
|
|
4100
|
+
}
|
|
4101
|
+
if (c === PIPE) {
|
|
4102
|
+
pushCommand();
|
|
4103
|
+
i += 1;
|
|
4104
|
+
continue;
|
|
4105
|
+
}
|
|
4106
|
+
let j = i;
|
|
4107
|
+
while (j < n && !/[\s|()"`']/.test(src[j])) j += 1;
|
|
4108
|
+
if (j === i) j = i + 1;
|
|
4109
|
+
current.push(src.slice(i, j));
|
|
4110
|
+
i = j;
|
|
4111
|
+
}
|
|
4112
|
+
pushCommand();
|
|
4113
|
+
firstWords.forEach((word, idx) => {
|
|
4114
|
+
if (idx > 0 && word === FUNCTION_NAME) pipedDefault = true;
|
|
4115
|
+
});
|
|
4116
|
+
const text = decl + commands.map((cmd) => cmd.join(" ")).join(` ${PIPE} `);
|
|
4117
|
+
if (pipedDefault) found.add(text);
|
|
4118
|
+
return { text, end: i };
|
|
4119
|
+
}
|
|
4120
|
+
|
|
3928
4121
|
// src/validators/processingOperations.ts
|
|
3929
4122
|
var PROCESSING_OP_GUARD_KEY = PROCESSING_OPERATIONS.guardKey;
|
|
3930
4123
|
var PROCESSING_PHASES = ["pre_processing", "post_processing"];
|
|
@@ -4071,6 +4264,17 @@ function checkTemplateString(value, field, stepID, issues, stats, opts, demote =
|
|
|
4071
4264
|
});
|
|
4072
4265
|
}
|
|
4073
4266
|
}
|
|
4267
|
+
if (errors.length > 0) return;
|
|
4268
|
+
for (const pipe of pipedDefaultPipelines(value)) {
|
|
4269
|
+
report({
|
|
4270
|
+
field,
|
|
4271
|
+
message: TEMPLATE_DEFAULT_PIPED.messageFormat.replace("%s", () => pipe),
|
|
4272
|
+
code: TEMPLATE_DEFAULT_PIPED.code,
|
|
4273
|
+
stepId: stepID,
|
|
4274
|
+
context: `Template: ${value}`,
|
|
4275
|
+
suggestion: TEMPLATE_DEFAULT_PIPED.suggestion
|
|
4276
|
+
});
|
|
4277
|
+
}
|
|
4074
4278
|
}
|
|
4075
4279
|
function walkStrings2(basePath, value, stepID, issues, stats, opts, check, demote = false) {
|
|
4076
4280
|
if (isString(value)) {
|
|
@@ -5302,6 +5506,141 @@ function warnOrchestratorToolWithheld(flow, orch, report, issues) {
|
|
|
5302
5506
|
}
|
|
5303
5507
|
}
|
|
5304
5508
|
|
|
5509
|
+
// src/validators/complianceResidency.ts
|
|
5510
|
+
function own2(m, key) {
|
|
5511
|
+
if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
|
|
5512
|
+
return m[key];
|
|
5513
|
+
}
|
|
5514
|
+
function sprintf(format, ...args) {
|
|
5515
|
+
let i = 0;
|
|
5516
|
+
return format.replace(/%[sqv]/g, (verb) => {
|
|
5517
|
+
const arg = args[i++] ?? "";
|
|
5518
|
+
return verb === "%q" ? JSON.stringify(arg) : arg;
|
|
5519
|
+
});
|
|
5520
|
+
}
|
|
5521
|
+
function literalOrEmpty(s) {
|
|
5522
|
+
const t = goTrimSpace2(s);
|
|
5523
|
+
return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
|
|
5524
|
+
}
|
|
5525
|
+
function euOnlyResidency(flow, issues) {
|
|
5526
|
+
const raw = own2(own2(flow, "compliance"), "residency");
|
|
5527
|
+
if (!isArray(raw)) return null;
|
|
5528
|
+
const codes = [];
|
|
5529
|
+
for (let i = 0; i < raw.length; i++) {
|
|
5530
|
+
if (raw[i] === null) continue;
|
|
5531
|
+
const code = issues.stringAt(raw[i], `compliance.residency[${i}]`);
|
|
5532
|
+
if (code === null) return null;
|
|
5533
|
+
codes.push(code);
|
|
5534
|
+
}
|
|
5535
|
+
if (codes.length === 0) return null;
|
|
5536
|
+
const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
|
|
5537
|
+
return codes.every((c) => eu.has(goTrimSpace2(c).toUpperCase())) ? codes : null;
|
|
5538
|
+
}
|
|
5539
|
+
function aiProvider(executor) {
|
|
5540
|
+
const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
|
|
5541
|
+
if (!executor.startsWith(prefix)) return "";
|
|
5542
|
+
const rest = executor.slice(prefix.length);
|
|
5543
|
+
const slash = rest.indexOf("/");
|
|
5544
|
+
const provider = slash > 0 ? rest.slice(0, slash) : "";
|
|
5545
|
+
return provider.includes(TEMPLATE_ACTION_OPEN) ? "" : provider;
|
|
5546
|
+
}
|
|
5547
|
+
function isRegionLane(provider) {
|
|
5548
|
+
const literal = literalOrEmpty(provider);
|
|
5549
|
+
return literal !== "" && COMPLIANCE_RESIDENCY.regionLaneProviders.includes(literal.toLowerCase());
|
|
5550
|
+
}
|
|
5551
|
+
function nonBlankString(m, key) {
|
|
5552
|
+
const v = own2(m, key);
|
|
5553
|
+
return typeof v === "string" && goTrimSpace2(v) !== "";
|
|
5554
|
+
}
|
|
5555
|
+
function queryEnforcesRegion(query) {
|
|
5556
|
+
const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
|
|
5557
|
+
if (typeof v === "boolean") return v;
|
|
5558
|
+
return typeof v === "string" && COMPLIANCE_RESIDENCY.enforceRegionTrueStrings.includes(v);
|
|
5559
|
+
}
|
|
5560
|
+
function flowDirectsEndpoint(flow, provider, issues) {
|
|
5561
|
+
const key = provider.toLowerCase();
|
|
5562
|
+
const inst = own2(own2(flow, "executor_config"), key);
|
|
5563
|
+
if (!isRecord(inst)) return false;
|
|
5564
|
+
const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
|
|
5565
|
+
return baseUrl !== null && goTrimSpace2(baseUrl) !== "";
|
|
5566
|
+
}
|
|
5567
|
+
function callPinsEndpoint(flow, provider, query, issues) {
|
|
5568
|
+
if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
|
|
5569
|
+
if (queryEnforcesRegion(query)) return true;
|
|
5570
|
+
if (nonBlankString(query, provider.toLowerCase() + COMPLIANCE_RESIDENCY.baseUrlParamSuffix)) return true;
|
|
5571
|
+
return flowDirectsEndpoint(flow, provider, issues);
|
|
5572
|
+
}
|
|
5573
|
+
function validateResidencyEnforcement(flow, issues) {
|
|
5574
|
+
const residency = euOnlyResidency(flow, issues);
|
|
5575
|
+
if (residency === null) return;
|
|
5576
|
+
const warn = (site, field, stepId, provider) => {
|
|
5577
|
+
issues.warn({
|
|
5578
|
+
field,
|
|
5579
|
+
...stepId === void 0 ? {} : { stepId },
|
|
5580
|
+
code: COMPLIANCE_RESIDENCY.code,
|
|
5581
|
+
message: sprintf(COMPLIANCE_RESIDENCY.messageFormat, site, provider, `[${residency.join(" ")}]`),
|
|
5582
|
+
suggestion: COMPLIANCE_RESIDENCY.suggestion
|
|
5583
|
+
});
|
|
5584
|
+
};
|
|
5585
|
+
const steps = flow.steps;
|
|
5586
|
+
if (isRecord(steps)) {
|
|
5587
|
+
for (const stepId of Object.keys(steps).sort()) {
|
|
5588
|
+
const step = steps[stepId];
|
|
5589
|
+
if (!isRecord(step)) continue;
|
|
5590
|
+
const calls = [
|
|
5591
|
+
{
|
|
5592
|
+
executor: issues.stringOf(step, "executor", `steps.${stepId}`) ?? "",
|
|
5593
|
+
query: own2(step, "query"),
|
|
5594
|
+
subId: null
|
|
5595
|
+
}
|
|
5596
|
+
];
|
|
5597
|
+
for (const sub of loopSubStepsOfStep(stepId, step)) {
|
|
5598
|
+
calls.push({
|
|
5599
|
+
executor: issues.stringOf(sub.raw, "executor", sub.basePath) ?? "",
|
|
5600
|
+
query: own2(sub.raw, "query"),
|
|
5601
|
+
subId: issues.stringOf(sub.raw, "id", sub.basePath) ?? ""
|
|
5602
|
+
});
|
|
5603
|
+
}
|
|
5604
|
+
for (const call of calls) {
|
|
5605
|
+
const provider = aiProvider(call.executor);
|
|
5606
|
+
if (!isRegionLane(provider)) continue;
|
|
5607
|
+
if (callPinsEndpoint(flow, provider, call.query, issues)) continue;
|
|
5608
|
+
if (call.subId === null) {
|
|
5609
|
+
warn(
|
|
5610
|
+
sprintf(COMPLIANCE_RESIDENCY.siteStepFormat, stepId),
|
|
5611
|
+
sprintf(COMPLIANCE_RESIDENCY.stepFieldFormat, stepId),
|
|
5612
|
+
stepId,
|
|
5613
|
+
provider
|
|
5614
|
+
);
|
|
5615
|
+
} else {
|
|
5616
|
+
warn(
|
|
5617
|
+
sprintf(COMPLIANCE_RESIDENCY.siteLoopStepFormat, call.subId, stepId),
|
|
5618
|
+
sprintf(COMPLIANCE_RESIDENCY.loopStepFieldFormat, stepId, call.subId),
|
|
5619
|
+
stepId,
|
|
5620
|
+
provider
|
|
5621
|
+
);
|
|
5622
|
+
}
|
|
5623
|
+
}
|
|
5624
|
+
}
|
|
5625
|
+
}
|
|
5626
|
+
warnOrchestrator(flow, issues, warn);
|
|
5627
|
+
}
|
|
5628
|
+
function warnOrchestrator(flow, issues, warn) {
|
|
5629
|
+
const orch = flow.orchestrator;
|
|
5630
|
+
if (!isRecord(orch)) return;
|
|
5631
|
+
const source = issues.stringOf(orch, "exons", "orchestrator");
|
|
5632
|
+
if (source === null || source === "") return;
|
|
5633
|
+
const report = inspectExonsFrontmatter(source);
|
|
5634
|
+
if (report.parseError !== null || !report.specRead || !report.hasSpec) return;
|
|
5635
|
+
const provider = literalOrEmpty(report.provider);
|
|
5636
|
+
if (!isRegionLane(provider)) return;
|
|
5637
|
+
const region = issues.stringOf(orch, "region", "orchestrator");
|
|
5638
|
+
if (region !== null && goTrimSpace2(region) !== "") return;
|
|
5639
|
+
if (orch.enforce_region === true) return;
|
|
5640
|
+
if (flowDirectsEndpoint(flow, provider, issues)) return;
|
|
5641
|
+
warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
|
|
5642
|
+
}
|
|
5643
|
+
|
|
5305
5644
|
// src/validators/examples.ts
|
|
5306
5645
|
var KEY_EXAMPLES = "examples";
|
|
5307
5646
|
var VISIBILITY_PUBLIC = "public";
|
|
@@ -5379,7 +5718,7 @@ function num(n) {
|
|
|
5379
5718
|
function has(o, key) {
|
|
5380
5719
|
return Object.prototype.hasOwnProperty.call(o, key) && o[key] !== null && o[key] !== void 0;
|
|
5381
5720
|
}
|
|
5382
|
-
function
|
|
5721
|
+
function own3(o, key) {
|
|
5383
5722
|
return Object.prototype.hasOwnProperty.call(o, key) ? o[key] : void 0;
|
|
5384
5723
|
}
|
|
5385
5724
|
function setOwn(o, key, value) {
|
|
@@ -5431,7 +5770,7 @@ function mergePatch(target, patch, depth) {
|
|
|
5431
5770
|
continue;
|
|
5432
5771
|
}
|
|
5433
5772
|
if (isRecord(pv)) {
|
|
5434
|
-
const current =
|
|
5773
|
+
const current = own3(target, k);
|
|
5435
5774
|
const existing = isRecord(current) ? deepCopy(current, 0) : {};
|
|
5436
5775
|
mergePatch(existing, pv, depth + 1);
|
|
5437
5776
|
setOwn(target, k, existing);
|
|
@@ -5451,7 +5790,7 @@ function asFileRef(v) {
|
|
|
5451
5790
|
if (keys.length === 0) return null;
|
|
5452
5791
|
for (const k of keys) if (!FILE_REF_KEYS.has(k)) return null;
|
|
5453
5792
|
const str = (k) => {
|
|
5454
|
-
const x =
|
|
5793
|
+
const x = own3(v, k);
|
|
5455
5794
|
return typeof x === "string" ? x : "";
|
|
5456
5795
|
};
|
|
5457
5796
|
return {
|
|
@@ -5519,7 +5858,7 @@ var Walker = class _Walker {
|
|
|
5519
5858
|
`the examples block is ${size} bytes; the limit is ${L.maxBlockBytes}. Move large inputs or target outputs to a file reference (https URL).`
|
|
5520
5859
|
);
|
|
5521
5860
|
}
|
|
5522
|
-
const allHeld = examples.every((e) => isRecord(e) &&
|
|
5861
|
+
const allHeld = examples.every((e) => isRecord(e) && own3(e, "hold_out") === true);
|
|
5523
5862
|
if (allHeld) {
|
|
5524
5863
|
this.warn(
|
|
5525
5864
|
"examples_all_held_out",
|
|
@@ -5607,9 +5946,9 @@ var Walker = class _Walker {
|
|
|
5607
5946
|
`example ${q(label)} notes are ${notesN} characters; the limit is ${L.maxNotesRunes}`
|
|
5608
5947
|
);
|
|
5609
5948
|
}
|
|
5610
|
-
this.validateTags(path, label,
|
|
5611
|
-
this.validateWeight(`${path}.weight`, label, numberOf(
|
|
5612
|
-
const minScore = numberOf(
|
|
5949
|
+
this.validateTags(path, label, own3(ex, "tags"));
|
|
5950
|
+
this.validateWeight(`${path}.weight`, label, numberOf(own3(ex, "weight")));
|
|
5951
|
+
const minScore = numberOf(own3(ex, "min_score"));
|
|
5613
5952
|
if (minScore !== void 0 && !scoreInRange(minScore)) {
|
|
5614
5953
|
this.err(
|
|
5615
5954
|
"example_min_score_range",
|
|
@@ -5625,7 +5964,7 @@ var Walker = class _Walker {
|
|
|
5625
5964
|
`example ${q(label)} has side_effects ${q(sideEffects)}; use refuse or allow`
|
|
5626
5965
|
);
|
|
5627
5966
|
}
|
|
5628
|
-
const holdOut =
|
|
5967
|
+
const holdOut = own3(ex, "hold_out") === true;
|
|
5629
5968
|
if (holdOut && this.isPublic()) {
|
|
5630
5969
|
this.err(
|
|
5631
5970
|
"example_holdout_in_public_flow",
|
|
@@ -5648,17 +5987,17 @@ var Walker = class _Walker {
|
|
|
5648
5987
|
`example ${q(label)} has neither input nor input_ref; use input: {} for a flow that takes no input`
|
|
5649
5988
|
);
|
|
5650
5989
|
}
|
|
5651
|
-
const rawInput =
|
|
5990
|
+
const rawInput = own3(ex, "input");
|
|
5652
5991
|
const baseInput = isRecord(rawInput) ? rawInput : null;
|
|
5653
5992
|
if (baseInput !== null) {
|
|
5654
5993
|
this.checkInput(`${path}.input`, label, baseInput, "example_input_invalid");
|
|
5655
5994
|
}
|
|
5656
|
-
const rawInputRef =
|
|
5995
|
+
const rawInputRef = own3(ex, "input_ref");
|
|
5657
5996
|
if (isRecord(rawInputRef)) {
|
|
5658
5997
|
this.validateFileRef(`${path}.input_ref`, this.fileRefOf(rawInputRef, `${path}.input_ref`));
|
|
5659
5998
|
}
|
|
5660
5999
|
let binaryOnly = false;
|
|
5661
|
-
const expected =
|
|
6000
|
+
const expected = own3(ex, "expected");
|
|
5662
6001
|
if (!has(ex, "expected")) {
|
|
5663
6002
|
this.err(
|
|
5664
6003
|
"example_expected_missing",
|
|
@@ -5677,7 +6016,7 @@ var Walker = class _Walker {
|
|
|
5677
6016
|
"this example can be run but not scored"
|
|
5678
6017
|
);
|
|
5679
6018
|
}
|
|
5680
|
-
this.validateCheckpoints(path, label,
|
|
6019
|
+
this.validateCheckpoints(path, label, own3(ex, "checkpoints"));
|
|
5681
6020
|
this.validateVariants(i, path, label, ex, hasInput, baseInput);
|
|
5682
6021
|
this.scanSecretLike(i, path, ex);
|
|
5683
6022
|
}
|
|
@@ -5737,8 +6076,8 @@ var Walker = class _Walker {
|
|
|
5737
6076
|
);
|
|
5738
6077
|
return;
|
|
5739
6078
|
}
|
|
5740
|
-
const schema =
|
|
5741
|
-
const query =
|
|
6079
|
+
const schema = own3(this.flow, "input_schema");
|
|
6080
|
+
const query = own3(this.flow, "query");
|
|
5742
6081
|
if (isRecord(schema)) {
|
|
5743
6082
|
this.checkInputAgainstSchema(field, label, input, schema, code);
|
|
5744
6083
|
} else if (isRecord(query) && Object.keys(query).length > 0) {
|
|
@@ -5806,29 +6145,29 @@ var Walker = class _Walker {
|
|
|
5806
6145
|
}
|
|
5807
6146
|
}
|
|
5808
6147
|
schemaFields(schema) {
|
|
5809
|
-
const raw =
|
|
6148
|
+
const raw = own3(schema, "fields");
|
|
5810
6149
|
if (!Array.isArray(raw)) return [];
|
|
5811
6150
|
const out = [];
|
|
5812
6151
|
raw.forEach((f, i) => {
|
|
5813
6152
|
if (!isRecord(f)) return;
|
|
5814
6153
|
const base = `input_schema.fields[${i}]`;
|
|
5815
|
-
const enumRaw =
|
|
6154
|
+
const enumRaw = own3(f, "enum");
|
|
5816
6155
|
const enumValues = [];
|
|
5817
6156
|
if (Array.isArray(enumRaw)) {
|
|
5818
6157
|
enumRaw.forEach((e, j) => {
|
|
5819
6158
|
enumValues.push(e === null ? "" : this.issues.stringAt(e, `${base}.enum[${j}]`) ?? "");
|
|
5820
6159
|
});
|
|
5821
6160
|
}
|
|
5822
|
-
const vw =
|
|
6161
|
+
const vw = own3(f, "visible_when");
|
|
5823
6162
|
out.push({
|
|
5824
6163
|
name: this.s(f, "name", base),
|
|
5825
6164
|
type: this.s(f, "type", base),
|
|
5826
|
-
required:
|
|
6165
|
+
required: own3(f, "required") === true,
|
|
5827
6166
|
enumValues,
|
|
5828
6167
|
visibleWhen: isRecord(vw) ? {
|
|
5829
6168
|
field: this.s(vw, "field", `${base}.visible_when`),
|
|
5830
|
-
equals:
|
|
5831
|
-
in: Array.isArray(
|
|
6169
|
+
equals: own3(vw, "equals"),
|
|
6170
|
+
in: Array.isArray(own3(vw, "in")) ? own3(vw, "in") : []
|
|
5832
6171
|
} : null
|
|
5833
6172
|
});
|
|
5834
6173
|
});
|
|
@@ -5839,7 +6178,7 @@ var Walker = class _Walker {
|
|
|
5839
6178
|
const failures = [];
|
|
5840
6179
|
for (const f of fields) {
|
|
5841
6180
|
if (!isVisible(f, runInput)) continue;
|
|
5842
|
-
const raw =
|
|
6181
|
+
const raw = own3(runInput, f.name);
|
|
5843
6182
|
if (raw === void 0 || raw === null) {
|
|
5844
6183
|
if (f.required) {
|
|
5845
6184
|
failures.push({
|
|
@@ -5950,7 +6289,7 @@ var Walker = class _Walker {
|
|
|
5950
6289
|
/** The names `fields` / `exact` may use, and whether such a list is declared at all. */
|
|
5951
6290
|
outputNamesFor(kind, stepId) {
|
|
5952
6291
|
if (kind === "final") {
|
|
5953
|
-
const out =
|
|
6292
|
+
const out = own3(this.flow, "output");
|
|
5954
6293
|
const names2 = [];
|
|
5955
6294
|
if (Array.isArray(out)) {
|
|
5956
6295
|
out.forEach((item, i) => {
|
|
@@ -5959,10 +6298,10 @@ var Walker = class _Walker {
|
|
|
5959
6298
|
}
|
|
5960
6299
|
return { names: names2, declared: names2.length > 0 };
|
|
5961
6300
|
}
|
|
5962
|
-
const steps =
|
|
5963
|
-
const step = isRecord(steps) ?
|
|
5964
|
-
const schema = isRecord(step) ?
|
|
5965
|
-
const fields = isRecord(schema) ?
|
|
6301
|
+
const steps = own3(this.flow, "steps");
|
|
6302
|
+
const step = isRecord(steps) ? own3(steps, stepId) : void 0;
|
|
6303
|
+
const schema = isRecord(step) ? own3(step, "output_schema") : void 0;
|
|
6304
|
+
const fields = isRecord(schema) ? own3(schema, "fields") : void 0;
|
|
5966
6305
|
if (!Array.isArray(fields) || fields.length === 0) return { names: [], declared: false };
|
|
5967
6306
|
const names = [];
|
|
5968
6307
|
fields.forEach((f, i) => {
|
|
@@ -5981,8 +6320,8 @@ var Walker = class _Walker {
|
|
|
5981
6320
|
);
|
|
5982
6321
|
}
|
|
5983
6322
|
const noOutput = status === STATUS_FAILED || status === STATUS_PAUSED_FOR_HUMAN;
|
|
5984
|
-
const fieldsRec =
|
|
5985
|
-
const exactRec =
|
|
6323
|
+
const fieldsRec = own3(e, "fields");
|
|
6324
|
+
const exactRec = own3(e, "exact");
|
|
5986
6325
|
const fieldKeys = isRecord(fieldsRec) ? sortedKeys(fieldsRec) : [];
|
|
5987
6326
|
const exactKeys = isRecord(exactRec) ? sortedKeys(exactRec) : [];
|
|
5988
6327
|
const hasFields = fieldKeys.length > 0;
|
|
@@ -6000,7 +6339,7 @@ var Walker = class _Walker {
|
|
|
6000
6339
|
`a case that ends in ${status} has no output to match; remove fields and exact, or expect status completed`
|
|
6001
6340
|
);
|
|
6002
6341
|
}
|
|
6003
|
-
const minScore = numberOf(
|
|
6342
|
+
const minScore = numberOf(own3(e, "min_score"));
|
|
6004
6343
|
if (minScore !== void 0 && !scoreInRange(minScore)) {
|
|
6005
6344
|
this.err(
|
|
6006
6345
|
"example_min_score_range",
|
|
@@ -6027,7 +6366,7 @@ var Walker = class _Walker {
|
|
|
6027
6366
|
}
|
|
6028
6367
|
}
|
|
6029
6368
|
}
|
|
6030
|
-
const reference =
|
|
6369
|
+
const reference = own3(e, "reference");
|
|
6031
6370
|
if (isRecord(reference)) this.validateReference(`${path}.reference`, reference);
|
|
6032
6371
|
const { names, declared } = this.outputNamesFor(kind, stepId);
|
|
6033
6372
|
const checkKey = (field, key) => {
|
|
@@ -6054,12 +6393,12 @@ var Walker = class _Walker {
|
|
|
6054
6393
|
for (const key of fieldKeys) {
|
|
6055
6394
|
const fpath = `${path}.fields.${key}`;
|
|
6056
6395
|
checkKey(fpath, key);
|
|
6057
|
-
const matcher =
|
|
6396
|
+
const matcher = own3(fieldsRec, key);
|
|
6058
6397
|
if (isRecord(matcher)) this.validateFieldMatcher(fpath, matcher);
|
|
6059
6398
|
}
|
|
6060
6399
|
for (const key of exactKeys) checkKey(`${path}.exact.${key}`, key);
|
|
6061
|
-
const mustNot = this.stringList(
|
|
6062
|
-
const mustNotContain = this.stringList(
|
|
6400
|
+
const mustNot = this.stringList(own3(e, "must_not"), `${path}.must_not`);
|
|
6401
|
+
const mustNotContain = this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`);
|
|
6063
6402
|
const mustNotMsg = `must_not takes up to ${L.maxMustNot} statements of at most ${L.maxMustNotRunes} characters each, none empty`;
|
|
6064
6403
|
if (mustNot.length > L.maxMustNot) {
|
|
6065
6404
|
this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
|
|
@@ -6080,9 +6419,9 @@ var Walker = class _Walker {
|
|
|
6080
6419
|
}
|
|
6081
6420
|
});
|
|
6082
6421
|
for (const key of fieldKeys) {
|
|
6083
|
-
const matcher =
|
|
6422
|
+
const matcher = own3(fieldsRec, key);
|
|
6084
6423
|
if (!isRecord(matcher)) continue;
|
|
6085
|
-
const eq =
|
|
6424
|
+
const eq = own3(matcher, "equals");
|
|
6086
6425
|
if (typeof eq !== "string" || eq === "") continue;
|
|
6087
6426
|
for (const banned of mustNotContain) {
|
|
6088
6427
|
if (banned !== "" && equalFold(banned, eq)) {
|
|
@@ -6142,7 +6481,7 @@ var Walker = class _Walker {
|
|
|
6142
6481
|
}
|
|
6143
6482
|
return;
|
|
6144
6483
|
}
|
|
6145
|
-
const refRec =
|
|
6484
|
+
const refRec = own3(r, "ref");
|
|
6146
6485
|
if (!isRecord(refRec)) return;
|
|
6147
6486
|
const ref = this.fileRefOf(refRec, `${path}.ref`);
|
|
6148
6487
|
this.validateFileRef(`${path}.ref`, ref);
|
|
@@ -6155,22 +6494,22 @@ var Walker = class _Walker {
|
|
|
6155
6494
|
}
|
|
6156
6495
|
}
|
|
6157
6496
|
expectationIsBinaryReferenceOnly(e, path) {
|
|
6158
|
-
const reference =
|
|
6159
|
-
const refRec = isRecord(reference) ?
|
|
6497
|
+
const reference = own3(e, "reference");
|
|
6498
|
+
const refRec = isRecord(reference) ? own3(reference, "ref") : void 0;
|
|
6160
6499
|
if (!isRecord(refRec)) return false;
|
|
6161
6500
|
const mediaType = this.s(refRec, "media_type", `${path}.reference.ref`);
|
|
6162
6501
|
if (mediaType === "" || isTextualMediaType(mediaType)) return false;
|
|
6163
6502
|
const status = this.s(e, "status", path);
|
|
6164
|
-
const fields =
|
|
6165
|
-
const exact =
|
|
6166
|
-
return this.s(e, "rubric", path) === "" && !(isRecord(fields) && Object.keys(fields).length > 0) && !(isRecord(exact) && Object.keys(exact).length > 0) && this.stringList(
|
|
6503
|
+
const fields = own3(e, "fields");
|
|
6504
|
+
const exact = own3(e, "exact");
|
|
6505
|
+
return this.s(e, "rubric", path) === "" && !(isRecord(fields) && Object.keys(fields).length > 0) && !(isRecord(exact) && Object.keys(exact).length > 0) && this.stringList(own3(e, "must_not"), `${path}.must_not`).length === 0 && this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`).length === 0 && (status === "" || status === STATUS_COMPLETED);
|
|
6167
6506
|
}
|
|
6168
6507
|
validateFieldMatcher(path, m) {
|
|
6169
6508
|
const L = EXAMPLES.limits;
|
|
6170
6509
|
const matches = this.s(m, "matches", path);
|
|
6171
|
-
const oneOf =
|
|
6172
|
-
const approx = numberOf(
|
|
6173
|
-
const tolerance = numberOf(
|
|
6510
|
+
const oneOf = own3(m, "one_of");
|
|
6511
|
+
const approx = numberOf(own3(m, "approx"));
|
|
6512
|
+
const tolerance = numberOf(own3(m, "tolerance"));
|
|
6174
6513
|
let operators = 0;
|
|
6175
6514
|
if (has(m, "equals")) operators++;
|
|
6176
6515
|
if (this.s(m, "contains", path) !== "") operators++;
|
|
@@ -6178,7 +6517,7 @@ var Walker = class _Walker {
|
|
|
6178
6517
|
if (matches !== "") operators++;
|
|
6179
6518
|
if (Array.isArray(oneOf) && oneOf.length > 0) operators++;
|
|
6180
6519
|
if (approx !== void 0) operators++;
|
|
6181
|
-
if (typeof
|
|
6520
|
+
if (typeof own3(m, "present") === "boolean") operators++;
|
|
6182
6521
|
if (operators !== 1) {
|
|
6183
6522
|
this.err(
|
|
6184
6523
|
"example_field_matcher_invalid",
|
|
@@ -6205,12 +6544,12 @@ var Walker = class _Walker {
|
|
|
6205
6544
|
// -- checkpoints ------------------------------------------------------
|
|
6206
6545
|
validateCheckpoints(path, label, cps) {
|
|
6207
6546
|
if (!isRecord(cps) || Object.keys(cps).length === 0) return;
|
|
6208
|
-
const stepsRaw =
|
|
6547
|
+
const stepsRaw = own3(this.flow, "steps");
|
|
6209
6548
|
const steps = isRecord(stepsRaw) ? stepsRaw : {};
|
|
6210
6549
|
const stepIds = sortedKeys(steps);
|
|
6211
6550
|
for (const id of sortedKeys(cps)) {
|
|
6212
6551
|
const cpath = `${path}.checkpoints.${id}`;
|
|
6213
|
-
const step =
|
|
6552
|
+
const step = own3(steps, id);
|
|
6214
6553
|
if (!isRecord(step)) {
|
|
6215
6554
|
this.err(
|
|
6216
6555
|
"example_checkpoint_step_unknown",
|
|
@@ -6220,7 +6559,7 @@ var Walker = class _Walker {
|
|
|
6220
6559
|
);
|
|
6221
6560
|
continue;
|
|
6222
6561
|
}
|
|
6223
|
-
const next =
|
|
6562
|
+
const next = own3(step, "next");
|
|
6224
6563
|
if (has(step, "for_each") || has(step, "loop") || isRecord(next) && has(next, "parallel")) {
|
|
6225
6564
|
this.err(
|
|
6226
6565
|
"example_checkpoint_step_composite",
|
|
@@ -6229,7 +6568,7 @@ var Walker = class _Walker {
|
|
|
6229
6568
|
);
|
|
6230
6569
|
continue;
|
|
6231
6570
|
}
|
|
6232
|
-
const cp =
|
|
6571
|
+
const cp = own3(cps, id);
|
|
6233
6572
|
if (cp === null || cp === void 0) {
|
|
6234
6573
|
this.validateExpectation(cpath, label, {}, "checkpoint", id);
|
|
6235
6574
|
} else if (isRecord(cp)) {
|
|
@@ -6240,7 +6579,7 @@ var Walker = class _Walker {
|
|
|
6240
6579
|
// -- variants ---------------------------------------------------------
|
|
6241
6580
|
validateVariants(i, path, label, ex, hasInput, baseInput) {
|
|
6242
6581
|
const L = EXAMPLES.limits;
|
|
6243
|
-
const variants =
|
|
6582
|
+
const variants = own3(ex, "variants");
|
|
6244
6583
|
if (!Array.isArray(variants) || variants.length === 0) return;
|
|
6245
6584
|
if (variants.length > L.maxVariants) {
|
|
6246
6585
|
this.err(
|
|
@@ -6303,8 +6642,8 @@ var Walker = class _Walker {
|
|
|
6303
6642
|
`example ${q(both)} notes are ${provN} characters; the limit is ${L.maxProvenanceRunes}`
|
|
6304
6643
|
);
|
|
6305
6644
|
}
|
|
6306
|
-
this.validateWeight(`${vpath}.weight`, both, numberOf(
|
|
6307
|
-
const patch =
|
|
6645
|
+
this.validateWeight(`${vpath}.weight`, both, numberOf(own3(v, "weight")));
|
|
6646
|
+
const patch = own3(v, "input_patch");
|
|
6308
6647
|
const patchRec = isRecord(patch) ? patch : null;
|
|
6309
6648
|
const hasPatch = patchRec !== null && Object.keys(patchRec).length > 0;
|
|
6310
6649
|
const hasRef = has(v, "input_ref");
|
|
@@ -6321,7 +6660,7 @@ var Walker = class _Walker {
|
|
|
6321
6660
|
`variant ${q(vlabel)} of example ${q(label)} changes neither the input nor the expectation`
|
|
6322
6661
|
);
|
|
6323
6662
|
}
|
|
6324
|
-
const refRec =
|
|
6663
|
+
const refRec = own3(v, "input_ref");
|
|
6325
6664
|
if (isRecord(refRec)) {
|
|
6326
6665
|
this.validateFileRef(`${vpath}.input_ref`, this.fileRefOf(refRec, `${vpath}.input_ref`));
|
|
6327
6666
|
}
|
|
@@ -6336,7 +6675,7 @@ var Walker = class _Walker {
|
|
|
6336
6675
|
this.checkVariantPatch(vpath, label, vlabel, baseInput, patchRec);
|
|
6337
6676
|
}
|
|
6338
6677
|
}
|
|
6339
|
-
const expected =
|
|
6678
|
+
const expected = own3(v, "expected");
|
|
6340
6679
|
if (isRecord(expected)) {
|
|
6341
6680
|
this.validateExpectation(`${vpath}.expected`, both, expected, "final", "");
|
|
6342
6681
|
}
|
|
@@ -6347,11 +6686,11 @@ var Walker = class _Walker {
|
|
|
6347
6686
|
* itself supplies. A null patch value deleting a secret is fine.
|
|
6348
6687
|
*/
|
|
6349
6688
|
checkVariantPatch(vpath, label, vlabel, base, patch) {
|
|
6350
|
-
const schema =
|
|
6689
|
+
const schema = own3(this.flow, "input_schema");
|
|
6351
6690
|
if (isRecord(schema)) {
|
|
6352
6691
|
for (const f of this.schemaFields(schema)) {
|
|
6353
6692
|
if (f.type !== TYPE_SECRET) continue;
|
|
6354
|
-
const val =
|
|
6693
|
+
const val = own3(patch, f.name);
|
|
6355
6694
|
if (val !== void 0 && val !== null) {
|
|
6356
6695
|
this.err(
|
|
6357
6696
|
"example_secret_value",
|
|
@@ -6391,18 +6730,18 @@ var Walker = class _Walker {
|
|
|
6391
6730
|
emit(`${path}.title`, this.s(ex, "title", path));
|
|
6392
6731
|
emit(`${path}.guidance`, this.s(ex, "guidance", path));
|
|
6393
6732
|
emit(`${path}.notes`, this.s(ex, "notes", path));
|
|
6394
|
-
const input =
|
|
6733
|
+
const input = own3(ex, "input");
|
|
6395
6734
|
if (isRecord(input)) scanLeaves(`${path}.input`, input, 0, emit);
|
|
6396
|
-
const expected =
|
|
6735
|
+
const expected = own3(ex, "expected");
|
|
6397
6736
|
if (isRecord(expected)) this.scanExpectationLeaves(`${path}.expected`, expected, emit);
|
|
6398
|
-
const cps =
|
|
6737
|
+
const cps = own3(ex, "checkpoints");
|
|
6399
6738
|
if (isRecord(cps)) {
|
|
6400
6739
|
for (const id of sortedKeys(cps)) {
|
|
6401
|
-
const cp =
|
|
6740
|
+
const cp = own3(cps, id);
|
|
6402
6741
|
if (isRecord(cp)) this.scanExpectationLeaves(`${path}.checkpoints.${id}`, cp, emit);
|
|
6403
6742
|
}
|
|
6404
6743
|
}
|
|
6405
|
-
const variants =
|
|
6744
|
+
const variants = own3(ex, "variants");
|
|
6406
6745
|
if (Array.isArray(variants)) {
|
|
6407
6746
|
variants.forEach((v, j) => {
|
|
6408
6747
|
if (!isRecord(v)) return;
|
|
@@ -6410,34 +6749,34 @@ var Walker = class _Walker {
|
|
|
6410
6749
|
emit(`${vpath}.title`, this.s(v, "title", vpath));
|
|
6411
6750
|
emit(`${vpath}.guidance`, this.s(v, "guidance", vpath));
|
|
6412
6751
|
emit(`${vpath}.provenance`, this.s(v, "provenance", vpath));
|
|
6413
|
-
scanLeaves(`${vpath}.input_patch`,
|
|
6414
|
-
const vexp =
|
|
6752
|
+
scanLeaves(`${vpath}.input_patch`, own3(v, "input_patch"), 0, emit);
|
|
6753
|
+
const vexp = own3(v, "expected");
|
|
6415
6754
|
if (isRecord(vexp)) this.scanExpectationLeaves(`${vpath}.expected`, vexp, emit);
|
|
6416
6755
|
});
|
|
6417
6756
|
}
|
|
6418
6757
|
}
|
|
6419
6758
|
scanExpectationLeaves(path, e, emit) {
|
|
6420
6759
|
emit(`${path}.rubric`, this.s(e, "rubric", path));
|
|
6421
|
-
const reference =
|
|
6760
|
+
const reference = own3(e, "reference");
|
|
6422
6761
|
if (isRecord(reference)) {
|
|
6423
6762
|
emit(`${path}.reference.text`, this.s(reference, "text", `${path}.reference`));
|
|
6424
6763
|
}
|
|
6425
|
-
this.stringList(
|
|
6764
|
+
this.stringList(own3(e, "must_not"), `${path}.must_not`).forEach(
|
|
6426
6765
|
(s, j) => emit(`${path}.must_not[${j}]`, s)
|
|
6427
6766
|
);
|
|
6428
|
-
this.stringList(
|
|
6767
|
+
this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`).forEach(
|
|
6429
6768
|
(s, j) => emit(`${path}.must_not_contain[${j}]`, s)
|
|
6430
6769
|
);
|
|
6431
|
-
const fields =
|
|
6770
|
+
const fields = own3(e, "fields");
|
|
6432
6771
|
if (isRecord(fields)) {
|
|
6433
6772
|
for (const key of sortedKeys(fields)) {
|
|
6434
|
-
const m =
|
|
6773
|
+
const m = own3(fields, key);
|
|
6435
6774
|
if (!isRecord(m)) continue;
|
|
6436
6775
|
const fpath = `${path}.fields.${key}`;
|
|
6437
|
-
scanLeaves(`${fpath}.equals`,
|
|
6776
|
+
scanLeaves(`${fpath}.equals`, own3(m, "equals"), 0, emit);
|
|
6438
6777
|
emit(`${fpath}.contains`, this.s(m, "contains", fpath));
|
|
6439
6778
|
emit(`${fpath}.not_contains`, this.s(m, "not_contains", fpath));
|
|
6440
|
-
const oneOf =
|
|
6779
|
+
const oneOf = own3(m, "one_of");
|
|
6441
6780
|
if (Array.isArray(oneOf)) {
|
|
6442
6781
|
oneOf.forEach(
|
|
6443
6782
|
(one, j) => scanLeaves(`${fpath}.one_of[${j}]`, one, 0, emit)
|
|
@@ -6445,7 +6784,7 @@ var Walker = class _Walker {
|
|
|
6445
6784
|
}
|
|
6446
6785
|
}
|
|
6447
6786
|
}
|
|
6448
|
-
scanLeaves(`${path}.exact`,
|
|
6787
|
+
scanLeaves(`${path}.exact`, own3(e, "exact"), 0, emit);
|
|
6449
6788
|
}
|
|
6450
6789
|
};
|
|
6451
6790
|
function scoreInRange(v) {
|
|
@@ -6561,7 +6900,7 @@ function inputValueFailures(f, raw) {
|
|
|
6561
6900
|
case TYPE_FILE2: {
|
|
6562
6901
|
if (typeof raw === "string") return raw === "" ? [mismatch(f, TYPE_FILE2)] : [];
|
|
6563
6902
|
if (isRecord(raw)) {
|
|
6564
|
-
const ref =
|
|
6903
|
+
const ref = own3(raw, FILE_REF_KEY);
|
|
6565
6904
|
return typeof ref === "string" && ref !== "" ? [] : [mismatch(f, TYPE_FILE2)];
|
|
6566
6905
|
}
|
|
6567
6906
|
return [mismatch(f, TYPE_FILE2)];
|
|
@@ -6641,6 +6980,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
6641
6980
|
validateCredentialEndpointPairing(f, issues);
|
|
6642
6981
|
validateExamples(f, issues);
|
|
6643
6982
|
validateOrchestratorExons(f, issues);
|
|
6983
|
+
validateResidencyEnforcement(f, issues);
|
|
6644
6984
|
validateUnknownKeys(f, issues);
|
|
6645
6985
|
const templateStats = validateTemplates(f, issues, opts);
|
|
6646
6986
|
const totalSteps = f.steps && typeof f.steps === "object" && !Array.isArray(f.steps) ? Object.keys(f.steps).length : 0;
|