Skip to main content

Framework-agnostic SDK for building Cadence AI agent plugins

Project description

Cadence SDK

Framework-agnostic plugin development kit for the Cadence AI platform.

Python 3.13+ PyPI version License: MIT

Write your plugin once — it works on LangGraph, OpenAI Agents SDK, and Google ADK without framework-specific code.

Full documentation: jonaskahn.github.io/cadence


Installation

pip install cadence-sdk

Quick Start

Create my_plugin/plugin.py:

from cadence_sdk import BasePlugin, BaseAgent, PluginMetadata, uvtool, plugin_settings, UvTool
from typing import List


class MyAgent(BaseAgent):
    def initialize(self, config: dict) -> None:
        self.api_key = config["api_key"]
        self._search_tool = self._make_search_tool()

    def _make_search_tool(self) -> UvTool:
        @uvtool
        def search(query: str) -> str:
            """Search for information."""
            return call_api(query, self.api_key)

        return search

    def get_tools(self) -> List[UvTool]:
        return [self._search_tool]

    def get_system_prompt(self) -> str:
        return "You are a helpful assistant."


@plugin_settings([
    {"key": "api_key", "type": "str", "description": "API key", "sensitive": True, "required": True},
    {"key": "timeout", "type": "int", "description": "Request timeout", "default": 30},
])
class MyPlugin(BasePlugin):
    @staticmethod
    def get_metadata() -> PluginMetadata:
        return PluginMetadata(
            pid="com.example.my_plugin",
            name="My Plugin",
            version="1.0.0",
            description="Does something useful",
            stateless=True,
        )

    @staticmethod
    def create_agent() -> BaseAgent:
        return MyAgent()

Cadence auto-discovers any BasePlugin subclass in a plugin.py file — no manual registration needed.

Package and upload:

zip -r my_plugin.zip my_plugin/ -x "**/__pycache__/*" "**/*.pyc"
curl -X POST http://localhost:8888/api/plugins/system \
  -H "Authorization: Bearer <token>" \
  -F "file=@my_plugin.zip"

Core Concepts

Concept Description
BasePlugin Factory class — declares metadata and creates agent instances
BaseAgent Provides tools and system prompt; receives resolved settings via initialize()
@uvtool Wraps a sync or async function as a framework-agnostic tool
@plugin_settings Declares the settings schema shown in the Cadence UI
PluginMetadata Declares pid, name, version, description, stateless, dependencies

PluginMetadata fields

Field Type Required Description
pid str Yes Reverse-domain unique ID, e.g. com.example.my_plugin
name str Yes Human-readable display name
version str Yes Semantic version string
description str Yes Human-readable description
stateless bool No True enables instance sharing (default: True)
agent_type str No Agent category tag (default: "specialized")
capabilities List[str] No Capability tags for filtering
dependencies List[str] No Pip requirements, e.g. ["requests>=2.28"]
sdk_version str No Compatible SDK range (default: ">=2.0.0,<4.0.0")

@plugin_settings field types

"str", "int", "float", "bool", "list", "dict"

Each entry: key (required), type (required), description (required), name, default, required, sensitive.

@uvtool options

Parameter Description
name Tool name (default: function name)
description Tool description (default: docstring)
args_schema Pydantic model for argument validation
stream If True, stream tool result to client before synthesizer
stream_filter Callable to filter result before streaming (e.g. expose only url, product_id)
validate If True, marks tool for LLM validation
cache True, False, or CacheConfig for semantic caching

Examples

Example Description
web_search_agent Web search via Serper.dev; site/time filters, image search
recommendation_agent Product recommendations via Qdrant hybrid search; dense + sparse embeddings

Each example includes a full plugin, agent, tools, and README with packaging instructions.


Agent Pattern — Tools as Closures

Tools that need agent state should be created as closures inside factory methods:

