cadence-sdk


Namecadence-sdk JSON
Version 1.3.3 PyPI version JSON
download
home_pagehttps://github.com/jonaskahn/cadence-sdk
SummaryCadence SDK - To building custom AI agent plugins for Cadence AI Framework
upload_time2025-10-19 06:36:41
maintainerNone
docs_urlNone
authorJonas Kahn
requires_python<3.14,>=3.13
licenseMIT
keywords ai agents cadence-ai cadence_sdk langchain langgraph plugins
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Cadence SDK ๐Ÿค–

**Plugin Development Framework for Cadence AI Multi-Agent System**

[![PyPI version](https://badge.fury.io/py/cadence-sdk.svg)](https://badge.fury.io/py/cadence-sdk)
[![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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[![PyPI version](https://badge.fury.io/py/cadence-sdk.svg)](https://badge.fury.io/py/cadence-sdk)\n[![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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"
}
        
Elapsed time: 1.36809s