DocumentationAdvancedCompilation Flow

Compilation Flow

This page explains how data flows through the SDK when compiling an Agent Definition.


Overview

The compilation process follows a clear pipeline:

Builder API -> AgentDefinition -> validate() -> export_yaml()
                 |                 |              |
               Domain      Schema + Gates + Static   YAML

Step-by-Step Breakdown

Step 1: Build

Developers use fluent builders to construct their agent:

from ainalyn import AgentBuilder, WorkflowBuilder, NodeBuilder
 
agent = (
    AgentBuilder("my-agent")
    .version("1.0.0")
    .description("My first agent")
    .add_workflow(
        WorkflowBuilder("main")
        .add_node(NodeBuilder("start").type("llm").build())
        .build()
    )
    .build()  # ← Returns AgentDefinition
)

What happens:

  • AgentBuilder is an Inbound Adapter
  • Collects configuration via fluent methods
  • .build() creates an immutable AgentDefinition

Step 2: Create Domain Entity

The builder creates an AgentDefinition domain entity:

@dataclass(frozen=True)
class AgentDefinition:
    name: str
    version: str
    description: str
    workflows: tuple[Workflow, ...]
 
    def __post_init__(self) -> None:
        # Domain validation runs immediately
        if not DefinitionRules.is_valid_name(self.name):
            raise InvalidFormatError(...)

What happens:

  • Entity is created as frozen (immutable)
  • __post_init__ runs domain validation
  • Invalid entities cannot exist

Step 3: Compile via API

Developer calls the high-level API:

from ainalyn import compile_agent
from pathlib import Path
 
result = compile_agent(agent, Path("agent.yaml"))

What happens:

  • compile_agent() is an Inbound Adapter (public API)
  • Gets DefinitionService from infrastructure
  • Delegates to service for orchestration

Internal flow:

# api.py
def compile_agent(definition, output_path=None):
    service = _get_service()  # From infrastructure
    if output_path:
        return service.compile_to_file(definition, output_path)
    return service.compile(definition)

Step 4a: Schema Validation

SchemaValidator checks structural correctness:

class SchemaValidator:
    """Outbound Adapter implementing IDefinitionSchemaValidator"""
 
    def validate_schema(self, definition: AgentDefinition) -> tuple[ValidationError, ...]:
        errors = []
 
        # Required fields
        if not definition.workflows:
            errors.append(ValidationError("E001", "At least one workflow required"))
 
        # Type validation
        for workflow in definition.workflows:
            if not workflow.nodes:
                errors.append(ValidationError("E002", f"Workflow '{workflow.name}' has no nodes"))
 
        return tuple(errors)

Checks performed:

  • Required fields present
  • Type correctness
  • Value constraints
  • Structural integrity

Step 4b: Review Gates

ReviewGateRules enforces platform-aligned contract checks:

  • Contract completeness
  • No shadow runtime patterns
  • Result sovereignty
  • Billing hint only
  • EIP dependency declarations

Step 4c: Static Analysis

StaticAnalyzer checks logical correctness:

from ainalyn.domain.rules import DefinitionRules
 
class StaticAnalyzer:
    def analyze(self, definition: AgentDefinition) -> tuple[ValidationError, ...]:
        issues = []
        for workflow in definition.workflows:
            cycles = DefinitionRules.detect_circular_dependencies(workflow)
            if cycles:
                issues.append(ValidationError(code="CIRCULAR_DEPENDENCY", path=f"workflow:{workflow.name}", message="Cycle detected"))
 
            unreachable = DefinitionRules.get_unreachable_nodes(workflow)
            for node_name in unreachable:
                issues.append(ValidationError(code="UNREACHABLE_NODE", path=f"workflow:{workflow.name}", message=f"Unreachable node: {node_name}"))
 
        return tuple(issues)

Checks performed:

  • Workflow cycles
  • Unreachable nodes
  • Unused resources

Step 4d: Serialization

YamlExporter converts domain to YAML:

class YamlExporter:
    """Outbound Adapter implementing IDefinitionSerializer"""
 
    def serialize(self, definition: AgentDefinition) -> str:
        data = {
            "name": definition.name,
            "version": definition.version,
            "description": definition.description,
            "workflows": [
                self._serialize_workflow(w) for w in definition.workflows
            ],
        }
        return yaml.dump(data, sort_keys=False)

What happens:

  • Domain entities → Python dicts
  • Dicts → YAML string
  • Platform-compatible format

Step 5: Output

CompilationResult contains the outcome:

@dataclass
class CompilationResult:
    validation_result: ValidationResult
    yaml_content: str | None  # None if validation failed
    output_path: Path | None  # Set if written to file
 
    @property
    def is_successful(self) -> bool:
        return self.validation_result.is_valid

Usage:

result = compile_agent(agent)
 
if result.is_successful:
    print(result.yaml_content)
    # Submit to platform
else:
    for error in result.validation_result.errors:
        print(f"{error.code}: {error.message}")

Validation Layers

The SDK has multiple validation layers, each with a specific responsibility:

LayerLocationWhenPurpose
Domaindomain/entities/Entity creationInvariants that must always hold
Schemaadapters/outbound/schema_validator.pyCompilationStructural correctness
Review Gatesdomain/rules/review_gate_rules.pyCompilationContract gate enforcement
Static Analysisadapters/outbound/static_analyzer.pyCompilationLogical correctness

Domain Validation Example

# Cannot create invalid entity
AgentDefinition(name="invalid name!")  # Raises InvalidFormatError

Schema Validation Example

# Valid entity, but missing required fields for platform
agent = AgentBuilder("test").build()  # Missing version
result = compile_agent(agent)
# result.validation_result.errors contains "version required"

Review Gates Example

# Example: missing task_goal or output_schema triggers gate violations
result = validate(agent)
for error in result.errors:
    print(error.code, error.message)

Static Analysis Example

# Valid structure, but logical error
workflow = (
    WorkflowBuilder("main")
    .add_node(NodeBuilder("a").next_nodes("b").build())
    .add_node(NodeBuilder("b").next_nodes("a").build())  # Creates cycle!
    .build()
)
result = compile_agent(agent)
# result.validation_result.errors contains "cycle detected"

Error Handling

Error Categories

CategoryCode RangeExample
Domain ErrorsExceptionsInvalidFormatError, CyclicDependencyError
Schema ErrorsE001-E099Missing required field
Analysis ErrorsE100-E199Invalid reference
Analysis WarningsW001-W099Unused definition

Error Response

result = compile_agent(agent)
 
if not result.is_successful:
    for error in result.validation_result.errors:
        print(f"[{error.code}] {error.message}")
        print(f"  Path: {error.path}")
        print(f"  Suggestion: {error.suggestion}")