@vaudience/aigentflow-flow-validator 0.19.0 → 0.20.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 +73 -35
- package/README.md +2 -2
- package/dist/cli.js +257 -73
- package/dist/index.cjs +256 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +256 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -436,7 +436,7 @@ function validateBasicStructure(flow, issues) {
|
|
|
436
436
|
// src/spec/aigentflow-spec.json
|
|
437
437
|
var aigentflow_spec_default = {
|
|
438
438
|
$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.
|
|
439
|
+
specVersion: "2.821.0",
|
|
440
440
|
inputSchemaVersion: 1,
|
|
441
441
|
executorSchemes: [
|
|
442
442
|
"a2a",
|
|
@@ -1275,6 +1275,35 @@ var aigentflow_spec_default = {
|
|
|
1275
1275
|
}
|
|
1276
1276
|
}
|
|
1277
1277
|
},
|
|
1278
|
+
complianceResidency: {
|
|
1279
|
+
$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).",
|
|
1280
|
+
code: "compliance_residency_unenforced",
|
|
1281
|
+
euResidencyCodes: ["EU", "DE", "FR", "IE", "NL", "IT", "ES"],
|
|
1282
|
+
regionLaneProviders: [
|
|
1283
|
+
"bedrock",
|
|
1284
|
+
"google",
|
|
1285
|
+
"azure",
|
|
1286
|
+
"openai",
|
|
1287
|
+
"assemblyai",
|
|
1288
|
+
"speechmatics",
|
|
1289
|
+
"deepgram",
|
|
1290
|
+
"mistral"
|
|
1291
|
+
],
|
|
1292
|
+
aiProtocol: "ai",
|
|
1293
|
+
protocolSeparator: "://",
|
|
1294
|
+
regionParam: "region",
|
|
1295
|
+
enforceRegionParam: "enforce_region",
|
|
1296
|
+
baseUrlParamSuffix: "_base_url",
|
|
1297
|
+
enforceRegionTrueStrings: ["true", "1", "yes"],
|
|
1298
|
+
stepFieldFormat: "steps.%s.executor",
|
|
1299
|
+
loopStepFieldFormat: "steps.%s.loop.steps.%s.executor",
|
|
1300
|
+
orchestratorField: "orchestrator.exons",
|
|
1301
|
+
siteStepFormat: "step %q",
|
|
1302
|
+
siteLoopStepFormat: "loop sub-step %q of step %q",
|
|
1303
|
+
siteOrchestrator: "the orchestrator",
|
|
1304
|
+
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",
|
|
1305
|
+
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."
|
|
1306
|
+
},
|
|
1278
1307
|
examples: {
|
|
1279
1308
|
$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
1309
|
limits: {
|
|
@@ -1943,6 +1972,25 @@ var CREDENTIAL_ENDPOINT_PAIRING = {
|
|
|
1943
1972
|
familyKeySeparator: aigentflow_spec_default.credentialEndpointPairing.familyKeySeparator,
|
|
1944
1973
|
families: aigentflow_spec_default.credentialEndpointPairing.families
|
|
1945
1974
|
};
|
|
1975
|
+
var COMPLIANCE_RESIDENCY = {
|
|
1976
|
+
code: aigentflow_spec_default.complianceResidency.code,
|
|
1977
|
+
euResidencyCodes: aigentflow_spec_default.complianceResidency.euResidencyCodes,
|
|
1978
|
+
regionLaneProviders: aigentflow_spec_default.complianceResidency.regionLaneProviders,
|
|
1979
|
+
aiProtocol: aigentflow_spec_default.complianceResidency.aiProtocol,
|
|
1980
|
+
protocolSeparator: aigentflow_spec_default.complianceResidency.protocolSeparator,
|
|
1981
|
+
regionParam: aigentflow_spec_default.complianceResidency.regionParam,
|
|
1982
|
+
enforceRegionParam: aigentflow_spec_default.complianceResidency.enforceRegionParam,
|
|
1983
|
+
baseUrlParamSuffix: aigentflow_spec_default.complianceResidency.baseUrlParamSuffix,
|
|
1984
|
+
enforceRegionTrueStrings: aigentflow_spec_default.complianceResidency.enforceRegionTrueStrings,
|
|
1985
|
+
stepFieldFormat: aigentflow_spec_default.complianceResidency.stepFieldFormat,
|
|
1986
|
+
loopStepFieldFormat: aigentflow_spec_default.complianceResidency.loopStepFieldFormat,
|
|
1987
|
+
orchestratorField: aigentflow_spec_default.complianceResidency.orchestratorField,
|
|
1988
|
+
siteStepFormat: aigentflow_spec_default.complianceResidency.siteStepFormat,
|
|
1989
|
+
siteLoopStepFormat: aigentflow_spec_default.complianceResidency.siteLoopStepFormat,
|
|
1990
|
+
siteOrchestrator: aigentflow_spec_default.complianceResidency.siteOrchestrator,
|
|
1991
|
+
messageFormat: aigentflow_spec_default.complianceResidency.messageFormat,
|
|
1992
|
+
suggestion: aigentflow_spec_default.complianceResidency.suggestion
|
|
1993
|
+
};
|
|
1946
1994
|
var EXAMPLES = {
|
|
1947
1995
|
limits: aigentflow_spec_default.examples.limits,
|
|
1948
1996
|
idPattern: new RegExp(aigentflow_spec_default.examples.idPattern),
|
|
@@ -5302,6 +5350,141 @@ function warnOrchestratorToolWithheld(flow, orch, report, issues) {
|
|
|
5302
5350
|
}
|
|
5303
5351
|
}
|
|
5304
5352
|
|
|
5353
|
+
// src/validators/complianceResidency.ts
|
|
5354
|
+
function own2(m, key) {
|
|
5355
|
+
if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
|
|
5356
|
+
return m[key];
|
|
5357
|
+
}
|
|
5358
|
+
function sprintf(format, ...args) {
|
|
5359
|
+
let i = 0;
|
|
5360
|
+
return format.replace(/%[sqv]/g, (verb) => {
|
|
5361
|
+
const arg = args[i++] ?? "";
|
|
5362
|
+
return verb === "%q" ? JSON.stringify(arg) : arg;
|
|
5363
|
+
});
|
|
5364
|
+
}
|
|
5365
|
+
function literalOrEmpty(s) {
|
|
5366
|
+
const t = goTrimSpace2(s);
|
|
5367
|
+
return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
|
|
5368
|
+
}
|
|
5369
|
+
function euOnlyResidency(flow, issues) {
|
|
5370
|
+
const raw = own2(own2(flow, "compliance"), "residency");
|
|
5371
|
+
if (!isArray(raw)) return null;
|
|
5372
|
+
const codes = [];
|
|
5373
|
+
for (let i = 0; i < raw.length; i++) {
|
|
5374
|
+
if (raw[i] === null) continue;
|
|
5375
|
+
const code = issues.stringAt(raw[i], `compliance.residency[${i}]`);
|
|
5376
|
+
if (code === null) return null;
|
|
5377
|
+
codes.push(code);
|
|
5378
|
+
}
|
|
5379
|
+
if (codes.length === 0) return null;
|
|
5380
|
+
const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
|
|
5381
|
+
return codes.every((c) => eu.has(goTrimSpace2(c).toUpperCase())) ? codes : null;
|
|
5382
|
+
}
|
|
5383
|
+
function aiProvider(executor) {
|
|
5384
|
+
const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
|
|
5385
|
+
if (!executor.startsWith(prefix)) return "";
|
|
5386
|
+
const rest = executor.slice(prefix.length);
|
|
5387
|
+
const slash = rest.indexOf("/");
|
|
5388
|
+
const provider = slash > 0 ? rest.slice(0, slash) : "";
|
|
5389
|
+
return provider.includes(TEMPLATE_ACTION_OPEN) ? "" : provider;
|
|
5390
|
+
}
|
|
5391
|
+
function isRegionLane(provider) {
|
|
5392
|
+
const literal = literalOrEmpty(provider);
|
|
5393
|
+
return literal !== "" && COMPLIANCE_RESIDENCY.regionLaneProviders.includes(literal.toLowerCase());
|
|
5394
|
+
}
|
|
5395
|
+
function nonBlankString(m, key) {
|
|
5396
|
+
const v = own2(m, key);
|
|
5397
|
+
return typeof v === "string" && goTrimSpace2(v) !== "";
|
|
5398
|
+
}
|
|
5399
|
+
function queryEnforcesRegion(query) {
|
|
5400
|
+
const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
|
|
5401
|
+
if (typeof v === "boolean") return v;
|
|
5402
|
+
return typeof v === "string" && COMPLIANCE_RESIDENCY.enforceRegionTrueStrings.includes(v);
|
|
5403
|
+
}
|
|
5404
|
+
function flowDirectsEndpoint(flow, provider, issues) {
|
|
5405
|
+
const key = provider.toLowerCase();
|
|
5406
|
+
const inst = own2(own2(flow, "executor_config"), key);
|
|
5407
|
+
if (!isRecord(inst)) return false;
|
|
5408
|
+
const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
|
|
5409
|
+
return baseUrl !== null && goTrimSpace2(baseUrl) !== "";
|
|
5410
|
+
}
|
|
5411
|
+
function callPinsEndpoint(flow, provider, query, issues) {
|
|
5412
|
+
if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
|
|
5413
|
+
if (queryEnforcesRegion(query)) return true;
|
|
5414
|
+
if (nonBlankString(query, provider.toLowerCase() + COMPLIANCE_RESIDENCY.baseUrlParamSuffix)) return true;
|
|
5415
|
+
return flowDirectsEndpoint(flow, provider, issues);
|
|
5416
|
+
}
|
|
5417
|
+
function validateResidencyEnforcement(flow, issues) {
|
|
5418
|
+
const residency = euOnlyResidency(flow, issues);
|
|
5419
|
+
if (residency === null) return;
|
|
5420
|
+
const warn = (site, field, stepId, provider) => {
|
|
5421
|
+
issues.warn({
|
|
5422
|
+
field,
|
|
5423
|
+
...stepId === void 0 ? {} : { stepId },
|
|
5424
|
+
code: COMPLIANCE_RESIDENCY.code,
|
|
5425
|
+
message: sprintf(COMPLIANCE_RESIDENCY.messageFormat, site, provider, `[${residency.join(" ")}]`),
|
|
5426
|
+
suggestion: COMPLIANCE_RESIDENCY.suggestion
|
|
5427
|
+
});
|
|
5428
|
+
};
|
|
5429
|
+
const steps = flow.steps;
|
|
5430
|
+
if (isRecord(steps)) {
|
|
5431
|
+
for (const stepId of Object.keys(steps).sort()) {
|
|
5432
|
+
const step = steps[stepId];
|
|
5433
|
+
if (!isRecord(step)) continue;
|
|
5434
|
+
const calls = [
|
|
5435
|
+
{
|
|
5436
|
+
executor: issues.stringOf(step, "executor", `steps.${stepId}`) ?? "",
|
|
5437
|
+
query: own2(step, "query"),
|
|
5438
|
+
subId: null
|
|
5439
|
+
}
|
|
5440
|
+
];
|
|
5441
|
+
for (const sub of loopSubStepsOfStep(stepId, step)) {
|
|
5442
|
+
calls.push({
|
|
5443
|
+
executor: issues.stringOf(sub.raw, "executor", sub.basePath) ?? "",
|
|
5444
|
+
query: own2(sub.raw, "query"),
|
|
5445
|
+
subId: issues.stringOf(sub.raw, "id", sub.basePath) ?? ""
|
|
5446
|
+
});
|
|
5447
|
+
}
|
|
5448
|
+
for (const call of calls) {
|
|
5449
|
+
const provider = aiProvider(call.executor);
|
|
5450
|
+
if (!isRegionLane(provider)) continue;
|
|
5451
|
+
if (callPinsEndpoint(flow, provider, call.query, issues)) continue;
|
|
5452
|
+
if (call.subId === null) {
|
|
5453
|
+
warn(
|
|
5454
|
+
sprintf(COMPLIANCE_RESIDENCY.siteStepFormat, stepId),
|
|
5455
|
+
sprintf(COMPLIANCE_RESIDENCY.stepFieldFormat, stepId),
|
|
5456
|
+
stepId,
|
|
5457
|
+
provider
|
|
5458
|
+
);
|
|
5459
|
+
} else {
|
|
5460
|
+
warn(
|
|
5461
|
+
sprintf(COMPLIANCE_RESIDENCY.siteLoopStepFormat, call.subId, stepId),
|
|
5462
|
+
sprintf(COMPLIANCE_RESIDENCY.loopStepFieldFormat, stepId, call.subId),
|
|
5463
|
+
stepId,
|
|
5464
|
+
provider
|
|
5465
|
+
);
|
|
5466
|
+
}
|
|
5467
|
+
}
|
|
5468
|
+
}
|
|
5469
|
+
}
|
|
5470
|
+
warnOrchestrator(flow, issues, warn);
|
|
5471
|
+
}
|
|
5472
|
+
function warnOrchestrator(flow, issues, warn) {
|
|
5473
|
+
const orch = flow.orchestrator;
|
|
5474
|
+
if (!isRecord(orch)) return;
|
|
5475
|
+
const source = issues.stringOf(orch, "exons", "orchestrator");
|
|
5476
|
+
if (source === null || source === "") return;
|
|
5477
|
+
const report = inspectExonsFrontmatter(source);
|
|
5478
|
+
if (report.parseError !== null || !report.specRead || !report.hasSpec) return;
|
|
5479
|
+
const provider = literalOrEmpty(report.provider);
|
|
5480
|
+
if (!isRegionLane(provider)) return;
|
|
5481
|
+
const region = issues.stringOf(orch, "region", "orchestrator");
|
|
5482
|
+
if (region !== null && goTrimSpace2(region) !== "") return;
|
|
5483
|
+
if (orch.enforce_region === true) return;
|
|
5484
|
+
if (flowDirectsEndpoint(flow, provider, issues)) return;
|
|
5485
|
+
warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
|
|
5486
|
+
}
|
|
5487
|
+
|
|
5305
5488
|
// src/validators/examples.ts
|
|
5306
5489
|
var KEY_EXAMPLES = "examples";
|
|
5307
5490
|
var VISIBILITY_PUBLIC = "public";
|
|
@@ -5379,7 +5562,7 @@ function num(n) {
|
|
|
5379
5562
|
function has(o, key) {
|
|
5380
5563
|
return Object.prototype.hasOwnProperty.call(o, key) && o[key] !== null && o[key] !== void 0;
|
|
5381
5564
|
}
|
|
5382
|
-
function
|
|
5565
|
+
function own3(o, key) {
|
|
5383
5566
|
return Object.prototype.hasOwnProperty.call(o, key) ? o[key] : void 0;
|
|
5384
5567
|
}
|
|
5385
5568
|
function setOwn(o, key, value) {
|
|
@@ -5431,7 +5614,7 @@ function mergePatch(target, patch, depth) {
|
|
|
5431
5614
|
continue;
|
|
5432
5615
|
}
|
|
5433
5616
|
if (isRecord(pv)) {
|
|
5434
|
-
const current =
|
|
5617
|
+
const current = own3(target, k);
|
|
5435
5618
|
const existing = isRecord(current) ? deepCopy(current, 0) : {};
|
|
5436
5619
|
mergePatch(existing, pv, depth + 1);
|
|
5437
5620
|
setOwn(target, k, existing);
|
|
@@ -5451,7 +5634,7 @@ function asFileRef(v) {
|
|
|
5451
5634
|
if (keys.length === 0) return null;
|
|
5452
5635
|
for (const k of keys) if (!FILE_REF_KEYS.has(k)) return null;
|
|
5453
5636
|
const str = (k) => {
|
|
5454
|
-
const x =
|
|
5637
|
+
const x = own3(v, k);
|
|
5455
5638
|
return typeof x === "string" ? x : "";
|
|
5456
5639
|
};
|
|
5457
5640
|
return {
|
|
@@ -5519,7 +5702,7 @@ var Walker = class _Walker {
|
|
|
5519
5702
|
`the examples block is ${size} bytes; the limit is ${L.maxBlockBytes}. Move large inputs or target outputs to a file reference (https URL).`
|
|
5520
5703
|
);
|
|
5521
5704
|
}
|
|
5522
|
-
const allHeld = examples.every((e) => isRecord(e) &&
|
|
5705
|
+
const allHeld = examples.every((e) => isRecord(e) && own3(e, "hold_out") === true);
|
|
5523
5706
|
if (allHeld) {
|
|
5524
5707
|
this.warn(
|
|
5525
5708
|
"examples_all_held_out",
|
|
@@ -5607,9 +5790,9 @@ var Walker = class _Walker {
|
|
|
5607
5790
|
`example ${q(label)} notes are ${notesN} characters; the limit is ${L.maxNotesRunes}`
|
|
5608
5791
|
);
|
|
5609
5792
|
}
|
|
5610
|
-
this.validateTags(path, label,
|
|
5611
|
-
this.validateWeight(`${path}.weight`, label, numberOf(
|
|
5612
|
-
const minScore = numberOf(
|
|
5793
|
+
this.validateTags(path, label, own3(ex, "tags"));
|
|
5794
|
+
this.validateWeight(`${path}.weight`, label, numberOf(own3(ex, "weight")));
|
|
5795
|
+
const minScore = numberOf(own3(ex, "min_score"));
|
|
5613
5796
|
if (minScore !== void 0 && !scoreInRange(minScore)) {
|
|
5614
5797
|
this.err(
|
|
5615
5798
|
"example_min_score_range",
|
|
@@ -5625,7 +5808,7 @@ var Walker = class _Walker {
|
|
|
5625
5808
|
`example ${q(label)} has side_effects ${q(sideEffects)}; use refuse or allow`
|
|
5626
5809
|
);
|
|
5627
5810
|
}
|
|
5628
|
-
const holdOut =
|
|
5811
|
+
const holdOut = own3(ex, "hold_out") === true;
|
|
5629
5812
|
if (holdOut && this.isPublic()) {
|
|
5630
5813
|
this.err(
|
|
5631
5814
|
"example_holdout_in_public_flow",
|
|
@@ -5648,17 +5831,17 @@ var Walker = class _Walker {
|
|
|
5648
5831
|
`example ${q(label)} has neither input nor input_ref; use input: {} for a flow that takes no input`
|
|
5649
5832
|
);
|
|
5650
5833
|
}
|
|
5651
|
-
const rawInput =
|
|
5834
|
+
const rawInput = own3(ex, "input");
|
|
5652
5835
|
const baseInput = isRecord(rawInput) ? rawInput : null;
|
|
5653
5836
|
if (baseInput !== null) {
|
|
5654
5837
|
this.checkInput(`${path}.input`, label, baseInput, "example_input_invalid");
|
|
5655
5838
|
}
|
|
5656
|
-
const rawInputRef =
|
|
5839
|
+
const rawInputRef = own3(ex, "input_ref");
|
|
5657
5840
|
if (isRecord(rawInputRef)) {
|
|
5658
5841
|
this.validateFileRef(`${path}.input_ref`, this.fileRefOf(rawInputRef, `${path}.input_ref`));
|
|
5659
5842
|
}
|
|
5660
5843
|
let binaryOnly = false;
|
|
5661
|
-
const expected =
|
|
5844
|
+
const expected = own3(ex, "expected");
|
|
5662
5845
|
if (!has(ex, "expected")) {
|
|
5663
5846
|
this.err(
|
|
5664
5847
|
"example_expected_missing",
|
|
@@ -5677,7 +5860,7 @@ var Walker = class _Walker {
|
|
|
5677
5860
|
"this example can be run but not scored"
|
|
5678
5861
|
);
|
|
5679
5862
|
}
|
|
5680
|
-
this.validateCheckpoints(path, label,
|
|
5863
|
+
this.validateCheckpoints(path, label, own3(ex, "checkpoints"));
|
|
5681
5864
|
this.validateVariants(i, path, label, ex, hasInput, baseInput);
|
|
5682
5865
|
this.scanSecretLike(i, path, ex);
|
|
5683
5866
|
}
|
|
@@ -5737,8 +5920,8 @@ var Walker = class _Walker {
|
|
|
5737
5920
|
);
|
|
5738
5921
|
return;
|
|
5739
5922
|
}
|
|
5740
|
-
const schema =
|
|
5741
|
-
const query =
|
|
5923
|
+
const schema = own3(this.flow, "input_schema");
|
|
5924
|
+
const query = own3(this.flow, "query");
|
|
5742
5925
|
if (isRecord(schema)) {
|
|
5743
5926
|
this.checkInputAgainstSchema(field, label, input, schema, code);
|
|
5744
5927
|
} else if (isRecord(query) && Object.keys(query).length > 0) {
|
|
@@ -5806,29 +5989,29 @@ var Walker = class _Walker {
|
|
|
5806
5989
|
}
|
|
5807
5990
|
}
|
|
5808
5991
|
schemaFields(schema) {
|
|
5809
|
-
const raw =
|
|
5992
|
+
const raw = own3(schema, "fields");
|
|
5810
5993
|
if (!Array.isArray(raw)) return [];
|
|
5811
5994
|
const out = [];
|
|
5812
5995
|
raw.forEach((f, i) => {
|
|
5813
5996
|
if (!isRecord(f)) return;
|
|
5814
5997
|
const base = `input_schema.fields[${i}]`;
|
|
5815
|
-
const enumRaw =
|
|
5998
|
+
const enumRaw = own3(f, "enum");
|
|
5816
5999
|
const enumValues = [];
|
|
5817
6000
|
if (Array.isArray(enumRaw)) {
|
|
5818
6001
|
enumRaw.forEach((e, j) => {
|
|
5819
6002
|
enumValues.push(e === null ? "" : this.issues.stringAt(e, `${base}.enum[${j}]`) ?? "");
|
|
5820
6003
|
});
|
|
5821
6004
|
}
|
|
5822
|
-
const vw =
|
|
6005
|
+
const vw = own3(f, "visible_when");
|
|
5823
6006
|
out.push({
|
|
5824
6007
|
name: this.s(f, "name", base),
|
|
5825
6008
|
type: this.s(f, "type", base),
|
|
5826
|
-
required:
|
|
6009
|
+
required: own3(f, "required") === true,
|
|
5827
6010
|
enumValues,
|
|
5828
6011
|
visibleWhen: isRecord(vw) ? {
|
|
5829
6012
|
field: this.s(vw, "field", `${base}.visible_when`),
|
|
5830
|
-
equals:
|
|
5831
|
-
in: Array.isArray(
|
|
6013
|
+
equals: own3(vw, "equals"),
|
|
6014
|
+
in: Array.isArray(own3(vw, "in")) ? own3(vw, "in") : []
|
|
5832
6015
|
} : null
|
|
5833
6016
|
});
|
|
5834
6017
|
});
|
|
@@ -5839,7 +6022,7 @@ var Walker = class _Walker {
|
|
|
5839
6022
|
const failures = [];
|
|
5840
6023
|
for (const f of fields) {
|
|
5841
6024
|
if (!isVisible(f, runInput)) continue;
|
|
5842
|
-
const raw =
|
|
6025
|
+
const raw = own3(runInput, f.name);
|
|
5843
6026
|
if (raw === void 0 || raw === null) {
|
|
5844
6027
|
if (f.required) {
|
|
5845
6028
|
failures.push({
|
|
@@ -5950,7 +6133,7 @@ var Walker = class _Walker {
|
|
|
5950
6133
|
/** The names `fields` / `exact` may use, and whether such a list is declared at all. */
|
|
5951
6134
|
outputNamesFor(kind, stepId) {
|
|
5952
6135
|
if (kind === "final") {
|
|
5953
|
-
const out =
|
|
6136
|
+
const out = own3(this.flow, "output");
|
|
5954
6137
|
const names2 = [];
|
|
5955
6138
|
if (Array.isArray(out)) {
|
|
5956
6139
|
out.forEach((item, i) => {
|
|
@@ -5959,10 +6142,10 @@ var Walker = class _Walker {
|
|
|
5959
6142
|
}
|
|
5960
6143
|
return { names: names2, declared: names2.length > 0 };
|
|
5961
6144
|
}
|
|
5962
|
-
const steps =
|
|
5963
|
-
const step = isRecord(steps) ?
|
|
5964
|
-
const schema = isRecord(step) ?
|
|
5965
|
-
const fields = isRecord(schema) ?
|
|
6145
|
+
const steps = own3(this.flow, "steps");
|
|
6146
|
+
const step = isRecord(steps) ? own3(steps, stepId) : void 0;
|
|
6147
|
+
const schema = isRecord(step) ? own3(step, "output_schema") : void 0;
|
|
6148
|
+
const fields = isRecord(schema) ? own3(schema, "fields") : void 0;
|
|
5966
6149
|
if (!Array.isArray(fields) || fields.length === 0) return { names: [], declared: false };
|
|
5967
6150
|
const names = [];
|
|
5968
6151
|
fields.forEach((f, i) => {
|
|
@@ -5981,8 +6164,8 @@ var Walker = class _Walker {
|
|
|
5981
6164
|
);
|
|
5982
6165
|
}
|
|
5983
6166
|
const noOutput = status === STATUS_FAILED || status === STATUS_PAUSED_FOR_HUMAN;
|
|
5984
|
-
const fieldsRec =
|
|
5985
|
-
const exactRec =
|
|
6167
|
+
const fieldsRec = own3(e, "fields");
|
|
6168
|
+
const exactRec = own3(e, "exact");
|
|
5986
6169
|
const fieldKeys = isRecord(fieldsRec) ? sortedKeys(fieldsRec) : [];
|
|
5987
6170
|
const exactKeys = isRecord(exactRec) ? sortedKeys(exactRec) : [];
|
|
5988
6171
|
const hasFields = fieldKeys.length > 0;
|
|
@@ -6000,7 +6183,7 @@ var Walker = class _Walker {
|
|
|
6000
6183
|
`a case that ends in ${status} has no output to match; remove fields and exact, or expect status completed`
|
|
6001
6184
|
);
|
|
6002
6185
|
}
|
|
6003
|
-
const minScore = numberOf(
|
|
6186
|
+
const minScore = numberOf(own3(e, "min_score"));
|
|
6004
6187
|
if (minScore !== void 0 && !scoreInRange(minScore)) {
|
|
6005
6188
|
this.err(
|
|
6006
6189
|
"example_min_score_range",
|
|
@@ -6027,7 +6210,7 @@ var Walker = class _Walker {
|
|
|
6027
6210
|
}
|
|
6028
6211
|
}
|
|
6029
6212
|
}
|
|
6030
|
-
const reference =
|
|
6213
|
+
const reference = own3(e, "reference");
|
|
6031
6214
|
if (isRecord(reference)) this.validateReference(`${path}.reference`, reference);
|
|
6032
6215
|
const { names, declared } = this.outputNamesFor(kind, stepId);
|
|
6033
6216
|
const checkKey = (field, key) => {
|
|
@@ -6054,12 +6237,12 @@ var Walker = class _Walker {
|
|
|
6054
6237
|
for (const key of fieldKeys) {
|
|
6055
6238
|
const fpath = `${path}.fields.${key}`;
|
|
6056
6239
|
checkKey(fpath, key);
|
|
6057
|
-
const matcher =
|
|
6240
|
+
const matcher = own3(fieldsRec, key);
|
|
6058
6241
|
if (isRecord(matcher)) this.validateFieldMatcher(fpath, matcher);
|
|
6059
6242
|
}
|
|
6060
6243
|
for (const key of exactKeys) checkKey(`${path}.exact.${key}`, key);
|
|
6061
|
-
const mustNot = this.stringList(
|
|
6062
|
-
const mustNotContain = this.stringList(
|
|
6244
|
+
const mustNot = this.stringList(own3(e, "must_not"), `${path}.must_not`);
|
|
6245
|
+
const mustNotContain = this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`);
|
|
6063
6246
|
const mustNotMsg = `must_not takes up to ${L.maxMustNot} statements of at most ${L.maxMustNotRunes} characters each, none empty`;
|
|
6064
6247
|
if (mustNot.length > L.maxMustNot) {
|
|
6065
6248
|
this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
|
|
@@ -6080,9 +6263,9 @@ var Walker = class _Walker {
|
|
|
6080
6263
|
}
|
|
6081
6264
|
});
|
|
6082
6265
|
for (const key of fieldKeys) {
|
|
6083
|
-
const matcher =
|
|
6266
|
+
const matcher = own3(fieldsRec, key);
|
|
6084
6267
|
if (!isRecord(matcher)) continue;
|
|
6085
|
-
const eq =
|
|
6268
|
+
const eq = own3(matcher, "equals");
|
|
6086
6269
|
if (typeof eq !== "string" || eq === "") continue;
|
|
6087
6270
|
for (const banned of mustNotContain) {
|
|
6088
6271
|
if (banned !== "" && equalFold(banned, eq)) {
|
|
@@ -6142,7 +6325,7 @@ var Walker = class _Walker {
|
|
|
6142
6325
|
}
|
|
6143
6326
|
return;
|
|
6144
6327
|
}
|
|
6145
|
-
const refRec =
|
|
6328
|
+
const refRec = own3(r, "ref");
|
|
6146
6329
|
if (!isRecord(refRec)) return;
|
|
6147
6330
|
const ref = this.fileRefOf(refRec, `${path}.ref`);
|
|
6148
6331
|
this.validateFileRef(`${path}.ref`, ref);
|
|
@@ -6155,22 +6338,22 @@ var Walker = class _Walker {
|
|
|
6155
6338
|
}
|
|
6156
6339
|
}
|
|
6157
6340
|
expectationIsBinaryReferenceOnly(e, path) {
|
|
6158
|
-
const reference =
|
|
6159
|
-
const refRec = isRecord(reference) ?
|
|
6341
|
+
const reference = own3(e, "reference");
|
|
6342
|
+
const refRec = isRecord(reference) ? own3(reference, "ref") : void 0;
|
|
6160
6343
|
if (!isRecord(refRec)) return false;
|
|
6161
6344
|
const mediaType = this.s(refRec, "media_type", `${path}.reference.ref`);
|
|
6162
6345
|
if (mediaType === "" || isTextualMediaType(mediaType)) return false;
|
|
6163
6346
|
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(
|
|
6347
|
+
const fields = own3(e, "fields");
|
|
6348
|
+
const exact = own3(e, "exact");
|
|
6349
|
+
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
6350
|
}
|
|
6168
6351
|
validateFieldMatcher(path, m) {
|
|
6169
6352
|
const L = EXAMPLES.limits;
|
|
6170
6353
|
const matches = this.s(m, "matches", path);
|
|
6171
|
-
const oneOf =
|
|
6172
|
-
const approx = numberOf(
|
|
6173
|
-
const tolerance = numberOf(
|
|
6354
|
+
const oneOf = own3(m, "one_of");
|
|
6355
|
+
const approx = numberOf(own3(m, "approx"));
|
|
6356
|
+
const tolerance = numberOf(own3(m, "tolerance"));
|
|
6174
6357
|
let operators = 0;
|
|
6175
6358
|
if (has(m, "equals")) operators++;
|
|
6176
6359
|
if (this.s(m, "contains", path) !== "") operators++;
|
|
@@ -6178,7 +6361,7 @@ var Walker = class _Walker {
|
|
|
6178
6361
|
if (matches !== "") operators++;
|
|
6179
6362
|
if (Array.isArray(oneOf) && oneOf.length > 0) operators++;
|
|
6180
6363
|
if (approx !== void 0) operators++;
|
|
6181
|
-
if (typeof
|
|
6364
|
+
if (typeof own3(m, "present") === "boolean") operators++;
|
|
6182
6365
|
if (operators !== 1) {
|
|
6183
6366
|
this.err(
|
|
6184
6367
|
"example_field_matcher_invalid",
|
|
@@ -6205,12 +6388,12 @@ var Walker = class _Walker {
|
|
|
6205
6388
|
// -- checkpoints ------------------------------------------------------
|
|
6206
6389
|
validateCheckpoints(path, label, cps) {
|
|
6207
6390
|
if (!isRecord(cps) || Object.keys(cps).length === 0) return;
|
|
6208
|
-
const stepsRaw =
|
|
6391
|
+
const stepsRaw = own3(this.flow, "steps");
|
|
6209
6392
|
const steps = isRecord(stepsRaw) ? stepsRaw : {};
|
|
6210
6393
|
const stepIds = sortedKeys(steps);
|
|
6211
6394
|
for (const id of sortedKeys(cps)) {
|
|
6212
6395
|
const cpath = `${path}.checkpoints.${id}`;
|
|
6213
|
-
const step =
|
|
6396
|
+
const step = own3(steps, id);
|
|
6214
6397
|
if (!isRecord(step)) {
|
|
6215
6398
|
this.err(
|
|
6216
6399
|
"example_checkpoint_step_unknown",
|
|
@@ -6220,7 +6403,7 @@ var Walker = class _Walker {
|
|
|
6220
6403
|
);
|
|
6221
6404
|
continue;
|
|
6222
6405
|
}
|
|
6223
|
-
const next =
|
|
6406
|
+
const next = own3(step, "next");
|
|
6224
6407
|
if (has(step, "for_each") || has(step, "loop") || isRecord(next) && has(next, "parallel")) {
|
|
6225
6408
|
this.err(
|
|
6226
6409
|
"example_checkpoint_step_composite",
|
|
@@ -6229,7 +6412,7 @@ var Walker = class _Walker {
|
|
|
6229
6412
|
);
|
|
6230
6413
|
continue;
|
|
6231
6414
|
}
|
|
6232
|
-
const cp =
|
|
6415
|
+
const cp = own3(cps, id);
|
|
6233
6416
|
if (cp === null || cp === void 0) {
|
|
6234
6417
|
this.validateExpectation(cpath, label, {}, "checkpoint", id);
|
|
6235
6418
|
} else if (isRecord(cp)) {
|
|
@@ -6240,7 +6423,7 @@ var Walker = class _Walker {
|
|
|
6240
6423
|
// -- variants ---------------------------------------------------------
|
|
6241
6424
|
validateVariants(i, path, label, ex, hasInput, baseInput) {
|
|
6242
6425
|
const L = EXAMPLES.limits;
|
|
6243
|
-
const variants =
|
|
6426
|
+
const variants = own3(ex, "variants");
|
|
6244
6427
|
if (!Array.isArray(variants) || variants.length === 0) return;
|
|
6245
6428
|
if (variants.length > L.maxVariants) {
|
|
6246
6429
|
this.err(
|
|
@@ -6303,8 +6486,8 @@ var Walker = class _Walker {
|
|
|
6303
6486
|
`example ${q(both)} notes are ${provN} characters; the limit is ${L.maxProvenanceRunes}`
|
|
6304
6487
|
);
|
|
6305
6488
|
}
|
|
6306
|
-
this.validateWeight(`${vpath}.weight`, both, numberOf(
|
|
6307
|
-
const patch =
|
|
6489
|
+
this.validateWeight(`${vpath}.weight`, both, numberOf(own3(v, "weight")));
|
|
6490
|
+
const patch = own3(v, "input_patch");
|
|
6308
6491
|
const patchRec = isRecord(patch) ? patch : null;
|
|
6309
6492
|
const hasPatch = patchRec !== null && Object.keys(patchRec).length > 0;
|
|
6310
6493
|
const hasRef = has(v, "input_ref");
|
|
@@ -6321,7 +6504,7 @@ var Walker = class _Walker {
|
|
|
6321
6504
|
`variant ${q(vlabel)} of example ${q(label)} changes neither the input nor the expectation`
|
|
6322
6505
|
);
|
|
6323
6506
|
}
|
|
6324
|
-
const refRec =
|
|
6507
|
+
const refRec = own3(v, "input_ref");
|
|
6325
6508
|
if (isRecord(refRec)) {
|
|
6326
6509
|
this.validateFileRef(`${vpath}.input_ref`, this.fileRefOf(refRec, `${vpath}.input_ref`));
|
|
6327
6510
|
}
|
|
@@ -6336,7 +6519,7 @@ var Walker = class _Walker {
|
|
|
6336
6519
|
this.checkVariantPatch(vpath, label, vlabel, baseInput, patchRec);
|
|
6337
6520
|
}
|
|
6338
6521
|
}
|
|
6339
|
-
const expected =
|
|
6522
|
+
const expected = own3(v, "expected");
|
|
6340
6523
|
if (isRecord(expected)) {
|
|
6341
6524
|
this.validateExpectation(`${vpath}.expected`, both, expected, "final", "");
|
|
6342
6525
|
}
|
|
@@ -6347,11 +6530,11 @@ var Walker = class _Walker {
|
|
|
6347
6530
|
* itself supplies. A null patch value deleting a secret is fine.
|
|
6348
6531
|
*/
|
|
6349
6532
|
checkVariantPatch(vpath, label, vlabel, base, patch) {
|
|
6350
|
-
const schema =
|
|
6533
|
+
const schema = own3(this.flow, "input_schema");
|
|
6351
6534
|
if (isRecord(schema)) {
|
|
6352
6535
|
for (const f of this.schemaFields(schema)) {
|
|
6353
6536
|
if (f.type !== TYPE_SECRET) continue;
|
|
6354
|
-
const val =
|
|
6537
|
+
const val = own3(patch, f.name);
|
|
6355
6538
|
if (val !== void 0 && val !== null) {
|
|
6356
6539
|
this.err(
|
|
6357
6540
|
"example_secret_value",
|
|
@@ -6391,18 +6574,18 @@ var Walker = class _Walker {
|
|
|
6391
6574
|
emit(`${path}.title`, this.s(ex, "title", path));
|
|
6392
6575
|
emit(`${path}.guidance`, this.s(ex, "guidance", path));
|
|
6393
6576
|
emit(`${path}.notes`, this.s(ex, "notes", path));
|
|
6394
|
-
const input =
|
|
6577
|
+
const input = own3(ex, "input");
|
|
6395
6578
|
if (isRecord(input)) scanLeaves(`${path}.input`, input, 0, emit);
|
|
6396
|
-
const expected =
|
|
6579
|
+
const expected = own3(ex, "expected");
|
|
6397
6580
|
if (isRecord(expected)) this.scanExpectationLeaves(`${path}.expected`, expected, emit);
|
|
6398
|
-
const cps =
|
|
6581
|
+
const cps = own3(ex, "checkpoints");
|
|
6399
6582
|
if (isRecord(cps)) {
|
|
6400
6583
|
for (const id of sortedKeys(cps)) {
|
|
6401
|
-
const cp =
|
|
6584
|
+
const cp = own3(cps, id);
|
|
6402
6585
|
if (isRecord(cp)) this.scanExpectationLeaves(`${path}.checkpoints.${id}`, cp, emit);
|
|
6403
6586
|
}
|
|
6404
6587
|
}
|
|
6405
|
-
const variants =
|
|
6588
|
+
const variants = own3(ex, "variants");
|
|
6406
6589
|
if (Array.isArray(variants)) {
|
|
6407
6590
|
variants.forEach((v, j) => {
|
|
6408
6591
|
if (!isRecord(v)) return;
|
|
@@ -6410,34 +6593,34 @@ var Walker = class _Walker {
|
|
|
6410
6593
|
emit(`${vpath}.title`, this.s(v, "title", vpath));
|
|
6411
6594
|
emit(`${vpath}.guidance`, this.s(v, "guidance", vpath));
|
|
6412
6595
|
emit(`${vpath}.provenance`, this.s(v, "provenance", vpath));
|
|
6413
|
-
scanLeaves(`${vpath}.input_patch`,
|
|
6414
|
-
const vexp =
|
|
6596
|
+
scanLeaves(`${vpath}.input_patch`, own3(v, "input_patch"), 0, emit);
|
|
6597
|
+
const vexp = own3(v, "expected");
|
|
6415
6598
|
if (isRecord(vexp)) this.scanExpectationLeaves(`${vpath}.expected`, vexp, emit);
|
|
6416
6599
|
});
|
|
6417
6600
|
}
|
|
6418
6601
|
}
|
|
6419
6602
|
scanExpectationLeaves(path, e, emit) {
|
|
6420
6603
|
emit(`${path}.rubric`, this.s(e, "rubric", path));
|
|
6421
|
-
const reference =
|
|
6604
|
+
const reference = own3(e, "reference");
|
|
6422
6605
|
if (isRecord(reference)) {
|
|
6423
6606
|
emit(`${path}.reference.text`, this.s(reference, "text", `${path}.reference`));
|
|
6424
6607
|
}
|
|
6425
|
-
this.stringList(
|
|
6608
|
+
this.stringList(own3(e, "must_not"), `${path}.must_not`).forEach(
|
|
6426
6609
|
(s, j) => emit(`${path}.must_not[${j}]`, s)
|
|
6427
6610
|
);
|
|
6428
|
-
this.stringList(
|
|
6611
|
+
this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`).forEach(
|
|
6429
6612
|
(s, j) => emit(`${path}.must_not_contain[${j}]`, s)
|
|
6430
6613
|
);
|
|
6431
|
-
const fields =
|
|
6614
|
+
const fields = own3(e, "fields");
|
|
6432
6615
|
if (isRecord(fields)) {
|
|
6433
6616
|
for (const key of sortedKeys(fields)) {
|
|
6434
|
-
const m =
|
|
6617
|
+
const m = own3(fields, key);
|
|
6435
6618
|
if (!isRecord(m)) continue;
|
|
6436
6619
|
const fpath = `${path}.fields.${key}`;
|
|
6437
|
-
scanLeaves(`${fpath}.equals`,
|
|
6620
|
+
scanLeaves(`${fpath}.equals`, own3(m, "equals"), 0, emit);
|
|
6438
6621
|
emit(`${fpath}.contains`, this.s(m, "contains", fpath));
|
|
6439
6622
|
emit(`${fpath}.not_contains`, this.s(m, "not_contains", fpath));
|
|
6440
|
-
const oneOf =
|
|
6623
|
+
const oneOf = own3(m, "one_of");
|
|
6441
6624
|
if (Array.isArray(oneOf)) {
|
|
6442
6625
|
oneOf.forEach(
|
|
6443
6626
|
(one, j) => scanLeaves(`${fpath}.one_of[${j}]`, one, 0, emit)
|
|
@@ -6445,7 +6628,7 @@ var Walker = class _Walker {
|
|
|
6445
6628
|
}
|
|
6446
6629
|
}
|
|
6447
6630
|
}
|
|
6448
|
-
scanLeaves(`${path}.exact`,
|
|
6631
|
+
scanLeaves(`${path}.exact`, own3(e, "exact"), 0, emit);
|
|
6449
6632
|
}
|
|
6450
6633
|
};
|
|
6451
6634
|
function scoreInRange(v) {
|
|
@@ -6561,7 +6744,7 @@ function inputValueFailures(f, raw) {
|
|
|
6561
6744
|
case TYPE_FILE2: {
|
|
6562
6745
|
if (typeof raw === "string") return raw === "" ? [mismatch(f, TYPE_FILE2)] : [];
|
|
6563
6746
|
if (isRecord(raw)) {
|
|
6564
|
-
const ref =
|
|
6747
|
+
const ref = own3(raw, FILE_REF_KEY);
|
|
6565
6748
|
return typeof ref === "string" && ref !== "" ? [] : [mismatch(f, TYPE_FILE2)];
|
|
6566
6749
|
}
|
|
6567
6750
|
return [mismatch(f, TYPE_FILE2)];
|
|
@@ -6641,6 +6824,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
6641
6824
|
validateCredentialEndpointPairing(f, issues);
|
|
6642
6825
|
validateExamples(f, issues);
|
|
6643
6826
|
validateOrchestratorExons(f, issues);
|
|
6827
|
+
validateResidencyEnforcement(f, issues);
|
|
6644
6828
|
validateUnknownKeys(f, issues);
|
|
6645
6829
|
const templateStats = validateTemplates(f, issues, opts);
|
|
6646
6830
|
const totalSteps = f.steps && typeof f.steps === "object" && !Array.isArray(f.steps) ? Object.keys(f.steps).length : 0;
|