@vaudience/aigentflow-flow-validator 0.21.0 → 0.23.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 +58 -1
- package/README.md +2 -1
- package/dist/cli.js +172 -6
- package/dist/index.cjs +170 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +170 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -433,7 +433,7 @@ function validateBasicStructure(flow, issues) {
|
|
|
433
433
|
message: "Executor is required for each step",
|
|
434
434
|
code: "missing_required_field",
|
|
435
435
|
stepId: stepID,
|
|
436
|
-
suggestion: "Specify an executor URL (e.g., 'function://
|
|
436
|
+
suggestion: "Specify an executor URL (e.g., 'function://utils/log')"
|
|
437
437
|
});
|
|
438
438
|
} else if (executorText === null) {
|
|
439
439
|
issues.error({
|
|
@@ -449,7 +449,7 @@ function validateBasicStructure(flow, issues) {
|
|
|
449
449
|
|
|
450
450
|
// src/spec/aigentflow-spec.json
|
|
451
451
|
var aigentflow_spec_default = {
|
|
452
|
-
specVersion: "2.
|
|
452
|
+
specVersion: "2.831.0",
|
|
453
453
|
inputSchemaVersion: 1,
|
|
454
454
|
executorSchemes: [
|
|
455
455
|
"a2a",
|
|
@@ -946,6 +946,73 @@ var aigentflow_spec_default = {
|
|
|
946
946
|
stepFieldFormat: "steps.%s.query.%s",
|
|
947
947
|
loopStepFieldFormat: "steps.%s.loop.steps.%s.query.%s"
|
|
948
948
|
},
|
|
949
|
+
functionOperations: {
|
|
950
|
+
code: "unknown_function_operation",
|
|
951
|
+
scheme: "function",
|
|
952
|
+
messageFormat: "step %s uses function://%s, which is not a built-in function. Available: %s",
|
|
953
|
+
suggestionFormat: "Use one of the built-in function operations: %s. For custom logic use a script://, http:// or ai:// executor instead.",
|
|
954
|
+
operations: [
|
|
955
|
+
"binary-processor/validate-and-store",
|
|
956
|
+
"data/create",
|
|
957
|
+
"data/from-json",
|
|
958
|
+
"data/to-json",
|
|
959
|
+
"data/validate",
|
|
960
|
+
"demo/adult-processor",
|
|
961
|
+
"demo/calculator",
|
|
962
|
+
"demo/data-processor",
|
|
963
|
+
"demo/finalizer",
|
|
964
|
+
"demo/senior-processor",
|
|
965
|
+
"demo/youth-processor",
|
|
966
|
+
"document/finalize",
|
|
967
|
+
"document/prepare",
|
|
968
|
+
"json/validate",
|
|
969
|
+
"math/basic",
|
|
970
|
+
"math/calculate",
|
|
971
|
+
"math/sum",
|
|
972
|
+
"results-compiler/aggregate",
|
|
973
|
+
"system/info",
|
|
974
|
+
"text/analysis",
|
|
975
|
+
"text/count-characters",
|
|
976
|
+
"text/count-lines",
|
|
977
|
+
"text/count-occurrences",
|
|
978
|
+
"text/count-words",
|
|
979
|
+
"text/find-pattern",
|
|
980
|
+
"text/generate",
|
|
981
|
+
"text/replace-text",
|
|
982
|
+
"text/search",
|
|
983
|
+
"utils/datetime",
|
|
984
|
+
"utils/format-date",
|
|
985
|
+
"utils/log",
|
|
986
|
+
"utils/parse-date"
|
|
987
|
+
]
|
|
988
|
+
},
|
|
989
|
+
flowDataReservedKeys: {
|
|
990
|
+
code: "flow_data_key_reserved",
|
|
991
|
+
fieldFormat: "data.%s",
|
|
992
|
+
messageFormat: "data: key %s is reserved: %s. It would write into the engine's own state, so it is not seeded.",
|
|
993
|
+
suggestion: "Rename the key (no leading `_` or `.`, and not one of the engine namespaces memory., orchestrator., campaign., voiceagent.).",
|
|
994
|
+
exact: {
|
|
995
|
+
org_id: "the mission's organization, set by the engine for Thalamus/Engram calls",
|
|
996
|
+
memory: "the memory scope namespace",
|
|
997
|
+
orchestrator: "the orchestrator's state namespace",
|
|
998
|
+
campaign: "the campaign's state namespace",
|
|
999
|
+
voiceagent: "the voice agent's state namespace",
|
|
1000
|
+
current_flow: "engine bookkeeping (the current flow definition)",
|
|
1001
|
+
modified_flow: "engine bookkeeping (dynamic flow modification)",
|
|
1002
|
+
modification_history: "engine bookkeeping (dynamic flow modification)",
|
|
1003
|
+
modification_pending: "engine bookkeeping (dynamic flow modification)",
|
|
1004
|
+
modification_requests: "engine bookkeeping (dynamic flow modification)",
|
|
1005
|
+
bottleneck_state: "engine bookkeeping (bottleneck analysis)"
|
|
1006
|
+
},
|
|
1007
|
+
prefixes: [
|
|
1008
|
+
{ prefix: "_", reason: "keys starting with `_` are engine bookkeeping (current flow, loop and for_each context, taint lists such as `__untrusted_*`)" },
|
|
1009
|
+
{ prefix: ".", reason: "keys starting with `.` are engine step-response slots" },
|
|
1010
|
+
{ prefix: "memory.", reason: "the `memory.` namespace belongs to the engine" },
|
|
1011
|
+
{ prefix: "orchestrator.", reason: "the `orchestrator.` namespace belongs to the orchestrator" },
|
|
1012
|
+
{ prefix: "campaign.", reason: "the `campaign.` namespace belongs to the campaign engine" },
|
|
1013
|
+
{ prefix: "voiceagent.", reason: "the `voiceagent.` namespace belongs to the voice agent" }
|
|
1014
|
+
]
|
|
1015
|
+
},
|
|
949
1016
|
credentialEndpointPairing: {
|
|
950
1017
|
stepFieldFormat: "steps.%s.query.%s",
|
|
951
1018
|
loopStepFieldFormat: "steps.%s.loop.steps.%s.query.%s",
|
|
@@ -1883,6 +1950,14 @@ var SERVER_OWNED_QUERY_KEYS = {
|
|
|
1883
1950
|
stepFieldFormat: aigentflow_spec_default.serverOwnedQueryKeys.stepFieldFormat,
|
|
1884
1951
|
loopStepFieldFormat: aigentflow_spec_default.serverOwnedQueryKeys.loopStepFieldFormat
|
|
1885
1952
|
};
|
|
1953
|
+
var FLOW_DATA_RESERVED_KEYS = {
|
|
1954
|
+
code: aigentflow_spec_default.flowDataReservedKeys.code,
|
|
1955
|
+
fieldFormat: aigentflow_spec_default.flowDataReservedKeys.fieldFormat,
|
|
1956
|
+
messageFormat: aigentflow_spec_default.flowDataReservedKeys.messageFormat,
|
|
1957
|
+
suggestion: aigentflow_spec_default.flowDataReservedKeys.suggestion,
|
|
1958
|
+
exact: aigentflow_spec_default.flowDataReservedKeys.exact,
|
|
1959
|
+
prefixes: aigentflow_spec_default.flowDataReservedKeys.prefixes
|
|
1960
|
+
};
|
|
1886
1961
|
var CREDENTIAL_ENDPOINT_PAIRING = {
|
|
1887
1962
|
stepFieldFormat: aigentflow_spec_default.credentialEndpointPairing.stepFieldFormat,
|
|
1888
1963
|
loopStepFieldFormat: aigentflow_spec_default.credentialEndpointPairing.loopStepFieldFormat,
|
|
@@ -1945,9 +2020,51 @@ var TEMPLATE_DEFAULT_PIPED = {
|
|
|
1945
2020
|
messageFormat: aigentflow_spec_default.templateDefaultPiped.messageFormat,
|
|
1946
2021
|
suggestion: aigentflow_spec_default.templateDefaultPiped.suggestion
|
|
1947
2022
|
};
|
|
2023
|
+
var FUNCTION_OPERATIONS = {
|
|
2024
|
+
code: aigentflow_spec_default.functionOperations.code,
|
|
2025
|
+
scheme: aigentflow_spec_default.functionOperations.scheme,
|
|
2026
|
+
messageFormat: aigentflow_spec_default.functionOperations.messageFormat,
|
|
2027
|
+
suggestionFormat: aigentflow_spec_default.functionOperations.suggestionFormat,
|
|
2028
|
+
operations: new Set(aigentflow_spec_default.functionOperations.operations),
|
|
2029
|
+
sorted: aigentflow_spec_default.functionOperations.operations
|
|
2030
|
+
};
|
|
1948
2031
|
|
|
1949
2032
|
// src/validators/executors.ts
|
|
1950
2033
|
var SCHEME_SEPARATOR = "://";
|
|
2034
|
+
var UNKNOWN_SCHEME_BASE = (scheme) => `Unknown executor scheme '${scheme}'. It may be valid in a newer AIgentFlow release, or it could be a typo.`;
|
|
2035
|
+
var DECIDE_SCHEME = "decide";
|
|
2036
|
+
var DECIDE_HINT = "Decision models run through ai://{provider}/decide (for example ai://openai/decide), not through a scheme of their own.";
|
|
2037
|
+
var MAX_SCHEME_EDIT_DISTANCE = 2;
|
|
2038
|
+
function editDistance(a, b) {
|
|
2039
|
+
let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
2040
|
+
for (let i = 1; i <= a.length; i++) {
|
|
2041
|
+
const cur = [i];
|
|
2042
|
+
for (let j = 1; j <= b.length; j++) {
|
|
2043
|
+
cur[j] = Math.min(
|
|
2044
|
+
prev[j] + 1,
|
|
2045
|
+
cur[j - 1] + 1,
|
|
2046
|
+
prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1)
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
prev = cur;
|
|
2050
|
+
}
|
|
2051
|
+
return prev[b.length];
|
|
2052
|
+
}
|
|
2053
|
+
function unknownSchemeMessage(scheme) {
|
|
2054
|
+
const lower = scheme.toLowerCase();
|
|
2055
|
+
const base = UNKNOWN_SCHEME_BASE(scheme);
|
|
2056
|
+
if (lower === DECIDE_SCHEME) return `${base} ${DECIDE_HINT}`;
|
|
2057
|
+
let best;
|
|
2058
|
+
let bestDist = MAX_SCHEME_EDIT_DISTANCE + 1;
|
|
2059
|
+
for (const known of [...EXECUTOR_SCHEMES].sort()) {
|
|
2060
|
+
const d = editDistance(lower, known);
|
|
2061
|
+
if (d < bestDist) {
|
|
2062
|
+
best = known;
|
|
2063
|
+
bestDist = d;
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
return best === void 0 ? base : `${base} Did you mean '${best}'?`;
|
|
2067
|
+
}
|
|
1951
2068
|
function checkExecutor(executor, field, stepID, issues) {
|
|
1952
2069
|
const sepIdx = executor.indexOf(SCHEME_SEPARATOR);
|
|
1953
2070
|
const scheme = sepIdx > 0 ? executor.slice(0, sepIdx) : "";
|
|
@@ -1966,11 +2083,28 @@ function checkExecutor(executor, field, stepID, issues) {
|
|
|
1966
2083
|
if (!EXECUTOR_SCHEMES.has(scheme.toLowerCase())) {
|
|
1967
2084
|
issues.warn({
|
|
1968
2085
|
field,
|
|
1969
|
-
message:
|
|
2086
|
+
message: unknownSchemeMessage(scheme),
|
|
1970
2087
|
code: "unknown_executor_scheme",
|
|
1971
2088
|
stepId: stepID
|
|
1972
2089
|
});
|
|
2090
|
+
return;
|
|
1973
2091
|
}
|
|
2092
|
+
checkFunctionOperation(executor, field, stepID, templated, issues);
|
|
2093
|
+
}
|
|
2094
|
+
function checkFunctionOperation(executor, field, stepID, templated, issues) {
|
|
2095
|
+
if (templated) return;
|
|
2096
|
+
const m = EXECUTOR_URL_PATTERN.exec(executor);
|
|
2097
|
+
if (m === null || m[1] !== FUNCTION_OPERATIONS.scheme) return;
|
|
2098
|
+
const op = `${m[2]}/${m[3]}`;
|
|
2099
|
+
if (FUNCTION_OPERATIONS.operations.has(op)) return;
|
|
2100
|
+
const list = FUNCTION_OPERATIONS.sorted.join(", ");
|
|
2101
|
+
issues.error({
|
|
2102
|
+
field,
|
|
2103
|
+
message: FUNCTION_OPERATIONS.messageFormat.replace("%s", () => JSON.stringify(stepID)).replace("%s", () => op).replace("%s", () => list),
|
|
2104
|
+
code: FUNCTION_OPERATIONS.code,
|
|
2105
|
+
stepId: stepID,
|
|
2106
|
+
suggestion: FUNCTION_OPERATIONS.suggestionFormat.replace("%s", () => list)
|
|
2107
|
+
});
|
|
1974
2108
|
}
|
|
1975
2109
|
function validateExecutors(flow, issues) {
|
|
1976
2110
|
const steps = flow.steps;
|
|
@@ -3802,16 +3936,16 @@ function skipSpaces(src, idx) {
|
|
|
3802
3936
|
}
|
|
3803
3937
|
return i;
|
|
3804
3938
|
}
|
|
3805
|
-
function scanString(src, start,
|
|
3939
|
+
function scanString(src, start, quote2) {
|
|
3806
3940
|
let i = start + 1;
|
|
3807
|
-
const raw =
|
|
3941
|
+
const raw = quote2 === "`";
|
|
3808
3942
|
while (i < src.length) {
|
|
3809
3943
|
const c = src[i];
|
|
3810
3944
|
if (!raw && c === "\\") {
|
|
3811
3945
|
i += 2;
|
|
3812
3946
|
continue;
|
|
3813
3947
|
}
|
|
3814
|
-
if (c ===
|
|
3948
|
+
if (c === quote2) return i;
|
|
3815
3949
|
i += 1;
|
|
3816
3950
|
}
|
|
3817
3951
|
return -1;
|
|
@@ -4414,6 +4548,35 @@ function validateRetiredKeys(flow, issues) {
|
|
|
4414
4548
|
}
|
|
4415
4549
|
}
|
|
4416
4550
|
|
|
4551
|
+
// src/validators/flowDataKeys.ts
|
|
4552
|
+
var KEY_DATA = "data";
|
|
4553
|
+
function quote(key) {
|
|
4554
|
+
return JSON.stringify(key);
|
|
4555
|
+
}
|
|
4556
|
+
function flowDataKeyReservation(key) {
|
|
4557
|
+
if (Object.prototype.hasOwnProperty.call(FLOW_DATA_RESERVED_KEYS.exact, key)) {
|
|
4558
|
+
return FLOW_DATA_RESERVED_KEYS.exact[key];
|
|
4559
|
+
}
|
|
4560
|
+
for (const p of FLOW_DATA_RESERVED_KEYS.prefixes) {
|
|
4561
|
+
if (key.startsWith(p.prefix)) return p.reason;
|
|
4562
|
+
}
|
|
4563
|
+
return void 0;
|
|
4564
|
+
}
|
|
4565
|
+
function validateFlowDataKeys(flow, issues) {
|
|
4566
|
+
const data = flow[KEY_DATA];
|
|
4567
|
+
if (!isRecord(data)) return;
|
|
4568
|
+
for (const key of Object.keys(data).sort()) {
|
|
4569
|
+
const reason = flowDataKeyReservation(key);
|
|
4570
|
+
if (reason === void 0) continue;
|
|
4571
|
+
issues.error({
|
|
4572
|
+
field: FLOW_DATA_RESERVED_KEYS.fieldFormat.replace("%s", () => key),
|
|
4573
|
+
message: FLOW_DATA_RESERVED_KEYS.messageFormat.replace("%s", () => quote(key)).replace("%s", () => reason),
|
|
4574
|
+
code: FLOW_DATA_RESERVED_KEYS.code,
|
|
4575
|
+
suggestion: FLOW_DATA_RESERVED_KEYS.suggestion
|
|
4576
|
+
});
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
|
|
4417
4580
|
// src/validators/saveDoor.ts
|
|
4418
4581
|
var TOOL_DISCOVERY_MODES = /* @__PURE__ */ new Set(["eager", "lazy", "off"]);
|
|
4419
4582
|
var TEMPLATE_ACTION_OPEN2 = "{{";
|
|
@@ -6876,6 +7039,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
6876
7039
|
validateSaveDoorExtras(f, issues);
|
|
6877
7040
|
validateExecutorConfigEnvScopes(f, issues);
|
|
6878
7041
|
validateServerOwnedQueryKeys(f, issues);
|
|
7042
|
+
validateFlowDataKeys(f, issues);
|
|
6879
7043
|
validateCredentialEndpointPairing(f, issues);
|
|
6880
7044
|
validateExamples(f, issues);
|
|
6881
7045
|
validateOrchestratorExons(f, issues);
|