Plugin Development Overview¶
Cadence's plugin system is the heart of its extensibility. This guide explains how plugins work, their architecture, and how to create your own.
What is a Plugin?¶
A plugin in Cadence is a self-contained module that provides:
- AI Agents: Specialized AI assistants with specific capabilities
- Tools: Functions that agents can use to perform tasks
- Metadata: Information about the plugin's purpose and requirements
- Configuration: Settings and parameters for customization
Plugin Architecture¶
graph TB
A[Plugin Package] --> B[Plugin Class]
B --> C[Agent Class]
B --> D[Tool Functions]
B --> E[Metadata]
C --> F[System Prompt]
C --> G[Tool Integration]
C --> H[LLM Binding]
D --> I[Function Logic]
D --> J[Input Validation]
D --> K[Error Handling]
Plugin Structure¶
Every Cadence plugin follows this structure:
my_plugin/
├── __init__.py # Plugin registration
├── plugin.py # Main plugin class
├── agent.py # Agent implementation
├── tools.py # Tool functions
├── pyproject.toml # Package configuration
└── README.md # Documentation
Core Components¶
1. Plugin Class¶
The main entry point that defines:
- Plugin metadata (name, version, description)
- Agent creation factory method
- Dependency validation
- Configuration schema
2. Agent Class¶
Implements the AI agent behavior:
- System prompt for LLM interaction
- Tool integration and management
- State management and decision making
- LLM model binding with parallel tool calls support
- Must inherit from
BaseAgent
and implement required methods
Parallel Tool Calls Support¶
Cadence agents support parallel tool execution, allowing multiple tools to be called simultaneously for improved performance and efficiency:
class MyAgent(BaseAgent):
def __init__(self, metadata: PluginMetadata):
# Enable parallel tool calls (default: True)
super().__init__(metadata, parallel_tool_calls=True)
# Or disable for sequential execution
# super().__init__(metadata, parallel_tool_calls=False)
Benefits of Parallel Tool Calls:
- Improved Performance: Multiple tools execute concurrently instead of sequentially
- Better User Experience: Faster response times for multi-step operations
- Resource Optimization: Efficient use of computational resources
- Scalability: Better handling of complex, multi-tool workflows
When to Use Parallel Tool Calls:
- ✅ Enable when tools are independent and can run concurrently
- ✅ Enable for performance-critical operations
- ✅ Disable when tools have dependencies or shared resources
- ✅ Disable for debugging and troubleshooting
3. Tools¶
Functions that agents can call:
- Input validation and processing
- External API integration
- Data transformation
- Error handling and logging
- Must be decorated with
@tool
decorator fromcadence_sdk
Plugin Lifecycle¶
sequenceDiagram
participant U as User
participant E as Cadence Core
participant P as Plugin Manager
participant A as Agent
participant T as Tools
participant L as LLM
U->>E: Request
E->>P: Route to Plugin
P->>A: Create Agent
A->>T: Get Tools
A->>L: Process Request
L->>A: Response
A->>E: Result
E->>U: Final Response
Plugin Requirements¶
Correct Import Patterns¶
# Main imports - recommended approach
from cadence_sdk import BasePlugin, PluginMetadata, BaseAgent, tool
from cadence_sdk.decorators import object_schema, list_schema
# Alternative specific imports if needed
from cadence_sdk.base.plugin import BasePlugin
from cadence_sdk.base.metadata import PluginMetadata
from cadence_sdk.base.agent import BaseAgent
from cadence_sdk.decorators.tool import tool
Important: Always use the main cadence_sdk
import for the core classes and tool
decorator. The specific submodule imports are available but not recommended for most use cases.
Required Methods¶
Every plugin must implement:
get_metadata()
- Return plugin informationcreate_agent()
- Create agent instance
Required Agent Methods¶
Every agent must implement:
get_tools()
- Return available toolsget_system_prompt()
- Define agent behaviorbind_model()
- Connect to LLMinitialize()
- Setup resourcescreate_agent_node()
- LangGraph integrationshould_continue()
- Workflow control
Plugin Types¶
1. Specialized Agents¶
- Focus on specific domains (math, search, analysis)
- Limited but powerful tool sets
- Optimized for particular tasks
2. General Agents¶
- Broad capabilities across multiple domains
- Extensive tool collections
- Flexible but potentially less focused
3. Utility Agents¶
- Support and coordination functions
- System management and monitoring
- Workflow orchestration
Plugin Discovery¶
Cadence automatically discovers plugins through multiple sources:
- Pip-installed Packages: Discovers plugins from installed packages that depend on
cadence_sdk
- Directory Scanning: Looks in configured plugin directories (via
CADENCE_PLUGINS_DIR
) - Uploaded Plugins: Manages plugins uploaded via UI/API to the store directory
- Auto-registration: Registers discovered plugins through the SDK registry
- Validation: Comprehensive structure, dependency, and health validation
- Hot Reloading: Dynamic plugin reload without system restart
Plugin Metadata¶
Essential information for each plugin:
PluginMetadata(
name="my_agent",
version="1.0.0",
description="Description of what this agent does",
capabilities=["capability1", "capability2"],
llm_requirements={
"provider": "openai",
"model": "gpt-4.1",
"temperature": 0.1,
"max_tokens": 1024
},
agent_type="specialized",
response_schema=MyResponseSchema, # Optional
response_suggestion="When presenting results, use clear formatting...", # Optional
dependencies=["cadence_sdk>=1.3.0,<2.0.0"],
)
Complete Plugin Example¶
Here's a complete example of a math plugin implementation:
__init__.py
¶
plugin.py
¶
from cadence_sdk import BasePlugin, PluginMetadata
from cadence_sdk.decorators import object_schema
from typing import TypedDict, Annotated
@object_schema
class MathResponseSchema(TypedDict):
"""Schema for math operation results."""
operation: Annotated[str, "The mathematical operation performed"]
result: Annotated[float, "The result of the calculation"]
class MathPlugin(BasePlugin):
@staticmethod
def get_metadata() -> PluginMetadata:
return PluginMetadata(
name="mathematics",
version="1.3.0",
description="Mathematical calculations and arithmetic operations agent",
agent_type="specialized",
capabilities=["addition", "subtraction", "multiplication", "division"],
response_schema=MathResponseSchema,
response_suggestion="When presenting mathematical results, always show the step-by-step calculation process.",
llm_requirements={
"provider": "openai",
"model": "gpt-4.1",
"temperature": 0.2,
"max_tokens": 1024,
},
dependencies=["cadence_sdk>=1.3.0,<2.0.0"],
)
@staticmethod
def create_agent():
from .agent import MathAgent
return MathAgent(MathPlugin.get_metadata())
agent.py
¶
from cadence_sdk import BaseAgent
from cadence_sdk.base.metadata import PluginMetadata
class MathAgent(BaseAgent):
def __init__(self, metadata: PluginMetadata):
# Enable parallel tool calls for better performance
super().__init__(metadata, parallel_tool_calls=True)
def get_tools(self):
from .tools import math_tools
return math_tools
def get_system_prompt(self) -> str:
return "You are a math agent specialized in mathematical operations. Always use the provided tools for calculations."
tools.py
¶
from cadence_sdk import tool
@tool
def add(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers together."""
return a * b
math_tools = [add, multiply]
Development Workflow¶
1. Design Phase¶
- Define agent purpose and capabilities
- Plan required tools and integrations
- Design system prompt and behavior
2. Implementation Phase¶
- Create plugin structure
- Implement agent logic
- Develop tool functions with
@tool
decorator - Add error handling
3. Testing Phase¶
- Unit test individual components
- Integration test with Cadence core
- Validate plugin behavior
- Performance testing
4. Deployment Phase¶
- Package plugin for distribution
- Deploy to plugin directory
- Monitor plugin health
- Gather user feedback
Security Considerations¶
- Input Validation: Always validate user inputs
- API Key Management: Secure external service credentials
- Rate Limiting: Prevent abuse of external APIs
- Error Handling: Don't expose sensitive information
- Dependency Scanning: Regular security updates
Best Practices¶
Code Quality¶
- Follow Python best practices (PEP 8)
- Comprehensive error handling
- Clear documentation and comments
- Type hints for better IDE support
Performance¶
- Efficient tool implementations
- Proper resource management
- Caching where appropriate
- Async operations for I/O-bound tasks
Maintainability¶
- Modular design
- Clear separation of concerns
- Comprehensive testing
- Version management
Plugin Management¶
Upload and Management¶
- UI-based Upload: Drag-and-drop plugin ZIP files through the Streamlit interface
- API-based Upload: Programmatic plugin upload via REST API endpoints
- Plugin Store: Centralized storage and versioning of uploaded plugins
- Health Monitoring: Real-time plugin health checks and status monitoring
- Dependency Management: Automatic installation of plugin dependencies
Plugin Lifecycle¶
- Discovery: Automatic detection from multiple sources
- Validation: Structure, dependency, and compatibility checks
- Loading: Dynamic plugin instantiation and model binding
- Health Checks: Continuous monitoring and failure isolation
- Hot Reload: Runtime plugin updates without system restart
Next Steps¶
Ready to build your first plugin? Continue with:
- Creating Your First Plugin - Step-by-step tutorial
- Plugin Upload Feature - Upload, manage, and reload plugins via UI/API
- Explore the code of existing plugins for deeper patterns
Examples¶
Examples in this repository:
- Math plugin:
plugins/src/cadence_example_plugins/math_agent/
- Search plugin:
plugins/src/cadence_example_plugins/search_agent/
Getting Help¶
- Review plugin validation in
sdk/src/cadence_sdk/utils/validation.py
- Explore SDK base classes in
sdk/src/cadence_sdk/base/
- Join our community discussions