DrexDocs

Migrate from TypeSafe

Point the TypeSafe SDK at Drex, then fix the requests Drex rejects on purpose.

Drex is wire-compatible with TypeSafe's Jev. The @typesafe-ai/sdk package works against https://console.nace.ai without a fork. This guide covers the configuration change, the requests that Drex rejects, and a check that the switch worked. It is written against SDK version 0.6.0.

Or switch to the Drex SDK

The TypeScript and Python Drex SDKs are built on the TypeSafe SDKs. systemOne / system_one, the question helpers, the answer types, RetryPolicy, the logging options and the error classes keep their names and arguments, so a migration is mostly a rename:

TypeSafeDrex
@typesafe-ai/sdk, typesafe-sdkdrex-sdk on npm and PyPI
TypeSafeClient, AsyncTypeSafeClientDrexClient, AsyncDrexClient
TYPESAFE_API_KEY, TYPESAFE_BASE_URL, TYPESAFE_DEFAULT_MODEL, TYPESAFE_LOG_LEVELDREX_API_KEY, DREX_BASE_URL, DREX_DEFAULT_MODEL, DREX_LOG_LEVEL
TypeSafeError, TypeSafeAPIError (Python)DrexError, DrexAPIError

The Drex SDKs already default to https://console.nace.ai, drex-latest and a 60-second timeout. They leave out a null instructions rather than sending it, add error classes for 402 and 529, and read request_id from x-request-id. They also cover the document routes. The rest of this guide is for code that keeps the TypeSafe SDK.

Change three environment variables

The SDK reads its base URL, key, and default model from the environment when the constructor does not set them.

.env
TYPESAFE_BASE_URL=https://console.nace.ai
TYPESAFE_API_KEY=nace_sk_...
TYPESAFE_DEFAULT_MODEL=drex-v1.0

If your code sets these in the constructor instead, change them there. Explicit options take precedence over environment variables.

Before
import { TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient({
  apiKey: process.env.TYPESAFE_API_KEY,
});
After
import { TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient({
  baseURL: "https://console.nace.ai",
  apiKey: process.env.DREX_API_KEY,
  defaultModel: "drex-v1.0",
  timeout: 60_000,
});

Set defaultModel in one of the two places. Without it, the SDK sends jev-latest, and Drex returns 422. The timeout line is explained under Raise the SDK timeout.

Verify the switch

List the models. The SDK unwraps the { "models": [...] } envelope and returns the array.

const models = await client.models.list();
console.log(models.map((m) => m.name));
// [ 'drex-v1.0', 'drex-v1.5', 'drex-latest', 'drex-v1.1' ]

The list has each pinned version, then the drex-latest alias, then retired ids such as drex-v1.1, which drex-v1.5 now answers. See Models. GET /v1/models needs a valid key but works with zero credit, so this check does not spend anything. A 401 here means the key is wrong. See Authentication.

What changes

Work through this list before you send production traffic. Each item is a request that TypeSafe accepted and Drex rejects, or a behavior that differs.

Send a drex-* model name

Drex accepts pinned versions such as drex-v1.0, the drex-latest alias, any other drex-* name, and legacy nacedm-* names. Anything else returns 422, so a half-migrated client fails on the first call instead of silently using the wrong model. A request with "model": "jev-latest" returns this issue:

{
  "path": "model",
  "message": "unknown model \"jev-latest\"; use \"drex-v1.0\", \"drex-v1.5\" or \"drex-latest\""
}

Search your code for hard-coded jev- model names and for calls that pass model per request.

Pass instructions as a string

Drex requires instructions to be a string when present. The SDK types allow a JSON object, an array, or null, and noul() with no arguments sends instructions: null. Drex rejects both:

{
  "path": "questions.a.instructions",
  "message": "must be a string"
}

Replace noul() and noul(null, criteria) with noul("Your question as text", criteria). Replace JSON instructions with text.

Pass criteria descriptions as strings

The SDK types allow a JSON object or array as any criteria description. Drex does not.

  • choice: each label's description must be a string or null. A JSON description returns the issue must be a string or null at questions.<name>.criteria.<label>.
  • noul: the true and false descriptions must be strings or null. A JSON description returns must be a string.
  • score: criteria must be an array of level labels, each a string. The SDK types allow null entries, but Drex returns must be a string at questions.<name>.criteria.<index> for a null level.

Raise the SDK timeout

The SDK's per-attempt timeout defaults to 10,000 ms. Drex waits up to 55 s for the model on a heavy request, so a large state with many questions can exceed the default and surface as an APITimeoutError. Set timeout: 60_000 on the client, or per call in the second argument to systemOne. The timeout applies per attempt, and the SDK retries APITimeoutError by default. Errors and retries covers retries in detail.

Handle 402 and 529

Drex adds 402 to TypeSafe's statuses. Handle it next to 529, which Drex returns when it cannot serve a request right now.

  • 402 with type insufficient_credit is new in Drex. It means the account has no spendable credit. The SDK raises this as a plain APIError with status 402. It is not retried. Top up or add a card on Billing. 402 with type payment_required means an unpaid invoice; it is not retried either, and the invoice is paid on Billing.
  • 529 with type overloaded means Drex is at capacity or the model did not respond in time. It carries retry-after and retry-after-ms. The SDK treats it as a 5xx, raises InternalServerError if retries run out, and honors the retry-after headers while retrying.

Errors lists every type with its status.

Read legend as an array

Drex returns the score answer's legend as an array of level labels. The SDK types describe it as an object keyed by score. Index access works the same either way: answers.sentiment.legend[2] returns the third label.

What stays the same

  • The endpoints, POST /v1/systemone and GET /v1/models.
  • The request shape: state, questions, and optional model.
  • The response shape: model, answers keyed by question name, and usage with input_tokens and output_tokens. Drex's body also carries evaluation_time_ms and request_id, which the SDK's SystemOneResult type does not declare.
  • The statuses 401, 422, 429, and 5xx, which the SDK maps to AuthenticationError, UnprocessableEntityError, RateLimitError, and InternalServerError.
  • The x-typesafe-request-id header. The SDK reads it into APIError.requestId and withResponse().requestId. Drex sends the same value as x-request-id.
  • The SDK's retry behavior: 2 retries by default, backoff from 500 ms doubling to 5 s, on 408, 429, and 500 to 599, honoring retry-after and retry-after-ms.
  • The noul, choice, and score helpers, and the answer types they infer.

Checklist

  1. Set TYPESAFE_BASE_URL, TYPESAFE_API_KEY, and TYPESAFE_DEFAULT_MODEL, or the matching constructor options.
  2. Remove hard-coded jev-* model names.
  3. Make sure that every instructions value is a string.
  4. Make sure that every criteria description is a string, and that score levels contain no null.
  5. Raise timeout for large requests.
  6. Handle 402 and 529 where you handle other APIError cases.
  7. Run client.models.list() and confirm that it includes drex-v1.0.

On this page