SDKs and clients
Sonoe doesn't need its own SDK: TypeSafe's official SDKs work with it unchanged, and any HTTP client works too.
TypeSafe's SDKs
Both SDKs read their configuration from the environment. To use Sonoe, set the base URL and a Sonoe key:
export TYPESAFE_BASE_URL="https://api.sonoeai.com"
export TYPESAFE_API_KEY="sk_sonoe_..."
export TYPESAFE_DEFAULT_MODEL="sonoe-latest" # optional: the SDKs default to jev-latest, which Sonoe also acceptsPython
pip install typesafe-sdkfrom typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient() # or TypeSafeClient(api_key=..., base_url="https://api.sonoeai.com")
result = client.system_one(
"I was charged twice. Please help ASAP.",
{
"refund": Noul(instructions="Does the customer want their money back?"),
"tone": Choice(instructions="What is the tone?", criteria={"calm": None, "angry": None}),
"urgency": Score(instructions="How urgent is this?", criteria=["low", "medium", "high"]),
},
)
print(result.nouls["refund"].noul, result.choices["tone"].choice, result.scores["urgency"].score)
print(result.usage.input_tokens, result.request_id)import asyncio
from typesafe_sdk import AsyncTypeSafeClient, Noul
async def main() -> None:
async with AsyncTypeSafeClient() as client:
result = await client.system_one(
{"ticket": "refund for order 18"},
{"refund": Noul(instructions="Does the customer want a refund?")},
)
print(result.nouls["refund"].noul)
asyncio.run(main())JavaScript and TypeScript
npm install @typesafe-ai/sdkimport { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient(); // or new TypeSafeClient({ apiKey, baseURL: "https://api.sonoeai.com" })
const { answers, usage } = await client.systemOne({
state: { document: "I was charged twice. Please fix this ASAP." },
questions: {
category: choice("What is this ticket about?", { billing: null, technical: null, other: null }),
urgent: noul("Is it urgent?"),
anger: score("How angry is the customer?", ["calm", "annoyed", "furious"]),
},
});
console.log(answers.category.choice, answers.urgent.noul, answers.anger.score, usage);What works
Tested with typesafe-sdk 0.7.5 and @typesafe-ai/sdk 0.7.0:
- Noul, Choice and Score questions, and typed answers.
- Sync and async clients (Python),
withResponse()and request ids (JavaScript). models.list().- zstd-compressed request bodies (the SDKs compress from 1 KiB on).
- Automatic retries on
429and5xx, followingRetry-After. - Errors as the SDKs' own exception classes (
AuthenticationError,UnprocessableEntityError,RateLimitError…).
Images (image(), withAssets, box()) aren't supported: Sonoe reads text only and returns 422.
Any HTTP client
The API is plain JSON over HTTPS. Send Authorization: Bearer <key> and Content-Type: application/json:
import os
import requests
r = requests.post(
"https://api.sonoeai.com/v1/systemone",
headers={"Authorization": f"Bearer {os.environ['SONOE_API_KEY']}"},
json={
"model": "sonoe-latest",
"state": "Help! My payouts have been failing for 3 days.",
"questions": {"urgent": {"type": "noul", "instructions": "Is this urgent?"}},
},
timeout=10,
)
if r.status_code == 429:
wait = int(r.headers.get("Retry-After", "10"))
r.raise_for_status()
print(r.json()["answers"]["urgent"]["noul"])const r = await fetch("https://api.sonoeai.com/v1/systemone", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.SONOE_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
model: "sonoe-latest",
state: "Help! My payouts have been failing for 3 days.",
questions: { urgent: { type: "noul", instructions: "Is this urgent?" } },
}),
signal: AbortSignal.timeout(10_000),
});
const body = await r.json();
if (!r.ok) throw new Error(body.error?.message ?? `Sonoe: ${r.status}`);
console.log(body.answers.urgent.noul);When you write your own client:
- Retry
429and503afterRetry-Afterseconds (or a short backoff). Don't retry other4xx. - Log the
x-request-idheader; it identifies the request if you need help. - Call Sonoe from your server only. The key must never reach a browser or an app.