Skip to main content

Overview

TypeSafe is a specialized decision provider serving the jev family of System One judgment models. A decision request carries a state (what to evaluate) and a map of named questions; the response carries one typed answer per question. Bifrost performs conversions including:
  • Model ID mapping - Uses provider model identifier directly (jev-1.13.0, jev-1.14.0, jev-latest, jev-preview)
  • Question conversion - Maps Bifrost question types (predicate, choice, score, box) to TypeSafe’s native System One types (noul, choice, score, box), and choices and levels to its criteria
  • Images - Images placed by reference in the state, instructions, or criteria reach TypeSafe as its assets, as base64 JSON or multipart, with the TypeSafe-Danger-Zone-Images header added for you
  • Answer normalization - Native noul/choice/score value fields normalize to a unified value, with confidence, probabilities, and legend metadata preserved
  • Usage normalization - input_tokens/output_tokens map to Bifrost’s prompt_tokens/completion_tokens (TypeSafe bills input tokens only)
  • SDK-faithful validation - Unsupported kinds and malformed criteria are rejected locally with a 400; everything the official SDK types allow (null state, optional instructions, null descriptions, extra top-level fields) is forwarded so the endpoint gives its own verdict

Supported Operations

Unsupported Operations (❌): Chat Completions, Responses API, Text Completions, Embeddings, and every other operation return UnsupportedOperationError - TypeSafe serves judgment models only.Model listing: Bifrost calls the endpoint’s native GET /v1/models. Against api.typesafe.ai the live listing (aliases) is merged with the pinned versioned jev entries, and the pinned catalog stands in when the call fails; a custom base_url serves its own catalog as-is. Pricing and context length still come from the model datasheet.

Setup & Configuration

Configure TypeSafe as a provider with a bearer API key:

Custom TypeSafe Providers

A custom provider can use typesafe as its base_provider_type, for example to reach a second TypeSafe endpoint with its own keys alongside the standard typesafe provider:
The custom provider is addressed by its own name: typesafe-eu/jev-latest on /v1/decisions, and on the native /typesafe/v1/systemone route. Responses, logs, and key selection report typesafe-eu. It supports the usual custom provider options:
  • allowed_requests - set decisions (and list_models) to true. When allowed_requests is present, an operation that is not listed is refused with unsupported_operation.
  • request_path_overrides - decisions and list_models accept a path on base_url or a full URL in place of /v1/systemone and /v1/models.
  • is_key_less - for endpoints that need no bearer token.
To list a custom provider’s models on the native /typesafe/v1/models route, send x-bf-model-provider: typesafe-eu. Model names come back bare (jev-latest), as on the standard provider. The pinned jev catalog is only merged in when no base_url is set. To run Laya or Nimble on your own infrastructure this way, follow Self-Hosted Decision Models, which covers model listing, allowed models, pricing, and the settings that otherwise make the provider look broken.

Decisions API

POST /v1/decisions asks a list of questions about an input. Each question has a type, optional name, instructions (string or structured data), and type-specific details:
The response lists one answer per question, in order. The earlier map-form body (state plus questions keyed by name, with kind and criteria) is still served and answered in the map form; see Decisions.

Images and Box

TypeSafe reads images placed by reference. Each image is listed once with an ID, and the image is placed wherever that ID is written: in the input, in a question’s instructions, or in choice, score, and noul criteria, as a whole value or inside a sentence. An image in the input is evidence every question judges; an image in a question is only that question’s reference material, such as an example that defines a choice option. A box question answers where something is in an image, and needs Jev 1.14: send jev-preview or jev-1.14.0 until jev-latest resolves to 1.14. Bifrost adds the TypeSafe-Danger-Zone-Images: true header that TypeSafe requires whenever a request carries images or a box question, so clients do not send it. It is listed in the provider’s Beta Headers settings, supported by default; overriding it to unsupported, or setting network_config.beta_header_overrides to {"typesafe-danger-zone-images": false}, stops Bifrost from sending it, so TypeSafe rejects image and box requests.
An image sent by reference is an input_image part with an id and its file base64-encoded in data; Bifrost reads the format from the bytes, as TypeSafe does. A single message with one input_text part plus such parts is sent to TypeSafe as that text for the state, and the text may be a string, an object, or an array, so a structured state stays structured:
The same request can also be sent as multipart, with each image in its own file part named by the image part’s name instead of data; see Images by Reference. TypeSafe receives {"state": {"camera": "r-cam"}, "assets": {"r-cam": {...}, "r-thumb": {...}}, ...}: the example image r-thumb appears only in the gesture criteria, never in the state. The box answer reads:
TypeSafe judges the images themselves: an image that is not PNG or JPEG, and size, dimension, and unreferenced-asset limits, return TypeSafe’s own 400 or 413, passed through unchanged. Bifrost rejects only a request it cannot build: an asset naming a file part the request does not carry, a file part or form field no asset names, a repeated part name, a part outside a multipart request, an asset type other than image, data_base64 that is not valid base64, an image part with an id but no data (TypeSafe does not fetch URLs), an image part’s name in a JSON request or with no matching file part, and an id used twice. Images sent by reference work only with TypeSafe and Databricks’ System One models. Bifrost does not refuse them for other providers, but those providers do not read them: a provider that needs an image_url rejects the part, and one that receives TypeSafe’s request shape as is, such as Azure, returns its own error for assets. Inline input_image parts without an id keep working on the providers that read inline images.
Large-payload mode streams an oversized request body to TypeSafe without parsing it, so Bifrost cannot see its images. To send one, forward the client’s own TypeSafe-Danger-Zone-Images header by adding it to the header allowlist, or send it as x-bf-eh-typesafe-danger-zone-images.

Field Mapping Reference

How Bifrost’s /v1/decisions request reaches TypeSafe’s native /v1/systemone API, and how the answers come back.

Request

Descriptions may be a string, object, array, or null, and pass through to TypeSafe unchanged. The conversion path re-encodes JSON, so whitespace and object-key ordering can differ; raw-request passthrough bypasses conversion and preserves the original request bytes.

Response

Every requested question must produce an answer of its declared type; a missing answer, a type mismatch, or a missing value fails the request rather than returning partial results.

Errors

Requests rejected by Bifrost’s own validation (see tables above) return 400 with caller_invalid_request before any upstream call is made.

Native Integration

Bifrost also exposes TypeSafe’s native API 1:1 under the /typesafe prefix, for clients written against TypeSafe directly: The native route accepts bare model IDs (jev-1.13.0) exactly as TypeSafe does, and additionally accepts typesafe/-prefixed IDs.
Success and error responses from the TypeSafe provider are relayed byte-for-byte (answer and usage metadata outside the shared shape, and native detail values, all survive), together with upstream headers such as x-typesafe-request-id and Retry-After. Cached and fallback responses are rebuilt in the native shape. Additional top-level request fields the SDK forwards (for example a compatible endpoint’s images) reach the endpoint unchanged; a fallback to an LLM refuses such a request with 400 instead of answering it text-only. Requests rejected by Bifrost’s local validation use the {"detail": {"error_type", "message"}} envelope with 400.

Model Naming

Aliases resolve upstream, and responses always report the resolved versioned model. TypeSafe bills input tokens only; the jev pricing, 64k context window, and rate limits are documented at docs.typesafe.ai/models.