Utilisation
Guides et schémas d’utilisation du SDK Python de TypeSafe.
Appeler l’API System One
import asyncio
from typesafe_sdk import AsyncTypeSafeClient, Choice, Noul, Score
async def main() -> None:
async with AsyncTypeSafeClient() as client:
result = await client.system_one(
"I was charged twice. Please help ASAP.",
{
"billing": Noul(instructions="Is this about billing?"),
"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["billing"].noul,
result.choices["tone"].choice,
result.scores["urgency"].score,
)
asyncio.run(main())from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient()
state = "I was charged twice. Please help ASAP."
questions = {
"billing": Noul(instructions="Is this about billing?"),
"tone": Choice(
instructions="What is the tone?", criteria={"calm": None, "angry": None}
),
"urgency": Score(
instructions="How urgent is this?", criteria=["low", "medium", "high"]
),
}
result = client.system_one(state, questions)
print(
result.nouls["billing"].noul,
result.choices["tone"].choice,
result.scores["urgency"].score,
)Réponses system_one typées
Tu peux fournir un modèle de réponse à system_one pour rendre l’usage de la réponse plus sûr en typage :
import asyncio
from typesafe_sdk import AsyncTypeSafeClient, Noul, NoulAnswer, SystemOneResponse
class BillingResponse(SystemOneResponse):
billing: NoulAnswer
async def main() -> None:
async with AsyncTypeSafeClient() as client:
result = await client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
response_model=BillingResponse,
)
assert 0 <= result.billing.noul <= 1
assert result.billing == result.nouls["billing"]
print(result.request_id)
asyncio.run(main())from typesafe_sdk import Noul, NoulAnswer, SystemOneResponse, TypeSafeClient
class BillingResponse(SystemOneResponse):
billing: NoulAnswer
with TypeSafeClient() as client:
result = client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
response_model=BillingResponse,
)
assert 0 <= result.billing.noul <= 1
assert result.billing == result.nouls["billing"]
print(result.request_id)Types de réponse personnalisés
Tu peux aussi définir un modèle de réponse entièrement nouveau, sans hériter de SystemOneResponse :
import asyncio
from pydantic import BaseModel
from typesafe_sdk import AsyncTypeSafeClient, Noul, NoulAnswer
class BillingAnswers(BaseModel):
billing: NoulAnswer
class BillingResponse(BaseModel):
answers: BillingAnswers
async def main() -> None:
async with AsyncTypeSafeClient() as client:
result = await client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
response_model=BillingResponse,
)
assert 0 <= result.answers.billing.noul <= 1
asyncio.run(main())from pydantic import BaseModel
from typesafe_sdk import Noul, NoulAnswer, TypeSafeClient
class BillingAnswers(BaseModel):
billing: NoulAnswer
class BillingResponse(BaseModel):
answers: BillingAnswers
result = TypeSafeClient().system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
response_model=BillingResponse,
)
assert 0 <= result.answers.billing.noul <= 1Choisir un modèle
Inspecte les modèles disponibles :
import asyncio
from typesafe_sdk import AsyncTypeSafeClient
async def main() -> None:
async with AsyncTypeSafeClient() as client:
print(await client.models.list())
asyncio.run(main())from typesafe_sdk import TypeSafeClient
print(TypeSafeClient().models.list())Sélectionne le modèle au moment de construire un client :
client = AsyncTypeSafeClient(model="jev")client = TypeSafeClient(model="jev")Consulte la référence de la ressource Models pour plus de détails.
Configurer l’URL de base
Pour utiliser le SDK avec une autre URL d’API, définis base_url sur le client ou la variable d’environnement TYPESAFE_BASE_URL. Cela suppose que l’API alternative respecte la spécification OpenAPI de TypeSafe.
Par exemple, connecte-toi via une passerelle IA avec sa clé d’API et son ID de modèle.
Utilise une clé d’API OpenRouter et un ID de modèle OpenRouter :
import asyncio
import os
from typesafe_sdk import AsyncTypeSafeClient, Noul
async def main() -> None:
async with AsyncTypeSafeClient(
api_key=os.environ["OPENROUTER_API_KEY"],
base_url="https://openrouter.ai/api",
model="~typesafe/jev-latest",
) as client:
result = await client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
)
print(result.nouls["billing"].noul)
asyncio.run(main())import os
from typesafe_sdk import Noul, TypeSafeClient
with TypeSafeClient(
api_key=os.environ["OPENROUTER_API_KEY"],
base_url="https://openrouter.ai/api",
model="~typesafe/jev-latest",
) as client:
result = client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
)
print(result.nouls["billing"].noul)L’API de Vercel compatible avec TypeSafe peut être utilisée avec le SDK :
import asyncio
import os
from typesafe_sdk import AsyncTypeSafeClient, Noul
async def main() -> None:
async with AsyncTypeSafeClient(
api_key=os.environ["AI_GATEWAY_API_KEY"],
base_url="https://ai-gateway.vercel.sh/typesafe",
model="typesafe-ai/jev",
) as client:
result = await client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
)
print(result.nouls["billing"].noul)
asyncio.run(main())import os
from typesafe_sdk import Noul, TypeSafeClient
with TypeSafeClient(
api_key=os.environ["AI_GATEWAY_API_KEY"],
base_url="https://ai-gateway.vercel.sh/typesafe",
model="typesafe-ai/jev",
) as client:
result = client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
)
print(result.nouls["billing"].noul)Utilise une clé d’API Pydantic AI Gateway :
import asyncio
import os
from typesafe_sdk import AsyncTypeSafeClient, Noul
async def main() -> None:
async with AsyncTypeSafeClient(
api_key=os.environ["PYDANTIC_AI_GATEWAY_API_KEY"],
base_url="https://gateway-us.pydantic.dev/proxy/typesafe",
model="jev-latest",
) as client:
result = await client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
)
print(result.nouls["billing"].noul)
asyncio.run(main())import os
from typesafe_sdk import Noul, TypeSafeClient
with TypeSafeClient(
api_key=os.environ["PYDANTIC_AI_GATEWAY_API_KEY"],
base_url="https://gateway-us.pydantic.dev/proxy/typesafe",
model="jev-latest",
) as client:
result = client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
)
print(result.nouls["billing"].noul)HTTP/2
import httpx2
from typesafe_sdk import AsyncTypeSafeClient
client = AsyncTypeSafeClient(http_client=httpx2.AsyncClient(http2=True))import httpx2
from typesafe_sdk import TypeSafeClient
client = TypeSafeClient(http_client=httpx2.Client(http2=True))Nouvelles tentatives
Passe un RetryPolicy personnalisé via retry sur le client ou pour chaque appel. Les clés d’API invalides lèvent TypeSafeError à la création du client, avant toute requête ou nouvelle tentative.
Sur le client :
from typesafe_sdk import AsyncTypeSafeClient, RetryPolicy
client = AsyncTypeSafeClient(
retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0)
)from typesafe_sdk import RetryPolicy, TypeSafeClient
client = TypeSafeClient(retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0))Pour chaque appel :
import asyncio
from typesafe_sdk import AsyncTypeSafeClient, RetryPolicy
async def main() -> None:
async with AsyncTypeSafeClient() as client:
await client.system_one(
state,
questions,
retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0),
)
asyncio.run(main())from typesafe_sdk import RetryPolicy
client.system_one(
state, questions, retry=RetryPolicy(max_retries=3, backoff_max=0.2, timeout=1.0)
)Gestion des erreurs
Gère les exceptions levées par le SDK :
import asyncio
from typesafe_sdk import AsyncTypeSafeClient, TypeSafeAPIError
async def main() -> None:
async with AsyncTypeSafeClient() as client:
try:
await client.system_one(state, questions)
except TypeSafeAPIError as error:
print(error.status, error.request_id)
asyncio.run(main())from typesafe_sdk import TypeSafeAPIError
try:
client.system_one(state, questions)
except TypeSafeAPIError as error:
print(error.status, error.request_id)Journalisation
Le SDK journalise via le logger typesafe_sdk. Configure-le en suivant le guide de la journalisation standard :
import logging
logging.getLogger("typesafe_sdk").setLevel(logging.DEBUG)
Ou définis TYPESAFE_LOG_LEVEL sur l’une des valeurs debug, info, warning, error ou off avant d’importer le SDK.
info journalise une ligne de résumé par requête ; debug journalise aussi les en-têtes et les corps des requêtes et des réponses. Les en-têtes secrets — autorisation, clés d’API, cookies, et tout en-tête dont le nom contient token ou secret — sont masqués dans la sortie du journal. Les corps des requêtes et des réponses ne sont pas masqués.
Variables d’environnement
Le SDK lit et utilise les variables d’environnement suivantes :
| Variable | Configure | Par défaut |
|---|---|---|
TYPESAFE_API_KEY |
Clé d’API (obligatoire) | — |
TYPESAFE_BASE_URL |
URL racine de l’API | https://api.typesafe.ai |
TYPESAFE_DEFAULT_MODEL |
Modèle par défaut | jev-latest |
TYPESAFE_LOG_LEVEL |
niveau du logger typesafe_sdk, appliqué une fois à l’import |
non défini |
Consulte la référence des constantes pour les valeurs par défaut du SDK.
Les clés d’API fournies via api_key ou TYPESAFE_API_KEY voient leurs espaces de début et de fin supprimés, y compris les retours à la ligne des fichiers de clés. Les clés vides, les espaces internes, les caractères de contrôle et les caractères non ASCII sont rejetés avant l’envoi d’une requête. Une clé explicitement vide ne se rabat pas sur l’environnement.
Compatibilité future
Le SDK continue de fonctionner à mesure que l’API TypeSafe évolue, ce qui te permet d’adopter de nouvelles fonctionnalités de l’API avant qu’une version du SDK ne les prenne en charge nativement.
Champs de requête supplémentaires
Envoie des champs de requête supplémentaires avec extra_body. Le champ beam_width ci-dessous est illustratif ; n’envoie que des champs pris en charge par l’API.
import asyncio
from typesafe_sdk import AsyncTypeSafeClient, Noul
async def main() -> None:
async with AsyncTypeSafeClient() as client:
await client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="About billing?")},
extra_body={"beam_width": 4},
)
asyncio.run(main())from typesafe_sdk import Noul, TypeSafeClient
with TypeSafeClient() as client:
client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="About billing?")},
extra_body={"beam_width": 4},
)Dictionnaires de questions bruts
import asyncio
from typesafe_sdk import AsyncTypeSafeClient
async def main() -> None:
async with AsyncTypeSafeClient() as client:
await client.system_one(
"I was charged twice.",
{
"billing": {
"type": "noul",
"instructions": "About billing?",
"weight": 2,
}
},
)
asyncio.run(main())from typesafe_sdk import TypeSafeClient
with TypeSafeClient() as client:
client.system_one(
"I was charged twice.",
{"billing": {"type": "noul", "instructions": "About billing?", "weight": 2}},
)Types de réponse inconnus
Le SDK journalise un avertissement et ignore les types de réponse non reconnus. Utilise raw_http_response pour inspecter la réponse complète de l’API, y compris ces réponses :
import asyncio
from typesafe_sdk import AsyncTypeSafeClient, Noul
async def main() -> None:
async with AsyncTypeSafeClient() as client:
result = await client.system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
)
print(result.raw_http_response.json()["answers"])
asyncio.run(main())from typesafe_sdk import Noul, TypeSafeClient
result = TypeSafeClient().system_one(
"I was charged twice.",
{"billing": Noul(instructions="Is this about billing?")},
)
raw_answers = result.raw_http_response.json()["answers"]Champs de réponse inconnus
Les champs supplémentaires inconnus sur les réponses reconnues sont ignorés.