Skip to content

Native Decisions

Available since gateway 0.4.2.

POST /v1/decisions evaluates predicate, choice and score questions using native decision models. OpenAI gpt-6-luna calls /v1/decisions; TypeSafe Jev calls /v1/systemone. There is no Chat/Responses emulation, text-generation fallback, or extra classifier call. Responses are ordinary JSON, not SSE.

Configuration

providers:
  openai:
    api_key: ${OPENAI_API_KEY}
    capabilities:
      decisions: true
      decision_models: [gpt-6-luna]
  typesafe:
    type: typesafe
    api_key: ${TYPESAFE_API_KEY}
    default_model: jev-latest
    models:
      mode: fetch
    capabilities:
      decisions: true
      decision_models: [jev-latest, jev-preview, jev-1.14.0]
      decision_images: false
routing:
  default_strategy: weighted
  routes:
    - name: native-decisions
      match:
        path: /v1/decisions
      targets:
        - {provider: openai, model: gpt-6-luna, weight: 1}
        - {provider: typesafe, model: jev-latest, weight: 1}

Native capabilities and model allowlists are explicit and hot reloadable. Models are filtered before load balancing, including effective default models. model: openai/gpt-6-luna or model: typesafe/jev-latest selects a provider; lunargate/auto uses the compatible configured route pool. A cross-provider fallback requires an explicit route fallback entry and compatible input. The upstream transport is derived from the provider; do not set a new upstream_request_type in routing configuration.

Send a request

Set model to openai/gpt-6-luna, typesafe/jev-latest, or lunargate/auto. The last option lets the gateway select a compatible target from the first matching route. The provider prefix is your configured provider ID, so a custom TypeSafe ID such as classify uses classify/jev-latest.

curl http://localhost:8080/v1/decisions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "typesafe/jev-latest",
    "input": "I was charged twice. Please refund the extra payment.",
    "questions": [
      {
        "type": "predicate",
        "name": "refund",
        "instructions": "Does the customer request a refund?"
      },
      {
        "type": "choice",
        "name": "team",
        "instructions": "Which team should handle this?",
        "choices": [
          {"value": "billing", "description": "Charges and refunds"},
          {"value": "technical", "description": "Software faults"}
        ]
      },
      {
        "type": "score",
        "name": "severity",
        "instructions": "How severe is the issue?",
        "levels": [
          {"label": "Routine", "description": "An ordinary question"},
          {"label": "Action needed", "description": "An issue requires resolution"},
          {"label": "Blocked", "description": "The customer cannot use the service"}
        ]
      }
    ]
  }'

Add your configured inbound authentication header if gateway security is enabled.

The response contains model, answers in question order, and usage. Each question can be interpreted independently:

Question Answer fields Meaning
predicate probability probability that the statement is true, from 0 to 1
choice typed choice, probabilities, confidence selected option, full option distribution, and provider confidence
score score, probabilities, confidence ordinal score, distribution over zero-based levels with their labels, and provider confidence
native OpenAI refusal type: refusal, name that question was declined; other answers remain available

An unnamed question returns name: null. A response's model may be a concrete version such as jev-1.14.0 even when the request used jev-latest. Confidence is a provider-defined statistic, separate from any individual option probability; choose application thresholds for each provider/model.

Translation and limits

OpenAI preserves the native JSON contract, including additive fields, prompt-cache controls, token details and per-question refusals. Jev translates questions and returns OpenAI-shaped answer arrays in the original order. Its Noul probability becomes a predicate probability. Choice values retain their JSON types, so true and "true" remain distinct; question names may repeat or be absent. Score levels start at zero and retain their labels and descriptions.

Messages and tool evidence become structured state, preserving roles, sequence, call IDs and numeric precision. Tool evidence is never executed. Jev evaluates the supplied structure as state; this is not an OpenAI conversation runtime.

