Builders API

Builders provide a fluent API for creating agent definitions with immediate validation.

AgentBuilder

Creates an agent definition.

from ainalyn import AgentBuilder
 
agent = (
    AgentBuilder("my-agent")
    .description("What the agent does")
    .version("1.0.0")
    .add_workflow(workflow)
    .build()
)

Constructor

AgentBuilder(name: str)

Parameters:

  • name (required) - Agent identifier. Must match pattern [a-z][a-z0-9-]*

Raises:

  • InvalidFormatError - If name doesn’t match required pattern

Methods

.description(text: str) -> Self

Set agent description.

Parameters:

  • text (required) - Human-readable description of what this agent does

Returns: Self for method chaining

Required: Yes


.version(version: str) -> Self

Set agent version.

Parameters:

  • version (required) - Semantic version string (e.g., “1.0.0”)

Returns: Self for method chaining

Required: Yes

Raises:

  • InvalidFormatError - If version doesn’t follow semantic versioning

.add_workflow(workflow: Workflow) -> Self

Add a workflow to this agent.

Parameters:

  • workflow (required) - Workflow instance created with WorkflowBuilder

Returns: Self for method chaining

Required: At least one workflow required

Raises:

  • DuplicateError - If workflow name already exists in this agent

.workflows(*workflows: Workflow) -> Self

Set all workflows at once.

Parameters:

  • *workflows (required) - Variable number of Workflow instances

Returns: Self for method chaining

Raises:

  • DuplicateError - If any workflow names are duplicated

.add_prompt(prompt: Prompt) -> Self

Add a prompt template to this agent.

Parameters:

  • prompt (required) - Prompt instance created with PromptBuilder

Returns: Self for method chaining

Required: No (optional)

Raises:

  • DuplicateError - If prompt name already exists in this agent

.prompts(*prompts: Prompt) -> Self

Set all prompts at once.

Parameters:

  • *prompts (required) - Variable number of Prompt instances

Returns: Self for method chaining

Raises:

  • DuplicateError - If any prompt names are duplicated

.add_tool(tool: Tool) -> Self

Add a tool definition to this agent.

Parameters:

  • tool (required) - Tool instance created with ToolBuilder

Returns: Self for method chaining

Required: No (optional)

Raises:

  • DuplicateError - If tool name already exists in this agent

.tools(*tools: Tool) -> Self

Set all tools at once.

Parameters:

  • *tools (required) - Variable number of Tool instances

Returns: Self for method chaining

Raises:

  • DuplicateError - If any tool names are duplicated

.add_module(module: Module) -> Self

Add a reusable module to this agent.

Parameters:

  • module (required) - Module instance created with ModuleBuilder

Returns: Self for method chaining

Required: No (optional)

Raises:

  • DuplicateError - If module name already exists in this agent

.modules(*modules: Module) -> Self

Set all modules at once.

Parameters:

  • *modules (required) - Variable number of Module instances

Returns: Self for method chaining

Raises:

  • DuplicateError - If any module names are duplicated

.task_goal(goal: str) -> Self

Set the high-level task goal for Platform Review Gate 1.

Parameters:

  • goal (required) - Human-readable description of what task this agent accomplishes

Returns: Self for method chaining

Required: No (but recommended for Platform submission)

Example:

.task_goal("Convert meeting audio recordings into structured text transcripts with timestamps")

.completion_criteria(criteria: CompletionCriteria) -> Self

Set success/failure conditions for Platform Review Gate 1.

Parameters:

  • criteria (required) - CompletionCriteria instance defining success and failure conditions

Returns: Self for method chaining

Required: No (but recommended for Platform submission)

Example:

from ainalyn.domain.entities import CompletionCriteria
 
.completion_criteria(CompletionCriteria(
    success="Complete transcript with timestamps generated",
    failure="Audio format unsupported or speech unrecognizable"
))

.add_eip_dependency(dependency: EIPDependency) -> Self

Add an EIP dependency for Platform Review Gate 5.

Parameters:

  • dependency (required) - EIPDependency instance

Returns: Self for method chaining

Required: No (but required if agent uses external EIP services)

Example:

from ainalyn.domain.entities import EIPDependency
 
.add_eip_dependency(EIPDependency(
    provider="openai",
    service="whisper",
    version=">=1.0.0",
    config_hints={"streaming": True, "model": "whisper-1"}
))

