Building Type-Safe Crypto Agents with PydanticAI
PydanticAI, created by Samuel Colvin (author of Pydantic), brings the same rigorous type safety that Python developers love to the world of AI agents. When you combine PydanticAI's strict schema validation with Purple Flea's financial APIs, you get something powerful: crypto agents that are not just functional, but provably correct at the type level.
This guide walks through building a complete crypto agent with PydanticAI — one that can create wallets, check balances, open trading positions, and play casino games, all with full Pydantic schema validation on every input and output.
Why Type Safety Matters for Financial Agents
Financial operations are uniquely intolerant of errors. Sending 0.1 when you meant 0.01, or passing a Solana address to an Ethereum function, can result in real money loss. Type safety catches these bugs at development time, not at runtime when funds are already moving.
PydanticAI enforces types at the boundary between the LLM and your code. When GPT-4o or Claude calls a tool, PydanticAI validates that the arguments match the expected schema before your code even sees them. This eliminates an entire class of bugs that are common in loosely-typed agent frameworks.
"Type safety in financial agents isn't pedantry — it's the difference between a working treasury and a catastrophic loss."
Installation
# Install PydanticAI and the Purple Flea SDK pip install pydantic-ai purpleflea-pydanticai # Set your API key export PURPLE_FLEA_API_KEY="pf_..."
Defining Typed Tool Schemas
Before building the agent, let's define our Pydantic models for tool inputs and outputs. These schemas are shared between the tool definitions and your business logic, ensuring consistency end-to-end.
from pydantic import BaseModel, Field from typing import Literal # Wallet models class WalletResult(BaseModel): address: str = Field(description="The wallet's public address") chain: str = Field(description="The blockchain this address is for") balance_usd: float = Field(default=0.0) class BalanceRequest(BaseModel): address: str chain: Literal["eth", "btc", "sol", "bnb", "matic", "trx"] = "eth" # Trading models class TradeRequest(BaseModel): market: str = Field(description="e.g. 'ETH-PERP', 'BTC-PERP'") size_usd: float = Field(gt=0, le=100_000) side: Literal["long", "short"] leverage: float = Field(default=1.0, ge=1.0, le=50.0) class TradeResult(BaseModel): position_id: str market: str entry_price: float size_usd: float side: str leverage: float # Casino models class CoinFlipRequest(BaseModel): amount_usd: float = Field(gt=0, le=1000) choice: Literal["heads", "tails"] class CoinFlipResult(BaseModel): outcome: Literal["heads", "tails"] won: bool payout_usd: float proof_hash: str # Cryptographic proof of fairness
Building the Agent
Now we wire everything together with PydanticAI's Agent class and Tool wrapper. Notice how tool functions are typed with the Pydantic models we defined — PydanticAI automatically validates LLM outputs before they reach our functions.
import asyncio import os from pydantic_ai import Agent from pydantic_ai.tools import Tool from purpleflea import PurpleFleas flea = PurpleFleas(api_key=os.environ["PURPLE_FLEA_API_KEY"]) # Define tools as typed async functions async def create_wallet() -> WalletResult: """Create a new non-custodial BIP-39 crypto wallet.""" raw = await flea.wallet.create() return WalletResult(**raw) async def get_balance(request: BalanceRequest) -> WalletResult: """Get the balance of a crypto wallet on a specific chain.""" raw = await flea.wallet.balance(request.address, request.chain) return WalletResult(**raw) async def open_trade(request: TradeRequest) -> TradeResult: """Open a perpetual futures position on Hyperliquid.""" raw = await flea.trading.open_position( market=request.market, size_usd=request.size_usd, side=request.side, leverage=request.leverage, ) return TradeResult(**raw) async def coin_flip(request: CoinFlipRequest) -> CoinFlipResult: """Flip a provably fair coin for a USDC wager.""" raw = await flea.casino.coin_flip( amount=request.amount_usd, choice=request.choice, ) return CoinFlipResult(**raw) # Create the agent with typed tools agent = Agent( model='openai:gpt-4o', tools=[ Tool(create_wallet, takes_ctx=False), Tool(get_balance, takes_ctx=False), Tool(open_trade, takes_ctx=False), Tool(coin_flip, takes_ctx=False), ], system_prompt="""You are a crypto agent with financial capabilities. Always confirm with the user before opening trades or placing bets. Provide clear summaries of any financial operations you perform.""" )
Running the Agent
async def main(): result = await agent.run( "Create a new wallet, then flip a coin for $1 USDC on heads. Show me the proof hash." ) print(result.data) asyncio.run(main())
The agent will call create_wallet(), receive a WalletResult, then call coin_flip(CoinFlipRequest(amount_usd=1.0, choice='heads')). PydanticAI validates both the LLM's function call arguments AND your return values.
Type-Safe Error Handling
PydanticAI's validation happens before your business logic runs. If the LLM hallucinates an invalid leverage value (like 200.0 when max is 50.0), Pydantic catches it at the boundary and returns a structured error to the model for self-correction — no money moves.
from pydantic import ValidationError # This will fail validation before reaching your code # leverage=200 violates le=50.0 constraint try: bad_trade = TradeRequest( market="BTC-PERP", size_usd=100, side="long", leverage=200.0 # INVALID: max is 50 ) except ValidationError as e: print(e.errors()) # [{'type': 'less_than_equal', 'loc': ('leverage',), 'msg': 'Input should be <= 50'}]
Testing Your Agent
Because all inputs and outputs are typed Pydantic models, testing is straightforward. You can mock the Purple Flea client and verify that your agent handles edge cases correctly — without making real API calls or spending real money.
from unittest.mock import AsyncMock, patch async def test_coin_flip_win(): mock_result = CoinFlipResult( outcome="heads", won=True, payout_usd=2.0, proof_hash="0xabc123..." ) with patch.object(flea.casino, 'coin_flip', AsyncMock(return_value=mock_result.dict())): result = await agent.run("Flip a coin for $1 on heads") assert "won" in result.data.lower()
Referral Commissions
Every Purple Flea API key carries an embedded referral code. When you build PydanticAI agents that use Purple Flea and share them with others, you earn:
Trading: 20% of fees · Casino: 10% of wagers · Wallets: 10% of swap fees · Domains: 15% of registration fees
Commissions accrue automatically and are withdrawable at any time via the Purple Flea dashboard.
Next Steps
You've built a type-safe crypto agent with PydanticAI and Purple Flea. The Pydantic schemas protect you from LLM hallucination bugs, and the full suite of financial tools means your agents can do real on-chain work.
Explore more: Purple Flea for PydanticAI · LangChain integration · Trading API reference · Wallet API reference