Validation System
Validation System
Section titled “Validation System”Moira performs comprehensive validation at multiple levels to ensure workflow integrity and correct agent responses.
Validation Levels
Section titled “Validation Levels”1. JSON Schema Validation
Section titled “1. JSON Schema Validation”Workflows are validated against a JSON Schema definition:
- Structure validation against workflow schema
- Required field checking (id, metadata, nodes)
- Type validation for all properties
- Enum validation for node types
2. Structural Validation
Section titled “2. Structural Validation”Graph structure is analyzed for correctness:
- Node connectivity - All connections point to valid nodes
- Required nodes - Start node must exist
- Circular dependencies - Loops are detected and flagged
- Unreachable nodes - Nodes not connected from start
- Registry entries - Each
variableRegistryentry must be a valid JSON Schema (a malformeditems/pattern/etc. is a blocking error) with a non-empty description
3. Input Validation
Section titled “3. Input Validation”Agent responses are validated against inputSchema:
- AJV-based JSON Schema validation
- Type checking for response fields
- Required field validation
- Pattern and format validation
Validation Results
Section titled “Validation Results”Validation returns structured results:
{ valid: boolean; errors: ValidationError[]; warnings: ValidationWarning[];}Error Types
Section titled “Error Types”| Type | Description | Example |
|---|---|---|
schema | JSON structure invalid | Missing required field |
structure | Graph structure invalid | Orphan node |
connection | Connection invalid | Points to non-existent node |
reference | Reference invalid | Invalid subgraph ID |
Warning Types
Section titled “Warning Types”| Type | Description | Threshold |
|---|---|---|
performance | Large workflow | >20 agent-directive nodes |
complexity | Complex conditions | Deeply nested conditions |
context | Large context | >100KB context size |
Validation Examples
Section titled “Validation Examples”Valid Workflow
Section titled “Valid Workflow”{ "id": "valid-workflow", "metadata": { "name": "Valid Workflow", "version": "1.0.0", "description": "A valid workflow" }, "nodes": [ { "id": "start", "type": "start", "connections": { "default": "task" } }, { "id": "task", "type": "agent-directive", "directive": "...", "completionCondition": "...", "connections": { "success": "end" } }, { "id": "end", "type": "end" } ]}Result:
{ "valid": true, "errors": [], "warnings": [] }Invalid Workflow - Missing Connection
Section titled “Invalid Workflow - Missing Connection”{ "nodes": [ { "id": "start", "type": "start", "connections": { "default": "missing" } }, { "id": "end", "type": "end" } ]}Result:
{ "valid": false, "errors": [ { "type": "connection", "message": "Node 'start' references non-existent node 'missing'", "nodeId": "start" } ]}Workflow with Warning
Section titled “Workflow with Warning”Large workflow triggers performance warning:
{ "valid": true, "errors": [], "warnings": [ { "type": "performance", "message": "Workflow has 25 agent-directive nodes. Consider breaking into subgraphs.", "count": 25 } ]}Input Schema Validation
Section titled “Input Schema Validation”Agent responses are validated against inputSchema defined on agent-directive nodes.
Nodes Without inputSchema
Section titled “Nodes Without inputSchema”Nodes without inputSchema require empty input from agent. Non-empty responses are rejected:
// Node without inputSchema{ "id": "task", "type": "agent-directive", "directive": "..." }
// Valid: empty response{}
// Invalid: non-empty response{ "result": "done" } // Rejected with validation errorSchema Definition
Section titled “Schema Definition”{ "type": "agent-directive", "inputSchema": { "type": "object", "properties": { "result": { "type": "string" }, "confidence": { "type": "number", "minimum": 0, "maximum": 10 } }, "required": ["result"] }}Valid Response
Section titled “Valid Response”{ "result": "completed", "confidence": 8 }Invalid Response
Section titled “Invalid Response”{ "confidence": "high" }Error:
{ "valid": false, "errors": [ { "field": "result", "message": "Required field missing" }, { "field": "confidence", "message": "Expected number, got string" } ]}Declared-But-No-Default Variable Warning
Section titled “Declared-But-No-Default Variable Warning”The validator emits a warning (severity warning, not an error — the workflow is still valid) when a variableRegistry variable is referenced in a directive, completionCondition, message, or condition, but the variable has no default and is never written by any upstream node’s globalInputs (and is not present in the start node’s initialData).
At runtime, such a reference renders the literal placeholder [[UNDEFINED_VARIABLE]] instead of a value.
{ "valid": true, "errors": [], "warnings": [ { "type": "structure", "severity": "warning", "nodeId": "do-work", "message": "Variable 'iteration' is referenced in node 'do-work' but has no default and is never written by an upstream node. It will render [[UNDEFINED_VARIABLE]] at runtime." } ]}Fix it one of two ways:
- Add a
defaultto the variable invariableRegistry. - Have an upstream node write the variable via its
globalInputsbefore the node that references it.
Injection Safety
Section titled “Injection Safety”Substituted variable and data VALUES are never re-executed as templates. When the engine interpolates a value into a directive or message, that value is treated as a literal string — brace syntax originating from substituted data is neutralized and not re-parsed.
This means templates only ever execute in author-controlled static node fields, not in values that arrive from agent input or external data.
Best Practices
Section titled “Best Practices”- Always include inputSchema - Validate agent responses for consistent data
- Keep workflows focused - Split large workflows into subgraphs
- Test validation - Use
managewithincludeValidation: true - Handle errors gracefully - Define error connections for validation failures