Python SDK
pip install pensievelabfrom pensievelab import Pensieve
client = Pensieve() # reads PENSIEVE_API_KEYdecision = client.models.decide("grade-audit", input=trial, key=trial["task"])It needs Python 3.10 or later, and depends on httpx and pydantic. Every answer is a typed model generated from the OpenAPI spec; fields a newer API adds are kept, so an older SDK keeps working.
The client
Section titled “The client”client = Pensieve( api_key="pk_test_yourname", # or PENSIEVE_API_KEY base_url="https://api.pensievelabs.co", # or PENSIEVE_BASE_URL timeout=60.0, # seconds per try max_retries=2, http_client=None, # your own httpx.Client default_headers=None, webhook_secret=None, # or PENSIEVE_WEBHOOK_SECRET on_error=None, # errors from capture's background work)Use it as a context manager, or call client.close(). Any call takes idempotency_key, timeout, max_retries and extra_headers keyword arguments.
AsyncPensieve has the same methods, as coroutines:
import asyncio
from pensievelab import AsyncPensieve
async def main(): async with AsyncPensieve() as client: decision = await client.models.decide("grade-audit", input=trial) async for call in client.calls.list(model="grade-audit"): ...
asyncio.run(main())Methods
Section titled “Methods”Path ids are positional; every other field is a keyword argument named as in the API.
| Resource | Methods |
|---|---|
models |
list, retrieve, update, decide |
models.routing |
update |
models.versions |
list, retrieve, weights |
batches |
create, retrieve |
calls |
list, retrieve |
outcomes |
send, send_many |
corrections |
send |
captures |
create |
tests |
retrieve |
tests.cases |
list, add |
experiments |
list, start, retrieve, stop |
experiments.runs |
list |
methods |
list, create, retrieve, update, remove |
releases |
list, shadow, retrieve, signoff, split, promote, stop, rollback |
review |
list, retrieve, answer |
tasks |
create |
frontier |
list |
sources |
list, connect, retrieve, update, remove |
keys |
list, create, revoke |
members |
list, invite, update, remove |
usage |
retrieve |
webhooks |
list, create, remove, unwrap |
events |
list |
workspace |
retrieve |
Plus the @client.capture(...) decorator and client.flush(): see Record the calls you make today.
Iterating a list gives every item across pages. The page itself has data, has_more, next_cursor and get_next_page():
for call in client.calls.list(model="grade-audit"): ...
page = client.calls.list(model="grade-audit", limit=50)page.dataif page.has_next_page(): page = page.get_next_page()Request ids
Section titled “Request ids”Every answer carries the id of the request that made it, to quote when asking for help:
model = client.models.retrieve("grade-audit")model._request_id # 'req_...'Errors
Section titled “Errors”import pensievelab
try: client.releases.promote(release.id, expect="v7")except pensievelab.ConflictError as e: print(e.param, e.message, e.request_id)BadRequestError 400, AuthenticationError 401, PermissionDeniedError 403, NotFoundError 404, ConflictError 409, RateLimitError 429, NotAvailableError 501, InternalServerError 5xx, and APIConnectionError and APITimeoutError when no answer came back. See Errors and retries.
Webhooks
Section titled “Webhooks”event = client.webhooks.unwrap(request.body, request.headers) # checks the signature and ageSee Webhooks and events.