Installation
SDK requires Python 3.10+. Install latest via pip.
pip install ieda-agent-sdk
# Verify installation
python -c "import ieda; print(ieda.__version__)"
# Output: 0.2.0
# Install with optional dependencies
pip install ieda-agent-sdk[dev] # Development tools: pytest, mypy, ruff
pip install ieda-agent-sdk[tracing] # Performance tracing support
pip install ieda-agent-sdk[all] # Everything
Configuration
Configure via env vars, config file, or code init. Priority: code params > env vars > config file.
Environment variables
# Required
export IEDA_HOST=localhost # iEDA Platform address
export IEDA_PORT=9090 # Interface gateway port
# Optional
export IEDA_PROTOCOL=python # Default protocol: python | mcp | tcl
export IEDA_TIMEOUT_MS=30000 # Default timeout (ms)
export IEDA_TRACING=false # Enable performance tracing
export IEDA_MAX_RETRIES=3 # Default retry count
export IEDA_LOG_LEVEL=INFO # Log level: DEBUG | INFO | WARN | ERROR
Config file
# ~/.ieda/config.yaml
host: localhost
port: 9090
protocol: python
timeout_ms: 30000
tracing: false
max_retries: 3
log_level: INFO
connection:
pool_size: 4
keepalive_sec: 60
reconnect_delay_ms: 1000
Connection settings
from ieda import AgentClient
# Minimal configuration
client = AgentClient()
client.connect()
# Full configuration
client = AgentClient(
host="ieda-platform.local",
port=9090,
protocol="python",
timeout_ms=60000,
tracing=True,
log_level="DEBUG",
connection_pool_size=8,
keepalive_sec=30,
)
client.connect()
assert client.is_connected()
Error handling
SDK defines layered exceptions—from network to tool layer—each with clear meaning and recovery guidance.
Exception hierarchy
IEDAError # Base exception
├── ConnectionError # Network: cannot connect / disconnected
│ ├── ConnectionRefused
│ └── ConnectionTimeout
├── ValidationError # Params: schema validation failed
│ ├── MissingField
│ ├── InvalidType
│ └── OutOfRange
├── ToolError # Tool layer: execution failed
│ ├── ToolNotFound
│ └── ToolExecutionError
├── TimeoutError # Timeout
├── GateFailure # Gate: evaluation gate failed
├── CASConflict # Concurrency: CAS commit conflict
└── RateLimitError # Rate limit exceeded
Retry strategy
from ieda import retry, RetryConfig
# Built-in retry with exponential backoff
result = retry(
lambda: client.call("iSTA.analyze", snap=snap.id),
config=RetryConfig(
max_attempts=3,
backoff_ms=1000,
backoff_multiplier=2.0,
max_backoff_ms=30000,
retry_on={TimeoutError, ConnectionError},
),
)
# Manual retry with CAS conflict handling
for attempt in range(3):
try:
result = client.call("iDB.commit", expected_head=head, proposal=prop)
break
except CASConflict as e:
print(f"Rebasing to {e.conflict_with} (attempt {attempt+1})")
prop = rebase_proposal(prop, e.conflict_with)
Degraded mode
# Graceful degradation when a tool is unavailable
try:
timing = client.call("iSTA.analyze", snap=snap.id)
except ToolNotFound:
logging.warning("iSTA not available — falling back to basic timing")
timing = basic_timing_estimate(design)
except RateLimitError:
logging.warning("Rate limited — using cached result")
timing = cache.get("timing", snap.id)
Best practices
Batch operations
# Avoid: N individual calls
for cell in critical_cells:
result = client.call("iDB.inspect", cell_id=cell.id) # Latency adds up
# Prefer: single batch call
results = client.call("iDB.batch_inspect", cell_ids=[c.id for c in critical_cells])
Result caching
from ieda import cached_call
# Cache snapshot-based results — same snap = same result
timing = cached_call(
client, "iSTA.analyze",
snap=snap.id,
ttl_sec=300, # Cache for 5 minutes
)
Connection pool reuse
# Production setup — reuse connection pool
client = AgentClient(connection_pool_size=8)
client.connect()
# Use context manager for automatic cleanup
with AgentClient(connection_pool_size=4) as client:
design = client.load_design("aes_core", tech="sky130")
result = client.call("iPL.place", design=design)
# Connection pool automatically closed
Graceful shutdown
import signal
client = AgentClient()
client.connect()
def shutdown(signum, frame):
print("Shutting down...")
client.disconnect()
print("Disconnected.")
signal.signal(signal.SIGINT, shutdown)
signal.signal(signal.SIGTERM, shutdown)
Health check
# Periodic health check in long-running agents
def ensure_connected(client: AgentClient):
if not client.is_connected():
logging.warning("Connection lost — reconnecting...")
client.connect()
health = client.health_check()
if not health.ok:
raise ConnectionError(f"Platform unhealthy: {health.message}")