AI Decisions Reference
Prefer useAIDecisions for programmatic judgments: a yes/no, one category from a fixed set, or a position on an ordered rubric. decide() is far cheaper and faster than text or object generation. One request can answer several questions about the same state, and the probability can drive the interface: labels, routing, filters, thresholds, and checks while the user is still working.
Use useAIObject when the result needs generated or extracted fields these three types cannot express, such as titles, lists, nested fields, or prose inside a schema. A feature can use both.
useAIDecisions
Returns
decide(function): Evaluate questions against shared state.isLoading(boolean): Whether a decision is in progress.error(Error | null): Current error.clearError(() => void): Clear the current error.
Result Shape
decide resolves to a result object or undefined. On success the result contains answers, keyed by your question IDs:
boolean:probability, the probability of true from 0 to 1.choice:choice, andprobabilitieswhen the model provides a distribution.score:score, a position from 0 through one less than the number of levels, andprobabilitieswhen provided. With probabilities, the position is their weighted mean and can fall between levels. Probability keys are the level indexes.
Distributions are optional. A probability does not itself authorize an action.
decide resolves to undefined on failure or when this hook instance already has a request in flight, and never rejects.
decide Input
state(string, object, or array, required): JSON value shared by every question. An array is one state, not a batch of requests.questions(object, required): Nonempty map of question IDs. Each question hastype,instructions, and type-specificcriteria.model(string): Model ID for the request. Omit it and the platform selects the model.
Example
import * as React from 'react'
import { useAIDecisions } from '@/hooks/use-ai'
export default function App() {
const [entry, setEntry] = React.useState('')
const [probability, setProbability] = React.useState<number | null>(null)
const { decide, isLoading, error } = useAIDecisions()
const handleDecide = async () => {
const result = await decide({
state: entry,
questions: {
wantsFollowUp: {
type: 'boolean',
instructions: 'Does the writer want to come back to this later?',
},
},
})
if (result) setProbability(result.answers.wantsFollowUp.probability)
}
return (
<div>
<label htmlFor="entry">Journal entry</label>
<textarea
id="entry"
value={entry}
onChange={(event) => setEntry(event.target.value)}
/>
<button disabled={isLoading} onClick={handleDecide}>
Check for a follow-up
</button>
{probability !== null ? (
<p>Follow-up probability: {Math.round(probability * 100)}%</p>
) : null}
{error ? <p className="text-destructive">{error.message}</p> : null}
</div>
)
}
Question types
Choice criteria are a map of options to descriptions. null means the option has no description. Score criteria are 2–10 levels, and each level needs a description. answers.<id>.score is a position from 0 through one less than the number of levels. With probabilities, it is their weighted mean and can fall between levels; probability keys are those indexes. An 0–10 scale is 11 levels, which is over the maximum. Boolean criteria are optional.
const result = await decide({
state: { note, minutes },
questions: {
focus: {
type: 'choice',
instructions: 'Which kind of session is this?',
criteria: {
strength: 'Lifting or resistance work',
cardio: 'Running, cycling, or other endurance work',
mobility: 'Stretching or easy movement',
},
},
effort: {
type: 'score',
instructions: 'How hard did the session feel?',
criteria: ['Easy', 'Solid', 'All out'],
},
mentionsPain: {
type: 'boolean',
instructions: 'Does the note mention pain or an injury?',
criteria: {
true: 'Names pain, soreness that concerns them, or an injury',
false: 'No pain or injury mentioned',
},
},
},
})
if (result) {
// result.answers.focus.choice is inferred as 'strength' | 'cardio' | 'mobility'.
const focus = result.answers.focus.choice
}
Instructions and descriptions can be strings, JSON objects, or JSON arrays.
Model Selection
When no model is specified, the platform chooses a decision model. To expose model choice, pass a model ID and build selectors from listDecisionModels():
import { listDecisionModels, useAIDecisions } from '@/hooks/use-ai'
const models = listDecisionModels()
const [modelId, setModelId] = React.useState<string | undefined>(undefined)
const { decide } = useAIDecisions()
await decide({
state: message,
questions,
model: modelId,
})
Available models:
- Jev 1.14 —
typesafe/jev-1.14(TypeSafe). Pinnedtypesafe/jev-1.13runs as Jev 1.14. - GPT-6 Luna —
gpt-6-luna(OpenAI)
listDecisionModels() returns an array of model objects with:
id: Model ID to pass asmodel.displayName: Human-readable display name.provider: Provider name.tier:"lite","standard", or"advanced".description: Short model description.capabilities:boolean,choice, andscore.
Best Practices
- Omit
modelunless the app has a model picker. - Use
if (result)and store the answers the app needs with React state orusePersistentItem. - Choose thresholds in the application. A probability does not by itself take an action.
- One in-flight request per
useAIDecisions()instance. Use separate instances for parallel calls.