The public contract accepts 1–400 questions; Jev supports at most 255 choices per Choice and 2–10 Score levels. Native context limits also apply. There is no automatic question splitting or experimental long-context enablement. Jev fields with no faithful native equivalent are rejected with a field-specific 400 instead of being discarded. Streaming and service-tier controls are not Decisions controls: omit stream, stream_options, and service_tier. OpenAI-only controls such as prompt_cache_key, prompt_cache_options, and safety_identifier are not translated to Jev. TypeSafe also rejects client Idempotency-Key, OpenAI-Beta, and Anthropic-Beta headers because it has no equivalent native controls.

Probabilities and confidence are provider-native values. The gateway does not repair distributions or invent certainty/refusals. Invalid native responses fail; low confidence is a valid answer. Tune thresholds per provider/model, especially when configuring Luna/Jev fallback. Actual provider and versioned model are exposed through X-LunarGate-Provider, X-LunarGate-Model and the response model; X-LunarGate-Upstream-Request-Type identifies the transport. Luna currently requires unique supplied question names; the gateway filters incompatible targets with a field error before upstream I/O. Jev can preserve duplicate or absent names using internal IDs. The provider may report score and probabilities at different rounding precision. Both are retained independently; the gateway validates the score's ordinal range without replacing it with a mean computed from rounded probabilities.

TypeSafe is Decisions-only and rejects generative/embedding APIs before I/O. Model inventory includes additive capabilities metadata. All non-versioned Jev aliases bypass exact-match caching; pinned jev-X.Y.Z models can use the full-payload/provider/model/transport/config-generation cache.

Routes retain first-match ordering. Put a /v1/decisions route before any catch-all chat route, or explicitly select its name with X-LunarGate-Route. Advertised route capabilities describe that explicit Sandbox selection.

Images with Jev

Jev images are disabled by default. Enable them explicitly for a suitable native model/account:

providers:
  typesafe:
    type: typesafe
    api_key: ${TYPESAFE_API_KEY}
    capabilities:
      decisions: true
      decision_models: [jev-latest]
      decision_images: true

Supply input_image parts with inline data:image/png;base64,... or data:image/jpeg;base64,... URLs. They are supported in input content and in question instructions; the gateway builds native TypeSafe image assets and sets its experimental image header. Invalid base64, non-PNG/JPEG bytes, remote URLs, other formats, and image detail controls other than omitted/auto return a compatibility error identifying the field. The gateway does not fetch images from remote URLs for Jev. The ordinary 10 MiB HTTP request-body limit still applies, including base64 and JSON overhead.

Explicit native fallback

Use one native primary and an explicit fallback if you want a failure on Luna to continue to Jev:

routing:
  routes:
    - name: native-decisions
      match:
        path: /v1/decisions
      targets:
        - {provider: openai, model: gpt-6-luna, weight: 1}
      fallback:
        - {provider: typesafe, model: jev-latest, weight: 1}

Send model: lunargate/auto to permit the route's configured provider choice. An explicit provider/model pins selection and also constrains fallbacks. Each fallback must support the request; for example, a Luna-only prompt-cache control excludes Jev. TypeSafe never falls back to a generative model.

The same retry and circuit-breaker policy applies to native attempts. Compatibility errors are rejected before upstream I/O and do not count as breaker failures. See routing for first-match rules and request-level controls.

Dashboard and request history

Client request_type is decisions; upstream type is decisions for Luna and systemone for Jev. Tokens, native cache usage, timing, retries, fallback and content-sharing settings follow the normal collector path. Sandbox lists only models and routes advertised as Decisions-capable by a connected gateway. Upgrade older gateway instances to use Decisions in Sandbox.

The Dashboard exposes Decisions as a Sandbox API with the three-question example, compatible group/instance targets, and replay. It hides streaming and service-tier controls for this API. Sandbox and request details display context, questions, predicate probabilities, Choice/Score distributions, native confidence, refusals and errors, alongside raw JSON. Filters, live events, CSV and scoped request/log APIs retain the client and upstream types. systemone is upstream metadata, never a public Sandbox mode.

Existing content-sharing flags, access scope and retention still apply.

See HTTP API, provider configuration, caching, and observability.

References: OpenAI Decisions, TypeSafe System One.