circuit-agent-sdk


Namecircuit-agent-sdk JSON
Version 0.3.2 PyPI version JSON
download
home_pageNone
SummaryOfficial Python SDK for building and deploying agents on the Circuit platform
upload_time2025-08-20 23:33:35
maintainerNone
docs_urlNone
authorNone
requires_python>=3.12
licenseProprietary
keywords agent circuit sdk
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 🚀 Agent SDK (Python)

> **A simple Python SDK for building cross-chain agents**

[![PyPI version](https://badge.fury.io/py/circuit-agent-sdk.svg)](https://badge.fury.io/py/circuit-agent-sdk)
[![Python Version](https://img.shields.io/pypi/pyversions/circuit-agent-sdk.svg)](https://pypi.org/project/circuit-agent-sdk/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A Python SDK for building automated agents to deploy on Circuit. Features an incredibly simple API surface with just **2 main methods**.

> **💡 Best used with [Circuit Agents CLI](https://github.com/circuitorg/agents-cli)** - Deploy, manage, and test your agents with ease

## 📖 SDK Philosophy

This SDK is built on a **low-level first** approach:

1. **Core Functionality**: At its heart, the SDK provides `sign_and_send()` - a single, powerful method that accepts any pre-built transaction for any supported network. This gives you complete control over transaction construction.


2. **Bring Your Own Tools**: For production agents, we recommend using:
   - **Solana**: Use `solana-py`, `solders`, or `anchorpy` for transaction construction
   - **EVM**: Use `web3.py` or `eth-account` for transaction building
   - **RPC**: Make your own RPC calls for complex queries and custom needs


## ✨ Features

- **🎯 Simple API**: Only 2 main methods - `add_message()` and `sign_and_send()`
- **🔒 Type Hinting**: Network parameter determines valid request shapes automatically
- **🚀 Cross-Chain**: Unified interface for EVM and Solana networks
- **⚡ Low-Level Control**: `sign_and_send()` accepts any pre-built transaction
- **🛠️ Smart Deployment**: The agent wrapper detects its environment and exposes the necessary endpoints and handlers so you can focus on execution logic and easily test locally via our CLI tool

## 🚀 Quick Start

### Install the SDK

```bash
pip install circuit-agent-sdk
# or with uv
uv pip install circuit-agent-sdk
```

### Sample usage
>**Tip:** Use the cli tool to spin up a sample agent, simple run 'circuit agent init' and select the python option. This will give you a fully functioning agent that will send a sample message. Simply plug in your execution logic, we will handle the rest.
```python
"""
Circuit Agent - Python SDK Example

This demonstrates how to use the Circuit Agent Python SDK to create
an agent that can run locally via FastAPI and deploy to AWS Lambda.
"""

from agent_sdk import (
    Agent,
    AgentRequest,
    AgentResponse,
    AgentSdk,
    SDKConfig,
    setup_logging,
)

# Set up logging
logger = setup_logging()
logger.info("Python Agent SDK module loaded - executing main.py")


async def execution_function(request: AgentRequest) -> AgentResponse:
    """
    Main execution function for the agent.

    This function demonstrates proper usage of the Circuit Agent SDK with
    the new clean API using add_message() and sign_and_send().

    Args:
        request: Validated request containing sessionId,
                sessionWalletAddress, and otherParameters

    Returns:
        AgentResponse: Validated response indicating success/failure
    """
    # Create SDK instance with the session ID from the request
    sdk = AgentSdk(
        SDKConfig(session_id=request.sessionId, verbose=True)  # Enable debug logging
    )

    try:
        # Send observation message
        await sdk.add_message(
            {
                "type": "observe",
                "short_message": f"Python SDK Agent - Checking balance for {request.sessionWalletAddress[:8]}...",
            }
        )

        # Example transaction (commented out for safety)
        # result = await sdk.sign_and_send({
        #     "network": "ethereum:1",
        #     "request": {
        #         "to_address": request.sessionWalletAddress,
        #         "data": "0x",
        #         "value": "100000000000000000"  # 0.1 ETH
        #     },
        #     "message": "Self-transfer demo"
        # })

        # Return success response
        return AgentResponse(success=True, message="Execution completed")

    except Exception as error:
        logger.error(f"Error in agent execution: {error}")

        try:
            # Send error message to user
            await sdk.add_message(
                {
                    "type": "error",
                    "short_message": f"Agent execution error: {str(error)}",
                }
            )
        except Exception as msg_error:
            logger.error(f"Failed to send error message: {msg_error}")

        return AgentResponse(success=False, error=str(error))


async def stop_function(request: AgentRequest) -> AgentResponse:
    """
    Agent stop/cleanup function.

    This function is called when an agent session is being stopped.
    Use this to perform any necessary cleanup operations.

    Args:
        request: Validated request containing sessionId, sessionWalletAddress, and otherParameters

    Returns:
        AgentResponse: Validated response indicating cleanup success/failure
    """
    # Create SDK for cleanup operations
    sdk = AgentSdk(SDKConfig(session_id=request.sessionId))

    try:
        # Notify about cleanup
        await sdk.add_message(
            {
                "type": "observe",
                "short_message": f"Agent session {request.sessionId} stopping...",
            }
        )

        return AgentResponse(success=True, message="Cleanup completed")

    except Exception as error:
        logger.error(f"Error in stop function: {error}")
        return AgentResponse(success=False, error=str(error))


# NOTE: Everything below this should remain unchanged, unless you want to
# customize the agent configuration. This setup ensures you can run the agent
# locally and in the Circuit platform without any changes.

# Create the agent (configuration read from pyproject.toml)
agent = Agent(execution_function=execution_function, stop_function=stop_function)

# Export the Lambda handler for AWS deployment
handler = agent.get_lambda_handler()

# Local development server
if __name__ == "__main__":
    logger.info("Starting Circuit Agent development server...")
    logger.info(
        "The agent will automatically log available endpoints and example usage"
    )

    # Start the server for local development
    agent.run()
```

## 🎯 Core API (Only 2 Methods!)

The SDK is designed around just two main methods that cover all agent interactions:

### 1. Add Messages to Timeline

> **Use this for all agent communication and observability**

```python
await sdk.add_message({
    "type": "observe",
    "short_message": "Starting swap operation"
})

# Long messages are automatically truncated to 250 characters (when using dict input)
await sdk.add_message({
    "type": "observe",
    "short_message": "This is a very long message that will be automatically truncated if it exceeds 250 characters to prevent validation failures and ensure the message gets through successfully"
})

# Note: Pydantic models must be valid when created (max 250 chars)
# Dict inputs are automatically truncated by the SDK

## ✂️ Smart Message Truncation

The SDK automatically handles long messages to prevent validation failures:

```python
# Long messages are automatically truncated to 250 characters
await sdk.add_message({
    "type": "error",
    "short_message": "This is a very long error message that contains a lot of details and would normally cause validation to fail because it exceeds 250 characters, but the SDK automatically truncates it and adds '...' to indicate truncation, ensuring your message gets through successfully"
})

# Result: Message is truncated to 250 chars with "..." suffix
# This prevents the common error: "String should have at most 250 characters"
```

**How it works:**
- **Dict inputs**: Automatically truncated before validation
- **Pydantic models**: Must be valid when created (max 250 chars)
- **Truncation**: Adds "..." suffix to indicate truncation
- **Logging**: Debug logs show when truncation occurs

### 2. Sign & Send Transactions

> **This is the core method for executing transactions across all supported networks**

The `sign_and_send()` method accepts **any pre-built transaction** for the target network. You have complete control over how you build these transactions.

#### Ethereum (any EVM chain)

```python
# Native ETH transfer
await sdk.sign_and_send({
    "network": "ethereum:1",  # Chain ID in network string
    "request": {
        "to_address": "0x742d35cc6634C0532925a3b8D65e95f32B6b5582",
        "data": "0x",
        "value": "1000000000000000000"  # 1 ETH in wei
    },
    "message": "Sending 1 ETH"
})

# Contract interaction (e.g., ERC-20 transfer)
await sdk.sign_and_send({
    "network": "ethereum:42161",  # Arbitrum
    "request": {
        "to_address": "0xTokenContract...",
        "data": "0xa9059cbb...",  # encoded transfer(address,uint256)
        "value": "0"
    },
    "message": "ERC-20 transfer"
})

# You can build the transaction data using web3.py:
from web3 import Web3
w3 = Web3()
contract = w3.eth.contract(abi=ERC20_ABI)
data = contract.encodeABI(fn_name="transfer", args=[recipient, amount])
```

#### Solana

```python
# Any Solana transaction (transfers, swaps, etc.)
await sdk.sign_and_send({
    "network": "solana",
    "request": {
        "hex_transaction": "010001030a0b..."  # serialized VersionedTransaction
    },
    "message": "Solana transaction"
})

# Build transactions using solana-py or solders:
from solders.transaction import VersionedTransaction
from solders.message import Message
# ... build your transaction
tx = VersionedTransaction(message, [NullSigner(payer)])
hex_transaction = bytes(tx).hex()

# Or use our optional utilities for simple cases:
from agent_sdk.utils.solana import create_native_sol_transfer_transaction
hex_tx = await create_native_sol_transfer_transaction(...)
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "circuit-agent-sdk",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "agent, circuit, sdk",
    "author": null,
    "author_email": "Circuit <kyle@selvlabs.com>",
    "download_url": "https://files.pythonhosted.org/packages/d1/7b/d284fd0042899556a4284d62189c8df0aa2215cf5a1670da508e386721d2/circuit_agent_sdk-0.3.2.tar.gz",
    "platform": null,
    "description": "# \ud83d\ude80 Agent SDK (Python)\n\n> **A simple Python SDK for building cross-chain agents**\n\n[![PyPI version](https://badge.fury.io/py/circuit-agent-sdk.svg)](https://badge.fury.io/py/circuit-agent-sdk)\n[![Python Version](https://img.shields.io/pypi/pyversions/circuit-agent-sdk.svg)](https://pypi.org/project/circuit-agent-sdk/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA Python SDK for building automated agents to deploy on Circuit. Features an incredibly simple API surface with just **2 main methods**.\n\n> **\ud83d\udca1 Best used with [Circuit Agents CLI](https://github.com/circuitorg/agents-cli)** - Deploy, manage, and test your agents with ease\n\n## \ud83d\udcd6 SDK Philosophy\n\nThis SDK is built on a **low-level first** approach:\n\n1. **Core Functionality**: At its heart, the SDK provides `sign_and_send()` - a single, powerful method that accepts any pre-built transaction for any supported network. This gives you complete control over transaction construction.\n\n\n2. **Bring Your Own Tools**: For production agents, we recommend using:\n   - **Solana**: Use `solana-py`, `solders`, or `anchorpy` for transaction construction\n   - **EVM**: Use `web3.py` or `eth-account` for transaction building\n   - **RPC**: Make your own RPC calls for complex queries and custom needs\n\n\n## \u2728 Features\n\n- **\ud83c\udfaf Simple API**: Only 2 main methods - `add_message()` and `sign_and_send()`\n- **\ud83d\udd12 Type Hinting**: Network parameter determines valid request shapes automatically\n- **\ud83d\ude80 Cross-Chain**: Unified interface for EVM and Solana networks\n- **\u26a1 Low-Level Control**: `sign_and_send()` accepts any pre-built transaction\n- **\ud83d\udee0\ufe0f Smart Deployment**: The agent wrapper detects its environment and exposes the necessary endpoints and handlers so you can focus on execution logic and easily test locally via our CLI tool\n\n## \ud83d\ude80 Quick Start\n\n### Install the SDK\n\n```bash\npip install circuit-agent-sdk\n# or with uv\nuv pip install circuit-agent-sdk\n```\n\n### Sample usage\n>**Tip:** Use the cli tool to spin up a sample agent, simple run 'circuit agent init' and select the python option. This will give you a fully functioning agent that will send a sample message. Simply plug in your execution logic, we will handle the rest.\n```python\n\"\"\"\nCircuit Agent - Python SDK Example\n\nThis demonstrates how to use the Circuit Agent Python SDK to create\nan agent that can run locally via FastAPI and deploy to AWS Lambda.\n\"\"\"\n\nfrom agent_sdk import (\n    Agent,\n    AgentRequest,\n    AgentResponse,\n    AgentSdk,\n    SDKConfig,\n    setup_logging,\n)\n\n# Set up logging\nlogger = setup_logging()\nlogger.info(\"Python Agent SDK module loaded - executing main.py\")\n\n\nasync def execution_function(request: AgentRequest) -> AgentResponse:\n    \"\"\"\n    Main execution function for the agent.\n\n    This function demonstrates proper usage of the Circuit Agent SDK with\n    the new clean API using add_message() and sign_and_send().\n\n    Args:\n        request: Validated request containing sessionId,\n                sessionWalletAddress, and otherParameters\n\n    Returns:\n        AgentResponse: Validated response indicating success/failure\n    \"\"\"\n    # Create SDK instance with the session ID from the request\n    sdk = AgentSdk(\n        SDKConfig(session_id=request.sessionId, verbose=True)  # Enable debug logging\n    )\n\n    try:\n        # Send observation message\n        await sdk.add_message(\n            {\n                \"type\": \"observe\",\n                \"short_message\": f\"Python SDK Agent - Checking balance for {request.sessionWalletAddress[:8]}...\",\n            }\n        )\n\n        # Example transaction (commented out for safety)\n        # result = await sdk.sign_and_send({\n        #     \"network\": \"ethereum:1\",\n        #     \"request\": {\n        #         \"to_address\": request.sessionWalletAddress,\n        #         \"data\": \"0x\",\n        #         \"value\": \"100000000000000000\"  # 0.1 ETH\n        #     },\n        #     \"message\": \"Self-transfer demo\"\n        # })\n\n        # Return success response\n        return AgentResponse(success=True, message=\"Execution completed\")\n\n    except Exception as error:\n        logger.error(f\"Error in agent execution: {error}\")\n\n        try:\n            # Send error message to user\n            await sdk.add_message(\n                {\n                    \"type\": \"error\",\n                    \"short_message\": f\"Agent execution error: {str(error)}\",\n                }\n            )\n        except Exception as msg_error:\n            logger.error(f\"Failed to send error message: {msg_error}\")\n\n        return AgentResponse(success=False, error=str(error))\n\n\nasync def stop_function(request: AgentRequest) -> AgentResponse:\n    \"\"\"\n    Agent stop/cleanup function.\n\n    This function is called when an agent session is being stopped.\n    Use this to perform any necessary cleanup operations.\n\n    Args:\n        request: Validated request containing sessionId, sessionWalletAddress, and otherParameters\n\n    Returns:\n        AgentResponse: Validated response indicating cleanup success/failure\n    \"\"\"\n    # Create SDK for cleanup operations\n    sdk = AgentSdk(SDKConfig(session_id=request.sessionId))\n\n    try:\n        # Notify about cleanup\n        await sdk.add_message(\n            {\n                \"type\": \"observe\",\n                \"short_message\": f\"Agent session {request.sessionId} stopping...\",\n            }\n        )\n\n        return AgentResponse(success=True, message=\"Cleanup completed\")\n\n    except Exception as error:\n        logger.error(f\"Error in stop function: {error}\")\n        return AgentResponse(success=False, error=str(error))\n\n\n# NOTE: Everything below this should remain unchanged, unless you want to\n# customize the agent configuration. This setup ensures you can run the agent\n# locally and in the Circuit platform without any changes.\n\n# Create the agent (configuration read from pyproject.toml)\nagent = Agent(execution_function=execution_function, stop_function=stop_function)\n\n# Export the Lambda handler for AWS deployment\nhandler = agent.get_lambda_handler()\n\n# Local development server\nif __name__ == \"__main__\":\n    logger.info(\"Starting Circuit Agent development server...\")\n    logger.info(\n        \"The agent will automatically log available endpoints and example usage\"\n    )\n\n    # Start the server for local development\n    agent.run()\n```\n\n## \ud83c\udfaf Core API (Only 2 Methods!)\n\nThe SDK is designed around just two main methods that cover all agent interactions:\n\n### 1. Add Messages to Timeline\n\n> **Use this for all agent communication and observability**\n\n```python\nawait sdk.add_message({\n    \"type\": \"observe\",\n    \"short_message\": \"Starting swap operation\"\n})\n\n# Long messages are automatically truncated to 250 characters (when using dict input)\nawait sdk.add_message({\n    \"type\": \"observe\",\n    \"short_message\": \"This is a very long message that will be automatically truncated if it exceeds 250 characters to prevent validation failures and ensure the message gets through successfully\"\n})\n\n# Note: Pydantic models must be valid when created (max 250 chars)\n# Dict inputs are automatically truncated by the SDK\n\n## \u2702\ufe0f Smart Message Truncation\n\nThe SDK automatically handles long messages to prevent validation failures:\n\n```python\n# Long messages are automatically truncated to 250 characters\nawait sdk.add_message({\n    \"type\": \"error\",\n    \"short_message\": \"This is a very long error message that contains a lot of details and would normally cause validation to fail because it exceeds 250 characters, but the SDK automatically truncates it and adds '...' to indicate truncation, ensuring your message gets through successfully\"\n})\n\n# Result: Message is truncated to 250 chars with \"...\" suffix\n# This prevents the common error: \"String should have at most 250 characters\"\n```\n\n**How it works:**\n- **Dict inputs**: Automatically truncated before validation\n- **Pydantic models**: Must be valid when created (max 250 chars)\n- **Truncation**: Adds \"...\" suffix to indicate truncation\n- **Logging**: Debug logs show when truncation occurs\n\n### 2. Sign & Send Transactions\n\n> **This is the core method for executing transactions across all supported networks**\n\nThe `sign_and_send()` method accepts **any pre-built transaction** for the target network. You have complete control over how you build these transactions.\n\n#### Ethereum (any EVM chain)\n\n```python\n# Native ETH transfer\nawait sdk.sign_and_send({\n    \"network\": \"ethereum:1\",  # Chain ID in network string\n    \"request\": {\n        \"to_address\": \"0x742d35cc6634C0532925a3b8D65e95f32B6b5582\",\n        \"data\": \"0x\",\n        \"value\": \"1000000000000000000\"  # 1 ETH in wei\n    },\n    \"message\": \"Sending 1 ETH\"\n})\n\n# Contract interaction (e.g., ERC-20 transfer)\nawait sdk.sign_and_send({\n    \"network\": \"ethereum:42161\",  # Arbitrum\n    \"request\": {\n        \"to_address\": \"0xTokenContract...\",\n        \"data\": \"0xa9059cbb...\",  # encoded transfer(address,uint256)\n        \"value\": \"0\"\n    },\n    \"message\": \"ERC-20 transfer\"\n})\n\n# You can build the transaction data using web3.py:\nfrom web3 import Web3\nw3 = Web3()\ncontract = w3.eth.contract(abi=ERC20_ABI)\ndata = contract.encodeABI(fn_name=\"transfer\", args=[recipient, amount])\n```\n\n#### Solana\n\n```python\n# Any Solana transaction (transfers, swaps, etc.)\nawait sdk.sign_and_send({\n    \"network\": \"solana\",\n    \"request\": {\n        \"hex_transaction\": \"010001030a0b...\"  # serialized VersionedTransaction\n    },\n    \"message\": \"Solana transaction\"\n})\n\n# Build transactions using solana-py or solders:\nfrom solders.transaction import VersionedTransaction\nfrom solders.message import Message\n# ... build your transaction\ntx = VersionedTransaction(message, [NullSigner(payer)])\nhex_transaction = bytes(tx).hex()\n\n# Or use our optional utilities for simple cases:\nfrom agent_sdk.utils.solana import create_native_sol_transfer_transaction\nhex_tx = await create_native_sol_transfer_transaction(...)\n```\n",
    "bugtrack_url": null,
    "license": "Proprietary",
    "summary": "Official Python SDK for building and deploying agents on the Circuit platform",
    "version": "0.3.2",
    "project_urls": {
        "Issues": "https://github.com/circuitorg/agent-sdk-python/issues",
        "Repository": "https://github.com/circuitorg/agent-sdk-python"
    },
    "split_keywords": [
        "agent",
        " circuit",
        " sdk"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "4ecd3886dd3f62aa9905218801609cea2e4d1f2498cbfbc617248d067133fcb2",
                "md5": "99759d0319b6dd23a75708f272149b27",
                "sha256": "04c1a25f2eeeee3693855b89f1484c131ce32107149a4808fbf4395052588dc6"
            },
            "downloads": -1,
            "filename": "circuit_agent_sdk-0.3.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "99759d0319b6dd23a75708f272149b27",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 35787,
            "upload_time": "2025-08-20T23:33:34",
            "upload_time_iso_8601": "2025-08-20T23:33:34.092958Z",
            "url": "https://files.pythonhosted.org/packages/4e/cd/3886dd3f62aa9905218801609cea2e4d1f2498cbfbc617248d067133fcb2/circuit_agent_sdk-0.3.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d17bd284fd0042899556a4284d62189c8df0aa2215cf5a1670da508e386721d2",
                "md5": "4417aea8b82c52cf104a65dca44b093c",
                "sha256": "d04e52e3c3a190291c10e32334059161cfd979f1125da4bc1d82547ec3a337c3"
            },
            "downloads": -1,
            "filename": "circuit_agent_sdk-0.3.2.tar.gz",
            "has_sig": false,
            "md5_digest": "4417aea8b82c52cf104a65dca44b093c",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 134342,
            "upload_time": "2025-08-20T23:33:35",
            "upload_time_iso_8601": "2025-08-20T23:33:35.048959Z",
            "url": "https://files.pythonhosted.org/packages/d1/7b/d284fd0042899556a4284d62189c8df0aa2215cf5a1670da508e386721d2/circuit_agent_sdk-0.3.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-20 23:33:35",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "circuitorg",
    "github_project": "agent-sdk-python",
    "github_not_found": true,
    "lcname": "circuit-agent-sdk"
}
        
Elapsed time: 0.83690s