@vaudience/aigentflow-flow-validator 0.18.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 +86 -35
- package/README.md +2 -2
- package/dist/cli.js +270 -73
- package/dist/index.cjs +269 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +269 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -430,7 +430,7 @@ function validateBasicStructure(flow, issues) {
|
|
|
430
430
|
|
|
431
431
|
// src/spec/aigentflow-spec.json
|
|
432
432
|
var aigentflow_spec_default = {
|
|
433
|
-
specVersion: "2.
|
|
433
|
+
specVersion: "2.821.0",
|
|
434
434
|
inputSchemaVersion: 1,
|
|
435
435
|
executorSchemes: [
|
|
436
436
|
"a2a",
|
|
@@ -1255,6 +1255,34 @@ var aigentflow_spec_default = {
|
|
|
1255
1255
|
}
|
|
1256
1256
|
}
|
|
1257
1257
|
},
|
|
1258
|
+
complianceResidency: {
|
|
1259
|
+
code: "compliance_residency_unenforced",
|
|
1260
|
+
euResidencyCodes: ["EU", "DE", "FR", "IE", "NL", "IT", "ES"],
|
|
1261
|
+
regionLaneProviders: [
|
|
1262
|
+
"bedrock",
|
|
1263
|
+
"google",
|
|
1264
|
+
"azure",
|
|
1265
|
+
"openai",
|
|
1266
|
+
"assemblyai",
|
|
1267
|
+
"speechmatics",
|
|
1268
|
+
"deepgram",
|
|
1269
|
+
"mistral"
|
|
1270
|
+
],
|
|
1271
|
+
aiProtocol: "ai",
|
|
1272
|
+
protocolSeparator: "://",
|
|
1273
|
+
regionParam: "region",
|
|
1274
|
+
enforceRegionParam: "enforce_region",
|
|
1275
|
+
baseUrlParamSuffix: "_base_url",
|
|
1276
|
+
enforceRegionTrueStrings: ["true", "1", "yes"],
|
|
1277
|
+
stepFieldFormat: "steps.%s.executor",
|
|
1278
|
+
loopStepFieldFormat: "steps.%s.loop.steps.%s.executor",
|
|
1279
|
+
orchestratorField: "orchestrator.exons",
|
|
1280
|
+
siteStepFormat: "step %q",
|
|
1281
|
+
siteLoopStepFormat: "loop sub-step %q of step %q",
|
|
1282
|
+
siteOrchestrator: "the orchestrator",
|
|
1283
|
+
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",
|
|
1284
|
+
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."
|
|
1285
|
+
},
|
|
1258
1286
|
examples: {
|
|
1259
1287
|
limits: {
|
|
1260
1288
|
maxPerFlow: 50,
|
|
@@ -1642,6 +1670,7 @@ var aigentflow_spec_default = {
|
|
|
1642
1670
|
deny_tools: "list<scalar>",
|
|
1643
1671
|
discoverable_tools: "list<scalar>",
|
|
1644
1672
|
enable_signals: "scalar",
|
|
1673
|
+
enforce_region: "scalar",
|
|
1645
1674
|
engram_scope: "scalar",
|
|
1646
1675
|
exons: "scalar",
|
|
1647
1676
|
human_question_timeout: "scalar",
|
|
@@ -1650,6 +1679,7 @@ var aigentflow_spec_default = {
|
|
|
1650
1679
|
max_tool_turns: "scalar",
|
|
1651
1680
|
max_turns: "scalar",
|
|
1652
1681
|
mode: "scalar",
|
|
1682
|
+
region: "scalar",
|
|
1653
1683
|
require_approval_for: "list<scalar>",
|
|
1654
1684
|
timeout_seconds: "scalar",
|
|
1655
1685
|
tool_discovery: "scalar",
|
|
@@ -1848,6 +1878,25 @@ var CREDENTIAL_ENDPOINT_PAIRING = {
|
|
|
1848
1878
|
familyKeySeparator: aigentflow_spec_default.credentialEndpointPairing.familyKeySeparator,
|
|
1849
1879
|
families: aigentflow_spec_default.credentialEndpointPairing.families
|
|
1850
1880
|
};
|
|
1881
|
+
var COMPLIANCE_RESIDENCY = {
|
|
1882
|
+
code: aigentflow_spec_default.complianceResidency.code,
|
|
1883
|
+
euResidencyCodes: aigentflow_spec_default.complianceResidency.euResidencyCodes,
|
|
1884
|
+
regionLaneProviders: aigentflow_spec_default.complianceResidency.regionLaneProviders,
|
|
1885
|
+
aiProtocol: aigentflow_spec_default.complianceResidency.aiProtocol,
|
|
1886
|
+
protocolSeparator: aigentflow_spec_default.complianceResidency.protocolSeparator,
|
|
1887
|
+
regionParam: aigentflow_spec_default.complianceResidency.regionParam,
|
|
1888
|
+
enforceRegionParam: aigentflow_spec_default.complianceResidency.enforceRegionParam,
|
|
1889
|
+
baseUrlParamSuffix: aigentflow_spec_default.complianceResidency.baseUrlParamSuffix,
|
|
1890
|
+
enforceRegionTrueStrings: aigentflow_spec_default.complianceResidency.enforceRegionTrueStrings,
|
|
1891
|
+
stepFieldFormat: aigentflow_spec_default.complianceResidency.stepFieldFormat,
|
|
1892
|
+
loopStepFieldFormat: aigentflow_spec_default.complianceResidency.loopStepFieldFormat,
|
|
1893
|
+
orchestratorField: aigentflow_spec_default.complianceResidency.orchestratorField,
|
|
1894
|
+
siteStepFormat: aigentflow_spec_default.complianceResidency.siteStepFormat,
|
|
1895
|
+
siteLoopStepFormat: aigentflow_spec_default.complianceResidency.siteLoopStepFormat,
|
|
1896
|
+
siteOrchestrator: aigentflow_spec_default.complianceResidency.siteOrchestrator,
|
|
1897
|
+
messageFormat: aigentflow_spec_default.complianceResidency.messageFormat,
|
|
1898
|
+
suggestion: aigentflow_spec_default.complianceResidency.suggestion
|
|
1899
|
+
};
|
|
1851
1900
|
var EXAMPLES = {
|
|
1852
1901
|
limits: aigentflow_spec_default.examples.limits,
|
|
1853
1902
|
idPattern: new RegExp(aigentflow_spec_default.examples.idPattern),
|
|
@@ -3062,6 +3111,17 @@ function validateOrchestratorCampaign(flow, issues, opts) {
|
|
|
3062
3111
|
code: "orchestrator_owner_needs_yield"
|
|
3063
3112
|
});
|
|
3064
3113
|
}
|
|
3114
|
+
if (orch.enforce_region === true) {
|
|
3115
|
+
const region = issues.stringOf(orch, "region", "orchestrator");
|
|
3116
|
+
if (region === null || region.trim() === "") {
|
|
3117
|
+
issues.error({
|
|
3118
|
+
field: "orchestrator.enforce_region",
|
|
3119
|
+
message: "orchestrator: enforce_region requires region (name the region the model must run in, e.g. region: eu)",
|
|
3120
|
+
code: "orchestrator_enforce_region_needs_region",
|
|
3121
|
+
suggestion: "Add `region: eu` (or the region the model must run in), or drop enforce_region"
|
|
3122
|
+
});
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3065
3125
|
if (Array.isArray(orch.triggers)) {
|
|
3066
3126
|
orch.triggers.forEach((rawTrigger, i) => {
|
|
3067
3127
|
if (!isRecord(rawTrigger)) return;
|
|
@@ -5189,6 +5249,141 @@ function warnOrchestratorToolWithheld(flow, orch, report, issues) {
|
|
|
5189
5249
|
}
|
|
5190
5250
|
}
|
|
5191
5251
|
|
|
5252
|
+
// src/validators/complianceResidency.ts
|
|
5253
|
+
function own2(m, key) {
|
|
5254
|
+
if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
|
|
5255
|
+
return m[key];
|
|
5256
|
+
}
|
|
5257
|
+
function sprintf(format, ...args) {
|
|
5258
|
+
let i = 0;
|
|
5259
|
+
return format.replace(/%[sqv]/g, (verb) => {
|
|
5260
|
+
const arg = args[i++] ?? "";
|
|
5261
|
+
return verb === "%q" ? JSON.stringify(arg) : arg;
|
|
5262
|
+
});
|
|
5263
|
+
}
|
|
5264
|
+
function literalOrEmpty(s) {
|
|
5265
|
+
const t = goTrimSpace2(s);
|
|
5266
|
+
return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
|
|
5267
|
+
}
|
|
5268
|
+
function euOnlyResidency(flow, issues) {
|
|
5269
|
+
const raw = own2(own2(flow, "compliance"), "residency");
|
|
5270
|
+
if (!isArray(raw)) return null;
|
|
5271
|
+
const codes = [];
|
|
5272
|
+
for (let i = 0; i < raw.length; i++) {
|
|
5273
|
+
if (raw[i] === null) continue;
|
|
5274
|
+
const code = issues.stringAt(raw[i], `compliance.residency[${i}]`);
|
|
5275
|
+
if (code === null) return null;
|
|
5276
|
+
codes.push(code);
|
|
5277
|
+
}
|
|
5278
|
+
if (codes.length === 0) return null;
|
|
5279
|
+
const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
|
|
5280
|
+
return codes.every((c) => eu.has(goTrimSpace2(c).toUpperCase())) ? codes : null;
|
|
5281
|
+
}
|
|
5282
|
+
function aiProvider(executor) {
|
|
5283
|
+
const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
|
|
5284
|
+
if (!executor.startsWith(prefix)) return "";
|
|
5285
|
+
const rest = executor.slice(prefix.length);
|
|
5286
|
+
const slash = rest.indexOf("/");
|
|
5287
|
+
const provider = slash > 0 ? rest.slice(0, slash) : "";
|
|
5288
|
+
return provider.includes(TEMPLATE_ACTION_OPEN) ? "" : provider;
|
|
5289
|
+
}
|
|
5290
|
+
function isRegionLane(provider) {
|
|
5291
|
+
const literal = literalOrEmpty(provider);
|
|
5292
|
+
return literal !== "" && COMPLIANCE_RESIDENCY.regionLaneProviders.includes(literal.toLowerCase());
|
|
5293
|
+
}
|
|
5294
|
+
function nonBlankString(m, key) {
|
|
5295
|
+
const v = own2(m, key);
|
|
5296
|
+
return typeof v === "string" && goTrimSpace2(v) !== "";
|
|
5297
|
+
}
|
|
5298
|
+
function queryEnforcesRegion(query) {
|
|
5299
|
+
const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
|
|
5300
|
+
if (typeof v === "boolean") return v;
|
|
5301
|
+
return typeof v === "string" && COMPLIANCE_RESIDENCY.enforceRegionTrueStrings.includes(v);
|
|
5302
|
+
}
|
|
5303
|
+
function flowDirectsEndpoint(flow, provider, issues) {
|
|
5304
|
+
const key = provider.toLowerCase();
|
|
5305
|
+
const inst = own2(own2(flow, "executor_config"), key);
|
|
5306
|
+
if (!isRecord(inst)) return false;
|
|
5307
|
+
const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
|
|
5308
|
+
return baseUrl !== null && goTrimSpace2(baseUrl) !== "";
|
|
5309
|
+
}
|
|
5310
|
+
function callPinsEndpoint(flow, provider, query, issues) {
|
|
5311
|
+
if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
|
|
5312
|
+
if (queryEnforcesRegion(query)) return true;
|
|
5313
|
+
if (nonBlankString(query, provider.toLowerCase() + COMPLIANCE_RESIDENCY.baseUrlParamSuffix)) return true;
|
|
5314
|
+
return flowDirectsEndpoint(flow, provider, issues);
|
|
5315
|
+
}
|
|
5316
|
+
function validateResidencyEnforcement(flow, issues) {
|
|
5317
|
+
const residency = euOnlyResidency(flow, issues);
|
|
5318
|
+
if (residency === null) return;
|
|
5319
|
+
const warn = (site, field, stepId, provider) => {
|
|
5320
|
+
issues.warn({
|
|
5321
|
+
field,
|
|
5322
|
+
...stepId === void 0 ? {} : { stepId },
|
|
5323
|
+
code: COMPLIANCE_RESIDENCY.code,
|
|
5324
|
+
message: sprintf(COMPLIANCE_RESIDENCY.messageFormat, site, provider, `[${residency.join(" ")}]`),
|
|
5325
|
+
suggestion: COMPLIANCE_RESIDENCY.suggestion
|
|
5326
|
+
});
|
|
5327
|
+
};
|
|
5328
|
+
const steps = flow.steps;
|
|
5329
|
+
if (isRecord(steps)) {
|
|
5330
|
+
for (const stepId of Object.keys(steps).sort()) {
|
|
5331
|
+
const step = steps[stepId];
|
|
5332
|
+
if (!isRecord(step)) continue;
|
|
5333
|
+
const calls = [
|
|
5334
|
+
{
|
|
5335
|
+
executor: issues.stringOf(step, "executor", `steps.${stepId}`) ?? "",
|
|
5336
|
+
query: own2(step, "query"),
|
|
5337
|
+
subId: null
|
|
5338
|
+
}
|
|
5339
|
+
];
|
|
5340
|
+
for (const sub of loopSubStepsOfStep(stepId, step)) {
|
|
5341
|
+
calls.push({
|
|
5342
|
+
executor: issues.stringOf(sub.raw, "executor", sub.basePath) ?? "",
|
|
5343
|
+
query: own2(sub.raw, "query"),
|
|
5344
|
+
subId: issues.stringOf(sub.raw, "id", sub.basePath) ?? ""
|
|
5345
|
+
});
|
|
5346
|
+
}
|
|
5347
|
+
for (const call of calls) {
|
|
5348
|
+
const provider = aiProvider(call.executor);
|
|
5349
|
+
if (!isRegionLane(provider)) continue;
|
|
5350
|
+
if (callPinsEndpoint(flow, provider, call.query, issues)) continue;
|
|
5351
|
+
if (call.subId === null) {
|
|
5352
|
+
warn(
|
|
5353
|
+
sprintf(COMPLIANCE_RESIDENCY.siteStepFormat, stepId),
|
|
5354
|
+
sprintf(COMPLIANCE_RESIDENCY.stepFieldFormat, stepId),
|
|
5355
|
+
stepId,
|
|
5356
|
+
provider
|
|
5357
|
+
);
|
|
5358
|
+
} else {
|
|
5359
|
+
warn(
|
|
5360
|
+
sprintf(COMPLIANCE_RESIDENCY.siteLoopStepFormat, call.subId, stepId),
|
|
5361
|
+
sprintf(COMPLIANCE_RESIDENCY.loopStepFieldFormat, stepId, call.subId),
|
|
5362
|
+
stepId,
|
|
5363
|
+
provider
|
|
5364
|
+
);
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5368
|
+
}
|
|
5369
|
+
warnOrchestrator(flow, issues, warn);
|
|
5370
|
+
}
|
|
5371
|
+
function warnOrchestrator(flow, issues, warn) {
|
|
5372
|
+
const orch = flow.orchestrator;
|
|
5373
|
+
if (!isRecord(orch)) return;
|
|
5374
|
+
const source = issues.stringOf(orch, "exons", "orchestrator");
|
|
5375
|
+
if (source === null || source === "") return;
|
|
5376
|
+
const report = inspectExonsFrontmatter(source);
|
|
5377
|
+
if (report.parseError !== null || !report.specRead || !report.hasSpec) return;
|
|
5378
|
+
const provider = literalOrEmpty(report.provider);
|
|
5379
|
+
if (!isRegionLane(provider)) return;
|
|
5380
|
+
const region = issues.stringOf(orch, "region", "orchestrator");
|
|
5381
|
+
if (region !== null && goTrimSpace2(region) !== "") return;
|
|
5382
|
+
if (orch.enforce_region === true) return;
|
|
5383
|
+
if (flowDirectsEndpoint(flow, provider, issues)) return;
|
|
5384
|
+
warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
|
|
5385
|
+
}
|
|
5386
|
+
|
|
5192
5387
|
// src/validators/examples.ts
|
|
5193
5388
|
var KEY_EXAMPLES = "examples";
|
|
5194
5389
|
var VISIBILITY_PUBLIC = "public";
|
|
@@ -5266,7 +5461,7 @@ function num(n) {
|
|
|
5266
5461
|
function has(o, key) {
|
|
5267
5462
|
return Object.prototype.hasOwnProperty.call(o, key) && o[key] !== null && o[key] !== void 0;
|
|
5268
5463
|
}
|
|
5269
|
-
function
|
|
5464
|
+
function own3(o, key) {
|
|
5270
5465
|
return Object.prototype.hasOwnProperty.call(o, key) ? o[key] : void 0;
|
|
5271
5466
|
}
|
|
5272
5467
|
function setOwn(o, key, value) {
|
|
@@ -5318,7 +5513,7 @@ function mergePatch(target, patch, depth) {
|
|
|
5318
5513
|
continue;
|
|
5319
5514
|
}
|
|
5320
5515
|
if (isRecord(pv)) {
|
|
5321
|
-
const current =
|
|
5516
|
+
const current = own3(target, k);
|
|
5322
5517
|
const existing = isRecord(current) ? deepCopy(current, 0) : {};
|
|
5323
5518
|
mergePatch(existing, pv, depth + 1);
|
|
5324
5519
|
setOwn(target, k, existing);
|
|
@@ -5338,7 +5533,7 @@ function asFileRef(v) {
|
|
|
5338
5533
|
if (keys.length === 0) return null;
|
|
5339
5534
|
for (const k of keys) if (!FILE_REF_KEYS.has(k)) return null;
|
|
5340
5535
|
const str = (k) => {
|
|
5341
|
-
const x =
|
|
5536
|
+
const x = own3(v, k);
|
|
5342
5537
|
return typeof x === "string" ? x : "";
|
|
5343
5538
|
};
|
|
5344
5539
|
return {
|
|
@@ -5406,7 +5601,7 @@ var Walker = class _Walker {
|
|
|
5406
5601
|
`the examples block is ${size} bytes; the limit is ${L.maxBlockBytes}. Move large inputs or target outputs to a file reference (https URL).`
|
|
5407
5602
|
);
|
|
5408
5603
|
}
|
|
5409
|
-
const allHeld = examples.every((e) => isRecord(e) &&
|
|
5604
|
+
const allHeld = examples.every((e) => isRecord(e) && own3(e, "hold_out") === true);
|
|
5410
5605
|
if (allHeld) {
|
|
5411
5606
|
this.warn(
|
|
5412
5607
|
"examples_all_held_out",
|
|
@@ -5494,9 +5689,9 @@ var Walker = class _Walker {
|
|
|
5494
5689
|
`example ${q(label)} notes are ${notesN} characters; the limit is ${L.maxNotesRunes}`
|
|
5495
5690
|
);
|
|
5496
5691
|
}
|
|
5497
|
-
this.validateTags(path, label,
|
|
5498
|
-
this.validateWeight(`${path}.weight`, label, numberOf(
|
|
5499
|
-
const minScore = numberOf(
|
|
5692
|
+
this.validateTags(path, label, own3(ex, "tags"));
|
|
5693
|
+
this.validateWeight(`${path}.weight`, label, numberOf(own3(ex, "weight")));
|
|
5694
|
+
const minScore = numberOf(own3(ex, "min_score"));
|
|
5500
5695
|
if (minScore !== void 0 && !scoreInRange(minScore)) {
|
|
5501
5696
|
this.err(
|
|
5502
5697
|
"example_min_score_range",
|
|
@@ -5512,7 +5707,7 @@ var Walker = class _Walker {
|
|
|
5512
5707
|
`example ${q(label)} has side_effects ${q(sideEffects)}; use refuse or allow`
|
|
5513
5708
|
);
|
|
5514
5709
|
}
|
|
5515
|
-
const holdOut =
|
|
5710
|
+
const holdOut = own3(ex, "hold_out") === true;
|
|
5516
5711
|
if (holdOut && this.isPublic()) {
|
|
5517
5712
|
this.err(
|
|
5518
5713
|
"example_holdout_in_public_flow",
|
|
@@ -5535,17 +5730,17 @@ var Walker = class _Walker {
|
|
|
5535
5730
|
`example ${q(label)} has neither input nor input_ref; use input: {} for a flow that takes no input`
|
|
5536
5731
|
);
|
|
5537
5732
|
}
|
|
5538
|
-
const rawInput =
|
|
5733
|
+
const rawInput = own3(ex, "input");
|
|
5539
5734
|
const baseInput = isRecord(rawInput) ? rawInput : null;
|
|
5540
5735
|
if (baseInput !== null) {
|
|
5541
5736
|
this.checkInput(`${path}.input`, label, baseInput, "example_input_invalid");
|
|
5542
5737
|
}
|
|
5543
|
-
const rawInputRef =
|
|
5738
|
+
const rawInputRef = own3(ex, "input_ref");
|
|
5544
5739
|
if (isRecord(rawInputRef)) {
|
|
5545
5740
|
this.validateFileRef(`${path}.input_ref`, this.fileRefOf(rawInputRef, `${path}.input_ref`));
|
|
5546
5741
|
}
|
|
5547
5742
|
let binaryOnly = false;
|
|
5548
|
-
const expected =
|
|
5743
|
+
const expected = own3(ex, "expected");
|
|
5549
5744
|
if (!has(ex, "expected")) {
|
|
5550
5745
|
this.err(
|
|
5551
5746
|
"example_expected_missing",
|
|
@@ -5564,7 +5759,7 @@ var Walker = class _Walker {
|
|
|
5564
5759
|
"this example can be run but not scored"
|
|
5565
5760
|
);
|
|
5566
5761
|
}
|
|
5567
|
-
this.validateCheckpoints(path, label,
|
|
5762
|
+
this.validateCheckpoints(path, label, own3(ex, "checkpoints"));
|
|
5568
5763
|
this.validateVariants(i, path, label, ex, hasInput, baseInput);
|
|
5569
5764
|
this.scanSecretLike(i, path, ex);
|
|
5570
5765
|
}
|
|
@@ -5624,8 +5819,8 @@ var Walker = class _Walker {
|
|
|
5624
5819
|
);
|
|
5625
5820
|
return;
|
|
5626
5821
|
}
|
|
5627
|
-
const schema =
|
|
5628
|
-
const query =
|
|
5822
|
+
const schema = own3(this.flow, "input_schema");
|
|
5823
|
+
const query = own3(this.flow, "query");
|
|
5629
5824
|
if (isRecord(schema)) {
|
|
5630
5825
|
this.checkInputAgainstSchema(field, label, input, schema, code);
|
|
5631
5826
|
} else if (isRecord(query) && Object.keys(query).length > 0) {
|
|
@@ -5693,29 +5888,29 @@ var Walker = class _Walker {
|
|
|
5693
5888
|
}
|
|
5694
5889
|
}
|
|
5695
5890
|
schemaFields(schema) {
|
|
5696
|
-
const raw =
|
|
5891
|
+
const raw = own3(schema, "fields");
|
|
5697
5892
|
if (!Array.isArray(raw)) return [];
|
|
5698
5893
|
const out = [];
|
|
5699
5894
|
raw.forEach((f, i) => {
|
|
5700
5895
|
if (!isRecord(f)) return;
|
|
5701
5896
|
const base = `input_schema.fields[${i}]`;
|
|
5702
|
-
const enumRaw =
|
|
5897
|
+
const enumRaw = own3(f, "enum");
|
|
5703
5898
|
const enumValues = [];
|
|
5704
5899
|
if (Array.isArray(enumRaw)) {
|
|
5705
5900
|
enumRaw.forEach((e, j) => {
|
|
5706
5901
|
enumValues.push(e === null ? "" : this.issues.stringAt(e, `${base}.enum[${j}]`) ?? "");
|
|
5707
5902
|
});
|
|
5708
5903
|
}
|
|
5709
|
-
const vw =
|
|
5904
|
+
const vw = own3(f, "visible_when");
|
|
5710
5905
|
out.push({
|
|
5711
5906
|
name: this.s(f, "name", base),
|
|
5712
5907
|
type: this.s(f, "type", base),
|
|
5713
|
-
required:
|
|
5908
|
+
required: own3(f, "required") === true,
|
|
5714
5909
|
enumValues,
|
|
5715
5910
|
visibleWhen: isRecord(vw) ? {
|
|
5716
5911
|
field: this.s(vw, "field", `${base}.visible_when`),
|
|
5717
|
-
equals:
|
|
5718
|
-
in: Array.isArray(
|
|
5912
|
+
equals: own3(vw, "equals"),
|
|
5913
|
+
in: Array.isArray(own3(vw, "in")) ? own3(vw, "in") : []
|
|
5719
5914
|
} : null
|
|
5720
5915
|
});
|
|
5721
5916
|
});
|
|
@@ -5726,7 +5921,7 @@ var Walker = class _Walker {
|
|
|
5726
5921
|
const failures = [];
|
|
5727
5922
|
for (const f of fields) {
|
|
5728
5923
|
if (!isVisible(f, runInput)) continue;
|
|
5729
|
-
const raw =
|
|
5924
|
+
const raw = own3(runInput, f.name);
|
|
5730
5925
|
if (raw === void 0 || raw === null) {
|
|
5731
5926
|
if (f.required) {
|
|
5732
5927
|
failures.push({
|
|
@@ -5837,7 +6032,7 @@ var Walker = class _Walker {
|
|
|
5837
6032
|
/** The names `fields` / `exact` may use, and whether such a list is declared at all. */
|
|
5838
6033
|
outputNamesFor(kind, stepId) {
|
|
5839
6034
|
if (kind === "final") {
|
|
5840
|
-
const out =
|
|
6035
|
+
const out = own3(this.flow, "output");
|
|
5841
6036
|
const names2 = [];
|
|
5842
6037
|
if (Array.isArray(out)) {
|
|
5843
6038
|
out.forEach((item, i) => {
|
|
@@ -5846,10 +6041,10 @@ var Walker = class _Walker {
|
|
|
5846
6041
|
}
|
|
5847
6042
|
return { names: names2, declared: names2.length > 0 };
|
|
5848
6043
|
}
|
|
5849
|
-
const steps =
|
|
5850
|
-
const step = isRecord(steps) ?
|
|
5851
|
-
const schema = isRecord(step) ?
|
|
5852
|
-
const fields = isRecord(schema) ?
|
|
6044
|
+
const steps = own3(this.flow, "steps");
|
|
6045
|
+
const step = isRecord(steps) ? own3(steps, stepId) : void 0;
|
|
6046
|
+
const schema = isRecord(step) ? own3(step, "output_schema") : void 0;
|
|
6047
|
+
const fields = isRecord(schema) ? own3(schema, "fields") : void 0;
|
|
5853
6048
|
if (!Array.isArray(fields) || fields.length === 0) return { names: [], declared: false };
|
|
5854
6049
|
const names = [];
|
|
5855
6050
|
fields.forEach((f, i) => {
|
|
@@ -5868,8 +6063,8 @@ var Walker = class _Walker {
|
|
|
5868
6063
|
);
|
|
5869
6064
|
}
|
|
5870
6065
|
const noOutput = status === STATUS_FAILED || status === STATUS_PAUSED_FOR_HUMAN;
|
|
5871
|
-
const fieldsRec =
|
|
5872
|
-
const exactRec =
|
|
6066
|
+
const fieldsRec = own3(e, "fields");
|
|
6067
|
+
const exactRec = own3(e, "exact");
|
|
5873
6068
|
const fieldKeys = isRecord(fieldsRec) ? sortedKeys(fieldsRec) : [];
|
|
5874
6069
|
const exactKeys = isRecord(exactRec) ? sortedKeys(exactRec) : [];
|
|
5875
6070
|
const hasFields = fieldKeys.length > 0;
|
|
@@ -5887,7 +6082,7 @@ var Walker = class _Walker {
|
|
|
5887
6082
|
`a case that ends in ${status} has no output to match; remove fields and exact, or expect status completed`
|
|
5888
6083
|
);
|
|
5889
6084
|
}
|
|
5890
|
-
const minScore = numberOf(
|
|
6085
|
+
const minScore = numberOf(own3(e, "min_score"));
|
|
5891
6086
|
if (minScore !== void 0 && !scoreInRange(minScore)) {
|
|
5892
6087
|
this.err(
|
|
5893
6088
|
"example_min_score_range",
|
|
@@ -5914,7 +6109,7 @@ var Walker = class _Walker {
|
|
|
5914
6109
|
}
|
|
5915
6110
|
}
|
|
5916
6111
|
}
|
|
5917
|
-
const reference =
|
|
6112
|
+
const reference = own3(e, "reference");
|
|
5918
6113
|
if (isRecord(reference)) this.validateReference(`${path}.reference`, reference);
|
|
5919
6114
|
const { names, declared } = this.outputNamesFor(kind, stepId);
|
|
5920
6115
|
const checkKey = (field, key) => {
|
|
@@ -5941,12 +6136,12 @@ var Walker = class _Walker {
|
|
|
5941
6136
|
for (const key of fieldKeys) {
|
|
5942
6137
|
const fpath = `${path}.fields.${key}`;
|
|
5943
6138
|
checkKey(fpath, key);
|
|
5944
|
-
const matcher =
|
|
6139
|
+
const matcher = own3(fieldsRec, key);
|
|
5945
6140
|
if (isRecord(matcher)) this.validateFieldMatcher(fpath, matcher);
|
|
5946
6141
|
}
|
|
5947
6142
|
for (const key of exactKeys) checkKey(`${path}.exact.${key}`, key);
|
|
5948
|
-
const mustNot = this.stringList(
|
|
5949
|
-
const mustNotContain = this.stringList(
|
|
6143
|
+
const mustNot = this.stringList(own3(e, "must_not"), `${path}.must_not`);
|
|
6144
|
+
const mustNotContain = this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`);
|
|
5950
6145
|
const mustNotMsg = `must_not takes up to ${L.maxMustNot} statements of at most ${L.maxMustNotRunes} characters each, none empty`;
|
|
5951
6146
|
if (mustNot.length > L.maxMustNot) {
|
|
5952
6147
|
this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
|
|
@@ -5967,9 +6162,9 @@ var Walker = class _Walker {
|
|
|
5967
6162
|
}
|
|
5968
6163
|
});
|
|
5969
6164
|
for (const key of fieldKeys) {
|
|
5970
|
-
const matcher =
|
|
6165
|
+
const matcher = own3(fieldsRec, key);
|
|
5971
6166
|
if (!isRecord(matcher)) continue;
|
|
5972
|
-
const eq =
|
|
6167
|
+
const eq = own3(matcher, "equals");
|
|
5973
6168
|
if (typeof eq !== "string" || eq === "") continue;
|
|
5974
6169
|
for (const banned of mustNotContain) {
|
|
5975
6170
|
if (banned !== "" && equalFold(banned, eq)) {
|
|
@@ -6029,7 +6224,7 @@ var Walker = class _Walker {
|
|
|
6029
6224
|
}
|
|
6030
6225
|
return;
|
|
6031
6226
|
}
|
|
6032
|
-
const refRec =
|
|
6227
|
+
const refRec = own3(r, "ref");
|
|
6033
6228
|
if (!isRecord(refRec)) return;
|
|
6034
6229
|
const ref = this.fileRefOf(refRec, `${path}.ref`);
|
|
6035
6230
|
this.validateFileRef(`${path}.ref`, ref);
|
|
@@ -6042,22 +6237,22 @@ var Walker = class _Walker {
|
|
|
6042
6237
|
}
|
|
6043
6238
|
}
|
|
6044
6239
|
expectationIsBinaryReferenceOnly(e, path) {
|
|
6045
|
-
const reference =
|
|
6046
|
-
const refRec = isRecord(reference) ?
|
|
6240
|
+
const reference = own3(e, "reference");
|
|
6241
|
+
const refRec = isRecord(reference) ? own3(reference, "ref") : void 0;
|
|
6047
6242
|
if (!isRecord(refRec)) return false;
|
|
6048
6243
|
const mediaType = this.s(refRec, "media_type", `${path}.reference.ref`);
|
|
6049
6244
|
if (mediaType === "" || isTextualMediaType(mediaType)) return false;
|
|
6050
6245
|
const status = this.s(e, "status", path);
|
|
6051
|
-
const fields =
|
|
6052
|
-
const exact =
|
|
6053
|
-
return this.s(e, "rubric", path) === "" && !(isRecord(fields) && Object.keys(fields).length > 0) && !(isRecord(exact) && Object.keys(exact).length > 0) && this.stringList(
|
|
6246
|
+
const fields = own3(e, "fields");
|
|
6247
|
+
const exact = own3(e, "exact");
|
|
6248
|
+
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);
|
|
6054
6249
|
}
|
|
6055
6250
|
validateFieldMatcher(path, m) {
|
|
6056
6251
|
const L = EXAMPLES.limits;
|
|
6057
6252
|
const matches = this.s(m, "matches", path);
|
|
6058
|
-
const oneOf =
|
|
6059
|
-
const approx = numberOf(
|
|
6060
|
-
const tolerance = numberOf(
|
|
6253
|
+
const oneOf = own3(m, "one_of");
|
|
6254
|
+
const approx = numberOf(own3(m, "approx"));
|
|
6255
|
+
const tolerance = numberOf(own3(m, "tolerance"));
|
|
6061
6256
|
let operators = 0;
|
|
6062
6257
|
if (has(m, "equals")) operators++;
|
|
6063
6258
|
if (this.s(m, "contains", path) !== "") operators++;
|
|
@@ -6065,7 +6260,7 @@ var Walker = class _Walker {
|
|
|
6065
6260
|
if (matches !== "") operators++;
|
|
6066
6261
|
if (Array.isArray(oneOf) && oneOf.length > 0) operators++;
|
|
6067
6262
|
if (approx !== void 0) operators++;
|
|
6068
|
-
if (typeof
|
|
6263
|
+
if (typeof own3(m, "present") === "boolean") operators++;
|
|
6069
6264
|
if (operators !== 1) {
|
|
6070
6265
|
this.err(
|
|
6071
6266
|
"example_field_matcher_invalid",
|
|
@@ -6092,12 +6287,12 @@ var Walker = class _Walker {
|
|
|
6092
6287
|
// -- checkpoints ------------------------------------------------------
|
|
6093
6288
|
validateCheckpoints(path, label, cps) {
|
|
6094
6289
|
if (!isRecord(cps) || Object.keys(cps).length === 0) return;
|
|
6095
|
-
const stepsRaw =
|
|
6290
|
+
const stepsRaw = own3(this.flow, "steps");
|
|
6096
6291
|
const steps = isRecord(stepsRaw) ? stepsRaw : {};
|
|
6097
6292
|
const stepIds = sortedKeys(steps);
|
|
6098
6293
|
for (const id of sortedKeys(cps)) {
|
|
6099
6294
|
const cpath = `${path}.checkpoints.${id}`;
|
|
6100
|
-
const step =
|
|
6295
|
+
const step = own3(steps, id);
|
|
6101
6296
|
if (!isRecord(step)) {
|
|
6102
6297
|
this.err(
|
|
6103
6298
|
"example_checkpoint_step_unknown",
|
|
@@ -6107,7 +6302,7 @@ var Walker = class _Walker {
|
|
|
6107
6302
|
);
|
|
6108
6303
|
continue;
|
|
6109
6304
|
}
|
|
6110
|
-
const next =
|
|
6305
|
+
const next = own3(step, "next");
|
|
6111
6306
|
if (has(step, "for_each") || has(step, "loop") || isRecord(next) && has(next, "parallel")) {
|
|
6112
6307
|
this.err(
|
|
6113
6308
|
"example_checkpoint_step_composite",
|
|
@@ -6116,7 +6311,7 @@ var Walker = class _Walker {
|
|
|
6116
6311
|
);
|
|
6117
6312
|
continue;
|
|
6118
6313
|
}
|
|
6119
|
-
const cp =
|
|
6314
|
+
const cp = own3(cps, id);
|
|
6120
6315
|
if (cp === null || cp === void 0) {
|
|
6121
6316
|
this.validateExpectation(cpath, label, {}, "checkpoint", id);
|
|
6122
6317
|
} else if (isRecord(cp)) {
|
|
@@ -6127,7 +6322,7 @@ var Walker = class _Walker {
|
|
|
6127
6322
|
// -- variants ---------------------------------------------------------
|
|
6128
6323
|
validateVariants(i, path, label, ex, hasInput, baseInput) {
|
|
6129
6324
|
const L = EXAMPLES.limits;
|
|
6130
|
-
const variants =
|
|
6325
|
+
const variants = own3(ex, "variants");
|
|
6131
6326
|
if (!Array.isArray(variants) || variants.length === 0) return;
|
|
6132
6327
|
if (variants.length > L.maxVariants) {
|
|
6133
6328
|
this.err(
|
|
@@ -6190,8 +6385,8 @@ var Walker = class _Walker {
|
|
|
6190
6385
|
`example ${q(both)} notes are ${provN} characters; the limit is ${L.maxProvenanceRunes}`
|
|
6191
6386
|
);
|
|
6192
6387
|
}
|
|
6193
|
-
this.validateWeight(`${vpath}.weight`, both, numberOf(
|
|
6194
|
-
const patch =
|
|
6388
|
+
this.validateWeight(`${vpath}.weight`, both, numberOf(own3(v, "weight")));
|
|
6389
|
+
const patch = own3(v, "input_patch");
|
|
6195
6390
|
const patchRec = isRecord(patch) ? patch : null;
|
|
6196
6391
|
const hasPatch = patchRec !== null && Object.keys(patchRec).length > 0;
|
|
6197
6392
|
const hasRef = has(v, "input_ref");
|
|
@@ -6208,7 +6403,7 @@ var Walker = class _Walker {
|
|
|
6208
6403
|
`variant ${q(vlabel)} of example ${q(label)} changes neither the input nor the expectation`
|
|
6209
6404
|
);
|
|
6210
6405
|
}
|
|
6211
|
-
const refRec =
|
|
6406
|
+
const refRec = own3(v, "input_ref");
|
|
6212
6407
|
if (isRecord(refRec)) {
|
|
6213
6408
|
this.validateFileRef(`${vpath}.input_ref`, this.fileRefOf(refRec, `${vpath}.input_ref`));
|
|
6214
6409
|
}
|
|
@@ -6223,7 +6418,7 @@ var Walker = class _Walker {
|
|
|
6223
6418
|
this.checkVariantPatch(vpath, label, vlabel, baseInput, patchRec);
|
|
6224
6419
|
}
|
|
6225
6420
|
}
|
|
6226
|
-
const expected =
|
|
6421
|
+
const expected = own3(v, "expected");
|
|
6227
6422
|
if (isRecord(expected)) {
|
|
6228
6423
|
this.validateExpectation(`${vpath}.expected`, both, expected, "final", "");
|
|
6229
6424
|
}
|
|
@@ -6234,11 +6429,11 @@ var Walker = class _Walker {
|
|
|
6234
6429
|
* itself supplies. A null patch value deleting a secret is fine.
|
|
6235
6430
|
*/
|
|
6236
6431
|
checkVariantPatch(vpath, label, vlabel, base, patch) {
|
|
6237
|
-
const schema =
|
|
6432
|
+
const schema = own3(this.flow, "input_schema");
|
|
6238
6433
|
if (isRecord(schema)) {
|
|
6239
6434
|
for (const f of this.schemaFields(schema)) {
|
|
6240
6435
|
if (f.type !== TYPE_SECRET) continue;
|
|
6241
|
-
const val =
|
|
6436
|
+
const val = own3(patch, f.name);
|
|
6242
6437
|
if (val !== void 0 && val !== null) {
|
|
6243
6438
|
this.err(
|
|
6244
6439
|
"example_secret_value",
|
|
@@ -6278,18 +6473,18 @@ var Walker = class _Walker {
|
|
|
6278
6473
|
emit(`${path}.title`, this.s(ex, "title", path));
|
|
6279
6474
|
emit(`${path}.guidance`, this.s(ex, "guidance", path));
|
|
6280
6475
|
emit(`${path}.notes`, this.s(ex, "notes", path));
|
|
6281
|
-
const input =
|
|
6476
|
+
const input = own3(ex, "input");
|
|
6282
6477
|
if (isRecord(input)) scanLeaves(`${path}.input`, input, 0, emit);
|
|
6283
|
-
const expected =
|
|
6478
|
+
const expected = own3(ex, "expected");
|
|
6284
6479
|
if (isRecord(expected)) this.scanExpectationLeaves(`${path}.expected`, expected, emit);
|
|
6285
|
-
const cps =
|
|
6480
|
+
const cps = own3(ex, "checkpoints");
|
|
6286
6481
|
if (isRecord(cps)) {
|
|
6287
6482
|
for (const id of sortedKeys(cps)) {
|
|
6288
|
-
const cp =
|
|
6483
|
+
const cp = own3(cps, id);
|
|
6289
6484
|
if (isRecord(cp)) this.scanExpectationLeaves(`${path}.checkpoints.${id}`, cp, emit);
|
|
6290
6485
|
}
|
|
6291
6486
|
}
|
|
6292
|
-
const variants =
|
|
6487
|
+
const variants = own3(ex, "variants");
|
|
6293
6488
|
if (Array.isArray(variants)) {
|
|
6294
6489
|
variants.forEach((v, j) => {
|
|
6295
6490
|
if (!isRecord(v)) return;
|
|
@@ -6297,34 +6492,34 @@ var Walker = class _Walker {
|
|
|
6297
6492
|
emit(`${vpath}.title`, this.s(v, "title", vpath));
|
|
6298
6493
|
emit(`${vpath}.guidance`, this.s(v, "guidance", vpath));
|
|
6299
6494
|
emit(`${vpath}.provenance`, this.s(v, "provenance", vpath));
|
|
6300
|
-
scanLeaves(`${vpath}.input_patch`,
|
|
6301
|
-
const vexp =
|
|
6495
|
+
scanLeaves(`${vpath}.input_patch`, own3(v, "input_patch"), 0, emit);
|
|
6496
|
+
const vexp = own3(v, "expected");
|
|
6302
6497
|
if (isRecord(vexp)) this.scanExpectationLeaves(`${vpath}.expected`, vexp, emit);
|
|
6303
6498
|
});
|
|
6304
6499
|
}
|
|
6305
6500
|
}
|
|
6306
6501
|
scanExpectationLeaves(path, e, emit) {
|
|
6307
6502
|
emit(`${path}.rubric`, this.s(e, "rubric", path));
|
|
6308
|
-
const reference =
|
|
6503
|
+
const reference = own3(e, "reference");
|
|
6309
6504
|
if (isRecord(reference)) {
|
|
6310
6505
|
emit(`${path}.reference.text`, this.s(reference, "text", `${path}.reference`));
|
|
6311
6506
|
}
|
|
6312
|
-
this.stringList(
|
|
6507
|
+
this.stringList(own3(e, "must_not"), `${path}.must_not`).forEach(
|
|
6313
6508
|
(s, j) => emit(`${path}.must_not[${j}]`, s)
|
|
6314
6509
|
);
|
|
6315
|
-
this.stringList(
|
|
6510
|
+
this.stringList(own3(e, "must_not_contain"), `${path}.must_not_contain`).forEach(
|
|
6316
6511
|
(s, j) => emit(`${path}.must_not_contain[${j}]`, s)
|
|
6317
6512
|
);
|
|
6318
|
-
const fields =
|
|
6513
|
+
const fields = own3(e, "fields");
|
|
6319
6514
|
if (isRecord(fields)) {
|
|
6320
6515
|
for (const key of sortedKeys(fields)) {
|
|
6321
|
-
const m =
|
|
6516
|
+
const m = own3(fields, key);
|
|
6322
6517
|
if (!isRecord(m)) continue;
|
|
6323
6518
|
const fpath = `${path}.fields.${key}`;
|
|
6324
|
-
scanLeaves(`${fpath}.equals`,
|
|
6519
|
+
scanLeaves(`${fpath}.equals`, own3(m, "equals"), 0, emit);
|
|
6325
6520
|
emit(`${fpath}.contains`, this.s(m, "contains", fpath));
|
|
6326
6521
|
emit(`${fpath}.not_contains`, this.s(m, "not_contains", fpath));
|
|
6327
|
-
const oneOf =
|
|
6522
|
+
const oneOf = own3(m, "one_of");
|
|
6328
6523
|
if (Array.isArray(oneOf)) {
|
|
6329
6524
|
oneOf.forEach(
|
|
6330
6525
|
(one, j) => scanLeaves(`${fpath}.one_of[${j}]`, one, 0, emit)
|
|
@@ -6332,7 +6527,7 @@ var Walker = class _Walker {
|
|
|
6332
6527
|
}
|
|
6333
6528
|
}
|
|
6334
6529
|
}
|
|
6335
|
-
scanLeaves(`${path}.exact`,
|
|
6530
|
+
scanLeaves(`${path}.exact`, own3(e, "exact"), 0, emit);
|
|
6336
6531
|
}
|
|
6337
6532
|
};
|
|
6338
6533
|
function scoreInRange(v) {
|
|
@@ -6448,7 +6643,7 @@ function inputValueFailures(f, raw) {
|
|
|
6448
6643
|
case TYPE_FILE2: {
|
|
6449
6644
|
if (typeof raw === "string") return raw === "" ? [mismatch(f, TYPE_FILE2)] : [];
|
|
6450
6645
|
if (isRecord(raw)) {
|
|
6451
|
-
const ref =
|
|
6646
|
+
const ref = own3(raw, FILE_REF_KEY);
|
|
6452
6647
|
return typeof ref === "string" && ref !== "" ? [] : [mismatch(f, TYPE_FILE2)];
|
|
6453
6648
|
}
|
|
6454
6649
|
return [mismatch(f, TYPE_FILE2)];
|
|
@@ -6531,6 +6726,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
6531
6726
|
validateCredentialEndpointPairing(f, issues);
|
|
6532
6727
|
validateExamples(f, issues);
|
|
6533
6728
|
validateOrchestratorExons(f, issues);
|
|
6729
|
+
validateResidencyEnforcement(f, issues);
|
|
6534
6730
|
validateUnknownKeys(f, issues);
|
|
6535
6731
|
const templateStats = validateTemplates(f, issues, opts);
|
|
6536
6732
|
const totalSteps = f.steps && typeof f.steps === "object" && !Array.isArray(f.steps) ? Object.keys(f.steps).length : 0;
|