Agenix Extensions and SDK
This document covers the Extensions system and Programmatic SDK.
Table of Contents
Programmatic SDK
Agenix can be used as a library in your Python applications.
Basic Usage
import asyncio
from agenix import create_session
async def main():
# Create a session
session = await create_session(
api_key="your-openai-api-key",
model="gpt-4o",
working_dir="/path/to/project"
)
# Send a prompt
response = await session.prompt("What files are in the current directory?")
print(response)
# Continue conversation
response = await session.prompt("Can you read the README?")
print(response)
# Get conversation history
messages = session.get_messages()
print(f"Conversation has {len(messages)} messages")
# Clear history
session.clear_messages()
# Close session
await session.close()
if __name__ == "__main__":
asyncio.run(main())
API Reference
create_session(**kwargs) → AgentSession
Create a new agent session.
Parameters:
api_key(str, optional): API key for LLM provider (or setOPENAI_API_KEYenv var)base_url(str, optional): Custom API base URLmodel(str): Model to use (default: “gpt-4o”)system_prompt(str, optional): Custom system promptworking_dir(str): Working directory for file operations (default: “.”)max_turns(int): Maximum conversation turns per prompt (default: 10)enable_extensions(bool): Whether to load extensions (default: True)
Returns: AgentSession instance
AgentSession.prompt(message: str) → str
Send a message to the agent and get the response.
Parameters:
message(str): User message/prompt
Returns: Agent’s text response as string
AgentSession.get_messages() → List[Message]
Get conversation history.
Returns: List of messages in the conversation
AgentSession.clear_messages() → None
Clear conversation history.
AgentSession.close() → None
Close the session and cleanup resources.
Extensions System
Extensions are Python modules that extend agenix with custom tools, commands, and event handlers.
Extension Locations
Extensions are discovered from these locations (in order):
Global:
~/.agenix/extensions/Project:
.agenix/extensions/
Creating an Extension
Create a Python file with a setup(agenix) function:
# ~/.agenix/extensions/my_extension.py
async def setup(agenix):
"""Extension setup function.
Args:
agenix: ExtensionAPI instance
"""
# Register tools, commands, and event handlers here
pass
Extension API
Registering Custom Tools
from agenix.extensions import ToolDefinition
async def setup(agenix):
async def my_tool_execute(params, ctx):
"""Tool execution function.
Args:
params: Dictionary of parameters from LLM
ctx: ExtensionContext instance
Returns:
String result to send back to LLM
"""
input_text = params.get("input", "")
# Do something with input
return f"Processed: {input_text}"
agenix.register_tool(ToolDefinition(
name="my_tool",
description="My custom tool for doing X",
parameters={
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "Input text to process"
}
},
"required": ["input"]
},
execute=my_tool_execute
))
Registering Commands
from agenix.extensions import CommandDefinition
async def setup(agenix):
async def stats_handler(ctx, args):
"""Command handler function.
Args:
ctx: ExtensionContext instance
args: Command arguments as string
"""
# Access agent state
message_count = len(ctx.messages)
ctx.notify(f"Total messages: {message_count}", "info")
agenix.register_command(CommandDefinition(
name="stats",
description="Show conversation statistics",
handler=stats_handler
))
Event Handlers
from agenix.extensions import EventType
async def setup(agenix):
@agenix.on(EventType.AGENT_START)
async def on_agent_start(event, ctx):
"""Called when agent loop starts.
Args:
event: AgentStartEvent instance
ctx: ExtensionContext instance
"""
print(f"Agent starting with prompt: {event.prompt}")
@agenix.on(EventType.TOOL_CALL)
async def on_tool_call(event, ctx):
"""Called before each tool execution.
Args:
event: ToolCallEvent instance
ctx: ExtensionContext instance
"""
print(f"Tool {event.tool_name} called with args: {event.args}")
@agenix.on(EventType.TOOL_RESULT)
async def on_tool_result(event, ctx):
"""Called after each tool execution.
Args:
event: ToolResultEvent instance
ctx: ExtensionContext instance
"""
print(f"Tool {event.tool_name} returned: {event.result}")
Available Events
EventType.SESSION_START- Session startedEventType.SESSION_END- Session endedEventType.AGENT_START- Agent loop startedEventType.AGENT_END- Agent loop endedEventType.TURN_START- Turn startedEventType.TURN_END- Turn endedEventType.TOOL_CALL- Before tool executionEventType.TOOL_RESULT- After tool executionEventType.USER_INPUT- User input received
Extension Context
The ExtensionContext object provides access to agent state:
async def my_handler(event, ctx):
# Access current messages
messages = ctx.messages
# Access agent instance
agent = ctx.agent
# Access working directory
cwd = ctx.cwd
# Access available tools
tools = ctx.tools
# Show notification
ctx.notify("Something happened!", "info")
Examples
Example 1: Custom Deployment Tool
# ~/.agenix/extensions/deploy.py
import subprocess
from agenix.extensions import ToolDefinition
async def setup(agenix):
async def deploy_execute(params, ctx):
environment = params.get("environment", "staging")
# Run deployment
result = subprocess.run(
["./deploy.sh", environment],
cwd=ctx.cwd,
capture_output=True,
text=True
)
if result.returncode == 0:
return f"Deployment to {environment} successful!"
else:
return f"Deployment failed: {result.stderr}"
agenix.register_tool(ToolDefinition(
name="deploy",
description="Deploy application to specified environment",
parameters={
"type": "object",
"properties": {
"environment": {
"type": "string",
"enum": ["staging", "production"],
"description": "Target environment"
}
},
"required": ["environment"]
},
execute=deploy_execute
))
Example 2: Code Statistics Command
# ~/.agenix/extensions/code_stats.py
import os
from pathlib import Path
from agenix.extensions import CommandDefinition, EventType
async def setup(agenix):
# Track tool usage
tool_usage = {}
@agenix.on(EventType.TOOL_CALL)
async def track_tool_usage(event, ctx):
tool_name = event.tool_name
tool_usage[tool_name] = tool_usage.get(tool_name, 0) + 1
async def stats_handler(ctx, args):
# Count files
file_count = sum(1 for _ in Path(ctx.cwd).rglob("*.py"))
# Show statistics
ctx.notify(f"Python files: {file_count}", "info")
ctx.notify(f"Messages: {len(ctx.messages)}", "info")
if tool_usage:
ctx.notify("Tool usage:", "info")
for tool, count in sorted(tool_usage.items()):
ctx.notify(f" {tool}: {count} calls", "info")
agenix.register_command(CommandDefinition(
name="stats",
description="Show project and session statistics",
handler=stats_handler
))
Example 3: Git Auto-commit
# .agenix/extensions/git_autocommit.py
import subprocess
from agenix.extensions import EventType
async def setup(agenix):
@agenix.on(EventType.TOOL_RESULT)
async def auto_commit(event, ctx):
# Auto-commit after file writes
if event.tool_name == "write" and not event.is_error:
# Check if in git repo
result = subprocess.run(
["git", "rev-parse", "--git-dir"],
cwd=ctx.cwd,
capture_output=True
)
if result.returncode == 0:
# Stage and commit
subprocess.run(["git", "add", "-A"], cwd=ctx.cwd)
subprocess.run(
["git", "commit", "-m", "Auto-commit by agenix"],
cwd=ctx.cwd,
capture_output=True
)
ctx.notify("Changes auto-committed to git", "info")
Example 4: SDK with Custom Extension
# my_app.py
import asyncio
from agenix import create_session
from agenix.extensions import ToolDefinition
# Define a custom tool inline
async def custom_tool_execute(params, ctx):
return f"Custom processing: {params['input']}"
async def main():
# Create session with extensions
session = await create_session(
api_key="your-key",
model="gpt-4o"
)
# The session automatically loads extensions from:
# - ~/.agenix/extensions/
# - .agenix/extensions/
# Use the session
response = await session.prompt(
"Use the custom tool to process 'hello world'"
)
print(response)
if __name__ == "__main__":
asyncio.run(main())
Best Practices
Error Handling: Always handle errors in tool execution and event handlers
Async: Use
async deffor all handlers and tool execute functionsDocumentation: Add docstrings to your tools and commands
Namespacing: Use descriptive, unique names for tools to avoid conflicts
Testing: Test your extensions before deploying
Troubleshooting
Extension Not Loading
Check the file is in the correct location (
~/.agenix/extensions/or.agenix/extensions/)Ensure the file has a
setup(agenix)functionCheck for syntax errors in the extension code
Look for error messages in the console output
Tool Not Being Called
Verify the tool name and description are clear
Check the parameters schema is correct
Ensure the tool is actually registered (check for errors during setup)
Try explicitly asking the LLM to use your tool by name
For more examples, see the examples/ directory in the agenix repository.