.build() -> AgentDefinition

Build and return immutable AgentDefinition.

Returns: AgentDefinition instance

Raises:

  • MissingFieldError - If required fields (version, description) not set
  • EmptyCollectionError - If no workflows added
  • ReferenceError - If nodes reference undefined resources

Naming Convention

Agent names must match pattern: [a-z][a-z0-9-]*

Valid names:

  • my-agent
  • data-processor
  • email-extractor-v2

Invalid names:

  • MyAgent (uppercase)
  • my_agent (underscore)
  • 123agent (starts with number)
  • my agent (space)

WorkflowBuilder

Creates a workflow definition.

from ainalyn import WorkflowBuilder, NodeBuilder
 
workflow = (
    WorkflowBuilder("main-flow")
    .description("Main workflow")
    .add_node(
        NodeBuilder("task1")
        .description("Complete task 1")
        .uses_prompt("task-prompt")
        .build()
    )
    .entry_node("task1")
    .build()
)

Constructor

WorkflowBuilder(name: str)

Parameters:

  • name (required) - Workflow identifier. Must match pattern [a-z][a-z0-9-]*

Raises:

  • InvalidFormatError - If name doesn’t match required pattern

Methods

.description(text: str) -> Self

Set workflow description.

Parameters:

  • text (required) - Human-readable description of workflow purpose

Returns: Self for method chaining

Required: Yes


.add_node(node: Node) -> Self

Add a node to this workflow.

Parameters:

  • node (required) - Node instance created with NodeBuilder

Returns: Self for method chaining

Required: At least one node required

Raises:

  • DuplicateError - If node name already exists in this workflow

.nodes(*nodes: Node) -> Self

Set all nodes at once.

Parameters:

  • *nodes (required) - Variable number of Node instances

Returns: Self for method chaining

Raises:

  • DuplicateError - If any node names are duplicated

.entry_node(name: str) -> Self

Set the starting node for this workflow.

Parameters:

  • name (required) - Name of the node that serves as workflow entry point

Returns: Self for method chaining

Required: Yes

Raises:

  • ReferenceError - If named node doesn’t exist in workflow

.build() -> Workflow

Build and return immutable Workflow.

Returns: Workflow instance

Raises:

  • MissingFieldError - If required fields (description, entry_node) not set
  • EmptyCollectionError - If no nodes added

Naming Convention

Workflow names must match pattern: [a-z][a-z0-9-]*

NodeBuilder

Creates a node (individual workflow step).

from ainalyn import NodeBuilder
 
node = (
    NodeBuilder("my-task")
    .description("What this task accomplishes")
    .uses_prompt("my-prompt")
    .inputs("input_data")
    .outputs("result_data")
    .next_nodes("next-task")
    .build()
)

Constructor

NodeBuilder(name: str)

Parameters:

  • name (required) - Node identifier. Must match pattern [a-z][a-z0-9-]*

Raises:

  • InvalidFormatError - If name doesn’t match required pattern

Methods

.description(text: str) -> Self

Set node description.

Parameters:

  • text (required) - Human-readable description of what this node does

Returns: Self for method chaining

Required: Yes


.uses_module(name: str) -> Self

Set this node to use a module.

Parameters:

  • name (required) - Name of module defined in agent

Returns: Self for method chaining

Required: Exactly one of uses_module, uses_prompt, or uses_tool required

Note: Sets node type to “module”. Cannot be used with uses_prompt() or uses_tool().


.uses_prompt(name: str) -> Self

Set this node to use a prompt.

Parameters:

  • name (required) - Name of prompt defined in agent

Returns: Self for method chaining

Required: Exactly one of uses_module, uses_prompt, or uses_tool required

Note: Sets node type to “prompt”. Cannot be used with uses_module() or uses_tool().


.uses_tool(name: str) -> Self

Set this node to use a tool.

Parameters:

  • name (required) - Name of tool defined in agent

Returns: Self for method chaining

Required: Exactly one of uses_module, uses_prompt, or uses_tool required

Note: Sets node type to “tool”. Cannot be used with uses_module() or uses_prompt().


.inputs(*names: str) -> Self

Define input parameter names.

Parameters:

  • *names (optional) - Variable number of input parameter names

Returns: Self for method chaining

Required: No


.outputs(*names: str) -> Self

Define output parameter names.

