HTTP server & the Jev API¶
polyjev serve --config polyjev.yaml --host 0.0.0.0 --port 8011 --playground
| route | |
|---|---|
POST /v1/systemone |
a decision (JSON or multipart with images) |
GET /v1/models |
configured model ids and aliases (no endpoints or keys) |
GET /health, GET /healthz |
liveness |
GET /, GET /playground |
the playground page (with --playground) |
Request¶
The body is Jev's: state, questions (a map of id → {type, instructions,
criteria}) and model.
{
"model": "jev-latest",
"state": {"ticket": "Everything is down and we have a demo at noon."},
"questions": {
"urgent": {"type": "noul", "instructions": "Does the customer need a reply within the hour?"},
"team": {"type": "choice", "instructions": "Which team owns this?",
"criteria": {"billing": null, "outage": "service down", "feature": null}},
"tone": {"type": "score", "instructions": "How angry is the customer?",
"criteria": ["calm", "annoyed", "furious"]}
}
}
noulcriteria: optional{"true": "...", "false": "..."}descriptions.choicecriteria: option name → description (ornull), 2–26 options, order kept.scorecriteria: level names, lowest first, 2–26 levels.span/spanscriteria: optional{"max_tokens": n, "max_items": n}(defaults 24 / 64 tokens, 16 items).- A question may add
depends_on,ask_if({id: [answer names]}, with noul answers being"yes"/"no") andalone; span questions cannot depend or be depended on. - At most 64 questions. Ids may not contain
:or newlines.
model is a configured name or alias. jev-latest means default_model.
Extensions (all optional, same meaning as djev's):
| field | default | |
|---|---|---|
samples |
"auto" |
reads per question, or "auto" (one read, more if unsure) |
auto_max |
4 | most reads under auto |
auto_threshold |
0.1 | entropy (nats) above which auto reads again |
think |
0 | thought budget in tokens before reading (0–4096) |
instructions |
shared context placed before the state | |
ask |
answer only these ids (the others are null) |
|
sequential |
false | answer one at a time, each seeing earlier answers |
seed |
42 | sampling seed where the provider supports one |
images |
data URLs, or {"content_type", "base64"} objects |
|
strategy |
polyjev only: force logprobs / logits / verbalized / vote |
steps, chunk_rows and chunk_prompt only mean something to diffusion
models. They are accepted and listed in diagnostics.ignored.
Images can also be sent as multipart/form-data: the JSON body in a part
named request, then each image as a file part, in order.
curl -s localhost:8011/v1/systemone -F 'request=<examples/requests/readme_example.json' -F 'image=@photo.jpg'
Response¶
{
"model": "local",
"answers": {
"urgent": {"type": "noul", "noul": 0.93},
"team": {"type": "choice", "choice": "outage",
"probabilities": {"billing": 0.02, "outage": 0.95, "feature": 0.03}, "confidence": 0.95},
"tone": {"type": "score", "score": 1.38, "legend": {"0": "calm", "1": "annoyed", "2": "furious"},
"probabilities": {"0": 0.07, "1": 0.48, "2": 0.45}, "confidence": 0.48}
},
"usage": {"input_tokens": 612, "output_tokens": 9},
"diagnostics": {"engine": "polyjev", "strategy": "logprobs", "questions": {"team": {"reads": 1, "label_mass": [0.99]}}}
}
Span answers:
"invoice_id": {"type": "span", "found": true, "text": "A-1042", "start": 9, "end": 15, "confidence": 0.97, "reads": 1},
"dates": {"type": "spans", "found": true, "items": [{"text": "2024-03-15", "start": 64, "end": 74, "confidence": 0.93}]}
A skipped question's answer is null. score is the probability-weighted
0-based level index, and confidence is the probability of the chosen option.
Errors¶
{"error": {"message": "...", "type": "..."}}:
| status | type | when |
|---|---|---|
| 400 | invalid_request_error |
the body is not JSON, or multipart without a request part |
| 401 | authentication_error |
missing or wrong bearer token |
| 422 | validation_error |
invalid schema, unknown model, images sent to a text-only backend |
| 502 | server_error |
the model provider failed |
| 502 | refusal_error |
the model declined (for example a Claude refusal) |
Authentication¶
Set server.api_key (or POLYJEV_API_KEY) and POST /v1/systemone and
GET /v1/models need Authorization: Bearer <key>. The health checks and the
playground page stay open; the playground asks for the key.