Modules
How to define reusable capability units for your agents.
What is a Module?
A module is a self-contained functional component that can perform specific tasks. It defines:
- What it does (description)
- What input it expects (input schema)
- What output it produces (output schema)
Important: The SDK only defines the module’s contract. The actual implementation is provided by the platform.
Creating a Module
from ainalyn import ModuleBuilder
module = (
ModuleBuilder("http-client")
.description("Fetches data from HTTP endpoints")
.input_schema({
"type": "object",
"properties": {
"url": {"type": "string", "format": "uri"},
"method": {"type": "string", "enum": ["GET", "POST"]}
},
"required": ["url"]
})
.output_schema({
"type": "object",
"properties": {
"status": {"type": "integer"},
"body": {"type": "string"}
}
})
.build()
)EIP Binding
Modules can be linked to EIP (Execution Implementation Provider) services using .eip_binding():
from ainalyn import ModuleBuilder
from ainalyn.domain.entities import EIPBinding
# Module with platform-provided implementation
audio_segmenter = (
ModuleBuilder("audio-segmenter")
.description("Splits long audio files into segments")
.eip_binding(EIPBinding(provider="platform", service="audio-segmenter"))
.input_schema({
"type": "object",
"properties": {
"audio_url": {"type": "string", "format": "uri"},
"max_segment_size_mb": {"type": "number", "default": 24}
},
"required": ["audio_url"]
})
.output_schema({
"type": "object",
"properties": {
"segments": {"type": "array"},
"segment_count": {"type": "integer"}
}
})
.build()
)When to use EIP binding:
- When the module requires a specific platform service implementation
- When Platform Core needs to know which service to invoke
- For modules that interface with external systems
Common EIP providers:
platform- Platform-provided servicesopenai- OpenAI servicesanthropic- Anthropic services
Using Modules in Workflows
Step 1: Define the module
http_module = (
ModuleBuilder("http-client")
.description("Fetches data from HTTP endpoints")
.input_schema({...})
.output_schema({...})
.build()
)Step 2: Add module to agent
agent = (
AgentBuilder("data-agent")
.version("1.0.0")
.add_module(http_module) # Register module
.add_workflow(workflow)
.build()
)Step 3: Reference in node
from ainalyn import NodeBuilder
node = (
NodeBuilder("fetch-data")
.description("Fetch user data")
.uses_module("http-client") # References the module
.inputs("url")
.outputs("response")
.build()
)JSON Schema
Modules use JSON Schema to define input/output contracts.
Basic types:
# String
{"type": "string"}
# Number
{"type": "number"}
# Integer
{"type": "integer"}
# Boolean
{"type": "boolean"}
# Array
{"type": "array", "items": {"type": "string"}}
# Object
{
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
}
}Required fields:
input_schema = {
"type": "object",
"properties": {
"url": {"type": "string"},
"timeout": {"type": "integer"}
},
"required": ["url"] # url is required, timeout is optional
}Default values:
input_schema = {
"type": "object",
"properties": {
"method": {
"type": "string",
"default": "GET" # Default if not provided
}
}
}Enums:
input_schema = {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["active", "inactive", "pending"]
}
}
}Common Module Patterns
HTTP Client
http_module = (
ModuleBuilder("http-client")
.description("Makes HTTP requests")
.input_schema({
"type": "object",
"properties": {
"url": {"type": "string", "format": "uri"},
"method": {"type": "string", "enum": ["GET", "POST", "PUT", "DELETE"]},
"headers": {"type": "object"},
"body": {"type": "string"}
},
"required": ["url", "method"]
})
.output_schema({
"type": "object",
"properties": {
"status": {"type": "integer"},
"headers": {"type": "object"},
"body": {"type": "string"}
}
})
.build()
)Data Processor
processor = (
ModuleBuilder("data-processor")
.description("Processes and transforms data")
.input_schema({
"type": "object",
"properties": {
"data": {"type": "array", "items": {"type": "object"}},
"operation": {"type": "string", "enum": ["filter", "map", "reduce"]}
},
"required": ["data", "operation"]
})
.output_schema({
"type": "object",
"properties": {
"result": {"type": "array"},
"count": {"type": "integer"}
}
})
.build()
)File Operations
file_module = (
ModuleBuilder("file-handler")
.description("Reads and writes files")
.input_schema({
"type": "object",
"properties": {
"path": {"type": "string"},
"operation": {"type": "string", "enum": ["read", "write"]},
"content": {"type": "string"}
},
"required": ["path", "operation"]
})
.output_schema({
"type": "object",
"properties": {
"success": {"type": "boolean"},
"content": {"type": "string"},
"size": {"type": "integer"}
}
})
.build()
)Module Naming
Valid names:
"http-client" # Lowercase with hyphens
"data-processor" # Descriptive
"file-handler-v2" # With version suffixInvalid names:
"HttpClient" # Must be lowercase
"data_processor" # No underscores
"my module" # No spacesBest Practices
1. Keep schemas simple
# Simple, focused schema
input_schema = {
"type": "object",
"properties": {
"url": {"type": "string"}
},
"required": ["url"]
}
# Avoid overly complex nested schemas2. Use descriptive property names
# Clear property names
{
"properties": {
"user_id": {"type": "string"},
"email_address": {"type": "string"}
}
}
# Avoid unclear names like "id" or "data"3. Document expected formats
# Specify format
{
"properties": {
"email": {"type": "string", "format": "email"},
"url": {"type": "string", "format": "uri"},
"date": {"type": "string", "format": "date"}
}
}4. Define required fields
# Explicit required fields
{
"properties": {
"id": {"type": "string"},
"name": {"type": "string"},
"age": {"type": "integer"}
},
"required": ["id", "name"] # age is optional
}Module vs Prompt vs Tool
Use Module when:
- You need custom business logic
- Platform provides the implementation
- Input/output are structured data
Use Prompt when:
- You need LLM-based reasoning
- Input/output are text-based
- See Prompts Guide
Use Tool when:
- You need external services (APIs, databases)
- Platform provides the integration
- See Tools Guide
Complete Example
from ainalyn import AgentBuilder, WorkflowBuilder, NodeBuilder, ModuleBuilder, NodeType
# Define module
email_module = (
ModuleBuilder("email-sender")
.description("Sends emails via SMTP")
.input_schema({
"type": "object",
"properties": {
"to": {"type": "string", "format": "email"},
"subject": {"type": "string"},
"body": {"type": "string"}
},
"required": ["to", "subject", "body"]
})
.output_schema({
"type": "object",
"properties": {
"sent": {"type": "boolean"},
"message_id": {"type": "string"}
}
})
.build()
)
# Use in workflow
workflow = (
WorkflowBuilder("send-notification")
.entry_node("send")
.add_node(
NodeBuilder("send")
.description("Send email notification")
.uses_module("email-sender") # Reference module
.inputs("to", "subject", "body")
.outputs("sent", "message_id")
.build()
)
.build()
)
# Create agent
agent = (
AgentBuilder("notification-agent")
.version("1.0.0")
.description("Sends email notifications")
.add_module(email_module) # Register module
.add_workflow(workflow)
.build()
)See Also
- ModuleBuilder API - Full API reference
- Prompts Guide - Using prompt templates
- Tools Guide - External tool integration
- Workflows - Using modules in workflows