Capture verifiable, replayable records of your AI agent's decisions — the Python SDK for the Verifiable Decision Record standard.
Project description
Determs Python SDK
Verifiable Decision Records for AI agents — Python client.
Capture each LLM call as a structured, verifiable record. Persist records
wherever you want. Verify and replay them later with the determs CLI.
This SDK is the open-core reference client for the Verifiable Decision Record specification.
Install
pip install determs
# With optional client SDKs:
pip install "determs[anthropic,openai]"
(Until the first public release, install from the built wheel in dist/:
pip install dist/determs-0.1.0-py3-none-any.whl.)
Quick start — Anthropic
import anthropic
from determs.anthropic import wrap as wrap_anthropic
from determs.storage import FileStorage
client = wrap_anthropic(
anthropic.Anthropic(),
agent_id="support-triage",
storage=FileStorage("./determs_records"),
)
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=512,
messages=[{"role": "user", "content": "Hi"}],
)
# A record file landed under ./determs_records/{action_id}.json.
Quick start — OpenAI
from openai import OpenAI
from determs.openai import wrap as wrap_openai
from determs.storage import FileStorage
client = wrap_openai(
OpenAI(),
agent_id="support-triage",
storage=FileStorage("./determs_records"),
)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Hi"}],
)
Storage backends
from determs.storage import FileStorage, StdoutStorage, CallbackStorage
# Write each record as <dir>/<action_id>.json
FileStorage("./records")
# Print each record as one JSON line on stdout — pipeable.
StdoutStorage()
# Hand the record dict to your own callback — for queues, custom sinks, tests.
CallbackStorage(callback=lambda record: print(record["agent_id"]))
Or pick a backend from environment variables:
from determs.storage import storage_from_env
storage = storage_from_env() # honours DETERMS_STORAGE and DETERMS_DIR
Manual records
If you don't use the Anthropic or OpenAI SDKs directly (e.g. you call an inference service through your own HTTP client), build records explicitly:
from determs import build_record
from determs.storage import FileStorage
storage = FileStorage("./records")
record = build_record(
agent_id="my-agent",
model={"provider": "anthropic", "name": "claude-3-5"},
params={"temperature": 0.0},
input={"messages": [{"role": "user", "content": "Hi"}]},
output={"content": "Hello.", "finish_reason": "stop"},
context={"trace_id": "trace-001"},
)
storage.put(record)
Verify and replay
The determs binary is the verification surface. The SDK emits the record
JSON; the CLI handles capture, replay, and verify.
# Bundle the action into a full record (input + execution + receipt):
determs capture --input ./records/act-xxx.json --output ./full.record.json
# Replay it later: returns 0 if bit-exact.
determs replay --record ./full.record.json
# Verify: returns 0 if no tampering, 1 if any digest mismatches.
determs verify --record ./full.record.json
Async clients
import anthropic
from determs.anthropic import wrap_async as wrap_anthropic_async
aclient = wrap_anthropic_async(
anthropic.AsyncAnthropic(),
agent_id="support-triage",
storage=FileStorage("./records"),
)
response = await aclient.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=512,
messages=[{"role": "user", "content": "Hi"}],
)
determs.openai.wrap_async(...) works the same way for AsyncOpenAI.
Streaming
stream = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=512,
messages=[{"role": "user", "content": "Hi"}],
stream=True,
)
for event in stream:
handle(event)
# A record is emitted only when the stream completes naturally.
# If the caller stops iterating before the end, no record is written.
Async streaming uses async for after await client.messages.create(stream=True, ...).
What this SDK does and does not do
Does:
- intercept
messages.create(Anthropic, sync + async, streaming + non-streaming) - intercept
chat.completions.create(OpenAI, sync + async, streaming + non-streaming) - accumulate streamed text, tool_use blocks, and tool_calls into a final record
- emit records only on complete streams; abandoned streams produce nothing
- build a well-formed action record consumable by the Determs CLI
- persist records via a swappable storage backend
- never let recording failures break the upstream LLM call
Does not yet:
- support Anthropic's
messages.stream(...)context manager (usemessages.create(stream=True)instead) - support the OpenAI Responses API (use
chat.completionsinstead) - talk to a Determs Cloud endpoint (phase 3)
- ship a replay UI
Tests
cd sdk/python
pip install -e ".[dev]"
pytest tests/
The end-to-end tests in test_cli_compatibility.py require the determs
binary built from the workspace root (cargo build or cargo build --release).
Build the wheel
cd sdk/python
pip install build
python -m build
# Produces dist/determs-0.1.0-py3-none-any.whl and dist/determs-0.1.0.tar.gz
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file determs-0.1.0.tar.gz.
File metadata
- Download URL: determs-0.1.0.tar.gz
- Upload date:
- Size: 32.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a79c8a65b06217d9b4b03d09a8b01ef4ed66b0f6d911fe747a7f26e5105ce26
|
|
| MD5 |
0fa78b3a1242bfb3bde9740922ddcbb7
|
|
| BLAKE2b-256 |
30d55965cf947c51cff41ccc409761801a3557fa0cbad9a7a4eeda2839aac442
|
File details
Details for the file determs-0.1.0-py3-none-any.whl.
File metadata
- Download URL: determs-0.1.0-py3-none-any.whl
- Upload date:
- Size: 25.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1141c1a4a612d076f5871d2eed98ef499a9e37780b50a45506d49fafbef6669
|
|
| MD5 |
384f58bf85b26eda7e858dbc2bb86cbb
|
|
| BLAKE2b-256 |
f115a7daf26f28710c89fb6d392a7a5f7ee91a7ccb3b9f92466a05c9c76ec5da
|