OpenAI
Use the OpenAI API for MainSDK AI calls and embeddings - API keys, main.yaml, the model allowlist, data-use rules, local testing and swapping.
OpenAI makes the GPT models and embedding models, and its API is one of the drivers behind ai. Your app calls ai.generate() and ai.embed(); the driver sends the redacted prompt to the OpenAI API. Pick it when your features are tuned for OpenAI models, when you want OpenAI embeddings for search, or as a fallback next to Amazon Bedrock, the default driver.
Interfaces it serves
Pick OpenAI in main.yaml for any of these. Your calls stay the same, and you can swap later.
aiBuilding for 0.3Driver openai OpenAI
ai:
driver: openaiSwap to another provider
Before you start
You need an OpenAI platform account with API access.
- Create a project and an API key. In the OpenAI platform settings, create a project for your app and a key scoped to it. Use separate keys per environment so you can revoke one at a time.
- Set usage limits on the project. MainSDK caps spend in your app; a provider-side limit is a second line of defence.
- Review the data controls for your organisation.
ai.datarequires no training and no retention. Check how OpenAI handles API inputs for your organisation, and whether the retention yourmain.yamlasks for needs an arrangement with OpenAI.
Store the key in your secrets manager, never in code or a committed env file.
Configure
ai:
driver: openai
key: secret:OPENAI_API_KEY # suggested name; [to be decided] key field name for drivers that need one
models: [openai/gpt-*, openai/text-embedding-*] # allowlist
data: { training: never, retention: zero }
limits: { per-user: $1/day, total: $500/month }The key is always a secret: reference; a literal key fails mainsdk check. OpenAI's API host comes from the driver's declared hosts, so you don't add it to network.allow.
Use it
Generate text:
import { ai } from "mainsdk";
export async function classifyTicket(text: string, user: { id: string }) {
return ai.generate({
model: "openai/gpt-4o-mini", // [to be decided] model identifiers per driver
feature: "ticket-triage",
user,
prompt: `Reply with one word, billing, bug, account or other, for this ticket:\n${text}`,
});
}Embed text for search:
import { ai } from "mainsdk";
export async function embedProducts(descriptions: string[]) {
return ai.embed({
model: "openai/text-embedding-3-small", // [to be decided] model identifiers per driver
input: descriptions,
feature: "product-search",
}); // number[][]
}Local development and testing
- No key: set
ai.driver: localinmain.env.dev.yamlto use the built-in local fake. - Real calls in development: use a development key with a low cap in the dev overlay, for example
limits: { total: $10/month }. - Tests:
createTestApp()from@mainsdk/testingrunsaion its in-memory fake with redaction, caps and audit enforced.chaos.on("ai:openai", { outage: true })simulates an OpenAI outage. The spec's conformance suite runs the OpenAI driver against recorded responses.
import { it } from "node:test";
import { createTestApp, chaos } from "@mainsdk/testing";
import { classifyTicket } from "./classify-ticket";
it("keeps triage working when openai is down", async () => {
createTestApp({ main: "./main.yaml" }); // with a second driver under fallback.ai
chaos.on("ai:openai", { outage: true });
await classifyTicket("I was charged twice", { id: "u_1" });
});What MainSDK adds on top
- The API key never in your code, only a
secret:reference. - Providers, models or account modes that train on or keep prompts are refused; a declaration that doesn't meet
ai.datafailsmainsdk checkwithMAIN-AI-0001. - Personal data redacted before the model sees it, and restored only inside your app.
- Spend limits per user, per feature and in total, checked before the call (
MAIN-AI-0007at the limit). - Every call, embeddings included, audited with feature, model, tokens and cost, never the prompt.
See AI calls for the full contract.
Limits and notes
- The OpenAI driver comes with the
aispec (phase 1, milestone 0.3). - The name of the key field for keyed AI drivers is not final.
- How "no retention" is proven for a provider is an open question in the spec.
- If prompts must stay in a MainSDK region (US, EU or India), check where OpenAI processes data for your organisation, or use Bedrock with a region set.
- Embeddings from different models are not interchangeable. If you swap drivers, re-embed stored vectors with the new model.
ai.raw()returns the OpenAI client for featuresaidoes not wrap.mainsdk checklists every use.
Swap to or from it
AI calls are stateless, so a swap is instant once mainsdk swap has run the contract tests:
ai:
driver: openai # was bedrock
key: secret:OPENAI_API_KEY # [to be decided] key field nameUpdate ai.models to models the new driver serves. Stored embeddings are the one piece of state: vectors made by one model must be rebuilt with the new one before search uses them.
FAQ
Can I use OpenAI for embeddings and another provider for chat? One ai block names one driver. Running two drivers side by side is not in the ai@1 contract; fallback.ai covers failover only.
Where does my OpenAI key go? In your secrets manager, referenced as secret:OPENAI_API_KEY, read on the server only.
Does streaming work? Token-by-token streaming is not in the ai@1 contract yet.
Next
Open questions
Was this page helpful?