Skip to content
Dashboard

5 things you can build with AI Gateway's Decision API

Content Engineer

AI Gateway's Decision API can help you interpret cancellation requests, organize release notes, score search results, review event submissions, and filter notifications. Each tool supplies evidence and a bounded question to a decision model, then uses the structured answer to suggest what should happen next.

Copy link to headingWhich models do these examples use?

The five examples use four decision models through the same AI SDK interface. Each pairing illustrates a workflow you can test with your own data; it isn't a ranking of models for that task.

Tool

Model

Question type

Application output

Cancellation-request interpreter

GPT-6 Luna Decisions

Choice

Suggested confirmation or clarification screen

Release-note audience classifier

Jev

Choice

Suggested editorial destination

Search-result relevance checker

Liquid d1

Score

Relevance score for a retrieved passage

Event-submission reviewer

Laya

Boolean and Choice

Topic assessment and proposed event format

Notification digest filter

Jev

Boolean

Immediate, digest, or review suggestion

Copy link to headingHow do you run the examples?

Use Node.js 22.18 or later and install the packages in your project:

npm install ai @ai-sdk/gateway

The experimental decision API requires ai 7.0.128 or later.

Configure AI_GATEWAY_API_KEY on the server, following the decision quickstart. If your team uses a provider allowlist, an allowed provider must be available for each model you run.

Save any example as decision.mjs and run node decision.mjs. If your credentials are in .env.local, add Node's --env-file=.env.local option before the filename.

For local Vercel OIDC, use the Vercel CLI to link your project with vercel link and pull its development environment variables with vercel env pull .env.local. Load that file with the same Node option and leave AI_GATEWAY_API_KEY unset so Gateway uses OIDC. Refresh the downloaded token when it expires.

Each script makes a decision request and prints the proposed result. Your application would connect that output to its interface or review queue. The examples use a 30-second timeout and disable SDK retries so a failed test doesn't automatically repeat the call.

Copy link to heading1. Interpret cancellation requests with GPT-6 Luna Decisions

"Don't renew this" and "cancel immediately" can lead to different account changes. Before showing a confirmation screen, a subscription application can classify the requested timing. Someone asking how cancellation works should reach help, while a request without clear timing should prompt a follow-up question.

This example asks Luna to distinguish those intents. The clarify option gives the model somewhere to send incomplete requests, and the instructions explicitly forbid assuming that an unspecified date means now.

import { experimental_decide as decide } from 'ai';
import { gateway } from '@ai-sdk/gateway';
const state = {
message: 'Keep my access until the paid period ends, but do not renew it.',
};
try {
const result = await decide({
model: gateway.decisionModel('openai/gpt-6-luna-decisions'),
state,
questions: {
intent: {
type: 'choice',
instructions: 'Interpret the cancellation request without taking action. ' +
'Never infer immediate cancellation from an unspecified date. ' +
'If cancellation is requested but timing is missing, choose clarify.',
criteria: {
now: 'Explicitly requests cancellation immediately.',
at_renewal: 'Requests no renewal while keeping current paid access.',
information: 'Asks about cancellation without requesting it.',
clarify: 'Requests cancellation with unclear or conflicting timing.',
},
},
},
maxRetries: 0,
abortSignal: AbortSignal.timeout(30_000),
});
const answer = result.answers.intent;
const screens = {
now: 'confirm_immediate_cancellation',
at_renewal: 'confirm_end_of_term_cancellation',
information: 'cancellation_help',
clarify: 'ask_about_timing',
};
console.log(JSON.stringify({
suggestedScreen: screens[answer.choice],
answer,
}, null, 2));
} catch {
console.error('Decision failed. Keep the request available for review.');
process.exitCode = 1;
}

For the supplied message, the intended suggestion is a confirmation screen for end-of-term cancellation. The application can display the actual paid-through date from its billing system and ask the customer to confirm. Authentication and permission checks still belong in the cancellation operation; the model's classification only helps select the screen.

Other OpenAI Decisions API use cases apply this approach to questions about incident handoffs and documentation.

Copy link to heading2. Choose a release-note audience with Jev

Engineering updates often mix user-facing changes with work that only affects maintainers. An editorial intake tool can suggest whether a change belongs in customer release notes, a developer changelog, or an internal engineering log.

For example, requiring a new API parameter affects developers maintaining an integration, while moving a dashboard navigation item affects people using the interface.

Give Jev the change's effect, including any API or interface behavior that changed. The descriptions below define the audience by who needs to act on that information. Ambiguous submissions go to editorial review instead of acquiring an audience from a technical keyword alone.

