@vaudience/aigentflow-flow-validator 0.15.3
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/LICENSE +21 -0
- package/PARITY.md +1247 -0
- package/README.md +214 -0
- package/dist/cli.js +5306 -0
- package/dist/index.cjs +5160 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +291 -0
- package/dist/index.d.ts +291 -0
- package/dist/index.js +5154 -0
- package/dist/index.js.map +1 -0
- package/package.json +76 -0
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# aigentflow-flow-validator
|
|
2
|
+
|
|
3
|
+
Static, offline validator for [AIgentFlow](https://aigentflow.dev.ai.vaud.one) workflow YAML — for **Node**, the **browser**, and the **command line**.
|
|
4
|
+
|
|
5
|
+
It catches the structural and semantic problems in a flow definition _before_ you upload it to a server: missing required fields, dangling step references, malformed executor URIs, broken Go-template syntax, invalid `input_schema` fields, unbalanced query/response schemas, and more. It is a faithful port of the **static** checks performed by the AIgentFlow Go engine, so a flow that passes here passes the server's structural validation.
|
|
6
|
+
|
|
7
|
+
- **Zero-config, offline, deterministic.** No network, no credentials, no server.
|
|
8
|
+
- **Tiny + portable.** One runtime dependency (`yaml`); the library entry uses no Node built-ins, so it runs in browsers and bundlers unchanged.
|
|
9
|
+
- **Typed.** Ships TypeScript declarations and a stable, machine-readable result shape.
|
|
10
|
+
- **Parity-tracked.** Mirrors a pinned AIgentFlow flow-schema version — see [PARITY.md](./PARITY.md).
|
|
11
|
+
|
|
12
|
+
> **Scope:** this validator does **static** checks only. It does **not** check credentials, the model-compliance catalogue, or runtime template field-resolution — those require a live server and are out of scope. See [What it does not check](#what-it-does-not-check).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @vaudience/aigentflow-flow-validator
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
You can also install straight from git (the `prepare` script builds `dist/`
|
|
23
|
+
automatically on install):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install github:itsatony/aigentflow-flow-validator-js
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Requires Node ≥ 20 (for library + CLI use). For browser/bundler use, any modern bundler works.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### Node (ESM)
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { validateFlow } from '@vaudience/aigentflow-flow-validator';
|
|
39
|
+
|
|
40
|
+
const result = validateFlow(yamlString);
|
|
41
|
+
if (!result.valid) {
|
|
42
|
+
for (const e of result.errors) {
|
|
43
|
+
console.error(`${e.code} [${e.field}]: ${e.message}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Node (CommonJS)
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
const { validateFlow } = require('@vaudience/aigentflow-flow-validator');
|
|
52
|
+
const result = validateFlow(yamlString);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Browser / bundler
|
|
56
|
+
|
|
57
|
+
The package's main entry pulls in no Node built-ins, so it works in the browser via any bundler (Vite, webpack, esbuild, Rollup):
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { validateFlow } from '@vaudience/aigentflow-flow-validator';
|
|
61
|
+
|
|
62
|
+
const result = validateFlow(editor.getValue());
|
|
63
|
+
renderDiagnostics(result.errors, result.warnings);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Already have a parsed object?
|
|
67
|
+
|
|
68
|
+
If you parsed the YAML yourself (or are validating JSON), skip the parse step:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { validateFlowObject } from '@vaudience/aigentflow-flow-validator';
|
|
72
|
+
const result = validateFlowObject(myFlowObject);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### CLI
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Validate one or more files
|
|
79
|
+
npx aigentflow-validate flow.yaml
|
|
80
|
+
npx aigentflow-validate flows/*.yaml
|
|
81
|
+
|
|
82
|
+
# Read from stdin
|
|
83
|
+
cat flow.yaml | npx aigentflow-validate -
|
|
84
|
+
|
|
85
|
+
# Machine-readable output
|
|
86
|
+
npx aigentflow-validate --json flow.yaml
|
|
87
|
+
|
|
88
|
+
# Treat warnings as failures (for CI gating)
|
|
89
|
+
npx aigentflow-validate --strict flow.yaml
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Exit codes: **0** = valid, **1** = validation failed, **2** = usage error. Add it to CI to fail a build on a broken flow.
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
✓ flow.yaml: valid — 0 error(s), 1 warning(s), 4 step(s)
|
|
96
|
+
warn unreachable_step [steps.cleanup]
|
|
97
|
+
Step 'cleanup' is not reachable from start step
|
|
98
|
+
↳ Add a path to this step or remove it if not needed
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## API
|
|
104
|
+
|
|
105
|
+
### `validateFlow(yaml: string, options?): ValidationResult`
|
|
106
|
+
|
|
107
|
+
Parse flow YAML and validate it. Parse failures (syntax errors, duplicate keys) are reported as `error`-severity issues with line/column when available.
|
|
108
|
+
|
|
109
|
+
### `validateFlowObject(flow: unknown, options?): ValidationResult`
|
|
110
|
+
|
|
111
|
+
Validate an already-parsed flow object.
|
|
112
|
+
|
|
113
|
+
### `parseFlow(yaml: string): ParseOutput`
|
|
114
|
+
|
|
115
|
+
Low-level: parse YAML into `{ flow?, parseErrors, parseWarnings }` without validating.
|
|
116
|
+
|
|
117
|
+
### `SPEC_VERSION: string`
|
|
118
|
+
|
|
119
|
+
The AIgentFlow flow-schema version this build tracks (e.g. `"2.802.0"`).
|
|
120
|
+
|
|
121
|
+
### Options
|
|
122
|
+
|
|
123
|
+
| Option | Default | Effect |
|
|
124
|
+
| ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
125
|
+
| `strictRegistries` | `false` | Report unknown orchestrator tool names and unknown template functions as **errors** instead of **warnings**. Off by default because the vendored allow-lists can lag the live AIgentFlow registries, and a false-positive error is worse than a missed lint. |
|
|
126
|
+
|
|
127
|
+
### Result shape
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
interface ValidationResult {
|
|
131
|
+
valid: boolean; // true when there are zero error-severity issues
|
|
132
|
+
errors: ValidationIssue[];
|
|
133
|
+
warnings: ValidationIssue[];
|
|
134
|
+
summary: {
|
|
135
|
+
totalSteps: number;
|
|
136
|
+
validSteps: number;
|
|
137
|
+
errorCount: number;
|
|
138
|
+
warningCount: number;
|
|
139
|
+
templatesFound: number;
|
|
140
|
+
templatesValid: number;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
interface ValidationIssue {
|
|
145
|
+
field: string; // dotted path, e.g. "steps.fetch.query.url"
|
|
146
|
+
message: string; // human-readable description
|
|
147
|
+
code: string; // stable machine code, e.g. "step_not_found"
|
|
148
|
+
severity: 'error' | 'warning' | 'info';
|
|
149
|
+
stepId?: string;
|
|
150
|
+
line?: number;
|
|
151
|
+
column?: number;
|
|
152
|
+
context?: string;
|
|
153
|
+
suggestion?: string;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`code` is the stable contract — branch on it programmatically. `message` wording may change between releases.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## What it checks
|
|
162
|
+
|
|
163
|
+
- **Required fields** — `aigentflow_version`, `name`, `start`, at least one step.
|
|
164
|
+
- **Unknown keys and value kinds** — any key a flow type does not declare, at every level (`unknown_yaml_key`), and a value of the wrong kind such as `next: end` (`invalid_type`). AIgentFlow refuses both at save, because the key would be silently dropped.
|
|
165
|
+
- **Steps** — `start` resolves to a real step; every non-loop step has an `executor`; loop steps don't; reserved `.` in step IDs and the reserved step ID `orchestrator` are rejected.
|
|
166
|
+
- **Executors** — `scheme://path` shape (error on malformed); unknown scheme (warning).
|
|
167
|
+
- **Query schema** — parameter types, `array` requires `items`, item-type validity, `min_items`/`max_items`, nested `object`/`array` recursion.
|
|
168
|
+
- **Response expectations** — valid data types; `array` requires `items`; `required` is boolean or template.
|
|
169
|
+
- **Error strategy** — action enum (`retry`/`fail`/`goto`/`continue`), `goto_step` existence, `max_delay` duration, `backoff_multiplier`, `retry_on` categories.
|
|
170
|
+
- **Connectivity** — `next.default` / `next.conditions[].goto` references (error; only `null` and `orchestrator` need no step, so `end` must name one, and is then an ordinary step); unreachable steps (warning); cycles (warning).
|
|
171
|
+
- **Parallel + orchestrator routing** — `next.parallel` rendezvous/steps; `orchestrator` next requires an orchestrator block.
|
|
172
|
+
- **Loop / for_each / throttle** — required fields, iteration limits, mutual exclusions, throttle ceilings.
|
|
173
|
+
- **Orchestrator / campaign** — exons presence, trigger types, timer intervals, tool names; campaign requires an orchestrator and at least one child flow, each naming a `flow_id` or `flow_name`; `max_credits_per_child` >= 0.
|
|
174
|
+
- **Orchestrator `.exons` frontmatter** — the document must open with a closed `---` frontmatter spec (`orchestrator_exons_parse_failed`) that sets `execution.provider` (`orchestrator_exons_no_provider`) and declares no `requirements.resources` (`exons_resources_unhonoured`); a tool that `orchestrator.tools` and the definition's `tools.allow` disagree about is never offered (`orchestrator_tool_withheld`, warning). The document body is not parsed: that needs the `.exons` engine (see PARITY.md).
|
|
175
|
+
- **`executor_config` environment references** — a `${NAME}` value may name only the variables of the provider or protocol it is written under (`executor_config_env_scope`).
|
|
176
|
+
- **Server-owned query keys** — a step's or loop sub-step's `query:` may not declare `aiv_api_key`, `aiv_base_url` or `aiv_delegation`, which only the server sets (`server_owned_query_key`).
|
|
177
|
+
- **Credential endpoints** — an endpoint a server-supplied credential will never be sent to (warning, `credential_endpoint_unpaired`): an `ai://` `<provider>_base_url` or a literal `executor_config.<provider>.base_url` with no key of the flow's own, a family secret that is a server `${AIGENTFLOW_…}` variable beside a literal non-default endpoint, a `nexus://` endpoint with no key of its own.
|
|
178
|
+
- **Credential bindings** — `stored/{provider}/{name}` format, `inject_as`, `credential`/`credentials` mutual exclusion.
|
|
179
|
+
- **Expression functions** — exactly one of `package`/`function`.
|
|
180
|
+
- **`input_schema`** — version, field-name pattern, type enum, per-type constraints, `pattern` compilation, `visible_when` predicate + reference resolution, duplicate-name detection, file-ordering lint.
|
|
181
|
+
- **Step `output_schema`** — the same JSON-Schema subset as `input_schema`, validated at step scope (and on loop sub-steps).
|
|
182
|
+
- **`quality_gate:`** — `rubric` required, `threshold` in `[0,1]`, `on_fail` enum (`fail`/`goto`/`retry`; `human` is rejected as not-yet-supported), `goto_step` existence + no self-goto when `on_fail=goto`, and the composite/parallel-member scope guards.
|
|
183
|
+
- **`tool_discovery`** — `eager`/`lazy`/`off` on the flow, the orchestrator, and a step `query` (empty and templated values skipped).
|
|
184
|
+
- **Mock scenarios** — each `delay` must be a Go duration (`100ms`, not `100`), judged by its written spelling: `0` saves, `0.0` does not.
|
|
185
|
+
- **`output:`** — no empty-string entries.
|
|
186
|
+
- **Templates** — Go `text/template` **syntax** across query, processing, and conditions.
|
|
187
|
+
|
|
188
|
+
## What it does **not** check
|
|
189
|
+
|
|
190
|
+
These need a live server / org context and are intentionally out of scope:
|
|
191
|
+
|
|
192
|
+
- **Credentials** — whether a bound credential actually exists or is authorised.
|
|
193
|
+
- **Model compliance** — the `compliance:` block is enforced against the provider catalogue at flow-create time on the server.
|
|
194
|
+
- **`.exons` document bodies** — whether an inline `.exons` document parses and whether its tags can render (`exons_attributes`) needs the `.exons` template engine, which this package does not embed.
|
|
195
|
+
- **Template field resolution** — whether `.data.x.y` will actually be populated at runtime (we validate syntax, not data flow).
|
|
196
|
+
- **Publish gates** — `visibility`/`classification`/template-metadata publish rules are server- and org-context dependent.
|
|
197
|
+
|
|
198
|
+
A clean result here means the flow is **structurally** sound — not that it will execute successfully against your specific credentials and data.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Versioning & parity
|
|
203
|
+
|
|
204
|
+
This validator tracks a specific AIgentFlow flow-schema version, exposed as `SPEC_VERSION`. The enum surface (executor schemes, data types, error actions, input-schema field types, template functions, …) lives in [`src/spec/aigentflow-spec.json`](./src/spec/aigentflow-spec.json) and the rule-by-rule mapping to the Go reference is documented in [PARITY.md](./PARITY.md). When AIgentFlow's flow grammar changes, the validator is updated and the spec version bumped.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Contributing
|
|
209
|
+
|
|
210
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md). In short: `npm install`, then `npm run typecheck && npm run lint && npm test && npm run build`.
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
[MIT](./LICENSE) © vAudience.AI
|