SDKs
Python — annamal-vana
pip install annamal-vana
from annamal_vana import Vana, AsyncVana, Choice, YesNo, Score, RateLimitError
client = Vana(api_key="vana_live_...", model="vana-3.0", timeout=30, max_retries=3) # or env VANA_API_KEY
r = client.decide(state={"ticket": "charged twice"}, questions={
"refund": YesNo("Refund?"),
"team": Choice({"billing": "Billing", "tech": "Technical"}, "Which team?"),
"urgency": Score(["low", "normal", "high"], "Urgency?"),
})
r["team"].choice, r["refund"].noul, r["urgency"].score, r.usage.input_tokens
r.rate_limit.balance_usd, r.rate_limit.low_balance # prepaid balance headers
client.balance() # GET /v1/balance
async with AsyncVana() as c:
r = await c.systemone("...", {"spam": YesNo("Spam?")})
TypeScript / JavaScript — @annamal/vana
npm install @annamal/vana # Node 18+, Deno, Bun, Workers, Edge
import { Vana, choice, yesNo, score, RateLimitError } from '@annamal/vana';
const vana = new Vana({ apiKey: process.env.VANA_API_KEY, timeout: 30_000, maxRetries: 3 });
const r = await vana.decide({ ticket: 'charged twice' }, {
refund: yesNo('Refund?'),
team: choice({ billing: 'Billing', tech: 'Technical' }, 'Which team?'),
});
r.answers.team.choice; // typed
r.rateLimit.balanceUsd; await vana.balance();
Both SDKs send model: "vana-latest" by default (override per client or per call; responses report the resolved
vana-3.0), use the default base URL https://api.vana.annamal.ai, retries on 429/5xx/network errors with exponential
backoff honoring Retry-After, per-request timeouts, and an error hierarchy mirroring errors
(AuthenticationError, PaymentRequiredError / InsufficientBalanceError, PermissionDeniedError, RateLimitError, QuotaExceededError, …).