import { experimental_decide as decide } from 'ai';
import { gateway } from '@ai-sdk/gateway';
const state = {
change: 'The export API now requires callers to send a timezone parameter.',
};
try {
const result = await decide({
model: gateway.decisionModel('typesafe-ai/jev'),
state,
questions: {
audience: {
type: 'choice',
instructions:
'Choose the primary audience for communicating this change. ' +
'Use review if the effect is unclear or no primary audience is evident.',
criteria: {
customers: 'Changes how people use the product interface.',
developers: 'Changes API or SDK behavior that integrators must account for.',
internal: 'Internal maintenance with no external behavior change.',
review: 'Insufficient context or several audiences without a clear primary one.',
},
},
},
maxRetries: 0,
abortSignal: AbortSignal.timeout(30_000),
});
const answer = result.answers.audience;
const destinations = {
customers: 'customer_release_notes',
developers: 'developer_changelog',
internal: 'internal_engineering_log',
review: 'editorial_review',
};
console.log(JSON.stringify({
suggestedDestination: destinations[answer.choice],
answer,
}, null, 2));
} catch {
console.error('Decision failed. Keep the change available for editorial review.');
process.exitCode = 1;
}

Requiring a new API parameter should suggest developer_changelog. Editors can then inspect the change and decide whether it also needs a migration notice or a customer-facing explanation. This single-choice question selects a primary destination; it doesn't enumerate every affected audience.

For the integration details behind this classifier, the Jev and AI SDK guide covers typed questions and handling their answers.

Copy link to heading3. Check search-result relevance with Liquid d1

Search can retrieve a passage about the right topic that never answers the question. Someone asking whether a project transfer preserves its public URL needs more than instructions for finding the transfer button.

After retrieval, pass a candidate passage and the original query to d1. This example uses a fictional product and a four-level rubric to distinguish an unrelated result, a topical result without an answer, a partial answer, and a direct answer.

import { experimental_decide as decide } from 'ai';
import { gateway } from '@ai-sdk/gateway';
const state = {
query: 'Can I transfer a project without changing its public URL?',
passage: 'Transferring a project to another workspace preserves its public URL. ' +
'The destination workspace must accept the transfer.',
};
try {
const result = await decide({
model: gateway.decisionModel('liquid/d1'),
state,
questions: {
usefulness: {
type: 'score',
instructions: 'Rate how fully the passage answers the supplied query.',
criteria: [
'Unrelated to the question.',
'Related topic, but provides no answer to the question.',
'Answers part of the question while leaving a material gap.',
'Directly answers the question with the relevant conditions.',
],
},
},
maxRetries: 0,
abortSignal: AbortSignal.timeout(30_000),
});
const answer = result.answers.usefulness;
console.log(JSON.stringify({
candidate: { text: state.passage, relevanceScore: answer.score },
distribution: answer.probabilities ?? null,
}, null, 2));
} catch {
console.error('Relevance check failed. Keep the original retrieval result.');
process.exitCode = 1;
}

The rubric's positions run from 0 to 3. The returned score can be fractional, so keep its numeric value when sorting candidate passages. The supplied passage belongs near the top of this rubric because it answers the URL question and states the transfer condition.

In a search application, retrieve only sources the user may access and preserve each candidate's source identifier alongside the score. Relevance measures whether the passage addresses the question; it doesn't establish that the source is accurate or current. If the check fails, keep the original retrieval result available.

Copy link to heading4. Prepare event review cards with Laya

Community calendars need to distinguish a relevant workshop from an unrelated event or a sales presentation. Topic and format are separate judgments: a hands-on activity can be a workshop even when it doesn't belong on a web-development calendar.

Ask Laya both questions against the same submission. The Boolean question checks whether the subject concerns web application development or operations, independently of whether the event is educational or promotional. The Choice question identifies the format. Display both answers in a review card beside the submitted description so a moderator can assess the event.

import { experimental_decide as decide } from 'ai';
import { gateway } from '@ai-sdk/gateway';
const state = {
calendar: 'Educational events about building and operating web applications.',
submission: {
title: 'Debugging slow database queries in a web application',
description: 'Bring a sample query. We will inspect query plans and practice ' +
'adding an index, then compare the results.',
},
};
try {
const result = await decide({
model: gateway.decisionModel('convaiinnovations/laya'),
state,
questions: {
onTopic: {
type: 'boolean',
instructions: 'Is the event about building or operating web applications? ' +
'Use the title and description to identify its subject, ' +
'independently of whether it is educational or promotional.',
criteria: {
true: 'The subject concerns web application development or operations.',
false: 'The subject is unrelated to web application development or operations.',
},
},
format: {
type: 'choice',
instructions: 'Classify the activity participants are being offered.',
criteria: {
workshop: 'Participants practice a skill or work through an exercise.',
talk: 'Participants listen to an educational presentation.',
promotion: 'The primary activity is a product sales pitch.',
unclear: 'The description does not establish the activity.',
},
},
},
providerOptions: { gateway: { only: ['boundless'] } },
maxRetries: 0,
abortSignal: AbortSignal.timeout(30_000),
});
console.log(JSON.stringify({
reviewCard: {
title: state.submission.title,
topicProbability: result.answers.onTopic.probability,
proposedFormat: result.answers.format.choice,
},
answers: result.answers,
}, null, 2));
} catch {
console.error('Decision failed. Leave the submission in the review queue.');
process.exitCode = 1;
}