class MyAgent(BaseAgent):
    def __init__(self):
        self.api_key = None
        self._search_tool = self._make_search_tool()

    def _make_search_tool(self) -> UvTool:
        @uvtool
        def search(query: str) -> str:
            """Search using agent's API key."""
            return call_api(query, self.api_key)  # captures self

        return search

Configurable System Prompt

To make the system prompt configurable via plugin settings:

  1. Add system_prompt to @plugin_settings:

    {"key": "system_prompt", "name": "System Prompt Override", "type": "str",
     "required": False, "description": "Optional override for the agent system prompt. Leave empty to use default."}
    
  2. In initialize(), store the value: self._system_prompt = config.get("system_prompt")

  3. In get_system_prompt(), return the override or default: return self._system_prompt or self._default_system_prompt


Async Tools

@uvtool
async def fetch(url: str) -> str:
    """Fetch URL asynchronously."""
    async with aiohttp.ClientSession() as s:
        async with s.get(url) as r:
            return await r.text()


result = await fetch.ainvoke(url="https://example.com")

Packaging & Deployment

# Create a deployable zip
zip -r my_plugin.zip path/to/my_plugin/ -x "**/__pycache__/*" "**/*.pyc"
# Upload to Cadence
curl -X POST http://localhost:8888/api/plugins/system \
  -H "Authorization: Bearer <token>" \
  -F "file=@my_plugin.zip"

Validation & Dependency Utilities

from cadence_sdk import validate_plugin_structure, validate_plugin_structure_shallow, check_dependency_installed, install_dependencies

# Deep validation (checks all required methods and metadata)
is_valid, errors = validate_plugin_structure(MyPlugin)

# Shallow validation (checks metadata fields only)
is_valid, errors = validate_plugin_structure_shallow(MyPlugin)

# Check / install dependencies
if not check_dependency_installed("requests"):
    install_dependencies(["requests>=2.28"])

Best Practices

  • Set stateless=True when agents carry no mutable state — enables bundle sharing across orchestrators
  • Declare dependencies in PluginMetadata so the platform can auto-install them
  • Implement async cleanup() on agents that hold connections or file handles
  • Use validate_dependencies() to surface missing env vars or packages at startup

Development

git clone https://github.com/jonaskahn/cadence.git
cd cadence/sdk
poetry install --with dev

# Run tests
PYTHONPATH=src python -m pytest tests/ -v

# Run example
PYTHONPATH=src python examples/test_sdk.py

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cadence_sdk-2.0.10.tar.gz (23.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cadence_sdk-2.0.10-py3-none-any.whl (28.3 kB view details)

Uploaded Python 3

File details

Details for the file cadence_sdk-2.0.10.tar.gz.

File metadata

  • Download URL: cadence_sdk-2.0.10.tar.gz
  • Upload date:
  • Size: 23.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.2 CPython/3.14.3 Darwin/25.3.0

File hashes

Hashes for cadence_sdk-2.0.10.tar.gz
Algorithm Hash digest
SHA256 02c2d1f945a348d58c1312e38ec52a02223dc7237f391daa1d744e03b69c96ee
MD5 08f948e96d2fbc564cb196e455381bfb
BLAKE2b-256 a371b58193489dde79e8c783ce8b57c03837d206065bafbade00abae7027ac56

See more details on using hashes here.

File details

Details for the file cadence_sdk-2.0.10-py3-none-any.whl.

File metadata

  • Download URL: cadence_sdk-2.0.10-py3-none-any.whl
  • Upload date:
  • Size: 28.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.2 CPython/3.14.3 Darwin/25.3.0

File hashes

Hashes for cadence_sdk-2.0.10-py3-none-any.whl
Algorithm Hash digest
SHA256 40a14ce81a72c787b56426e43a8786ff73befecd6e3b8290998dda48d23ccd08
MD5 6f7c80aa9c70454a9dad04d73b60e00a
BLAKE2b-256 a851c7ce8ef6c20c90d7864e5744c37135f89e2815aefa0abadb6f3441f327ac

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page