Draft · v1

Phronic API

One endpoint for Phronic's One-Pass Models, starting with Pip. Send a state and a set of typed questions in one request, and get a typed answer to each, with the evidence it rests on.

State + questions
Pip one pass, read together
Typed answers + evidence + confidence
Your code

Questions are read together

Every question in a request is read in the same pass as the state. An answer can use the others, so a chain of dependent decisions fits in a single request instead of one request per step.

Every answer shows its evidence

Answers carry the spans of the state they rest on, with character offsets. When the state has no answer, or two that conflict, Pip abstains and says so.

Quickstart

1
Get an API key
export PHRONIC_API_KEY=sk-...
2
Install the SDK
pip install phronic
3
Ask your first questions
from phronic import Phronic

res = Phronic().decide(
    model="pip-latest",
    state="Help! My payouts have failed for 3 days.",
    questions={"is_urgent": {"type": "binary",
        "instructions": "Does this need action today?"}},
)
print(res.answers["is_urgent"].probability)

Question types

Mix any types in one request. Click a row to load its example in the panel.

API reference

Hover any field to find it in the example.

POST https://api.phronic.ai/v1/decide

Request body

model string Required
The model to use. "pip-latest" always points to the newest Pip. New models will be served from the same endpoint.
state string | object | array Required
The input to decide on: plain text, a record, a chat log, or a batch of documents.
questions map<string, Question> Required
Typed questions keyed by ids you choose. Answers come back under the same ids. Pip reads the state and every question together in one pass.

Question

type "choice" | "score" | "binary" | "extract" Required
Sets the question type and the shape of its answer.
instructions string | object Required
The question in plain language. Point at part of a structured state by path, e.g. ticket.messages[0].text.
criteria varies by type
Choice: map of option to description, required, up to 255 options. Score: ordered list of levels, required, 2 to 10. Binary: what true and false mean, optional. Extract: a format hint, optional.

Response body

model string
The exact model version that answered.
answers map<string, Answer>
One answer per question, under the ids you chose.
usage object
input_tokens and output_tokens for the request.

Answer

type string
Matches the question type.
value choice | score | probability | value
The answer. The field name follows the type: choice (an option you defined), score (a position on your levels, can fall between two), probability (0 to 1, for binary), value (text copied from the state, for extract).
probabilities map<string, number>
Choice and score only. The distribution over your options or levels. Sums to 1.
confidence number
0 to 1. How certain Pip is. Use it to decide whether to act or send to a person.
evidence Span[]
The passages of the state the answer rests on: text, start and end character offsets.
abstained boolean
true when the state holds no answer, or two that conflict. The answer value is then null.

Errors

401 Missing or invalid API key. Check the Authorization header.
422 The body failed validation. The response names the field.
429 Rate limit exceeded. Retry with exponential backoff.
529 Temporarily overloaded. Retry after a short delay.

Models

ModelPoints toContext
pip-latest [pip-0.1] [X] tokens
Compatibility

TypeSafe-compatible endpoint

If your code already sends TypeSafe System One requests, point it at this endpoint and it keeps working. Requests and responses follow the TypeSafe format. Pip adds evidence and abstained to each answer; clients that don’t read them can ignore them.

This endpoint is supported but won’t get new features. New work should use /v1/decide.

Switching

Change the base URL, the API key and the model name. Nothing else.

- POST https://api.typesafe.ai/v1/systemone
+ POST https://api.phronic.ai/v1/systemone

- "model": "jev-latest"
+ "model": "pip-latest"

Endpoint

POST https://api.phronic.ai/v1/systemone
Authorization: Bearer $PHRONIC_API_KEY
Content-Type: application/json

Request body

FieldTypeDescription
state string | object | array The input to evaluate. Required.
model string Use "pip-latest". Required.
questions map<string, Question> Questions keyed by ids you choose. Answers return under the same ids. Required.

Question

FieldTypeDescription
type "noul" | "choice" | "score" The question type. Required.
instructions string | object | array The question. An object can carry the question in one field and reference data in others. Required.
criteria varies by type noul: optional object with "true" and "false" descriptions. choice: required map of option to description or null, up to 255 options. score: required ordered array of 2 to 10 levels.
{
  "state": "Help! My payouts have failed for 3 days.",
  "model": "pip-latest",
  "questions": {
    "is_urgent":  { "type": "noul", "instructions": "Does this need action today?" },
    "team":       { "type": "choice", "instructions": "Which team should handle this?",
                    "criteria": { "billing": null, "technical": null, "sales": null } },
    "frustration":{ "type": "score", "instructions": "How frustrated is the customer?",
                    "criteria": ["Calm", "Frustrated", "Very angry"] }
  }
}

Response body

FieldTypeDescription
model string The model version that answered.
answers map<string, Answer> One answer per question id.
usage object input_tokens and output_tokens.

Answer

TypeFieldsNotes
noul noul Probability of yes, 0 to 1.
choice choice, probabilities, confidence The top option, the distribution over all options, and confidence from 0 to 1.
score score, legend, probabilities, confidence A position on your levels (can fall between two), level names by index, the distribution, and confidence.
all types evidence, abstained Added by Pip. Spans of the state behind the answer, and whether Pip declined to answer.
{
  "model": "pip-0.1",
  "answers": {
    "is_urgent": { "type": "noul", "noul": 0.94,
                   "evidence": [{ "text": "for 3 days", "start": 29, "end": 39 }], "abstained": false },
    "team": { "type": "choice", "choice": "billing",
              "probabilities": { "billing": 0.91, "technical": 0.08, "sales": 0.01 }, "confidence": 0.86,
              "evidence": [{ "text": "payouts have failed", "start": 9, "end": 28 }], "abstained": false },
    "frustration": { "type": "score", "score": 1.12,
                     "legend": { "0": "Calm", "1": "Frustrated", "2": "Very angry" },
                     "probabilities": { "0": 0.02, "1": 0.84, "2": 0.14 }, "confidence": 0.79,
                     "evidence": [{ "text": "Help!", "start": 0, "end": 5 }], "abstained": false }
  },
  "usage": { "input_tokens": 132, "output_tokens": 30 }
}

Mapping to /v1/decide

/v1/systemone/v1/decide
type: "noul" type: "binary"
answer.noul answer.probability
choice, score choice, score (unchanged)
– type: "extract"

Errors

Same status codes as /v1/decide: 401, 422, 429 and 529.