Python SDK
Call Drex's decision model from Python with drex-sdk — calibrated questions, retries and typed errors.
drex-sdk is the official Python client for https://console.nace.ai. This page covers Drex's decision model: system_one and models.list. The same package also covers Perception's document jobs, uploads and saved schemas — see the Perception SDK page for those. It needs Python 3.11 or later and depends on httpx and pydantic.
The client is built on the TypeSafe Python SDK, so system_one, Noul, Choice, Score, SystemOneResponse with .nouls, .choices and .scores, RetryPolicy and the error classes match typesafe-sdk. Code written for TypeSafeClient runs on DrexClient once you rename the imports; see Migrate from TypeSafe.
pip install drex-sdk
export DREX_API_KEY="nace_sk_..."DrexClient() reads DREX_API_KEY, DREX_BASE_URL, DREX_DEFAULT_MODEL and DREX_LOG_LEVEL. Arguments you pass (api_key, base_url, model) take precedence. Create a key as shown in Authentication.
Ask questions
client.system_one(state, questions, **options)
| Parameter | Type | Required | Description |
|---|---|---|---|
state | Any | Yes | Text, a JSON object, or an array to evaluate. See State. |
questions | Mapping[str, Question] | Yes | Nonempty mapping of names to Noul, Choice or Score (or raw dictionaries). See Questions. |
model | str | No | Model override. Default: the client's model, itself drex-latest unless set. |
response_model | type[ResponseT] | No | Parse the response into your own Pydantic model instead of SystemOneResponse. |
extra_body | dict | No | Additional top-level fields sent with the request. |
from drex_sdk import Choice, DrexClient, Noul, Score
with DrexClient() as client:
result = client.system_one(
state="I was charged twice for my March invoice.",
questions={
"wants_refund": Noul(instructions="Is the customer asking for a refund?"),
"topic": Choice(instructions="Which topic is it?", criteria={"billing": None, "shipping": None, "other": None}),
"urgency": Score(instructions="How urgent is it?", criteria=["low", "medium", "high"]),
},
)
print(result.nouls["wants_refund"].noul)
print(result.choices["topic"].choice, result.choices["topic"].confidence)
print(result.scores["urgency"].score, result.usage.input_tokens, result.request_id)Questions can also be plain dictionaries such as {"type": "noul", "instructions": "..."}. state can be text or any JSON value; see State. Pass model= to override the client's default for one call, response_model= to parse the response into your own Pydantic model, and extra_body= to send additional top-level fields. client.models.list() lists the models you can use. AsyncDrexClient has the same methods, awaited.
For client.documents.* (parse, split, classify, extract, ground), uploads, jobs and saved schemas, see the Perception SDK page.
Handle errors
Every error the SDK raises is a DrexError. HTTP failures raise a DrexAPIError subclass:
| Status | Class |
|---|---|
| 400 | DrexBadRequestError |
| 401 | DrexAuthenticationError |
| 402 | DrexInsufficientCreditError (type is insufficient_credit or payment_required) |
| 403 | DrexPermissionDeniedError |
| 404, 410 | DrexNotFoundError |
| 409 | DrexConflictError |
| 422 | DrexUnprocessableEntityError |
| 429 | DrexRateLimitError |
| 5xx | DrexInternalServerError (529 is DrexOverloadedError) |
Each DrexAPIError has status, body, headers and request_id, plus Drex's type, code, issues and server_retryable. Include request_id in support requests. A failure without a response raises DrexAPIConnectionError or DrexAPITimeoutError.
The client retries 408, 429 and 5xx responses, dropped connections and timeouts, up to 2 retries within a 30-second budget, with backoff from 0.5 s doubling to 5 s. It honors retry-after-ms and retry-after, and it does not retry an error whose body says "retryable": false. A decision is billed only when it returns 200, so a retry never bills twice. To change the retry behavior or the per-request timeout (60 s by default):
from drex_sdk import DrexClient, RetryPolicy
client = DrexClient(timeout=90, retry=RetryPolicy(max_retries=4, backoff_max=10, timeout=120))Every method also takes retry=, timeout= and extra_headers= for one call. The SDK logs to the drex_sdk logger with credentials redacted; set DREX_LOG_LEVEL=info for request summaries. See Errors and retries for what each error means.