Execution
Run the same prompt with Vercel AI SDK, OpenAI, Google GenAI, Anthropic, or agent frameworks.
All adapters accept the same prompt() definitions: write once, run on any SDK.
import { generate, stream } from '@use-crux/ai'
import { openai } from '@ai-sdk/openai'
// Structured output
const result = await generate(editDraft, {
model: openai('gpt-4o'),
input: { instruction: 'Fix the intro' },
})
result.object // typed as z.infer<typeof OutputSchema>
// Text output
const text = await generate(greet, {
model: openai('gpt-4o'),
input: { name: 'Henri' },
})
text.text // string
// Streaming
const result = await stream(editDraft, {
model: openai('gpt-4o'),
input: { instruction: 'Fix the intro' },
})
for await (const partial of result.partialObjectStream) { ... }Use tool() from @use-crux/ai for AI SDK tools. Portable loop controls such as maxSteps() and hasToolCall() come from @use-crux/core.
import { createOpenAI } from "@use-crux/openai";
import OpenAI from "openai";
const adapter = createOpenAI(new OpenAI({ apiKey: "..." }));
// Structured output → chat.completions.parse
const result = await adapter.generate(editDraft, {
model: "gpt-4o",
input: { instruction: "Fix the intro" },
});
result.choices[0].message.parsed; // typed
// Text output → chat.completions.create
const text = await adapter.generate(greet, {
model: "gpt-4o-mini",
input: { name: "Henri" },
});
// Streaming
const stream = await adapter.stream(greet, {
model: "gpt-4o",
input: { name: "Henri" },
});Accepts OpenAI-native options: tools, tool_choice, parallel_tool_calls, and all OpenAISettings.
import { createGoogle } from "@use-crux/google";
import { GoogleGenAI } from "@google/genai";
const adapter = createGoogle(new GoogleGenAI({ apiKey: "..." }));
// Structured output → generateContent with JSON schema
const result = await adapter.generate(editDraft, {
model: "gemini-2.5-flash",
input: { instruction: "Fix the intro" },
});
result.object; // parsed + validated with Zod
// Text output
const text = await adapter.generate(greet, {
model: "gemini-2.0-flash",
input: { name: "Henri" },
});
// Streaming
const stream = await adapter.stream(greet, {
model: "gemini-2.5-flash",
input: { name: "Henri" },
});Accepts Google-native options: tools, temperature, maxOutputTokens, topP, topK, plus extra.cachedContent.skip and extra.cachedContent.ttlSeconds for per-call CachedContent control.
The Google adapter validates structured output with Zod after generation. If the model returns invalid JSON, you'll get a Zod error, not a Google SDK error.
import { createAnthropic } from "@use-crux/anthropic";
import Anthropic from "@anthropic-ai/sdk";
const adapter = createAnthropic(new Anthropic({ apiKey: "..." }));
// Structured output → messages.parse
const result = await adapter.generate(editDraft, {
model: "claude-sonnet-4-5-20250929",
input: { instruction: "Fix the intro" },
});
result.parsed_output; // typed
// Text output → messages.create
const text = await adapter.generate(greet, {
model: "claude-haiku-4-5-20251001",
input: { name: "Henri" },
});
// Streaming
const stream = await adapter.stream(greet, {
model: "claude-sonnet-4-5-20250929",
input: { name: "Henri" },
});Accepts Anthropic-native options: tools, tool_choice, thinking, metadata.
Anthropic requires max_tokens. If not set in your prompt's settings, the
adapter defaults to 4096.
Agent frameworks
For AI SDK-based agent frameworks that manage their own model calls, @use-crux/ai/agent returns composed instructions and a wrapped model instead of executing directly:
import { resolve } from "@use-crux/ai/agent";
const { instructions, model } = await resolve(chatAgent, {
model: languageModel,
input: { mode },
});
// Pass to any AI SDK-compatible agent framework
const agent = createAgent({
model,
instructions,
tools,
});See Framework Guides for specific integration examples with Convex Agent and other frameworks.
Same prompt, multiple SDKs
The same prompt works across all adapters without modification:
import { generate } from "@use-crux/ai";
import { createOpenAI } from "@use-crux/openai";
import { createGoogle } from "@use-crux/google";
import { createAnthropic } from "@use-crux/anthropic";
// Vercel AI SDK
await generate(sentiment, { model: openai("gpt-4o"), input });
// OpenAI SDK
const oai = createOpenAI(new OpenAI());
await oai.generate(sentiment, { model: "gpt-4o", input });
// Google GenAI
const google = createGoogle(new GoogleGenAI({ apiKey: "..." }));
await google.generate(sentiment, { model: "gemini-2.5-flash", input });
// Anthropic SDK
const anthropic = createAnthropic(new Anthropic({ apiKey: "..." }));
await anthropic.generate(sentiment, {
model: "claude-sonnet-4-5-20250929",
input,
});Message conversion
Each adapter provides toMessages() and fromMessages() to convert between SDK-specific message formats and Crux's canonical Message type. Use these when integrating with existing chat UIs or migrating from raw SDK calls.
import { toMessages, fromMessages } from "@use-crux/ai";
// SDK format → canonical
const messages = toMessages(coreMessages);
// Canonical → SDK format
const sdkMessages = fromMessages(messages);import { toMessages, fromMessages } from "@use-crux/openai";
// ChatCompletionMessageParam[] → canonical
const messages = toMessages(chatMessages);
// Canonical → OpenAI format
const sdkMessages = fromMessages(messages);import { toMessages, fromMessages } from "@use-crux/google";
// Google Content[] → canonical
const messages = toMessages(contents);
// Canonical → Google format
const sdkMessages = fromMessages(messages);import { toMessages, fromMessages } from "@use-crux/anthropic";
// Anthropic MessageParam[] → canonical
const messages = toMessages(anthropicMessages);
// Canonical → Anthropic format
const sdkMessages = fromMessages(messages);Framework-agnostic generate functions
Some @use-crux/core APIs (like judge, extractKeyFacts, summarizeMessages) accept a generic GenerateObjectFn or GenerateTextFn instead of being tied to a specific SDK. Each adapter exports these wrappers:
import { generateObjectFn, generateTextFn } from "@use-crux/ai";
import { judge } from "@use-crux/core/scoring";
const evaluator = judge({
id: "helpfulness",
criteria: "Does the answer resolve the request?",
scale: { min: 1, max: 5 },
generate: generateObjectFn,
model,
});
const result = await summarizeMessages({
generate: generateTextFn,
model,
messages,
});import { createGenerateObjectFn, createGenerateTextFn } from "@use-crux/openai";
const generateObj = createGenerateObjectFn(client, "gpt-4o");
const generateTxt = createGenerateTextFn(client, "gpt-4o");import { createGenerateObjectFn, createGenerateTextFn } from "@use-crux/google";
const generateObj = createGenerateObjectFn(client, "gemini-2.5-flash");
const generateTxt = createGenerateTextFn(client, "gemini-2.5-flash");import {
createGenerateObjectFn,
createGenerateTextFn,
} from "@use-crux/anthropic";
const generateObj = createGenerateObjectFn(
client,
"claude-sonnet-4-5-20250929",
);
const generateTxt = createGenerateTextFn(client, "claude-haiku-4-5-20251001");These helpers are provider-native, lightweight wrappers. They pass the schema
to the provider structured-output API and return {object}, but they do not
run Crux prompt resolution, validation retry, safety, tools, memory capture,
or instrumentation. Use full adapter generate() for normal prompt execution.
When a core API needs a GenerateObjectFn but you also need the full adapter runtime, bridge an existing adapter generate() function:
import { createGenerateObjectFnFromGenerate } from "@use-crux/core/compaction";
import { generate } from "@use-crux/ai";
const generateObj = createGenerateObjectFnFromGenerate(generate, {
promptId: "quality.judge",
});The Vercel AI SDK adapter exports pre-bound functions (generateObjectFn,
generateTextFn) since the model is passed per-call. Its generateObjectFn
shares the same structured-attempt mechanics as prompt structured generation.
The OpenAI, Google, and Anthropic adapters use factory functions that bind the
client and model upfront.
Managed generation results are finalized before hooks.onGenerate runs. The
hook and public caller therefore see the same exact generation.call
_meta.traceId/_meta.spanId; provider _meta.responseId remains separate.
Streaming exposes its operation pair immediately and repeats it on completion.
See Operation Result Correlation.
Next steps
Flows
Chain multiple generate() calls into structured pipelines with named steps.
Tools
Declare and compose tools across contexts and prompts.
Middleware & Hooks
Global middleware and per-prompt lifecycle hooks.
Examples
Full working examples combining execution with memory and agents.
API Reference
@use-crux/ai, @use-crux/openai, @use-crux/google, and @use-crux/anthropic adapter signatures.