Skip to content

Python SDK

Terminal window
pip install pensievelab
from pensievelab import Pensieve
client = Pensieve() # reads PENSIEVE_API_KEY
decision = 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.

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())

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.data
if page.has_next_page():
page = page.get_next_page()

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_...'
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.

event = client.webhooks.unwrap(request.body, request.headers) # checks the signature and age

See Webhooks and events.