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