Parameters:

  • *names (optional) - Variable number of output parameter names

Returns: Self for method chaining

Required: No


.next_nodes(*names: str) -> Self

Specify which nodes follow this one.

Parameters:

  • *names (optional) - Variable number of node names that can follow this node

Returns: Self for method chaining

Required: No

Note: Creates directed edges in the workflow DAG.


.build() -> Node

Build and return immutable Node.

Returns: Node instance

Raises:

  • MissingFieldError - If required fields (description, type) not set
  • InvalidStateError - If no uses_* method was called

Node Types

Node type is determined by resource reference:

  • uses_module() → type: “module”
  • uses_prompt() → type: “prompt”
  • uses_tool() → type: “tool”

Each node must reference exactly one resource type.

Naming Convention

Node names must match pattern: [a-z][a-z0-9-]*

ModuleBuilder

Creates a reusable module definition.

from ainalyn import ModuleBuilder
 
module = (
    ModuleBuilder("http-client")
    .description("HTTP request module")
    .input_schema({"type": "object", "properties": {"url": {"type": "string"}}})
    .output_schema({"type": "object", "properties": {"response": {"type": "string"}}})
    .build()
)

Constructor

ModuleBuilder(name: str)

Parameters:

  • name (required) - Module identifier. Must match pattern [a-z][a-z0-9-]*

Raises:

  • InvalidFormatError - If name doesn’t match required pattern

Methods

.description(text: str) -> Self

Set module description.

Parameters:

  • text (required) - Human-readable description of module functionality

Returns: Self for method chaining

Required: Yes


.input_schema(schema: dict) -> Self

Define input JSON Schema.

Parameters:

  • schema (optional) - JSON Schema dict defining expected input structure

Returns: Self for method chaining

Required: No

Example:

.input_schema({
    "type": "object",
    "properties": {
        "url": {"type": "string"},
        "method": {"type": "string", "enum": ["GET", "POST"]}
    },
    "required": ["url"]
})

.output_schema(schema: dict) -> Self

Define output JSON Schema.

Parameters:

  • schema (optional) - JSON Schema dict defining output structure

Returns: Self for method chaining

Required: No

Example:

.output_schema({
    "type": "object",
    "properties": {
        "status": {"type": "integer"},
        "body": {"type": "string"}
    }
})

.eip_binding(binding: EIPBinding) -> Self

Link this module to a specific EIP provider/service.

Parameters:

  • binding (required) - EIPBinding instance specifying provider and service

Returns: Self for method chaining

Required: No (but recommended for modules that use external services)

Example:

from ainalyn.domain.entities import EIPBinding
 
.eip_binding(EIPBinding(provider="platform", service="audio-segmenter"))

Note: EIP binding tells Platform Core which service implementation to use when executing this module.


.build() -> Module

Build and return immutable Module.

Returns: Module instance

Raises:

  • MissingFieldError - If required field (description) not set

Naming Convention

Module names must match pattern: [a-z][a-z0-9-]*

PromptBuilder

Creates an LLM prompt template.

from ainalyn import PromptBuilder
 
prompt = (
    PromptBuilder("greeting-prompt")
    .description("Generates a greeting message")
    .template("Hello {{name}}! Welcome to {{location}}.")
    .variables("name", "location")
    .build()
)

Constructor

PromptBuilder(name: str)

Parameters:

  • name (required) - Prompt identifier. Must match pattern [a-z][a-z0-9-]*

Raises:

  • InvalidFormatError - If name doesn’t match required pattern

Methods

.description(text: str) -> Self

Set prompt description.

Parameters:

  • text (required) - Human-readable description of prompt purpose

Returns: Self for method chaining

Required: Yes


.template(text: str) -> Self

Set prompt template with variable placeholders.

Parameters:

  • text (required) - Template string with {{variable}} placeholders

Returns: Self for method chaining

Required: Yes

Template Syntax: Use double curly braces {{variable_name}} for placeholders.

Example:

.template("""
Analyze the sentiment of the following text:
 
{{text}}
 
Provide a score from -1 (negative) to 1 (positive).
""")

.variables(*names: str) -> Self

List variable names used in template.

Parameters:

  • *names (optional) - Variable number of variable names matching template placeholders

Returns: Self for method chaining

Required: No (but recommended for documentation)

Example:

.variables("text", "language", "format")

.build() -> Prompt

Build and return immutable Prompt.

