
TL;DR
- Generate Jev question schemas from TypeScript types. Property and enum comments supply the instructions and choice descriptions.
- Call Jev directly or through Vercel AI SDK. Decode the answers back into the declared TypeScript type.
- Use the same type with OpenAI. Generate JSON Schema for Structured Outputs and call the official
openaiSDK.
import typia, { tags } from "typia";
enum Department {
/**
* Payments, invoicing, refunds.
*
* Duplicate charges, failed cards, and plan changes belong here, even when
* the customer also mentions a bug.
*
* @probability 0.3
*/
billing = "billing",
/**
* Bugs, outages, and broken integrations.
*
* Paging an engineer is expensive, so only pick this when the customer
* describes the product misbehaving.
*
* @probability 0.5
*/
technical = "technical",
/**
* Pricing, upgrades, and new accounts.
*
* @probability 0.2
*/
sales = "sales",
}
interface ITicketTriage {
/**
* Does the customer convey urgency?
*
* A deadline, an outage, lost revenue, or a threat to leave counts. An
* impatient tone alone does not.
*/
urgent: boolean;
/**
* Which team should handle this ticket?
*
* Decide by what the customer needs done, not by the words they use.
*/
department: Department;
/**
* Does the customer ask for their money back?
*
* Complaining about a charge is not a request. The customer has to ask.
*/
refund: boolean & tags.Probability<0.8>;
}
const triage = typia.llm.evaluation<ITicketTriage>();
const ticket = "I was charged twice this morning. Refund it now, or I leave.";typia.llm.evaluation<ITicketTriage>() generates a question map and answer decoder at compile time. Boolean properties become yes/no questions; Department becomes a choice question. Property comments supply instructions, and enum member comments describe each option.
The Jev examples below send triage.questions with the same ticket. Jev performs the inference; triage.decode() checks its answers and returns the reconstructed ITicketTriage in result.data, or validation errors in result.errors.
import { TypeSafeClient } from "@typesafe-ai/sdk";
import { toJevQuestions } from "@typia/jev";
const client = new TypeSafeClient(); // reads TYPESAFE_API_KEY
const { answers } = await client.systemOne({
model: "jev-1.13.0",
state: ticket,
questions: toJevQuestions(triage.questions),
});
const result = triage.decode(answers);
if (result.success) {
result.data.department; // Department
result.data.refund; // boolean
}@typesafe-ai/sdk calls Jev directly. toJevQuestions() converts the yes/no question type from "boolean" to Jev’s native "noul"; choice and score questions pass through unchanged. Set TYPESAFE_API_KEY for the client.
Pass the returned answers to triage.decode(). The decoded object contains the fields declared in ITicketTriage; keep the original answer map if you also need Jev’s probabilities.
import { typeSafeAi } from "@ai-sdk/typesafe-ai";
import { experimental_decide } from "ai";
const response = await experimental_decide({
model: typeSafeAi.decisionModel("jev-1.13.0"),
state: ticket,
questions: triage.questions,
});
const result = triage.decode(response.answers);
if (result.success) {
result.data.department; // Department
result.data.refund; // boolean
}Vercel AI SDK’s TypeSafe provider calls Jev through experimental_decide(). Pass triage.questions directly: the provider converts them to Jev’s native format. Decode response.answers with the same triage.decode() function.
Set TYPESAFE_AI_API_KEY for this provider, rather than the direct SDK’s TYPESAFE_API_KEY. The example uses AI SDK 7’s decision API.
import OpenAI from "openai";
const client = new OpenAI(); // reads OPENAI_API_KEY
const output = typia.llm.structuredOutput<ITicketTriage, { strict: true }>();
const response = await client.responses.create({
model: "gpt-5.6-luna",
input: [
{ role: "system", content: "Classify the customer ticket using the schema descriptions." },
{ role: "user", content: ticket },
],
text: {
format: {
type: "json_schema",
name: "ticket_triage",
strict: true,
schema: { ...output.parameters },
},
},
});
if (response.status !== "completed" || !response.output_text) {
throw new Error("OpenAI did not return a completed structured response.");
}
const result = output.validate(JSON.parse(response.output_text));
if (result.success) {
result.data.department; // Department
result.data.refund; // boolean
}OpenAI’s official openai SDK accepts JSON Schema for Structured Outputs. typia.llm.structuredOutput<ITicketTriage, { strict: true }>() generates that schema for text.format from the same type and comments. Set OPENAI_API_KEY for the client.
OpenAI returns the triage object as JSON text. The guard handles incomplete responses or refusals without text; output.validate() checks the parsed object. This path does not return Jev’s answer map or enforce the evaluation-specific probability annotations.
npm install -D ttsc typescript
npm install typia @typia/jev
npx ttsc # build
npx ttsx src/index.ts # or runInstall the SDK packages for the example you use. Save the shared declarations and one SDK example in src/index.ts, and set its API key. Use ttsc or ttsx to apply typia’s compile-time transform.