- SDK
- System One Models
SDK
System One Models
Classify requests, estimate probabilities, and score inputs with TypeSafe Jev using the Python and TypeScript SDKs.
TypeSafe Jev is a System One model: you give it context and typed questions, and it returns decisions, scores, and probabilities instead of generated prose. Your code can use those answers directly to route a support ticket, flag a request for review, or evaluate an item against a rubric.
Use Python send_message or TypeScript sendMessage. You do not need to create an assistant or thread first. For the full API response and HTTP examples, see System One in Core Concepts.
Before you start
- Set
BACKBOARD_API_KEYin your server environment. You use your Backboard key, not a separate TypeSafe key. - For SDK examples, use a version of
backboard-sdkthat includessystem_one(Python) orsystemOne(TypeScript). - Set the provider to
typesafe, the model tojev-latest, andstreamtofalse. - Put one or more named questions in
system_one.questions. Your question names become the answer keys.
Run SDK examples on your server; never expose your API key in browser code.
Quick start: evaluate a support request
This example asks three questions about the same message in one call:
| Question | Type | What your code receives |
|---|---|---|
refund_requested | noul | Probability that the customer wants a refund |
department | choice | Selected team and probabilities for each team |
urgency | score | A score against ordered urgency levels |
import asyncio
import os
from backboard import BackboardClient
questions = {
"refund_requested": {
"type": "noul",
"instructions": "Does the customer request a refund?",
},
"department": {
"type": "choice",
"instructions": "Which team should handle this request?",
"criteria": {
"billing": "Payments, charges, and refunds",
"technical": "Software errors and troubleshooting",
"general": "Other enquiries",
},
},
"urgency": {
"type": "score",
"instructions": "How urgent is this request?",
"criteria": ["Low: routine enquiry", "Medium: needs prompt attention", "High: immediate action needed"],
},
}
async def main():
async with BackboardClient(api_key=os.environ["BACKBOARD_API_KEY"]) as client:
result = await client.send_message(
"I was charged twice. Please refund me urgently.",
llm_provider="typesafe",
model_name="jev-latest",
stream=False,
system_one={"questions": questions},
)
if result.system_one is None:
raise RuntimeError("No System One result returned")
print("Thread:", result.thread_id)
print("Model:", result.system_one.model)
print("Answers:", result.system_one.answers)
print("Usage:", result.system_one.usage)
asyncio.run(main())
Choose a question type
Noul: estimate whether something is true
Use type: "noul" for a yes/no proposition. The answer’s noul field is a probability from 0 to 1, not a boolean: 0.97 means an estimated 97% probability that the proposition is true.
instructions is required. Optionally define what true and false mean with criteria:
refund_question = {
"type": "noul",
"instructions": "Does the customer request a refund?",
"criteria": {
"true": "The customer explicitly asks for money back",
"false": "The customer does not ask for money back",
},
}
Use this question as the value of questions.refund_requested in your System One configuration.
Choose thresholds for your application and evaluate them on representative data. An uncertain result can go to human review; a high probability alone should not authorize a payment or another irreversible action.
Choice: select one named option
Use type: "choice" for categories such as departments, intent labels, or workflow routes. criteria maps your option names to descriptions; at least one option is required. A description can be null, but clear descriptions help distinguish similar options.
The answer includes:
choice: the selected option name, such asbilling.probabilities: the distribution across the options.confidence: a summary of how concentrated that distribution is. This is not a guarantee of correctness.
Include an explicit fallback option such as general when none of the specific categories may apply.
Score: evaluate against an ordered rubric
Use type: "score" for urgency, quality, relevance, or other ordered assessments. criteria must contain at least two strings, ordered from the low end to the high end of your rubric.
The answer includes score, legend, probabilities, and confidence. Use the returned legend to interpret the numeric scale and the probability keys; do not assume the score is a percentage or an index into your criteria array.
All questions require instructions, which may be a string, object, or array. Text instructions are usually the simplest starting point. Multiple question types can share one request, and questions must be sent again on every inference turn.
Read and act on answers
Python exposes result.system_one.answers; TypeScript exposes result.systemOne.answers. The answer fields inside those objects keep their API names.
Full response example
The SDKs parse the following API response into their response objects. Python uses result.system_one; TypeScript uses result.systemOne. This JSON illustrates returned data, not an additional request example. IDs, timestamps, model resolution, token counts, and predictions below are illustrative, not a recorded live response. Optional fields unrelated to this evaluation are shown as null.
{
"message": "Message added successfully",
"thread_id": "11111111-1111-4111-8111-111111111111",
"assistant_id": "22222222-2222-4222-8222-222222222222",
"message_id": "33333333-3333-4333-8333-333333333333",
"run_id": "44444444-4444-4444-8444-444444444444",
"role": "assistant",
"status": "COMPLETED",
"content": "{\"refund_requested\": {\"type\": \"noul\", \"noul\": 0.97}, \"department\": {\"type\": \"choice\", \"choice\": \"billing\", \"probabilities\": {\"billing\": 0.96, \"technical\": 0.01, \"general\": 0.03}, \"confidence\": 0.82}, \"urgency\": {\"type\": \"score\", \"score\": 1.7, \"legend\": {\"0\": \"Low: routine enquiry\", \"1\": \"Medium: needs prompt attention\", \"2\": \"High: immediate action needed\"}, \"probabilities\": {\"0\": 0.05, \"1\": 0.2, \"2\": 0.75}, \"confidence\": 0.5}}",
"system_one": {
"model": "jev-1.13.0",
"answers": {
"refund_requested": {"type": "noul", "noul": 0.97},
"department": {
"type": "choice",
"choice": "billing",
"probabilities": {"billing": 0.96, "technical": 0.01, "general": 0.03},
"confidence": 0.82
},
"urgency": {
"type": "score",
"score": 1.7,
"legend": {
"0": "Low: routine enquiry",
"1": "Medium: needs prompt attention",
"2": "High: immediate action needed"
},
"probabilities": {"0": 0.05, "1": 0.2, "2": 0.75},
"confidence": 0.5
}
},
"usage": {"input_tokens": 312, "output_tokens": 0}
},
"model_provider": "typesafe",
"model_name": "jev-1.13.0",
"input_tokens": 312,
"output_tokens": 0,
"total_tokens": 312,
"created_at": "2026-09-17T12:00:00Z",
"timestamp": "2026-09-17T12:00:01Z",
"tool_calls": null,
"memory_operation_id": null,
"retrieved_memories": null,
"retrieved_files": null,
"retrieved_files_count": 0,
"reasoning": null,
"attachments": null,
"generated_media": null,
"voice_records": null,
"context_usage": null
}
Interpret the result
- Refund:
noul: 0.97estimates a 97% probability that a refund is requested. It is not a refund authorization. - Department:
choice: "billing"selects the billing team. Its option probability is0.96;confidenceis a separate distribution summary, not the selected option’s probability or a guarantee of correctness. - Urgency: the returned
legendmaps0to Low,1to Medium, and2to High. Herescore: 1.7lies between Medium and High, whileprobabilities["2"]: 0.75assigns 75% probability to the High level. The score can be fractional: do not use it as an array index or interpret it as 1.7%. - Content:
contentis a JSON string containing the same answers assystem_one.answers, not generated prose. Prefer the structuredanswersobject; the backslashes above are JSON string escaping. - Usage: top-level token counts mirror
system_one.usage, andtotal_tokensis their sum. Zero output tokens in this example does not mean the response has no answers; use the reported usage rather than counting the response JSON. - Identifiers: reuse
thread_idto continue the conversation;message_ididentifies this assistant reply.model_nameandsystem_one.modelidentify the resolved model rather than necessarily echoing the requested alias.
Use the answers in your application
These snippets continue the quick-start examples. Put the Python snippet inside main(), after checking result.system_one.
answers = result.system_one.answers
refund = answers["refund_requested"]
department = answers["department"]
urgency = answers["urgency"]
if refund["noul"] >= 0.9 and department["choice"] == "billing":
print("Queue for billing review")
else:
print("Queue for general review")
print("Urgency:", urgency["score"], "Scale:", urgency["legend"])
print("Team probabilities:", department["probabilities"])
The response also contains the usual thread and message identifiers. system_one.model identifies the resolved model, and system_one.usage contains input_tokens and output_tokens. The assistant message’s content is a JSON-encoded version of the answers; use the structured result rather than parsing prose.
Evaluate structured application data
Use system_one.state to pass an object, array, or string alongside your message. This is useful when the decision depends on data already in your application, such as transaction records or account status.
The following examples evaluate the same transaction data. The SDK snippets reuse the client from the quick start; put the Python call inside its async with block.
evaluation = await client.send_message(
"Check these charges for a possible duplicate.",
llm_provider="typesafe",
model_name="jev-latest",
stream=False,
system_one={
"state": {"charges": [
{"amount": 49, "currency": "USD", "order": "A123"},
{"amount": 49, "currency": "USD", "order": "A123"},
]},
"questions": {
"possible_duplicate": {
"type": "noul",
"instructions": "Do the charges in state appear to be a duplicate payment for the same order?",
},
},
},
)
print(evaluation.system_one.answers)
Backboard includes conversation messages, the effective system_prompt, available document_summaries, and your optional state in the context sent to Jev. Questions can refer to those fields. Supplying state does not replace conversation history. If you omit content, Backboard saves a serialized representation of the state as the user message.
For independent evaluations, omit thread_id to start a new conversation. For an evolving case, reuse the thread and pass updated state on the next turn.
Continue a conversation
Reuse the returned thread ID to evaluate new information alongside earlier messages. Send the provider, model, and questions again; they are per-turn settings.
The SDK snippets reuse result and client from the quick start; place the Python snippet inside its async with block.
followup = await client.send_message(
"The second charge was reversed. I no longer need a refund.",
thread_id=result.thread_id,
llm_provider="typesafe",
model_name="jev-latest",
stream=False,
system_one={"questions": {
"refund_still_needed": {
"type": "noul",
"instructions": "Considering the latest update and earlier messages, does the customer still need a refund?",
},
}},
)
print(followup.system_one.answers)
You can also use add_message(thread_id, ...) in Python or addMessage(threadId, {...}) in TypeScript with the same System One configuration. To start a separate conversation that shares an assistant’s configuration, pass assistant_id instead of thread_id (assistantId in TypeScript).
Models and usage
Use jev-latest for the latest alias, jev-1.13.0 for a pinned version, or jev-preview for the preview alias. Aliases can change; read the resolved system_one.model when recording evaluations.
See Models and usage in Core Concepts for catalog discovery and pricing.
Normal Backboard credit checks and usage billing apply. Questions and conversation context contribute to input usage. To save a message without inference, use send_to_llm="false" in Python or sendToLlm: 'false' in TypeScript; that turn does not call or charge Jev.
Request checklist
- Use non-streaming requests:
stream=false. - Provide at least one question: every question needs a supported
typeandinstructions; Choice and Score also needcriteria. - Pass text or structured data: attachment input, voice, and media generation are not supported on this path.
- Keep generation controls out: do not send
temperature,max_tokens,response_format, thinking settings, tools, or web-search options. Typed answers do not requirejson_output. - Check inherited settings: if reusing an assistant with tools, pass
tools=[]; disable enabled web-search or media settings for the turn.
Malformed questions or unsupported controls return 422. An insufficient-credit response is 402; check your Backboard balance before retrying.