تصمیمها (آلفا)
POST /v1/alpha/decisions یک وضعیت و مجموعهای از پرسشهای نوعدار میگیرد و برای هر پرسش یک پاسخ نوعدار برمیگرداند: یک احتمال (noul)، یک گزینهٔ برچسبدار (choice)، یا جایگاهی پیوسته روی نردبانی که خودتان میدهید (score). متن آزاد و استریم در کار نیست، پس کد شما مستقیماً روی پاسخ شرط میگذارد. تنها ورودی محاسبه میشود و خروجی رایگان است؛ هزینهٔ دقیق در usage.cost همان پاسخ برمیگردد — این فیلد در طرحوارهٔ ارائهدهنده اختیاری است، پس پاسخی که آن را نداشته باشد بهجای صفر روی مبلغ رزروشده تسویه میشود. واژهٔ alpha در مسیر هشدار خود ارائهدهنده است: شکل این سرویس هنوز ممکن است تغییر کند.
/v1/alpha/decisionsاحراز هویت BearerAsk a decisions model typed questions
ALPHA. Send some state plus a map of typed questions, get one
typed answer per question. Answers are values your code can branch
on directly — never prose, and never streamed.
Supported models: typesafe/jev-1.13 (pinned) and
~typesafe/jev-latest (always resolves to the newest model in the
Jev family). The tilde is part of the id upstream; Hormouz also
accepts typesafe/jev-latest and jev-latest and canonicalises
them for you. See GET /v1/models — note decisions models are
deliberately absent from that list, because no OpenAI-compatible
client can call them; browse them in the dashboard catalogue instead.
Three question types.
noul— returnsnoul, the probability in[0,1]that the condition holds. Gate an action on whatever threshold you choose.criteriais optional; when present it needs bothtrueandfalse.choice— picks one of the labels incriteriaand returns it aschoice, plusconfidenceand aprobabilitiesmap so a close call is visible rather than hidden.criteriais required and is an object oflabel -> description.score— places the input on the ORDERED ladder you supply incriteria(an array, lowest first) and returns a CONTINUOUSscore, pluslegendmapping each index to its label.1.99means "almost entirely the third rung".criteriais required.
Billing: input tokens only — output is free. A hold is placed
before the upstream call, sized from the size of the request; the
exact cost from usage.cost is settled inline the moment the response
arrives, and you are never charged more than the hold. There is no
async settlement. usage.cost is optional in the provider's schema;
a response that omits it is priced from its own token counts, which
that schema does require, so the charge is the same either way.
Limits. The request body is capped at 1 MiB on this endpoint
— lower than the 50 MiB the chat routes allow, because a decisions
body is state plus a questions map. Repeating a top-level key is
refused with 400: our parser resolves a duplicate to the first
occurrence and the provider to the last, so we reject rather than
price a body we cannot read the same way it will. A provider answer
over 1 MiB is refused with 502 UPSTREAM_RESPONSE_TOO_LARGE, kept
distinct from a plain UPSTREAM_ERROR because the answer was
already generated and a blind retry costs money and fails
identically.
Alpha: the request and response shapes are passed through from the provider unchanged, which is what lets you move existing code here by swapping the base URL — and also means they may change while this is in alpha. Pin a version and add a contract test before depending on it in production.
بدنه درخواستالزامی
| فیلد | نوع | توضیح |
|---|---|---|
modelالزامی | string | Model id. Accepts نمونه: |
stateالزامی | object | The content to judge — any JSON value. Typically a string,
or an object of related context. Required, but may be
empty: |
questionsالزامی | object | Map of your own question name to a question. The names you
choose are the keys you read back out of |
session_id | string | Optional grouping id for related requests, forwarded upstream as part of the body and used there for observability grouping. Hormouz neither reads nor strips it. Do not put anything sensitive in it. |
user | string | Optional end-user identifier, forwarded upstream as part of the body. Hormouz neither reads nor strips it. |
نمونه
پاسخها
200One typed answer per question.
{
"id": "gen-dec-1789738314-X5e5eKGQdvR9rblyX250",
"model": "typesafe/jev-1.13-20260917",
"provider": "TypeSafe",
"answers": {
"is_bug": {
"type": "noul",
"noul": 0.96
},
"team": {
"type": "choice",
"choice": "payments",
"confidence": 0.75,
"probabilities": {
"account": 0,
"frontend": 0.16,
"payments": 0.84
}
},
"urgency": {
"type": "score",
"score": 1.99,
"confidence": 0.99,
"legend": {
"0": "Can wait for the next release",
"1": "Should be fixed this week",
"2": "Blocking revenue right now"
},
"probabilities": {
"0": 0,
"1": 0.01,
"2": 0.99
}
}
},
"usage": {
"cost": 0.000019992,
"input_tokens": 476,
"output_tokens": 70
}
}400The request body or query parameters are invalid. Check the
error.code and error.message fields for details. Codes the
gateway emits at 400:
BAD_REQUEST: generic malformed JSON / missing required field.INVALID_TOOLS: thetoolsarray,pluginsfield, or model's:onlinesuffix uses an unsupported shape. The response names the offender and links to the supported form. See the dedicatedInvalidToolsresponse below for the three triggers and migration hints.UNSUPPORTED_TOOL: a built-in tool (file_search,code_interpreter,computer_use,mcp) whose pricing dimension is not yet wired into the gateway hold estimator.INVALID_AUDIO_FORMAT:input_audio.formatvalue is not in the supported set. The envelope lists every supported codec name. The gateway accepts both short names (wav,webm) and full MIME aliases (audio/wav,audio/webm); anything else fails fast at admission. See API guide §8b.AUDIO_NOT_SUPPORTED_ON_RESPONSES:input_audiocontent part sent toPOST /v1/responses. The Responses API has no audio content type today; resend toPOST /v1/chat/completionsinstead.
401Authentication failed. Either the Authorization header is missing,
the key format is invalid, or the key doesn't match any active account.
{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"status": 401
}
}402Insufficient credits.
409Idempotency key conflict: you sent the same Idempotency-Key with
a different request body.
413Request body exceeded the 1 MiB limit for this endpoint.
429Too many requests. Back off and retry after a short delay.
Check the Retry-After header for guidance.
499Your HTTP client cancelled the request before the gateway finished. No charge: the hold has been released. The most common cause is a 30 s default client timeout against a model whose p95 latency is 45-60 s; bump your client timeout to 120 s.
Retries with the same Idempotency-Key will replay this 499
forever (the prior outcome is "you cancelled"). For an actual
re-attempt, mint a fresh Idempotency-Key. See
docs/CUSTOMER_ERROR_HANDLING.md §3 for the full contract.
{
"error": {
"code": "CLIENT_CLOSED",
"message": "Client disconnected before response",
"status": 499
}
}500Unexpected server error. Please retry with exponential backoff. If the issue persists, contact your admin.
502The upstream AI provider is temporarily
unavailable. Retry with exponential backoff (1s, 2s, 4s) using the
same Idempotency-Key: if the upstream actually completed
the work and only the response failed, the gateway replays the
cached success without a second charge. Holds are released
automatically on upstream failures.
503The upstream AI provider is temporarily
unavailable. Retry with exponential backoff (1s, 2s, 4s) using the
same Idempotency-Key: if the upstream actually completed
the work and only the response failed, the gateway replays the
cached success without a second charge. Holds are released
automatically on upstream failures.
504The gateway's 120 s upstream deadline elapsed before the upstream
provider produced a response. Retry with the same
Idempotency-Key so a delayed-but-eventually-successful upstream
call can be replayed instead of re-charged. Consider switching
to a faster model or capping max_tokens if this recurs.
{
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "Upstream did not respond before timeout",
"status": 504
}
}