The card keeps subject and format separate: a web-monitoring sales presentation can concern the right subject while being labeled promotion. In a three-event test of this example, Laya selected the intended format for each submission, but assigned an unrelated workshop a topic probability of about 0.51. Keep uncertain submissions in review and use the description to assess relevance before accepting an event.

The only setting selects Boundless as the hosting provider for this request through Gateway provider options.

Required fields and valid dates can be checked in ordinary application code before this semantic review. For the differences between the models used in these middle examples, see Jev vs. Laya vs. Liquid d1.

Copy link to heading5. Separate interruptions from digest updates with Jev

An update marked "urgent" may describe a team lunch, while a plainly worded message may report a blocked production release. Notification preferences become more useful when the application can assess the situation described in a message.

Supply the recipient's preferences with the update and ask Jev whether it meets the interruption criteria. The application can then use the probability to choose among an immediate notification, a digest entry, and review.

import { experimental_decide as decide } from 'ai';
import { gateway } from '@ai-sdk/gateway';
const state = {
preferences: 'Interrupt me only for unresolved problems blocking a production ' +
'release or affecting customers. Put resolved incidents and routine updates in the digest.',
update: 'The release is blocked: database migrations fail before deployment. ' +
'No workaround is available and the team is still investigating.',
};
try {
const result = await decide({
model: gateway.decisionModel('typesafe-ai/jev'),
state,
questions: {
needsInterruption: {
type: 'boolean',
instructions: 'Does the update meet the supplied criteria for interrupting ' +
'this recipient now? Judge the described situation, not urgent wording.',
},
},
maxRetries: 0,
abortSignal: AbortSignal.timeout(30_000),
});
const probability = result.answers.needsInterruption.probability;
// Demonstration cutoffs; choose production values from reviewed examples.
const suggestion = probability >= 0.9 ? 'immediate'
: probability <= 0.1 ? 'digest'
: 'review';
console.log(JSON.stringify({ suggestion, probability }, null, 2));
} catch {
console.error('Decision failed. Keep the update pending for review.');
process.exitCode = 1;
}

The example treats probabilities of at least 0.9 as an immediate suggestion and at most 0.1 as a digest suggestion. Everything between those cutoffs goes to review. These values demonstrate the branching logic; choose your own thresholds from labeled updates and the cost of an unnecessary interruption or missed alert.

Apply quiet hours and mute settings separately before sending anything. For operational alerts, use the authoritative incident or deployment state to establish whether the problem remains unresolved. The model assesses the evidence supplied, so a stale update can produce a stale recommendation.

Copy link to headingWhat should you test before connecting these decisions to actions?

Build a small reviewed dataset for each tool, including incomplete evidence and cases with similar wording but different meanings. For cancellation, compare an explicit end-of-term request with an information-only question and a request that omits timing. For notifications, include an unresolved issue, a resolved incident, and an unrelated message labeled urgent.

Keep expected behavior separate from the model's output so you can inspect disagreements. Repeating the checks after a model or rubric change helps reveal regressions. If you switch models through Gateway, reassess any probability thresholds against the replacement model's results.

AI SDK decisions validates the returned answer structure, but that doesn't establish whether the judgment is correct. An invalid response or refusal causes the call to throw. Keep failed requests available for retry or review; never interpret a failed decision as a negative Boolean answer or permission to proceed.

Copy link to headingFrequently asked questions

Copy link to headingCan I use different decision models without rewriting the workflow?

AI Gateway exposes decision models through a shared request and answer interface. You can change the model passed to the Gateway decision-model factory while retaining the question definitions and application mapping. Test the replacement on reviewed examples, because matching response shapes doesn't imply matching judgments or probability calibration.

Copy link to headingDoes a decision model cancel subscriptions or send notifications?

No. The examples return suggestions that application code can display or act on. Your application performs any account change or notification delivery, including confirmation, permissions, and delivery preferences.

Copy link to headingIs the search example a complete search engine?

No. It scores a passage that another part of the application has already retrieved. You still need document retrieval, access filtering, and source tracking to turn that assessment into a search experience.

The 0.9 and 0.1 cutoffs illustrate a three-way policy for one example. Choose production thresholds by comparing model probabilities with reviewed outcomes and deciding how to handle uncertain cases. Changing the model or the question's wording can change the results, so repeat that assessment after either change.

More Decision models articles

Ready to deploy?