Returns: Prompt instance

Raises:

  • MissingFieldError - If required fields (description, template) not set

Template Variables

Variables in templates use Jinja2-style syntax: {{variable_name}}

Valid variable names: [a-zA-Z_][a-zA-Z0-9_]*

Example:

template = "Process {{input_data}} using {{model_name}} model"
variables = ("input_data", "model_name")

Naming Convention

Prompt names must match pattern: [a-z][a-z0-9-]*

ToolBuilder

Creates a tool definition (external service).

from ainalyn import ToolBuilder
 
tool = (
    ToolBuilder("calculator-tool")
    .description("Performs mathematical calculations")
    .input_schema({
        "type": "object",
        "properties": {
            "expression": {"type": "string"}
        },
        "required": ["expression"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "result": {"type": "number"}
        }
    })
    .build()
)

Constructor

ToolBuilder(name: str)

Parameters:

  • name (required) - Tool identifier. Must match pattern [a-z][a-z0-9-]*

Raises:

  • InvalidFormatError - If name doesn’t match required pattern

Methods

.description(text: str) -> Self

Set tool description.

Parameters:

  • text (required) - Human-readable description of tool functionality

Returns: Self for method chaining

Required: Yes


.input_schema(schema: dict) -> Self

Define input JSON Schema.

Parameters:

  • schema (optional) - JSON Schema dict defining expected input structure

Returns: Self for method chaining

Required: No

Example:

.input_schema({
    "type": "object",
    "properties": {
        "query": {"type": "string"},
        "max_results": {"type": "integer", "minimum": 1, "maximum": 100}
    },
    "required": ["query"]
})

.output_schema(schema: dict) -> Self

Define output JSON Schema.

Parameters:

  • schema (optional) - JSON Schema dict defining output structure

Returns: Self for method chaining

Required: No

Example:

.output_schema({
    "type": "object",
    "properties": {
        "results": {
            "type": "array",
            "items": {"type": "string"}
        },
        "count": {"type": "integer"}
    }
})

.eip_binding(binding: EIPBinding) -> Self

Link this tool to a specific EIP provider/service.

Parameters:

  • binding (required) - EIPBinding instance specifying provider and service

Returns: Self for method chaining

Required: No (but recommended for tools that use external services)

Example:

from ainalyn.domain.entities import EIPBinding
 
.eip_binding(EIPBinding(provider="openai", service="whisper"))

Note: EIP binding tells Platform Core which external service to invoke when executing this tool.


.build() -> Tool

Build and return immutable Tool.

Returns: Tool instance

Raises:

  • MissingFieldError - If required field (description) not set

Naming Convention

Tool names must match pattern: [a-z][a-z0-9-]*

Common Patterns

Always call .build()

# Correct
node = NodeBuilder("task").description("Do something").uses_prompt("task-prompt").build()
 
# Wrong - missing .build()
node = NodeBuilder("task").description("Do something").uses_prompt("task-prompt")

Chain methods

agent = (
    AgentBuilder("my-agent")
    .version("1.0.0")
    .description("My agent")
    .add_workflow(workflow)
    .build()
)

Sequential workflow with next_nodes

prompt1 = PromptBuilder("prompt1").description("First").template("Step 1").build()
prompt2 = PromptBuilder("prompt2").description("Second").template("Step 2").build()
 
workflow = (
    WorkflowBuilder("process")
    .description("Sequential processing")
    .add_node(
        NodeBuilder("step1")
        .description("First step")
        .uses_prompt("prompt1")
        .next_nodes("step2")  # Points to next step
        .build()
    )
    .add_node(
        NodeBuilder("step2")
        .description("Second step")
        .uses_prompt("prompt2")
        .build()
    )
    .entry_node("step1")  # Start at step1
    .build()
)

Branching workflow

# Node that splits into multiple paths
workflow = (
    WorkflowBuilder("branching")
    .description("Branching workflow")
    .add_node(
        NodeBuilder("analyze")
        .description("Analyze input")
        .uses_module("analyzer")
        .next_nodes("path-a", "path-b")  # Multiple next nodes
        .build()
    )
    .add_node(NodeBuilder("path-a").description("Path A").uses_prompt("prompt-a").build())
    .add_node(NodeBuilder("path-b").description("Path B").uses_prompt("prompt-b").build())
    .entry_node("analyze")
    .build()
)