Python SDK for Agent Fuel — credit vault + reputation primitives for AI agents on Solana.
Project description
agent-fuel-sdk
Python SDK for Agent Fuel — credit vault + reputation primitives for AI agents on Solana.
Status:
0.3.0(alpha). Slices 1–3 ship reads, actions, live events, and the x402 fetch wrapper:get_score,get_vault_balance,get_policy,check_service,pay(atomic spend + record_payment + compute_score),spend(no-receipt vault burn),request_spend,register_service,on_event(WebSocket with auto-reconnect),payment_required(HTTP 402 wrapper). Only PyPI publish automation + the docs site Python section remain (slice 4). Mirrors@agent-fuel/sdkline-for-line where the languages allow.
Install
pip install agent-fuel-sdk
Requires Python ≥ 3.10. Dependencies: solders (Rust-backed Solana types), httpx (async HTTP), websockets (live events, slice 3), construct (Borsh account parsing), base58.
Read methods (slice 1)
import asyncio
from solders.keypair import Keypair
from agent_fuel import AgentFuel, VaultRef
async def main() -> None:
async with AgentFuel(
agent=Keypair(), # any keypair; reads don't sign
cluster="devnet",
owner="Cowi12EU2QhobEtJoAzHVEQewcnU4BYVAYdboHMPdWAe",
) as fuel:
# REST snapshot — None for unscored agents.
score = await fuel.get_score("5ro8Tb16gD8P7D975ZwMfUvABZvkqyLCF6wySvpTntZj")
print(score.score, score.total_transactions)
# On-chain account fetches. With `owner` set on the constructor,
# no-arg calls default to the agent's own vault.
vault = await fuel.get_vault_balance(
VaultRef(
owner="Cowi12EU2QhobEtJoAzHVEQewcnU4BYVAYdboHMPdWAe",
agent="5ro8Tb16gD8P7D975ZwMfUvABZvkqyLCF6wySvpTntZj",
)
)
print(vault.balance, vault.frozen, vault.pending_count)
policy = await fuel.get_policy(
VaultRef(
owner="Cowi12EU2QhobEtJoAzHVEQewcnU4BYVAYdboHMPdWAe",
agent="5ro8Tb16gD8P7D975ZwMfUvABZvkqyLCF6wySvpTntZj",
)
)
print(policy.per_tx_limit_usdc, policy.whitelist)
service = await fuel.check_service("...service authority pubkey...")
print(service.name, service.category, service.active)
asyncio.run(main())
fuel.close() is called automatically by the context manager. If you can't use async with, call it yourself before your process exits.
Action methods (slice 2)
import asyncio
from hashlib import sha256
from solders.keypair import Keypair
from agent_fuel import AgentFuel
async def main() -> None:
agent = Keypair.from_json(open("agent.json").read())
service = Keypair.from_json(open("svc-pyth.json").read())
async with AgentFuel(agent=agent, cluster="devnet", owner="...your wallet...") as fuel:
# Atomic spend + record_payment + compute_score. One tx, one fee,
# vault burn and reputation accrual either both land or neither
# does. Receipt hash must be unique per call — replays hit
# ReceiptAlreadyRecordedError.
result = await fuel.pay(
service=service,
amount_usdc=10_000, # micro-USDC (0.01)
receipt_hash=sha256(b"tick-42").digest(), # 32 bytes
)
print("paid:", result.signature)
# Over-limit flow — owner approves from the mobile app.
pending = await fuel.request_spend(
service=service.pubkey(),
amount_usdc=5_000_000, # 5 USDC
)
print("pending:", pending.pending_spend, "nonce:", pending.nonce)
# Register a new service (two-signer).
sponsor = Keypair.from_json(open("sponsor.json").read())
new_service = Keypair()
reg = await fuel.register_service(
sponsor=sponsor,
service=new_service,
name="Helix RPC",
category="Rpc",
service_uri="https://helix.example/service.json",
)
print("registered:", new_service.pubkey(), "sig:", reg.signature)
asyncio.run(main())
The SpendPolicyError hierarchy is now active — except SpendPolicyError catches all six on-chain rejections (frozen / zero / whitelist / per-tx / hourly / lifetime) plus their pre-flight equivalents thrown by the local guardrail.
Live events (slice 3)
import asyncio
from solders.keypair import Keypair
from agent_fuel import AgentFuel, LiveEventFrame, LiveStatus
async def main() -> None:
agent = Keypair.from_json(open("agent.json").read())
async with AgentFuel(agent=agent, cluster="devnet", owner="...") as fuel:
def on_frame(frame: LiveEventFrame) -> None:
print(frame.event_name, frame.signature, frame.payload)
def on_status(status: LiveStatus) -> None:
print("ws:", status)
sub = fuel.on_event(on_frame, on_status=on_status)
try:
await asyncio.sleep(60)
finally:
await sub.close()
asyncio.run(main())
Reconnects automatically with exponential backoff up to 30s. fuel.on_service_event(service, ...) and fuel.on_vault_event(vault, ...) cover the other two entity channels — useful for service-side recorders that don't own the agent's keypair.
x402 (slice 3)
import asyncio
from solders.keypair import Keypair
from agent_fuel import AgentFuel
async def main() -> None:
agent = Keypair.from_json(open("agent.json").read())
async with AgentFuel(agent=agent, cluster="devnet", owner="...") as fuel:
fetcher = fuel.payment_required(
on_payment_required=lambda req: print("402:", req.recipient, req.amount_usdc),
on_paid=lambda sig, req: print("paid:", sig),
)
res = await fetcher.get("https://paid.example.com/weather?city=NYC")
print(res.status_code, res.text)
asyncio.run(main())
fetcher is fetch-shaped (get / post / put / patch / delete / request). On a 402 the requirement is parsed (accepts recipient / amount_usdc / amountUsdc / payTo / maxAmountRequired), the on-chain spend() lands, and the request is retried once with X-Payment: <signature>. A second 402 propagates so a misbehaving server can't drain the vault.
Errors
Every read raises AccountNotFoundError when the target doesn't exist on-chain or the backend returns 404. RPC and REST failures raise HttpError. Methods that need a vault owner without one configured raise OwnerNotConfiguredError. The full hierarchy mirrors @agent-fuel/sdk:
from agent_fuel import (
AccountNotFoundError,
AgentFuelError, # base
HourlyLimitExceededError, # SpendPolicyError subclass (reserved for slice 2)
HttpError,
OwnerNotConfiguredError,
PerTxLimitExceededError,
SpendPolicyError, # base for the six guardrail variants
VaultFrozenError,
)
What's coming
| Slice | Methods |
|---|---|
| 1 | get_score · get_vault_balance · get_policy · check_service |
| 2 | pay (atomic spend + record_payment + compute_score) · request_spend · register_service |
| 3 (this) | spend · on_event / on_service_event / on_vault_event (WebSocket with reconnect) · payment_required (x402 fetch wrapper) |
| 4 | PyPI publish workflow · docs site Python section |
License
Apache-2.0. See LICENSE.
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 agent_fuel_sdk-0.3.0.tar.gz.
File metadata
- Download URL: agent_fuel_sdk-0.3.0.tar.gz
- Upload date:
- Size: 34.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94b00905e524350f9831a9b2d47f171276e282927c6841438f3da9ae2ad23a7c
|
|
| MD5 |
eee9422047f45ef5de5939360c4ff3f3
|
|
| BLAKE2b-256 |
b360b7ea8bf4e7f329dcab63c4ef027a48b8130c12c89c3e7f6fb6636e9d7b11
|
Provenance
The following attestation bundles were made for agent_fuel_sdk-0.3.0.tar.gz:
Publisher:
sdk-python-release.yml on frankolien/agent_fuel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_fuel_sdk-0.3.0.tar.gz -
Subject digest:
94b00905e524350f9831a9b2d47f171276e282927c6841438f3da9ae2ad23a7c - Sigstore transparency entry: 1730103179
- Sigstore integration time:
-
Permalink:
frankolien/agent_fuel@c76b902fc448a3ebe0917d125b68ed096dbeda3c -
Branch / Tag:
refs/tags/sdk-py-v0.3.0 - Owner: https://github.com/frankolien
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-python-release.yml@c76b902fc448a3ebe0917d125b68ed096dbeda3c -
Trigger Event:
push
-
Statement type:
File details
Details for the file agent_fuel_sdk-0.3.0-py3-none-any.whl.
File metadata
- Download URL: agent_fuel_sdk-0.3.0-py3-none-any.whl
- Upload date:
- Size: 46.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5371db7e5b25780d04696a566cfe61f6da7129a5d84a42da4e3870718f4006e7
|
|
| MD5 |
eb7114a2a77579d5bc7bf44c6aa94ddb
|
|
| BLAKE2b-256 |
c1fe18ef5ff5982f511216068093d9d87a35021f8ebdbbdb6cbe3b32abf5540b
|
Provenance
The following attestation bundles were made for agent_fuel_sdk-0.3.0-py3-none-any.whl:
Publisher:
sdk-python-release.yml on frankolien/agent_fuel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_fuel_sdk-0.3.0-py3-none-any.whl -
Subject digest:
5371db7e5b25780d04696a566cfe61f6da7129a5d84a42da4e3870718f4006e7 - Sigstore transparency entry: 1730103399
- Sigstore integration time:
-
Permalink:
frankolien/agent_fuel@c76b902fc448a3ebe0917d125b68ed096dbeda3c -
Branch / Tag:
refs/tags/sdk-py-v0.3.0 - Owner: https://github.com/frankolien
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-python-release.yml@c76b902fc448a3ebe0917d125b68ed096dbeda3c -
Trigger Event:
push
-
Statement type: