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.9.tar.gz (25.9 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.9-py3-none-any.whl (32.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: cadence_sdk-2.0.9.tar.gz
  • Upload date:
  • Size: 25.9 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.9.tar.gz
Algorithm Hash digest
SHA256 27caf83f580f5d4a1508b12e4afb9b9e3bd2b8f081ab30b22d36186e60ed9b36
MD5 e322ab4727644210f13ddffcef939ca0
BLAKE2b-256 26ed6ac69c77a67e0e249fb71a7223bc1e67065d5dee5892727abecdd92579f1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: cadence_sdk-2.0.9-py3-none-any.whl
  • Upload date:
  • Size: 32.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.9-py3-none-any.whl
Algorithm Hash digest
SHA256 fed1f6d08cbd167b66853fdfc3f59ac7acafeccc8fe5a32deeb0ff9e8c16a0cc
MD5 9df09cfac05fefc76f1f8ca8e3b86009
BLAKE2b-256 44c233b622b6896385cc48ae7207fcb87a122c8263067506addf0362dbd888d4

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