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.