@vaudience/aigentflow-flow-validator 0.25.0 → 0.26.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 +37 -0
- package/dist/cli.js +127 -29
- package/dist/index.cjs +125 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +125 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -992,7 +992,7 @@ var aigentflow_spec_default = {
|
|
|
992
992
|
providerAgent: "agent",
|
|
993
993
|
providerCapability: "capability",
|
|
994
994
|
agentResource: "run",
|
|
995
|
-
capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_
|
|
995
|
+
capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$",
|
|
996
996
|
operationUnknown: {
|
|
997
997
|
code: "atlas_operation_unknown",
|
|
998
998
|
messageFormat: "step %s uses %s, which is not an Atlas operation. The providers are agent (resource run) and capability (resource: a capability reference).",
|
|
@@ -1000,7 +1000,7 @@ var aigentflow_spec_default = {
|
|
|
1000
1000
|
},
|
|
1001
1001
|
agentMissing: {
|
|
1002
1002
|
code: "atlas_agent_missing",
|
|
1003
|
-
messageFormat: "step %s runs an Atlas agent but query.agent is missing or
|
|
1003
|
+
messageFormat: "step %s runs an Atlas agent but query.agent is missing, empty or not a string.",
|
|
1004
1004
|
suggestion: "Set query.agent to the agent to run, written out as a literal such as @acme/reporter."
|
|
1005
1005
|
},
|
|
1006
1006
|
agentNotLiteral: {
|
|
@@ -1026,9 +1026,46 @@ var aigentflow_spec_default = {
|
|
|
1026
1026
|
capabilityRefInvalid: {
|
|
1027
1027
|
code: "atlas_capability_ref_invalid",
|
|
1028
1028
|
messageFormat: "step %s uses atlas://capability/%s, which is not a valid capability reference.",
|
|
1029
|
-
suggestion: "A capability reference starts with a letter or digit and continues with letters, digits
|
|
1029
|
+
suggestion: "A capability reference starts with a letter or digit and continues with letters, digits, _ and - up to 128 characters in all."
|
|
1030
|
+
},
|
|
1031
|
+
modelNotLiteral: {
|
|
1032
|
+
code: "atlas_model_not_literal",
|
|
1033
|
+
messageFormat: "step %s computes a value of query.model from a template. The provider, model and reasoning_effort must be fixed literals, never derived from input.",
|
|
1034
|
+
suggestion: "Write the model choice out as literals. Data may go into the prompt or the inputs instead."
|
|
1035
|
+
},
|
|
1036
|
+
paramRefused: {
|
|
1037
|
+
code: "atlas_param_refused",
|
|
1038
|
+
messageFormat: "step %s sets %s under query. Atlas decides these itself, so a step may not set them.",
|
|
1039
|
+
suggestion: "Remove these keys from the query.",
|
|
1040
|
+
agentKeys: [
|
|
1041
|
+
"api_key",
|
|
1042
|
+
"attribution",
|
|
1043
|
+
"base_url",
|
|
1044
|
+
"host",
|
|
1045
|
+
"idempotency_key",
|
|
1046
|
+
"org_id",
|
|
1047
|
+
"person",
|
|
1048
|
+
"untrusted_input",
|
|
1049
|
+
"untrusted_input_override",
|
|
1050
|
+
"url",
|
|
1051
|
+
"user_id"
|
|
1052
|
+
],
|
|
1053
|
+
capabilityKeys: [
|
|
1054
|
+
"attribution",
|
|
1055
|
+
"idempotency_key",
|
|
1056
|
+
"untrusted_input",
|
|
1057
|
+
"untrusted_input_override"
|
|
1058
|
+
]
|
|
1030
1059
|
}
|
|
1031
1060
|
},
|
|
1061
|
+
reservedInputNames: {
|
|
1062
|
+
prefix: "__",
|
|
1063
|
+
code: "reserved_input_name",
|
|
1064
|
+
messageFormat: "the input %s starts with two underscores. That namespace belongs to the platform (the acting person, the credential manifest, the untrusted-input marker): a flow cannot declare an input there, and a value or default written under such a name is never delivered.",
|
|
1065
|
+
suggestion: 'Rename the input so it does not start with "__".',
|
|
1066
|
+
queryFieldFormat: "query.%s",
|
|
1067
|
+
schemaFieldFormat: "input_schema.fields.%s"
|
|
1068
|
+
},
|
|
1032
1069
|
flowDataReservedKeys: {
|
|
1033
1070
|
code: "flow_data_key_reserved",
|
|
1034
1071
|
fieldFormat: "data.%s",
|
|
@@ -2084,7 +2121,23 @@ var ATLAS_EXECUTOR = {
|
|
|
2084
2121
|
capabilitiesNotLiteral: atlas.capabilitiesNotLiteral,
|
|
2085
2122
|
promptMissing: atlas.promptMissing,
|
|
2086
2123
|
promptBoth: atlas.promptBoth,
|
|
2087
|
-
capabilityRefInvalid: atlas.capabilityRefInvalid
|
|
2124
|
+
capabilityRefInvalid: atlas.capabilityRefInvalid,
|
|
2125
|
+
modelNotLiteral: atlas.modelNotLiteral,
|
|
2126
|
+
paramRefused: {
|
|
2127
|
+
code: atlas.paramRefused.code,
|
|
2128
|
+
messageFormat: atlas.paramRefused.messageFormat,
|
|
2129
|
+
suggestion: atlas.paramRefused.suggestion,
|
|
2130
|
+
agentKeys: atlas.paramRefused.agentKeys,
|
|
2131
|
+
capabilityKeys: atlas.paramRefused.capabilityKeys
|
|
2132
|
+
}
|
|
2133
|
+
};
|
|
2134
|
+
var RESERVED_INPUT_NAMES = {
|
|
2135
|
+
prefix: aigentflow_spec_default.reservedInputNames.prefix,
|
|
2136
|
+
code: aigentflow_spec_default.reservedInputNames.code,
|
|
2137
|
+
messageFormat: aigentflow_spec_default.reservedInputNames.messageFormat,
|
|
2138
|
+
suggestion: aigentflow_spec_default.reservedInputNames.suggestion,
|
|
2139
|
+
queryFieldFormat: aigentflow_spec_default.reservedInputNames.queryFieldFormat,
|
|
2140
|
+
schemaFieldFormat: aigentflow_spec_default.reservedInputNames.schemaFieldFormat
|
|
2088
2141
|
};
|
|
2089
2142
|
|
|
2090
2143
|
// src/validators/executors.ts
|
|
@@ -2151,10 +2204,12 @@ function checkExecutor(executor, field, stepID, issues) {
|
|
|
2151
2204
|
}
|
|
2152
2205
|
function checkAtlasStep(executor, query, stepField, stepID, issues) {
|
|
2153
2206
|
if (executor.includes(TEMPLATE_ACTION_OPEN)) return;
|
|
2154
|
-
const
|
|
2155
|
-
if (
|
|
2156
|
-
const
|
|
2157
|
-
const
|
|
2207
|
+
const prefix = `${ATLAS_EXECUTOR.scheme}://`;
|
|
2208
|
+
if (!executor.startsWith(prefix)) return;
|
|
2209
|
+
const rest = executor.slice(prefix.length);
|
|
2210
|
+
const slash = rest.indexOf("/");
|
|
2211
|
+
const provider = slash < 0 ? rest : rest.slice(0, slash);
|
|
2212
|
+
const resource = slash < 0 ? "" : rest.slice(slash + 1);
|
|
2158
2213
|
const quoted = JSON.stringify(stepID);
|
|
2159
2214
|
const report = (rule, ...args) => {
|
|
2160
2215
|
let message = rule.messageFormat.replace("%s", () => quoted);
|
|
@@ -2168,31 +2223,41 @@ function checkAtlasStep(executor, query, stepField, stepID, issues) {
|
|
|
2168
2223
|
});
|
|
2169
2224
|
};
|
|
2170
2225
|
const q2 = isRecord(query) ? query : {};
|
|
2226
|
+
let refusedKeys = ATLAS_EXECUTOR.paramRefused.capabilityKeys;
|
|
2171
2227
|
if (provider === ATLAS_EXECUTOR.providerCapability) {
|
|
2172
2228
|
if (!ATLAS_EXECUTOR.capabilityRefPattern.test(resource)) {
|
|
2173
2229
|
report(ATLAS_EXECUTOR.capabilityRefInvalid, resource);
|
|
2174
2230
|
}
|
|
2175
2231
|
} else if (provider === ATLAS_EXECUTOR.providerAgent && resource === ATLAS_EXECUTOR.agentResource) {
|
|
2232
|
+
refusedKeys = ATLAS_EXECUTOR.paramRefused.agentKeys;
|
|
2176
2233
|
const agent = q2.agent;
|
|
2177
|
-
if (typeof agent !== "string" || agent === "") {
|
|
2234
|
+
if (typeof agent !== "string" || agent.trim() === "") {
|
|
2178
2235
|
report(ATLAS_EXECUTOR.agentMissing);
|
|
2179
2236
|
} else if (agent.includes(TEMPLATE_ACTION_OPEN)) {
|
|
2180
2237
|
report(ATLAS_EXECUTOR.agentNotLiteral);
|
|
2181
2238
|
}
|
|
2182
|
-
const
|
|
2183
|
-
const
|
|
2184
|
-
const hasPrompt = prompt !== void 0 && prompt !== null && prompt !== "";
|
|
2185
|
-
const hasTemplate = promptTemplate !== void 0 && promptTemplate !== null && promptTemplate !== "";
|
|
2239
|
+
const hasPrompt = atlasTextPresent(q2.prompt);
|
|
2240
|
+
const hasTemplate = atlasTextPresent(q2.prompt_template);
|
|
2186
2241
|
if (!hasPrompt && !hasTemplate) report(ATLAS_EXECUTOR.promptMissing);
|
|
2187
2242
|
else if (hasPrompt && hasTemplate) report(ATLAS_EXECUTOR.promptBoth);
|
|
2243
|
+
if (anyTemplate(q2.model)) report(ATLAS_EXECUTOR.modelNotLiteral);
|
|
2188
2244
|
} else {
|
|
2189
2245
|
report(ATLAS_EXECUTOR.operationUnknown, executor);
|
|
2190
2246
|
return;
|
|
2191
2247
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2248
|
+
if (anyTemplate(q2.capabilities)) report(ATLAS_EXECUTOR.capabilitiesNotLiteral);
|
|
2249
|
+
const refused = refusedKeys.filter((key) => Object.prototype.hasOwnProperty.call(q2, key)).sort();
|
|
2250
|
+
if (refused.length > 0) report(ATLAS_EXECUTOR.paramRefused, refused.join(", "));
|
|
2251
|
+
}
|
|
2252
|
+
function anyTemplate(v) {
|
|
2253
|
+
if (typeof v === "string") return v.includes(TEMPLATE_ACTION_OPEN);
|
|
2254
|
+
if (Array.isArray(v)) return v.some(anyTemplate);
|
|
2255
|
+
if (isRecord(v)) return Object.values(v).some(anyTemplate);
|
|
2256
|
+
return false;
|
|
2257
|
+
}
|
|
2258
|
+
function atlasTextPresent(v) {
|
|
2259
|
+
if (v === void 0 || v === null) return false;
|
|
2260
|
+
return typeof v !== "string" || v.trim() !== "";
|
|
2196
2261
|
}
|
|
2197
2262
|
function checkFunctionOperation(executor, field, stepID, templated, issues) {
|
|
2198
2263
|
if (templated) return;
|
|
@@ -3878,6 +3943,37 @@ function validateInputSchema(flow, issues) {
|
|
|
3878
3943
|
validateSchemaDefinition(flow.input_schema, "input_schema", issues);
|
|
3879
3944
|
}
|
|
3880
3945
|
|
|
3946
|
+
// src/validators/reservedInputs.ts
|
|
3947
|
+
function formatField(format, name) {
|
|
3948
|
+
return format.replace("%s", () => name);
|
|
3949
|
+
}
|
|
3950
|
+
function validateReservedInputNames(flow, issues) {
|
|
3951
|
+
const rule = RESERVED_INPUT_NAMES;
|
|
3952
|
+
const report = (name, fieldFormat) => {
|
|
3953
|
+
issues.error({
|
|
3954
|
+
field: formatField(fieldFormat, name),
|
|
3955
|
+
message: rule.messageFormat.replace("%s", () => JSON.stringify(name)),
|
|
3956
|
+
code: rule.code,
|
|
3957
|
+
suggestion: rule.suggestion
|
|
3958
|
+
});
|
|
3959
|
+
};
|
|
3960
|
+
const query = flow.query;
|
|
3961
|
+
if (isRecord(query)) {
|
|
3962
|
+
for (const name of Object.keys(query).sort()) {
|
|
3963
|
+
if (name.startsWith(rule.prefix)) report(name, rule.queryFieldFormat);
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
const schema = flow.input_schema;
|
|
3967
|
+
const fields = isRecord(schema) ? schema.fields : void 0;
|
|
3968
|
+
if (!Array.isArray(fields)) return;
|
|
3969
|
+
for (const f of fields) {
|
|
3970
|
+
if (!isRecord(f)) continue;
|
|
3971
|
+
if (typeof f.name === "string" && f.name.startsWith(rule.prefix)) {
|
|
3972
|
+
report(f.name, rule.schemaFieldFormat);
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3881
3977
|
// src/validators/outputSchema.ts
|
|
3882
3978
|
function validateOutputSchemas(flow, issues) {
|
|
3883
3979
|
const steps = flow.steps;
|
|
@@ -4992,7 +5088,7 @@ var CODE2 = "server_owned_query_key";
|
|
|
4992
5088
|
var KEY_QUERY = "query";
|
|
4993
5089
|
var KEY_ID = "id";
|
|
4994
5090
|
var SERVER_OWNED = new Set(SERVER_OWNED_QUERY_KEYS.keys);
|
|
4995
|
-
function
|
|
5091
|
+
function formatField2(format, ...args) {
|
|
4996
5092
|
let i = 0;
|
|
4997
5093
|
return format.replace(/%s/g, () => args[i++] ?? "");
|
|
4998
5094
|
}
|
|
@@ -5010,7 +5106,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
|
|
|
5010
5106
|
issues,
|
|
5011
5107
|
stepID,
|
|
5012
5108
|
key,
|
|
5013
|
-
|
|
5109
|
+
formatField2(SERVER_OWNED_QUERY_KEYS.stepFieldFormat, stepID, key)
|
|
5014
5110
|
);
|
|
5015
5111
|
}
|
|
5016
5112
|
}
|
|
@@ -5024,7 +5120,7 @@ function validateServerOwnedQueryKeys(flow, issues) {
|
|
|
5024
5120
|
issues,
|
|
5025
5121
|
stepID,
|
|
5026
5122
|
key,
|
|
5027
|
-
|
|
5123
|
+
formatField2(SERVER_OWNED_QUERY_KEYS.loopStepFieldFormat, stepID, subID, key)
|
|
5028
5124
|
);
|
|
5029
5125
|
}
|
|
5030
5126
|
}
|
|
@@ -5291,7 +5387,7 @@ function own(m, key) {
|
|
|
5291
5387
|
if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
|
|
5292
5388
|
return m[key];
|
|
5293
5389
|
}
|
|
5294
|
-
function
|
|
5390
|
+
function formatField3(format, ...args) {
|
|
5295
5391
|
let i = 0;
|
|
5296
5392
|
return format.replace(/%s/g, () => args[i++] ?? "");
|
|
5297
5393
|
}
|
|
@@ -5313,14 +5409,14 @@ function credentialEndpointSteps(flow, issues) {
|
|
|
5313
5409
|
out.push({
|
|
5314
5410
|
executor: issues.stringOf(step, KEY_EXECUTOR, `steps.${stepId}`) ?? "",
|
|
5315
5411
|
query: own(step, KEY_QUERY2),
|
|
5316
|
-
field: (key) =>
|
|
5412
|
+
field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.stepFieldFormat, stepId, key)
|
|
5317
5413
|
});
|
|
5318
5414
|
for (const sub of loopSubStepsOfStep(stepId, step)) {
|
|
5319
5415
|
const subId = issues.stringOf(sub.raw, KEY_ID2, sub.basePath) ?? "";
|
|
5320
5416
|
out.push({
|
|
5321
5417
|
executor: issues.stringOf(sub.raw, KEY_EXECUTOR, sub.basePath) ?? "",
|
|
5322
5418
|
query: own(sub.raw, KEY_QUERY2),
|
|
5323
|
-
field: (key) =>
|
|
5419
|
+
field: (key) => formatField3(CREDENTIAL_ENDPOINT_PAIRING.loopStepFieldFormat, stepId, subId, key)
|
|
5324
5420
|
});
|
|
5325
5421
|
}
|
|
5326
5422
|
}
|
|
@@ -5384,7 +5480,7 @@ function validateAI(flow, steps, issues) {
|
|
|
5384
5480
|
if ((stepsUsing.get(provider) ?? 0) > 0 && (stepsWithoutOwnKey.get(provider) ?? 0) === 0) {
|
|
5385
5481
|
continue;
|
|
5386
5482
|
}
|
|
5387
|
-
warnStoredShape(issues,
|
|
5483
|
+
warnStoredShape(issues, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, provider), provider);
|
|
5388
5484
|
}
|
|
5389
5485
|
}
|
|
5390
5486
|
function warnStoredShape(issues, field, provider) {
|
|
@@ -5431,7 +5527,7 @@ function familySecret(flow, family, step, issues) {
|
|
|
5431
5527
|
if (apiKey !== "" && listHas(family.secretParams, family.configApiKeyParam)) {
|
|
5432
5528
|
return {
|
|
5433
5529
|
envName: serverEnvRef(family, apiKey),
|
|
5434
|
-
field:
|
|
5530
|
+
field: formatField3(
|
|
5435
5531
|
CREDENTIAL_ENDPOINT_PAIRING.executorConfigKeyFieldFormat,
|
|
5436
5532
|
configKey,
|
|
5437
5533
|
CREDENTIAL_ENDPOINT_PAIRING.executorConfigApiKeyField
|
|
@@ -5444,7 +5540,7 @@ function familySecret(flow, family, step, issues) {
|
|
|
5444
5540
|
if (v !== null) {
|
|
5445
5541
|
return {
|
|
5446
5542
|
envName: serverEnvRef(family, v),
|
|
5447
|
-
field:
|
|
5543
|
+
field: formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key)
|
|
5448
5544
|
};
|
|
5449
5545
|
}
|
|
5450
5546
|
}
|
|
@@ -5470,13 +5566,13 @@ function familyAuthorEndpoint(flow, family, step, issues) {
|
|
|
5470
5566
|
if (inst === null) continue;
|
|
5471
5567
|
const baseUrl = configStringField(inst, configKey, CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlField, issues);
|
|
5472
5568
|
if (baseUrl !== "" && listHas(family.endpointParams, family.configBaseUrlParam)) {
|
|
5473
|
-
return decide(baseUrl,
|
|
5569
|
+
return decide(baseUrl, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigBaseUrlFieldFormat, configKey));
|
|
5474
5570
|
}
|
|
5475
5571
|
const extra = own(inst, EXECUTOR_CONFIG_ENV_SCOPES.extraKey);
|
|
5476
5572
|
for (const key of family.endpointParams) {
|
|
5477
5573
|
const v = nonEmptyEndpoint(extra, key);
|
|
5478
5574
|
if (v !== null)
|
|
5479
|
-
return decide(v,
|
|
5575
|
+
return decide(v, formatField3(CREDENTIAL_ENDPOINT_PAIRING.executorConfigExtraFieldFormat, configKey, key));
|
|
5480
5576
|
}
|
|
5481
5577
|
}
|
|
5482
5578
|
return null;
|
|
@@ -7187,6 +7283,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
7187
7283
|
validateOrchestratorCampaign(f, issues, opts);
|
|
7188
7284
|
validateCredentialBindings(f, issues);
|
|
7189
7285
|
validateInputSchema(f, issues);
|
|
7286
|
+
validateReservedInputNames(f, issues);
|
|
7190
7287
|
validateOutputSchemas(f, issues);
|
|
7191
7288
|
validateQualityGates(f, issues);
|
|
7192
7289
|
validateProcessingOperations(f, issues);
|