# Cadence SDK ๐ค
**Plugin Development Framework for Cadence AI Multi-Agent System**
[](https://badge.fury.io/py/cadence-sdk)
[](https://www.python.org/downloads/release/python-3130/)
[](https://opensource.org/licenses/MIT)
The Cadence SDK provides a comprehensive framework for building custom AI agent plugins that integrate seamlessly with
the Cadence multi-agent conversational AI system. Built on LangChain and LangGraph, it offers powerful abstractions for
creating intelligent, tool-enabled agents with automatic routing and orchestration.
## ๐ Features
- **๐ Plugin Architecture**: Simple, extensible plugin system with automatic discovery
- **๐ค Agent Framework**: Complete agent lifecycle management with LangGraph integration
- **๐ ๏ธ Tool System**: Easy tool creation with the `@tool` decorator
- **๐ State Management**: Comprehensive state handling with type safety
- **๐ Automatic Routing**: Intelligent agent-to-agent communication and routing
- **โก Parallel Execution**: Support for parallel tool calls for improved performance
- **๐ Validation**: Built-in validation for plugins, agents, and tools
- **๐ Type Safety**: Full type hints and TypedDict support for robust development
- **๐ฅ Health Checks**: Built-in health monitoring and dependency validation
- **๐ฆ Registry System**: Centralized plugin discovery and management
## ๐ฆ Installation
### From PyPI (Recommended)
```bash
pip install cadence-sdk
```
### From Source
```bash
git clone https://github.com/jonaskahn/cadence-sdk.git
pip install -e .
```
### Development Installation
```bash
git clone https://github.com/jonaskahn/cadence-sdk.git
pip install -e ".[dev]"
```
## ๐ฏ Quick Start
### Basic Plugin Structure
```python
from cadence_sdk import BaseAgent, BasePlugin, PluginMetadata, tool
from typing_extensions import Annotated, TypedDict
class SearchResponseSchema(TypedDict):
"""Schema for structured search responses"""
title: Annotated[str, "Primary identifier or headline"]
description: Annotated[str, "Contextual summary or metadata"]
link: Annotated[str, "Canonical URI to the source"]
thumbnail_link: Annotated[str, "Optional visual representation URI"]
class SearchPlugin(BasePlugin):
@staticmethod
def get_metadata() -> PluginMetadata:
return PluginMetadata(
name="browse_internet",
version="1.3.3",
description="Internet Browser Search agent, using DuckDuckGo API",
agent_type="specialized",
response_schema=SearchResponseSchema,
response_suggestion="When presenting search results, always include source citations with clickable links",
capabilities=["web_search", "news_search", "image_search"],
llm_requirements={
"provider": "openai",
"model": "gpt-4.1",
"temperature": 0.2,
"max_tokens": 1024,
},
dependencies=["cadence-sdk>=1.3.3,<2.0.0", "ddgs>=9.5.4,<10.0.0"],
)
@staticmethod
def create_agent() -> BaseAgent:
return SearchAgent(SearchPlugin.get_metadata())
@staticmethod
def health_check() -> dict:
return {
"healthy": True,
"details": "Search plugin is operational",
"checks": {"search_engine": "OK", "dependencies": "OK"},
}
class SearchAgent(BaseAgent):
def __init__(self, metadata: PluginMetadata):
super().__init__(metadata)
def get_tools(self):
from .tools import search_tools
return search_tools
def get_system_prompt(self) -> str:
return """You are the Search Agent, specialized in web search and information retrieval.
Your responsibilities:
- Understand user search intent and information needs
- Choose the most appropriate search tool for each query
- Execute targeted searches with relevant keywords
- Analyze and summarize search results clearly
- Provide comprehensive, well-organized responses
- Cite sources when presenting information
- Always use the provided search decorators to find current information
"""
@tool
def web_search(query: str) -> str:
"""Search the web for information using DuckDuckGo.
Args:
query: The search query
Returns:
Search results from the web
"""
try:
from ddgs import DDGS
results = DDGS().text(query)
return results[:500]
except Exception as e:
return f"Web search error: {str(e)}"
```
### Plugin Discovery
Plugins are automatically discovered by the Cadence framework through the SDK's plugin discovery system. No manual registration is required - the framework scans for plugins that inherit from `BasePlugin`.
```python
# Plugins are automatically discovered when imported
from .plugin import SearchPlugin
# Or discover all plugins programmatically
from cadence_sdk import discover_plugins
plugins = discover_plugins()
```
## ๐ Core Components
### BasePlugin
The foundation of all Cadence plugins. Every plugin must implement:
- `get_metadata()`: Returns plugin metadata and configuration
- `create_agent()`: Creates and returns the plugin's agent instance
- `validate_dependencies()`: Optional dependency validation (returns list of error messages)
- `health_check()`: Optional health monitoring (returns health status dict)
```python
class MyPlugin(BasePlugin):
@staticmethod
def get_metadata() -> PluginMetadata:
return PluginMetadata(
name="my_plugin",
version="1.0.0",
description="Plugin description",
capabilities=["capability1", "capability2"],
agent_type="specialized", # or "general", "utility"
llm_requirements={
"provider": "openai",
"model": "gpt-4o",
"temperature": 0.1,
"max_tokens": 1024,
},
dependencies=["cadence-sdk>=1.3.3,<2.0.0"],
)
@staticmethod
def create_agent() -> BaseAgent:
return MyAgent(MyPlugin.get_metadata())
@staticmethod
def validate_dependencies() -> List[str]:
"""Validate plugin dependencies."""
errors = []
# Add your validation logic
return errors
@staticmethod
def health_check() -> dict:
"""Perform health check."""
return {"healthy": True, "details": "Plugin is operational"}
```
### BaseAgent
The agent implementation that handles LLM interactions and tool execution:
```python
class MyAgent(BaseAgent):
def __init__(self, metadata: PluginMetadata, parallel_tool_calls: bool = True):
super().__init__(metadata, parallel_tool_calls)
def get_tools(self) -> List[AgentTool]:
"""Return the tools this agent exposes."""
return [tool1, tool2, tool3]
def get_system_prompt(self) -> str:
"""Return the system prompt for this agent."""
return "You are a helpful AI assistant."
def initialize(self) -> None:
"""Initialize agent resources."""
super().initialize()
# Add custom initialization
def cleanup(self) -> None:
"""Cleanup agent resources."""
# Add custom cleanup
```
### PluginMetadata
Comprehensive metadata for plugin configuration:
```python
@dataclass
class PluginMetadata:
name: str
version: str
description: str
capabilities: List[str] = field(default_factory=list)
llm_requirements: Dict[str, Any] = field(default_factory=dict)
dependencies: List[str] = field(default_factory=list)
response_schema: Optional[Type[TypedDict]] = None
response_suggestion: Optional[str] = None
agent_type: str = "specialized" # "specialized", "general", "utility"
sdk_version: str = ">=1.0.1,<2.0.0"
def get_model_config(self) -> ModelConfig:
"""Convert LLM requirements to ModelConfig."""
# Implementation details...
```
### Tool System
Create tools using the `@tool` decorator:
```python
from cadence_sdk import tool
from ddgs import DDGS
@tool
def web_search(query: str) -> str:
"""Search the web for information using DuckDuckGo.
Args:
query: The search query
Returns:
Search results from the web
"""
try:
results = DDGS().text(query)
return results[:500]
except Exception as e:
return f"Web search error: {str(e)}"
@tool
def search_news(query: str) -> str:
"""Search for recent news articles.
Args:
query: The news search query
Returns:
News search results
"""
try:
results = DDGS().news(query)
return results[:500]
except Exception as e:
return f"News search error: {str(e)}"
@tool
def search_images(query: str) -> str:
"""Search for images and visual content related to the query.
Args:
query: The image search query
Returns:
Description of image search results
"""
try:
results = DDGS().images(query)
return results[:500]
except Exception as e:
return f"Image search error: {str(e)}"
# Export decorators as a list for easy import
search_tools = [web_search, search_news, search_images]
```
## ๐ State Management
The SDK provides comprehensive state management with type safety:
### AgentState
```python
class AgentState(TypedDict, total=False):
messages: Annotated[Sequence[BaseMessage], add_messages]
thread_id: Optional[str]
current_agent: Optional[str]
agent_hops: Optional[int]
plugin_context: Dict[str, Any]
metadata: Optional[Dict[str, Any]]
multi_agent: Optional[bool]
```
### PluginContext
```python
class PluginContext(TypedDict, total=False):
routing_history: List[str]
consecutive_agent_repeats: int
last_routed_agent: Optional[str]
synthesizer_output: Optional[Dict[str, Any]]
tools_used: List[str]
agent_outputs: Dict[str, Any]
```
### State Helpers
```python
from cadence_sdk.types.state import StateHelpers, RoutingHelpers, PluginContext
# Safe state operations
messages = StateHelpers.safe_get_messages(state)
agent_hops = StateHelpers.safe_get_agent_hops(state)
plugin_context = StateHelpers.get_plugin_context(state)
# Update plugin context
updated_state = StateHelpers.update_plugin_context(
state,
routing_history=["agent1", "agent2"],
tools_used=["tool1", "tool2"]
)
# Routing helpers
context = RoutingHelpers.add_to_routing_history(context, "my_agent")
context = RoutingHelpers.add_tool_used(context, "my_tool")
context = RoutingHelpers.update_consecutive_routes(context, "my_agent")
```
## ๐ Validation
Built-in validation for plugins, agents, and tools:
```python
from cadence_sdk.utils.validation import (
validate_plugin_structure,
validate_plugin_structure_shallow,
validate_metadata,
validate_tools,
validate_agent
)
# Validate plugin structure
errors = validate_plugin_structure(MyPlugin)
if errors:
print(f"Validation errors: {errors}")
# Validate metadata
metadata = MyPlugin.get_metadata()
errors = validate_metadata(metadata)
# Validate tools
tools = my_agent.get_tools()
errors = validate_tools(tools)
```
## ๐ฅ Health Monitoring
Implement health checks for your plugins:
```python
class MyPlugin(BasePlugin):
@staticmethod
def health_check() -> dict:
"""Perform comprehensive health check."""
try:
# Check dependencies
import requests
import numpy
# Check external services
response = requests.get("https://api.example.com/health", timeout=5)
api_healthy = response.status_code == 200
# Check configuration
config_valid = os.getenv("MY_API_KEY") is not None
return {
"healthy": api_healthy and config_valid,
"details": "All systems operational",
"checks": {
"dependencies": "OK",
"api_connectivity": "OK" if api_healthy else "FAILED",
"configuration": "OK" if config_valid else "MISSING_API_KEY",
},
}
except Exception as e:
return {
"healthy": False,
"details": f"Health check failed: {e}",
"error": str(e),
}
```
## ๐ง Advanced Features
### Parallel Tool Execution
Enable parallel tool calls for improved performance:
```python
class MyAgent(BaseAgent):
def __init__(self, metadata: PluginMetadata):
# Enable parallel tool calls (default: True)
super().__init__(metadata, parallel_tool_calls=True)
```
### Custom Model Configuration
Configure LLM requirements in plugin metadata:
```python
def get_metadata() -> PluginMetadata:
return PluginMetadata(
name="my_plugin",
version="1.0.0",
description="Plugin with custom LLM config",
llm_requirements={
"provider": "anthropic",
"model": "claude-3-sonnet-20240229",
"temperature": 0.7,
"max_tokens": 2048,
"additional_params": {
"top_p": 0.9,
"frequency_penalty": 0.1,
}
},
)
```
### Response Schemas
Define structured response schemas:
```python
from typing_extensions import Annotated, TypedDict
class SearchResponseSchema(TypedDict):
"""Unified schema for representing heterogeneous search response entities"""
title: Annotated[
str,
"Primary identifier or headline of the search result. For news articles: the article headline; for images: descriptive caption or filename; for general search: the page title or primary heading that encapsulates the content's essence",
]
description: Annotated[
str,
"Contextual summary or metadata providing substantive insight into the search result. For news: article excerpt or lead paragraph; for images: alt text, caption, or contextual description; for general search: meta description or extracted content snippet that offers semantic understanding of the result's relevance",
]
link: Annotated[
str,
"Canonical URI representing the authoritative source location. This serves as the primary navigation endpoint, ensuring consistent access to the original resource regardless of search result type or content modality",
]
thumbnail_link: Annotated[
str,
"Optional visual representation URI for enhanced user experience. For images: compressed preview version; for news articles: featured image or publication logo; for general search: favicon, screenshot, or representative visual element that aids in result recognition and selection",
]
class SearchPlugin(BasePlugin):
@staticmethod
def get_metadata() -> PluginMetadata:
return PluginMetadata(
name="browse_internet",
version="1.3.3",
description="Internet Browser Search agent, using DuckDuckGo API",
response_schema=SearchResponseSchema,
response_suggestion="When presenting search results, always include source citations with clickable links, organize information by relevance and recency, provide context about the credibility of sources, and offer follow-up search suggestions when appropriate.",
)
```
## ๐ Project Structure
### SDK Structure
```
cadence_sdk/
โโโ base/ # Core base classes
โ โโโ agent.py # BaseAgent implementation
โ โโโ plugin.py # BasePlugin interface
โ โโโ metadata.py # PluginMetadata and ModelConfig
โ โโโ loggable.py # Logging utilities
โโโ registry/ # Plugin discovery and management
โ โโโ plugin_registry.py # PluginRegistry implementation
โ โโโ contracts.py # Plugin contracts
โโโ decorators/ # Decorator system
โ โโโ tool.py # @tool decorator
โ โโโ schema.py # Schema decorators
โโโ types/ # Type definitions
โ โโโ state.py # AgentState and helpers
โ โโโ messages.py # Message types
โโโ utils/ # Utility functions
โ โโโ validation.py # Validation utilities
โ โโโ helpers.py # General helpers
โ โโโ installers.py # Installation utilities
โ โโโ directory_discovery.py # Directory-based discovery
โ โโโ environment_discovery.py # Environment detection
โโโ examples/ # Example implementations
โโโ template_plugin/ # Template plugin example
```
### Plugin Structure (Real Example)
Based on the search_agent implementation:
```
search_agent/
โโโ __init__.py # Auto-registration
โโโ plugin.py # Plugin class and metadata
โโโ agent.py # Agent implementation
โโโ tools.py # Tool definitions
```
**Key Files:**
- **`__init__.py`**: Plugin package initialization (usually empty)
- **`plugin.py`**: Contains the `BasePlugin` implementation with metadata
- **`agent.py`**: Contains the `BaseAgent` implementation with system prompt
- **`tools.py`**: Contains tool definitions using `@tool` decorator
## ๐งช Testing
The SDK includes comprehensive testing utilities:
```python
# Test plugin structure
def test_plugin_structure():
errors = validate_plugin_structure(MyPlugin)
assert not errors, f"Plugin validation failed: {errors}"
# Test agent creation
def test_agent_creation():
agent = MyPlugin.create_agent()
assert isinstance(agent, BaseAgent)
tools = agent.get_tools()
assert len(tools) > 0
system_prompt = agent.get_system_prompt()
assert isinstance(system_prompt, str)
# Test tool validation
def test_tools():
agent = MyPlugin.create_agent()
tools = agent.get_tools()
errors = validate_tools(tools)
assert not errors, f"Tool validation failed: {errors}"
```
## ๐ Integration with Cadence Core
The SDK is designed to integrate seamlessly with the Cadence core system:
1. **Automatic Discovery**: Plugins are automatically discovered and registered
2. **LangGraph Integration**: Agents work as LangGraph nodes out of the box
3. **State Synchronization**: State is automatically synchronized between agents
4. **Tool Binding**: Tools are automatically bound to LLM models
5. **Routing Logic**: Built-in routing decisions for agent-to-agent communication
## ๐ Examples
### Complete Plugin Example
See the `examples/template_plugin/` directory for a complete working example that demonstrates:
- Plugin metadata configuration
- Agent implementation with multiple tools
- Tool creation and validation
- Health checks and dependency validation
- Best practices for plugin development
### Real-World Plugin Ideas
- **Web Search Agent**: Search the web and return structured results
- **Code Analysis Agent**: Analyze code and provide suggestions
- **Data Processing Agent**: Process and transform data
- **API Integration Agent**: Integrate with external APIs
- **File Management Agent**: Handle file operations
- **Database Agent**: Query and manipulate databases
## ๐ค Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
### Development Setup
1. Fork the repository
2. Create a feature branch
3. Install development dependencies: `pip install -e ".[dev]"`
4. Run tests: `pytest`
5. Submit a pull request
## ๐ License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## ๐ Acknowledgments
- Built on [LangChain](https://langchain.com/) for LLM integration
- Powered by [LangGraph](https://langchain.com/langgraph) for agent orchestration
- Type safety with [Pydantic](https://pydantic.dev/) and Python typing
- Plugin architecture inspired by modern plugin systems
## ๐ Support
- **Issues**: [GitHub Issues](https://github.com/jonaskahn/cadence-sdk/issues)
- **Discussions**: [GitHub Discussions](https://github.com/jonaskahn/cadence-sdk/discussions)
- **Documentation**: [Read the Docs](https://cadence.readthedocs.io/)
---
**Made with โค๏ธ by the Cadence AI Team**
_Build intelligent agents that work together seamlessly with the Cadence SDK._
Raw data
{
"_id": null,
"home_page": "https://github.com/jonaskahn/cadence-sdk",
"name": "cadence-sdk",
"maintainer": null,
"docs_url": null,
"requires_python": "<3.14,>=3.13",
"maintainer_email": null,
"keywords": "ai, agents, cadence-ai, cadence_sdk, langchain, langgraph, plugins",
"author": "Jonas Kahn",
"author_email": "me@ifelse.one",
"download_url": "https://files.pythonhosted.org/packages/08/78/054d66fe76fd7d4624200a74eb903724f59869588bc5bc314dc071407987/cadence_sdk-1.3.3.tar.gz",
"platform": null,
"description": "# Cadence SDK \ud83e\udd16\n\n**Plugin Development Framework for Cadence AI Multi-Agent System**\n\n[](https://badge.fury.io/py/cadence-sdk)\n[](https://www.python.org/downloads/release/python-3130/)\n[](https://opensource.org/licenses/MIT)\n\nThe Cadence SDK provides a comprehensive framework for building custom AI agent plugins that integrate seamlessly with\nthe Cadence multi-agent conversational AI system. Built on LangChain and LangGraph, it offers powerful abstractions for\ncreating intelligent, tool-enabled agents with automatic routing and orchestration.\n\n## \ud83d\ude80 Features\n\n- **\ud83d\udd0c Plugin Architecture**: Simple, extensible plugin system with automatic discovery\n- **\ud83e\udd16 Agent Framework**: Complete agent lifecycle management with LangGraph integration\n- **\ud83d\udee0\ufe0f Tool System**: Easy tool creation with the `@tool` decorator\n- **\ud83d\udcca State Management**: Comprehensive state handling with type safety\n- **\ud83d\udd04 Automatic Routing**: Intelligent agent-to-agent communication and routing\n- **\u26a1 Parallel Execution**: Support for parallel tool calls for improved performance\n- **\ud83d\udd0d Validation**: Built-in validation for plugins, agents, and tools\n- **\ud83d\udcdd Type Safety**: Full type hints and TypedDict support for robust development\n- **\ud83c\udfe5 Health Checks**: Built-in health monitoring and dependency validation\n- **\ud83d\udce6 Registry System**: Centralized plugin discovery and management\n\n## \ud83d\udce6 Installation\n\n### From PyPI (Recommended)\n\n```bash\npip install cadence-sdk\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/jonaskahn/cadence-sdk.git\npip install -e .\n```\n\n### Development Installation\n\n```bash\ngit clone https://github.com/jonaskahn/cadence-sdk.git\npip install -e \".[dev]\"\n```\n\n## \ud83c\udfaf Quick Start\n\n### Basic Plugin Structure\n\n```python\nfrom cadence_sdk import BaseAgent, BasePlugin, PluginMetadata, tool\nfrom typing_extensions import Annotated, TypedDict\n\n\nclass SearchResponseSchema(TypedDict):\n \"\"\"Schema for structured search responses\"\"\"\n title: Annotated[str, \"Primary identifier or headline\"]\n description: Annotated[str, \"Contextual summary or metadata\"]\n link: Annotated[str, \"Canonical URI to the source\"]\n thumbnail_link: Annotated[str, \"Optional visual representation URI\"]\n\n\nclass SearchPlugin(BasePlugin):\n @staticmethod\n def get_metadata() -> PluginMetadata:\n return PluginMetadata(\n name=\"browse_internet\",\n version=\"1.3.3\",\n description=\"Internet Browser Search agent, using DuckDuckGo API\",\n agent_type=\"specialized\",\n response_schema=SearchResponseSchema,\n response_suggestion=\"When presenting search results, always include source citations with clickable links\",\n capabilities=[\"web_search\", \"news_search\", \"image_search\"],\n llm_requirements={\n \"provider\": \"openai\",\n \"model\": \"gpt-4.1\",\n \"temperature\": 0.2,\n \"max_tokens\": 1024,\n },\n dependencies=[\"cadence-sdk>=1.3.3,<2.0.0\", \"ddgs>=9.5.4,<10.0.0\"],\n )\n\n @staticmethod\n def create_agent() -> BaseAgent:\n return SearchAgent(SearchPlugin.get_metadata())\n\n @staticmethod\n def health_check() -> dict:\n return {\n \"healthy\": True,\n \"details\": \"Search plugin is operational\",\n \"checks\": {\"search_engine\": \"OK\", \"dependencies\": \"OK\"},\n }\n\n\nclass SearchAgent(BaseAgent):\n def __init__(self, metadata: PluginMetadata):\n super().__init__(metadata)\n\n def get_tools(self):\n from .tools import search_tools\n return search_tools\n\n def get_system_prompt(self) -> str:\n return \"\"\"You are the Search Agent, specialized in web search and information retrieval.\n\nYour responsibilities:\n - Understand user search intent and information needs\n - Choose the most appropriate search tool for each query\n - Execute targeted searches with relevant keywords\n - Analyze and summarize search results clearly\n - Provide comprehensive, well-organized responses\n - Cite sources when presenting information\n - Always use the provided search decorators to find current information\n\"\"\"\n\n\n@tool\ndef web_search(query: str) -> str:\n \"\"\"Search the web for information using DuckDuckGo.\n\n Args:\n query: The search query\n\n Returns:\n Search results from the web\n \"\"\"\n try:\n from ddgs import DDGS\n results = DDGS().text(query)\n return results[:500]\n except Exception as e:\n return f\"Web search error: {str(e)}\"\n```\n\n### Plugin Discovery\n\nPlugins are automatically discovered by the Cadence framework through the SDK's plugin discovery system. No manual registration is required - the framework scans for plugins that inherit from `BasePlugin`.\n\n```python\n# Plugins are automatically discovered when imported\nfrom .plugin import SearchPlugin\n\n# Or discover all plugins programmatically\nfrom cadence_sdk import discover_plugins\n\nplugins = discover_plugins()\n```\n\n## \ud83d\udcda Core Components\n\n### BasePlugin\n\nThe foundation of all Cadence plugins. Every plugin must implement:\n\n- `get_metadata()`: Returns plugin metadata and configuration\n- `create_agent()`: Creates and returns the plugin's agent instance\n- `validate_dependencies()`: Optional dependency validation (returns list of error messages)\n- `health_check()`: Optional health monitoring (returns health status dict)\n\n```python\nclass MyPlugin(BasePlugin):\n @staticmethod\n def get_metadata() -> PluginMetadata:\n return PluginMetadata(\n name=\"my_plugin\",\n version=\"1.0.0\",\n description=\"Plugin description\",\n capabilities=[\"capability1\", \"capability2\"],\n agent_type=\"specialized\", # or \"general\", \"utility\"\n llm_requirements={\n \"provider\": \"openai\",\n \"model\": \"gpt-4o\",\n \"temperature\": 0.1,\n \"max_tokens\": 1024,\n },\n dependencies=[\"cadence-sdk>=1.3.3,<2.0.0\"],\n )\n\n @staticmethod\n def create_agent() -> BaseAgent:\n return MyAgent(MyPlugin.get_metadata())\n\n @staticmethod\n def validate_dependencies() -> List[str]:\n \"\"\"Validate plugin dependencies.\"\"\"\n errors = []\n # Add your validation logic\n return errors\n\n @staticmethod\n def health_check() -> dict:\n \"\"\"Perform health check.\"\"\"\n return {\"healthy\": True, \"details\": \"Plugin is operational\"}\n```\n\n### BaseAgent\n\nThe agent implementation that handles LLM interactions and tool execution:\n\n```python\nclass MyAgent(BaseAgent):\n def __init__(self, metadata: PluginMetadata, parallel_tool_calls: bool = True):\n super().__init__(metadata, parallel_tool_calls)\n\n def get_tools(self) -> List[AgentTool]:\n \"\"\"Return the tools this agent exposes.\"\"\"\n return [tool1, tool2, tool3]\n\n def get_system_prompt(self) -> str:\n \"\"\"Return the system prompt for this agent.\"\"\"\n return \"You are a helpful AI assistant.\"\n\n def initialize(self) -> None:\n \"\"\"Initialize agent resources.\"\"\"\n super().initialize()\n # Add custom initialization\n\n def cleanup(self) -> None:\n \"\"\"Cleanup agent resources.\"\"\"\n # Add custom cleanup\n```\n\n### PluginMetadata\n\nComprehensive metadata for plugin configuration:\n\n```python\n@dataclass\nclass PluginMetadata:\n name: str\n version: str\n description: str\n capabilities: List[str] = field(default_factory=list)\n llm_requirements: Dict[str, Any] = field(default_factory=dict)\n dependencies: List[str] = field(default_factory=list)\n response_schema: Optional[Type[TypedDict]] = None\n response_suggestion: Optional[str] = None\n agent_type: str = \"specialized\" # \"specialized\", \"general\", \"utility\"\n sdk_version: str = \">=1.0.1,<2.0.0\"\n\n def get_model_config(self) -> ModelConfig:\n \"\"\"Convert LLM requirements to ModelConfig.\"\"\"\n # Implementation details...\n```\n\n### Tool System\n\nCreate tools using the `@tool` decorator:\n\n```python\nfrom cadence_sdk import tool\nfrom ddgs import DDGS\n\n@tool\ndef web_search(query: str) -> str:\n \"\"\"Search the web for information using DuckDuckGo.\n\n Args:\n query: The search query\n\n Returns:\n Search results from the web\n \"\"\"\n try:\n results = DDGS().text(query)\n return results[:500]\n except Exception as e:\n return f\"Web search error: {str(e)}\"\n\n@tool\ndef search_news(query: str) -> str:\n \"\"\"Search for recent news articles.\n\n Args:\n query: The news search query\n\n Returns:\n News search results\n \"\"\"\n try:\n results = DDGS().news(query)\n return results[:500]\n except Exception as e:\n return f\"News search error: {str(e)}\"\n\n@tool\ndef search_images(query: str) -> str:\n \"\"\"Search for images and visual content related to the query.\n\n Args:\n query: The image search query\n\n Returns:\n Description of image search results\n \"\"\"\n try:\n results = DDGS().images(query)\n return results[:500]\n except Exception as e:\n return f\"Image search error: {str(e)}\"\n\n# Export decorators as a list for easy import\nsearch_tools = [web_search, search_news, search_images]\n```\n\n## \ud83d\udd04 State Management\n\nThe SDK provides comprehensive state management with type safety:\n\n### AgentState\n\n```python\nclass AgentState(TypedDict, total=False):\n messages: Annotated[Sequence[BaseMessage], add_messages]\n thread_id: Optional[str]\n current_agent: Optional[str]\n agent_hops: Optional[int]\n plugin_context: Dict[str, Any]\n metadata: Optional[Dict[str, Any]]\n multi_agent: Optional[bool]\n```\n\n### PluginContext\n\n```python\nclass PluginContext(TypedDict, total=False):\n routing_history: List[str]\n consecutive_agent_repeats: int\n last_routed_agent: Optional[str]\n synthesizer_output: Optional[Dict[str, Any]]\n tools_used: List[str]\n agent_outputs: Dict[str, Any]\n```\n\n### State Helpers\n\n```python\nfrom cadence_sdk.types.state import StateHelpers, RoutingHelpers, PluginContext\n\n# Safe state operations\nmessages = StateHelpers.safe_get_messages(state)\nagent_hops = StateHelpers.safe_get_agent_hops(state)\nplugin_context = StateHelpers.get_plugin_context(state)\n\n# Update plugin context\nupdated_state = StateHelpers.update_plugin_context(\n state,\n routing_history=[\"agent1\", \"agent2\"],\n tools_used=[\"tool1\", \"tool2\"]\n)\n\n# Routing helpers\ncontext = RoutingHelpers.add_to_routing_history(context, \"my_agent\")\ncontext = RoutingHelpers.add_tool_used(context, \"my_tool\")\ncontext = RoutingHelpers.update_consecutive_routes(context, \"my_agent\")\n```\n\n## \ud83d\udd0d Validation\n\nBuilt-in validation for plugins, agents, and tools:\n\n```python\nfrom cadence_sdk.utils.validation import (\n validate_plugin_structure,\n validate_plugin_structure_shallow,\n validate_metadata,\n validate_tools,\n validate_agent\n)\n\n# Validate plugin structure\nerrors = validate_plugin_structure(MyPlugin)\nif errors:\n print(f\"Validation errors: {errors}\")\n\n# Validate metadata\nmetadata = MyPlugin.get_metadata()\nerrors = validate_metadata(metadata)\n\n# Validate tools\ntools = my_agent.get_tools()\nerrors = validate_tools(tools)\n```\n\n## \ud83c\udfe5 Health Monitoring\n\nImplement health checks for your plugins:\n\n```python\nclass MyPlugin(BasePlugin):\n @staticmethod\n def health_check() -> dict:\n \"\"\"Perform comprehensive health check.\"\"\"\n try:\n # Check dependencies\n import requests\n import numpy\n\n # Check external services\n response = requests.get(\"https://api.example.com/health\", timeout=5)\n api_healthy = response.status_code == 200\n\n # Check configuration\n config_valid = os.getenv(\"MY_API_KEY\") is not None\n\n return {\n \"healthy\": api_healthy and config_valid,\n \"details\": \"All systems operational\",\n \"checks\": {\n \"dependencies\": \"OK\",\n \"api_connectivity\": \"OK\" if api_healthy else \"FAILED\",\n \"configuration\": \"OK\" if config_valid else \"MISSING_API_KEY\",\n },\n }\n\n except Exception as e:\n return {\n \"healthy\": False,\n \"details\": f\"Health check failed: {e}\",\n \"error\": str(e),\n }\n```\n\n## \ud83d\udd27 Advanced Features\n\n### Parallel Tool Execution\n\nEnable parallel tool calls for improved performance:\n\n```python\nclass MyAgent(BaseAgent):\n def __init__(self, metadata: PluginMetadata):\n # Enable parallel tool calls (default: True)\n super().__init__(metadata, parallel_tool_calls=True)\n```\n\n### Custom Model Configuration\n\nConfigure LLM requirements in plugin metadata:\n\n```python\ndef get_metadata() -> PluginMetadata:\n return PluginMetadata(\n name=\"my_plugin\",\n version=\"1.0.0\",\n description=\"Plugin with custom LLM config\",\n llm_requirements={\n \"provider\": \"anthropic\",\n \"model\": \"claude-3-sonnet-20240229\",\n \"temperature\": 0.7,\n \"max_tokens\": 2048,\n \"additional_params\": {\n \"top_p\": 0.9,\n \"frequency_penalty\": 0.1,\n }\n },\n )\n```\n\n### Response Schemas\n\nDefine structured response schemas:\n\n```python\nfrom typing_extensions import Annotated, TypedDict\n\n\nclass SearchResponseSchema(TypedDict):\n \"\"\"Unified schema for representing heterogeneous search response entities\"\"\"\n\n title: Annotated[\n str,\n \"Primary identifier or headline of the search result. For news articles: the article headline; for images: descriptive caption or filename; for general search: the page title or primary heading that encapsulates the content's essence\",\n ]\n\n description: Annotated[\n str,\n \"Contextual summary or metadata providing substantive insight into the search result. For news: article excerpt or lead paragraph; for images: alt text, caption, or contextual description; for general search: meta description or extracted content snippet that offers semantic understanding of the result's relevance\",\n ]\n\n link: Annotated[\n str,\n \"Canonical URI representing the authoritative source location. This serves as the primary navigation endpoint, ensuring consistent access to the original resource regardless of search result type or content modality\",\n ]\n\n thumbnail_link: Annotated[\n str,\n \"Optional visual representation URI for enhanced user experience. For images: compressed preview version; for news articles: featured image or publication logo; for general search: favicon, screenshot, or representative visual element that aids in result recognition and selection\",\n ]\n\n\nclass SearchPlugin(BasePlugin):\n @staticmethod\n def get_metadata() -> PluginMetadata:\n return PluginMetadata(\n name=\"browse_internet\",\n version=\"1.3.3\",\n description=\"Internet Browser Search agent, using DuckDuckGo API\",\n response_schema=SearchResponseSchema,\n response_suggestion=\"When presenting search results, always include source citations with clickable links, organize information by relevance and recency, provide context about the credibility of sources, and offer follow-up search suggestions when appropriate.\",\n )\n```\n\n## \ud83d\udcc1 Project Structure\n\n### SDK Structure\n\n```\ncadence_sdk/\n\u251c\u2500\u2500 base/ # Core base classes\n\u2502 \u251c\u2500\u2500 agent.py # BaseAgent implementation\n\u2502 \u251c\u2500\u2500 plugin.py # BasePlugin interface\n\u2502 \u251c\u2500\u2500 metadata.py # PluginMetadata and ModelConfig\n\u2502 \u2514\u2500\u2500 loggable.py # Logging utilities\n\u251c\u2500\u2500 registry/ # Plugin discovery and management\n\u2502 \u251c\u2500\u2500 plugin_registry.py # PluginRegistry implementation\n\u2502 \u2514\u2500\u2500 contracts.py # Plugin contracts\n\u251c\u2500\u2500 decorators/ # Decorator system\n\u2502 \u251c\u2500\u2500 tool.py # @tool decorator\n\u2502 \u2514\u2500\u2500 schema.py # Schema decorators\n\u251c\u2500\u2500 types/ # Type definitions\n\u2502 \u251c\u2500\u2500 state.py # AgentState and helpers\n\u2502 \u2514\u2500\u2500 messages.py # Message types\n\u251c\u2500\u2500 utils/ # Utility functions\n\u2502 \u251c\u2500\u2500 validation.py # Validation utilities\n\u2502 \u251c\u2500\u2500 helpers.py # General helpers\n\u2502 \u251c\u2500\u2500 installers.py # Installation utilities\n\u2502 \u251c\u2500\u2500 directory_discovery.py # Directory-based discovery\n\u2502 \u2514\u2500\u2500 environment_discovery.py # Environment detection\n\u2514\u2500\u2500 examples/ # Example implementations\n \u2514\u2500\u2500 template_plugin/ # Template plugin example\n```\n\n### Plugin Structure (Real Example)\n\nBased on the search_agent implementation:\n\n```\nsearch_agent/\n\u251c\u2500\u2500 __init__.py # Auto-registration\n\u251c\u2500\u2500 plugin.py # Plugin class and metadata\n\u251c\u2500\u2500 agent.py # Agent implementation\n\u2514\u2500\u2500 tools.py # Tool definitions\n```\n\n**Key Files:**\n\n- **`__init__.py`**: Plugin package initialization (usually empty)\n- **`plugin.py`**: Contains the `BasePlugin` implementation with metadata\n- **`agent.py`**: Contains the `BaseAgent` implementation with system prompt\n- **`tools.py`**: Contains tool definitions using `@tool` decorator\n\n## \ud83e\uddea Testing\n\nThe SDK includes comprehensive testing utilities:\n\n```python\n# Test plugin structure\ndef test_plugin_structure():\n errors = validate_plugin_structure(MyPlugin)\n assert not errors, f\"Plugin validation failed: {errors}\"\n\n\n# Test agent creation\ndef test_agent_creation():\n agent = MyPlugin.create_agent()\n assert isinstance(agent, BaseAgent)\n\n tools = agent.get_tools()\n assert len(tools) > 0\n\n system_prompt = agent.get_system_prompt()\n assert isinstance(system_prompt, str)\n\n\n# Test tool validation\ndef test_tools():\n agent = MyPlugin.create_agent()\n tools = agent.get_tools()\n errors = validate_tools(tools)\n assert not errors, f\"Tool validation failed: {errors}\"\n```\n\n## \ud83d\udd17 Integration with Cadence Core\n\nThe SDK is designed to integrate seamlessly with the Cadence core system:\n\n1. **Automatic Discovery**: Plugins are automatically discovered and registered\n2. **LangGraph Integration**: Agents work as LangGraph nodes out of the box\n3. **State Synchronization**: State is automatically synchronized between agents\n4. **Tool Binding**: Tools are automatically bound to LLM models\n5. **Routing Logic**: Built-in routing decisions for agent-to-agent communication\n\n## \ud83d\udcd6 Examples\n\n### Complete Plugin Example\n\nSee the `examples/template_plugin/` directory for a complete working example that demonstrates:\n\n- Plugin metadata configuration\n- Agent implementation with multiple tools\n- Tool creation and validation\n- Health checks and dependency validation\n- Best practices for plugin development\n\n### Real-World Plugin Ideas\n\n- **Web Search Agent**: Search the web and return structured results\n- **Code Analysis Agent**: Analyze code and provide suggestions\n- **Data Processing Agent**: Process and transform data\n- **API Integration Agent**: Integrate with external APIs\n- **File Management Agent**: Handle file operations\n- **Database Agent**: Query and manipulate databases\n\n## \ud83e\udd1d Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n### Development Setup\n\n1. Fork the repository\n2. Create a feature branch\n3. Install development dependencies: `pip install -e \".[dev]\"`\n4. Run tests: `pytest`\n5. Submit a pull request\n\n## \ud83d\udcc4 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## \ud83d\ude4f Acknowledgments\n\n- Built on [LangChain](https://langchain.com/) for LLM integration\n- Powered by [LangGraph](https://langchain.com/langgraph) for agent orchestration\n- Type safety with [Pydantic](https://pydantic.dev/) and Python typing\n- Plugin architecture inspired by modern plugin systems\n\n## \ud83d\udcde Support\n\n- **Issues**: [GitHub Issues](https://github.com/jonaskahn/cadence-sdk/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/jonaskahn/cadence-sdk/discussions)\n- **Documentation**: [Read the Docs](https://cadence.readthedocs.io/)\n\n---\n\n**Made with \u2764\ufe0f by the Cadence AI Team**\n\n_Build intelligent agents that work together seamlessly with the Cadence SDK._\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Cadence SDK - To building custom AI agent plugins for Cadence AI Framework",
"version": "1.3.3",
"project_urls": {
"Documentation": "https://cadence_sdk.readthedocs.io/",
"Homepage": "https://github.com/jonaskahn/cadence-sdk",
"Repository": "https://github.com/jonaskahn/cadence-sdk.git",
"issues": "https://github.com/jonaskahn/cadence-sdk/issues"
},
"split_keywords": [
"ai",
" agents",
" cadence-ai",
" cadence_sdk",
" langchain",
" langgraph",
" plugins"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5d535c9e3d446448767b7df55f8c93e37f775cd6b6c7685af385ab307e40bec3",
"md5": "d8d33a04e0694b1c02b8d12bec0f1159",
"sha256": "93e749940af2f44e201383225e44434ef43a1d280fe60e223c02593d203785b2"
},
"downloads": -1,
"filename": "cadence_sdk-1.3.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "d8d33a04e0694b1c02b8d12bec0f1159",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<3.14,>=3.13",
"size": 38714,
"upload_time": "2025-10-19T06:36:39",
"upload_time_iso_8601": "2025-10-19T06:36:39.845887Z",
"url": "https://files.pythonhosted.org/packages/5d/53/5c9e3d446448767b7df55f8c93e37f775cd6b6c7685af385ab307e40bec3/cadence_sdk-1.3.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0878054d66fe76fd7d4624200a74eb903724f59869588bc5bc314dc071407987",
"md5": "528569100cb6c38a13f591dab3e733ed",
"sha256": "4ef10c3223c2dcd5389f15ec8fba7e3ad18f5cf139ecb390715d3a62a1912354"
},
"downloads": -1,
"filename": "cadence_sdk-1.3.3.tar.gz",
"has_sig": false,
"md5_digest": "528569100cb6c38a13f591dab3e733ed",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<3.14,>=3.13",
"size": 34684,
"upload_time": "2025-10-19T06:36:41",
"upload_time_iso_8601": "2025-10-19T06:36:41.380233Z",
"url": "https://files.pythonhosted.org/packages/08/78/054d66fe76fd7d4624200a74eb903724f59869588bc5bc314dc071407987/cadence_sdk-1.3.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-19 06:36:41",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "jonaskahn",
"github_project": "cadence-sdk",
"github_not_found": true,
"lcname": "cadence-sdk"
}