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 setEmptyCollectionError- If no workflows addedReferenceError- If nodes reference undefined resources
Naming Convention
Agent names must match pattern: [a-z][a-z0-9-]*
Valid names:
my-agentdata-processoremail-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 setEmptyCollectionError- 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 setInvalidStateError- 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()
)