Skip to content

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"]}
  }
}
  • noul criteria: optional {"true": "...", "false": "..."} descriptions.
  • choice criteria: option name → description (or null), 2–26 options, order kept.
  • score criteria: level names, lowest first, 2–26 levels.
  • span / spans criteria: 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") and alone; 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.