Official Python SDK for building and deploying agents on the Circuit platform
Project description
Circuit Agent SDK - Python
Clean, type-safe Python SDK for building cross-chain agents on the circuit platform
A Python SDK for building automated agents to deploy on Circuit. Features a simple API surface with just 2 core methods plus platform integrations with full type safety.
💡 Best used with Circuit Agents CLI - Deploy, manage, and test your agents with ease
✨ Features
- 🎯 Simple API: 2 core methods (
send_log(),sign_and_send()) + platform integrations - 🔒 Type Hinting: Network parameter determines valid request shapes automatically
- 🚀 Cross-Chain: Unified interface for EVM and Solana networks
- 🌉 Cross-Chain Swaps: Built-in Swidge integration for seamless token swaps and bridges
- 📈 Polymarket Integration: Trade prediction markets with
sdk.polymarket.*methods
🚀 Quick Start
Install the SDK
pip install circuit-agent-sdk
# or with uv
uv pip install circuit-agent-sdk
Sample SDK Usage
NOTE: The fastest, and recommended, way to get started is to setup an agent via the circuit CLI's 'circuit agent init' command. This will setup a sample agent directory with the necessary agent wireframe, and configure the cli to allow you for easy testing and deployment. You just simply need to add in your secret formula to the execution and stop functions.
from agent_sdk import AgentSdk, SDKConfig
# Initialize the sdk
sdk = AgentSdk(SDKConfig(
session_id=123
))
🎯 Core SDK API (Only 2 Methods!)
1. Add Logs to Timeline
await sdk.send_log({
"type": "observe",
"short_message": "Starting swap operation"
})
2. Sign & Send Transactions
Ethereum (any EVM chain)
# 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
await sdk.sign_and_send({
"network": "ethereum:42161", # Arbitrum
"request": {
"to_address": "0xTokenContract...",
"data": "0xa9059cbb...", # encoded transfer()
"value": "0"
}
})
Solana
await sdk.sign_and_send({
"network": "solana",
"request": {
"hex_transaction": "010001030a0b..." # serialized VersionedTransaction
}
})
🌉 Cross-Chain Swaps with Swidge
The SDK includes built-in Swidge integration for seamless cross-chain token swaps and bridges.
Swidge provides a unified interface that handles both swapping (exchanging tokens within the same network) and bridging (moving tokens across different networks) through a single, easy-to-use API. Whether you're doing a simple token swap on Ethereum or bridging assets across chains, the same quote-and-execute pattern works for everything.
3. Cross-Chain Swaps & Bridges
Get a Quote
# 🌉 Bridge USDC: Polygon → Arbitrum
bridge_quote = sdk.swidge.quote({
"from": {"network": "ethereum:137", "address": user_address},
"to": {"network": "ethereum:42161", "address": user_address},
"amount": "50000000", # $50 USDC (6 decimals)
"fromToken": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", # USDC on Polygon
"toToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", # USDC on Arbitrum
"slippage": "2.0", # 2% slippage for cross-chain (default: 0.5%)
"priceImpact": "1.0" # 1% max price impact (default: 0.5%)
})
# 🔄 Swap USDC → ETH on same chain (using defaults)
swap_quote = sdk.swidge.quote({
"from": {"network": "ethereum:42161", "address": user_address},
"to": {"network": "ethereum:42161", "address": user_address},
"amount": "100000000", # $100 USDC (6 decimals)
"fromToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", # USDC
# toToken omitted = native ETH (default behavior)
# slippage defaults to "0.5", priceImpact defaults to "0.5"
})
if quote.success and quote.data:
print(f"💰 You'll receive: {quote.data.asset_receive.amountFormatted}")
print(f"💸 Total fees: {', '.join([f.name for f in quote.data.fees])}")
elif quote.error:
# Check for specific error types
if quote.error == "Wallet not found":
print("👛 Wallet not found")
elif quote.error == "From wallet does not match session wallet":
print("🔐 Wallet address doesn't match session")
else:
print("❓ Quote not available for this swap")
Execute a Swap
# 1️⃣ Get a quote first
quote_request = {
"from": {"network": "ethereum:42161", "address": user_address},
"to": {"network": "ethereum:1", "address": user_address},
"amount": "100000000", # $100 USDC
"fromToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", # USDC on Arbitrum
"priceImpact": "0.1", # Conservative price impact setting
"slippage": "5.0"
}
quote = sdk.swidge.quote(quote_request)
# 2️⃣ Handle quote failures with retry logic
if quote.error == "No quote provided":
print("❓ Quote not available, increasing price impact and retrying...")
# Retry with more permissive parameters
quote_request["priceImpact"] = "10.0"
quote_request["slippage"] = "10.0"
quote = sdk.swidge.quote(quote_request)
# 3️⃣ Execute the swap if quote succeeded
if quote.success and quote.data:
print(f"💰 Expected to receive: {quote.data.asset_receive.amountFormatted}")
print(f"💸 Fees: {', '.join([f'{f.name}: {f.amountFormatted}' for f in quote.data.fees])}")
result = sdk.swidge.execute(quote.data)
if result.success and result.data:
print(f"🎉 Status: {result.data.status}")
if result.data.status == "success":
if result.data.in_data and result.data.in_data.txs:
print(f"📤 Sent: {result.data.in_data.txs[0]}")
if result.data.out and result.data.out.txs:
print(f"📥 Received: {result.data.out.txs[0]}")
print("✅ Cross-chain swap completed!")
elif result.data.status == "failure":
print("❌ Transaction failed")
elif result.data.status == "refund":
print("↩️ Transaction was refunded")
elif result.data.status == "delayed":
print("⏰ Transaction is delayed")
else:
print(f"❌ Execute failed: {result.error}")
else:
print(f"❌ Quote failed after retry: {quote.error}")
return {"success": False}
Swidge API Reference
sdk.swidge.quote(request: SwidgeQuoteRequest | dict) -> SwidgeQuoteResponse
Get pricing and routing information for token swaps between networks or within the same network.
Parameters:
{
"from": {"network": str, "address": str},
"to": {"network": str, "address": str},
"amount": str, # Amount in token's smallest unit
"fromToken": str | None, # Source token contract (omit for native tokens)
"toToken": str | None, # Destination token contract (omit for native tokens)
"slippage": str | None, # Slippage tolerance % (default: "0.5")
"priceImpact": str | None # Max price impact % (default: "0.5")
}
Returns:
{
"success": bool,
"data": {
"engine": "relay",
"asset_send": {
"network": str,
"address": str,
"token": str | None,
"amount": str,
"amountFormatted": str,
"amountUsd": str,
# ... additional fields
},
"asset_receive": {
"network": str,
"address": str,
"token": str | None,
"amount": str,
"amountFormatted": str,
"amountUsd": str,
# ... additional fields
},
"priceImpact": {
"usd": str | None,
"percentage": str | None
},
"fees": [
{
"name": str,
"amount": str | None,
"amountFormatted": str | None,
"amountUsd": str | None
}
],
"steps": [
# Transaction and signature steps
]
} | None,
"error": str | None,
"errorDetails": dict | None
}
⚠️ Important Notes:
- Small amounts may fail: Use at least $10-20 worth to avoid fee/slippage issues
- Slippage matters: Default is 0.5% for most cases, increase to 1-2% for volatile pairs
- Different networks = bridge: Same network = swap
sdk.swidge.execute(quoteData: SwidgeQuoteData) -> SwidgeExecuteResponse
Execute a cross-chain swap or bridge using a quote from sdk.swidge.quote().
⚠️ What happens:
- Signs transactions using your wallet's policy engine
- Broadcasts to the blockchain(s)
- Waits for cross-chain completion (this may take some time depending on network status)
- Returns final status with transaction hashes
Parameters:
quote_data: Complete quote object fromsdk.swidge.quote()
Returns:
{
"success": bool,
"data": {
"status": "success" | "failure" | "refund" | "delayed",
"in": {
"network": str,
"txs": [str] # Transaction hashes
},
"out": {
"network": str,
"txs": [str] # Transaction hashes
},
"lastUpdated": int # Timestamp
} | None,
"error": str | None,
"errorDetails": dict | None
}
📈 Polymarket Prediction Markets
The SDK includes built-in Polymarket integration for trading prediction markets on Polygon.
4. Polymarket Trading
Get Positions
Fetch all current positions for the session wallet:
positions = sdk.polymarket.positions()
if positions.success and positions.data:
print(f"Total value: ${positions.data.totalValue}")
for position in positions.data.positions:
print(f"{position.question} ({position.outcome})")
print(f" Shares: {position.formattedShares}")
print(f" Value: ${position.valueUsd}")
print(f" P&L: ${position.pnlUsd} ({position.pnlPercent}%)")
Place Market Orders
Execute buy or sell market orders:
# Buy order - size is USD amount to spend
buy_order = sdk.polymarket.market_order({
"tokenId": "123456789...", # Market token ID
"size": 10, # Spend $10 to buy shares
"side": "BUY"
})
# Sell order - size is number of shares to sell
sell_order = sdk.polymarket.market_order({
"tokenId": "123456789...",
"size": 5.5, # Sell 5.5 shares
"side": "SELL"
})
if buy_order.success and buy_order.data:
print(f"Order Success: {buy_order.data.success}")
print(f"Order ID: {buy_order.data.orderInfo.orderId}")
print(f"Filled at ${buy_order.data.orderInfo.priceUsd} per share")
print(f"Total cost: ${buy_order.data.orderInfo.totalPriceUsd}")
else:
print(f"Error: {buy_order.error}")
Redeem Positions
Claim winnings from settled positions:
# Redeem all redeemable positions
redemption = sdk.polymarket.redeem_positions()
if redemption.success and redemption.data:
for result in redemption.data:
if result.success and result.transactionHash:
print(f"✅ Redeemed: {result.position.question}")
print(f" TX: {result.transactionHash}")
else:
print(f"❌ Failed to redeem: {result.position.question}")
else:
print(f"Error: {redemption.error}")
# Redeem specific positions by token IDs
specific_redemption = sdk.polymarket.redeem_positions({
"tokenIds": ["123456", "789012"]
})
if specific_redemption.success and specific_redemption.data:
print(f"Redeemed {len([r for r in specific_redemption.data if r.success])} positions")
else:
print(f"Error: {specific_redemption.error}")
Polymarket API Reference
sdk.polymarket.positions() -> PolymarketPositionsResponse
Get all current positions for the session wallet.
Returns:
PolymarketPositionsResponse(
success=bool,
data=PolymarketPositionsData(
totalValue=float,
positions=[
PolymarketPosition(
contractAddress=str,
tokenId=str,
question=str,
outcome=str,
formattedShares=str,
shares=str,
valueUsd=str,
priceUsd=str,
averagePriceUsd=str,
pnlUsd=str,
pnlPercent=str,
isRedeemable=bool,
endDate=str,
# ... additional fields
)
]
) | None,
error=str | None,
errorDetails=dict | None
)
sdk.polymarket.market_order(request: PolymarketMarketOrderRequest | dict) -> PolymarketMarketOrderResponse
Place a buy or sell market order.
⚠️ Important: The size parameter meaning differs by order side:
- BUY:
sizeis the USD amount to spend (e.g., 10 = $10 worth of shares) - SELL:
sizeis the number of shares/tokens to sell (e.g., 10 = 10 shares)
Parameters:
{
"tokenId": str, # Market token ID for the position
"size": float, # For BUY: USD amount. For SELL: Number of shares
"side": "BUY" | "SELL"
}
Returns:
PolymarketMarketOrderResponse(
success=bool,
data=PolymarketMarketOrderData(
success=bool, # Whether the order was successfully submitted
orderInfo=PolymarketOrderInfo(
orderId=str,
side=str,
size=str,
priceUsd=str,
totalPriceUsd=str,
txHashes=list[str]
)
) | None,
error=str | None,
errorDetails=dict | None
)
sdk.polymarket.redeem_positions(request: PolymarketRedeemPositionsRequest | dict | None = None) -> PolymarketRedeemPositionsResponse
Redeem settled positions to claim winnings.
Parameters (optional):
{
"tokenIds": list[str] # Specific token IDs to redeem (default: all redeemable positions)
}
Returns:
PolymarketRedeemPositionsResponse(
success=bool,
data=list[
PolymarketRedeemPositionResult(
success=bool,
position=PolymarketPosition(...),
transactionHash=str | None
)
] | None,
error=str | None,
errorDetails=dict | None
)
Complete Polymarket Example
from agent_sdk import Agent, AgentRequest, AgentResponse, AgentSdk, SDKConfig
def execution_function(request: AgentRequest) -> AgentResponse:
sdk = AgentSdk(SDKConfig(session_id=request.sessionId))
try:
# Get current positions
positions = sdk.polymarket.positions()
if not positions.success or not positions.data:
raise Exception(f"Failed to get positions: {positions.error}")
# Find specific position
target_position = next(
(p for p in positions.data.positions if p.tokenId == "YOUR_TOKEN_ID"),
None
)
if target_position and float(target_position.formattedShares) > 0:
# Sell position
sell_order = sdk.polymarket.market_order({
"tokenId": target_position.tokenId,
"size": float(target_position.formattedShares),
"side": "SELL"
})
if sell_order.success and sell_order.data:
sdk.send_log({
"type": "observe",
"short_message": f"Sold {target_position.outcome} for ${sell_order.data.orderInfo.totalPriceUsd}"
})
return AgentResponse(success=True)
except Exception as error:
sdk.send_log({
"type": "error",
"short_message": f"Error: {str(error)}"
})
return AgentResponse(success=False, error=str(error))
def stop_function(request: AgentRequest) -> AgentResponse:
sdk = AgentSdk(SDKConfig(session_id=request.sessionId))
try:
# Redeem all settled positions on stop
redemption = sdk.polymarket.redeem_positions()
if redemption.success and redemption.data:
successful = [r for r in redemption.data if r.success]
sdk.send_log({
"type": "observe",
"short_message": f"✅ Redeemed {len(successful)} positions"
})
else:
sdk.send_log({
"type": "error",
"short_message": f"Failed to redeem positions: {redemption.error}"
})
return AgentResponse(success=True)
except Exception as error:
return AgentResponse(success=False, error=str(error))
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file circuit_agent_sdk-1.1.7.tar.gz.
File metadata
- Download URL: circuit_agent_sdk-1.1.7.tar.gz
- Upload date:
- Size: 142.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30e984086eee6af8ac1ca73ece1e8f8f21d2ae5e7eeef0fd6fad5341fa5b719e
|
|
| MD5 |
d84ba1bd75aa7aecf71835d288637c25
|
|
| BLAKE2b-256 |
7ff050aeff66e5d5b30e36d8c5534746101316a4060dcf762bae41a0c9f4f4ef
|
File details
Details for the file circuit_agent_sdk-1.1.7-py3-none-any.whl.
File metadata
- Download URL: circuit_agent_sdk-1.1.7-py3-none-any.whl
- Upload date:
- Size: 44.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fefe2c7714c264b5e235dcf1a51e9d7f944514f3d20841a9231a5de5c3184989
|
|
| MD5 |
4f6176c3629f7874d1d5009218a342e2
|
|
| BLAKE2b-256 |
7e85b622666eab6da90129eed912667808c1a1699ac2e192ff999dbaf50f3917
|