@vaudience/aigentflow-flow-validator 0.20.0 → 0.21.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/dist/index.d.cts CHANGED
@@ -256,6 +256,7 @@ interface Flow {
256
256
  input_schema?: InputSchema;
257
257
  classification?: Record<string, unknown>;
258
258
  is_template?: boolean;
259
+ strict_templates?: boolean;
259
260
  template?: Record<string, unknown> | null;
260
261
  [key: string]: unknown;
261
262
  }
package/dist/index.d.ts CHANGED
@@ -256,6 +256,7 @@ interface Flow {
256
256
  input_schema?: InputSchema;
257
257
  classification?: Record<string, unknown>;
258
258
  is_template?: boolean;
259
+ strict_templates?: boolean;
259
260
  template?: Record<string, unknown> | null;
260
261
  [key: string]: unknown;
261
262
  }
package/dist/index.js CHANGED
@@ -302,6 +302,17 @@ function isValidGoDuration(input) {
302
302
  var RESERVED_STEP_ID_CHAR = ".";
303
303
  var RESERVED_STEP_ID_ORCHESTRATOR = "orchestrator";
304
304
  var DISPLAY_NAME_MAX_LEN = 80;
305
+ var YAML11_BOOL_WORDS = new Set(
306
+ ["y", "yes", "on", "n", "no", "off"].flatMap((w) => [
307
+ w,
308
+ w.toUpperCase(),
309
+ w[0].toUpperCase() + w.slice(1)
310
+ ])
311
+ );
312
+ function isBoolLike(v) {
313
+ if (v === null || typeof v === "boolean") return true;
314
+ return typeof v === "string" && YAML11_BOOL_WORDS.has(v);
315
+ }
305
316
  function validateBasicStructure(flow, issues) {
306
317
  if (!issues.nonEmptyStringOf(flow, "aigentflow_version", "")) {
307
318
  issues.error({
@@ -331,6 +342,14 @@ function validateBasicStructure(flow, issues) {
331
342
  });
332
343
  }
333
344
  }
345
+ if (flow.strict_templates !== void 0 && !isBoolLike(flow.strict_templates)) {
346
+ issues.error({
347
+ field: "strict_templates",
348
+ message: "strict_templates must be a boolean (true or false)",
349
+ code: "invalid_type",
350
+ suggestion: "Write 'strict_templates: true' or remove the key"
351
+ });
352
+ }
334
353
  const start = issues.stringOf(flow, "start", "");
335
354
  if (start === null || start === "") {
336
355
  issues.error({
@@ -430,7 +449,7 @@ function validateBasicStructure(flow, issues) {
430
449
 
431
450
  // src/spec/aigentflow-spec.json
432
451
  var aigentflow_spec_default = {
433
- specVersion: "2.821.0",
452
+ specVersion: "2.827.0",
434
453
  inputSchemaVersion: 1,
435
454
  executorSchemes: [
436
455
  "a2a",
@@ -454,6 +473,7 @@ var aigentflow_spec_default = {
454
473
  "geocoding",
455
474
  "geovisualize",
456
475
  "getmd",
476
+ "here",
457
477
  "homeassistant",
458
478
  "hosting",
459
479
  "http",
@@ -1255,6 +1275,11 @@ var aigentflow_spec_default = {
1255
1275
  }
1256
1276
  }
1257
1277
  },
1278
+ templateDefaultPiped: {
1279
+ code: "template_default_piped",
1280
+ messageFormat: "`default` takes the value FIRST, and a pipe passes the piped value LAST: `%s` is `default <fallback> <value>`, so the fallback is always the result",
1281
+ suggestion: 'write the value first and the fallback second, as a call: `{{ default .x "fallback" }}`'
1282
+ },
1258
1283
  complianceResidency: {
1259
1284
  code: "compliance_residency_unenforced",
1260
1285
  euResidencyCodes: ["EU", "DE", "FR", "IE", "NL", "IT", "ES"],
@@ -1553,6 +1578,7 @@ var aigentflow_spec_default = {
1553
1578
  rate_limit: "FlowRateLimitConfig",
1554
1579
  start: "scalar",
1555
1580
  steps: "map<StepDefinition>",
1581
+ strict_templates: "scalar",
1556
1582
  tags: "list<scalar>",
1557
1583
  template: "FlowTemplateMetadata",
1558
1584
  tool_discovery: "scalar",
@@ -1914,6 +1940,11 @@ var EXAMPLES = {
1914
1940
  name: p.name,
1915
1941
  re: new RegExp(p.expr, p.flags)
1916
1942
  }))};
1943
+ var TEMPLATE_DEFAULT_PIPED = {
1944
+ code: aigentflow_spec_default.templateDefaultPiped.code,
1945
+ messageFormat: aigentflow_spec_default.templateDefaultPiped.messageFormat,
1946
+ suggestion: aigentflow_spec_default.templateDefaultPiped.suggestion
1947
+ };
1917
1948
 
1918
1949
  // src/validators/executors.ts
1919
1950
  var SCHEME_SEPARATOR = "://";
@@ -3877,6 +3908,117 @@ function splitPipeline(body) {
3877
3908
  return stages;
3878
3909
  }
3879
3910
 
3911
+ // src/template/gotmpl-default.ts
3912
+ var FUNCTION_NAME = "default";
3913
+ var PIPE = "|";
3914
+ var OPEN_PAREN = "(";
3915
+ var CLOSE_PAREN = ")";
3916
+ var MAX_NESTING_DEPTH = 100;
3917
+ var PIPELINE_KEYWORDS = /^(?:else\s+if|else\s+with|if|range|with|template|block)(?![\w$.])/;
3918
+ var NO_PIPELINE = /^(?:define|else|end|break|continue)(?![\w$.])/;
3919
+ var DECLARATION = /^\$\w*(?:\s*,\s*\$\w*)*\s*:?=/;
3920
+ function pipedDefaultPipelines(src) {
3921
+ const { actions, fatal } = lexActions(src);
3922
+ if (fatal) return [];
3923
+ const found = /* @__PURE__ */ new Set();
3924
+ try {
3925
+ for (const action of actions) {
3926
+ if (action.isComment || action.body === "") continue;
3927
+ scanAction(action.body, found);
3928
+ }
3929
+ } catch (err) {
3930
+ if (!(err instanceof RangeError)) throw err;
3931
+ return [];
3932
+ }
3933
+ return [...found].sort();
3934
+ }
3935
+ function scanAction(body, found) {
3936
+ let rest = body;
3937
+ const kw = PIPELINE_KEYWORDS.exec(rest);
3938
+ if (!kw && NO_PIPELINE.test(rest)) return;
3939
+ if (kw) {
3940
+ rest = rest.slice(kw[0].length).trimStart();
3941
+ const keyword = kw[0].replace(/\s+/g, " ");
3942
+ if (keyword === "template" || keyword === "block") {
3943
+ const q2 = rest[0];
3944
+ if (q2 === '"' || q2 === "`") {
3945
+ const end = scanString(rest, 0, q2);
3946
+ if (end === -1) return;
3947
+ rest = rest.slice(end + 1).trimStart();
3948
+ }
3949
+ }
3950
+ }
3951
+ if (rest === "") return;
3952
+ parsePipeline(rest, 0, false, found, 0);
3953
+ }
3954
+ function parsePipeline(src, start, nested, found, depth) {
3955
+ if (depth > MAX_NESTING_DEPTH) return { text: src.slice(start), end: src.length };
3956
+ let i = start;
3957
+ const n = src.length;
3958
+ let decl = "";
3959
+ const decMatch = DECLARATION.exec(src.slice(i));
3960
+ if (decMatch) {
3961
+ decl = decMatch[0].replace(/\s+/g, " ") + " ";
3962
+ i += decMatch[0].length;
3963
+ }
3964
+ const commands = [];
3965
+ let current = [];
3966
+ let firstWords = [];
3967
+ let pipedDefault = false;
3968
+ const pushCommand = () => {
3969
+ if (current.length > 0) {
3970
+ commands.push(current);
3971
+ firstWords.push(current[0]);
3972
+ }
3973
+ current = [];
3974
+ };
3975
+ while (i < n) {
3976
+ const c = src[i];
3977
+ if (c === " " || c === " " || c === "\n" || c === "\r") {
3978
+ i += 1;
3979
+ continue;
3980
+ }
3981
+ if (c === '"' || c === "`" || c === "'") {
3982
+ const end = scanString(src, i, c);
3983
+ const stop = end === -1 ? n - 1 : end;
3984
+ current.push(src.slice(i, stop + 1));
3985
+ i = stop + 1;
3986
+ continue;
3987
+ }
3988
+ if (c === OPEN_PAREN) {
3989
+ const inner = parsePipeline(src, i + 1, true, found, depth + 1);
3990
+ current.push(`(${inner.text})`);
3991
+ i = inner.end;
3992
+ continue;
3993
+ }
3994
+ if (c === CLOSE_PAREN) {
3995
+ if (nested) {
3996
+ i += 1;
3997
+ break;
3998
+ }
3999
+ i += 1;
4000
+ continue;
4001
+ }
4002
+ if (c === PIPE) {
4003
+ pushCommand();
4004
+ i += 1;
4005
+ continue;
4006
+ }
4007
+ let j = i;
4008
+ while (j < n && !/[\s|()"`']/.test(src[j])) j += 1;
4009
+ if (j === i) j = i + 1;
4010
+ current.push(src.slice(i, j));
4011
+ i = j;
4012
+ }
4013
+ pushCommand();
4014
+ firstWords.forEach((word, idx) => {
4015
+ if (idx > 0 && word === FUNCTION_NAME) pipedDefault = true;
4016
+ });
4017
+ const text = decl + commands.map((cmd) => cmd.join(" ")).join(` ${PIPE} `);
4018
+ if (pipedDefault) found.add(text);
4019
+ return { text, end: i };
4020
+ }
4021
+
3880
4022
  // src/validators/processingOperations.ts
3881
4023
  var PROCESSING_OP_GUARD_KEY = PROCESSING_OPERATIONS.guardKey;
3882
4024
  var PROCESSING_PHASES = ["pre_processing", "post_processing"];
@@ -4023,6 +4165,17 @@ function checkTemplateString(value, field, stepID, issues, stats, opts, demote =
4023
4165
  });
4024
4166
  }
4025
4167
  }
4168
+ if (errors.length > 0) return;
4169
+ for (const pipe of pipedDefaultPipelines(value)) {
4170
+ report({
4171
+ field,
4172
+ message: TEMPLATE_DEFAULT_PIPED.messageFormat.replace("%s", () => pipe),
4173
+ code: TEMPLATE_DEFAULT_PIPED.code,
4174
+ stepId: stepID,
4175
+ context: `Template: ${value}`,
4176
+ suggestion: TEMPLATE_DEFAULT_PIPED.suggestion
4177
+ });
4178
+ }
4026
4179
  }
4027
4180
  function walkStrings2(basePath, value, stepID, issues, stats, opts, check, demote = false) {
4028
4181
  if (isString(value)) {