ctx.ai(alias) gives you a real AI SDK provider bound to an authentication alias in helix.config.ts. The platform injects the model provider’s API key, so it never appears in your code. Call generateText, streamText, generateObject, streamObject, embed, embedMany, generateImage, transcribe, or generateSpeech on it, the same methods the AI SDK itself exposes.
Declare a provider
Add an authentication alias and tell Helix which service backs it with aiProviders:
// helix.config.ts
import { defineConfig } from '@trayai/helix-sdk';
export default defineConfig({
authentications: {
anthropicKey: '<your-anthropic-auth-uuid>',
},
aiProviders: {
anthropicKey: 'anthropic', // 'openai' | 'anthropic' | 'google' | 'mistral' | 'cohere'
},
});
aiProviders maps the same alias authentications uses to the AI SDK package that talks to it. An alias with no matching aiProviders entry throws SdkError.aiProviderNotConfigured, naming the exact config line to add.
Generate text
// functions/api/v1/summarize.post.ts
import { z } from 'zod';
import { defineFunction } from '@trayai/helix-sdk';
export const input = z.object({
text: z.string().min(1),
});
export default defineFunction<typeof input>(async (ctx) => {
const result = await ctx.ai('anthropicKey').generateText({
model: 'claude-sonnet-4-5',
prompt: `Summarize in two sentences: ${ctx.input.text}`,
});
ctx.log.info('Summarized', { cost: result.helix.cost.amount });
return { summary: result.text };
});
ctx.ai(alias) takes the model as a string id ('claude-sonnet-4-5', 'gpt-4o', and so on) resolved against the provider you declared for that alias.
Stream a response
streamText returns immediately with a stream you can pipe to the browser:
// functions/api/v1/chat.post.ts
import { z } from 'zod';
import { defineFunction } from '@trayai/helix-sdk';
export const input = z.object({
prompt: z.string().min(1),
});
export default defineFunction<typeof input>(async (ctx) => {
const result = ctx.ai('anthropicKey').streamText({
model: 'claude-sonnet-4-5',
prompt: ctx.input.prompt,
});
return result.toUIMessageStreamResponse();
});
See streaming for handling client disconnects and other production streaming behavior.
Structured output
generateObject and streamObject validate the response against a Zod schema instead of returning free text:
const result = await ctx.ai('anthropicKey').generateObject({
model: 'claude-sonnet-4-5',
schema: z.object({
sentiment: z.enum(['positive', 'neutral', 'negative']),
summary: z.string(),
}),
prompt: ctx.input.text,
});
result.object.sentiment; // typed as the enum above
Embeddings
const one = await ctx.ai('openaiKey').embed({
model: 'text-embedding-3-small',
value: 'How do I reset my password?',
});
const many = await ctx.ai('openaiKey').embedMany({
model: 'text-embedding-3-small',
values: ['First document', 'Second document', 'Third document'],
});
Images, transcription, and speech
const image = await ctx.ai('openaiKey').generateImage({
model: 'gpt-image-1',
prompt: 'A serene mountain landscape at sunset',
});
const transcript = await ctx.ai('openaiKey').transcribe({
model: 'whisper-1',
audio: audioBuffer,
});
const speech = await ctx.ai('openaiKey').generateSpeech({
model: 'tts-1',
text: 'Your order has shipped.',
});
Cost and request IDs
generateText, generateObject, and generateImage resolve with a result.helix field alongside the AI SDK’s own result fields:
| Field | Type | Description |
|---|---|---|
result.helix.cost.amount | number | Estimated cost of the request, in USD |
result.helix.cost.currency | 'USD' | Always 'USD' today |
result.helix.requestId | string | An ID for correlating this call in your own logs |
Cost is estimated from the provider’s reported token usage against public list prices; an unrecognized model estimates to 0. Most image models bill per image and report no token usage at all, so generateImage’s cost estimates to 0 for them regardless of whether the model is recognized. Token-billed image models get a real estimate.
Using a model instance directly
ctx.ai(alias) also exposes languageModel, embeddingModel, imageModel, transcriptionModel, and speechModel, which return a model instance instead of calling it immediately. Reach for these when you’re handing a model to a custom agent loop or a third-party helper that expects an AI SDK model instance:
const model = ctx.ai('anthropicKey').languageModel('claude-sonnet-4-5');
const result = await ctx.ai.generateText({ model, prompt: ctx.input.prompt });
The top-level ctx.ai.generateText, ctx.ai.streamText, and the other ctx.ai.* functions only accept a model instance obtained from ctx.ai(alias). Passing a string throws SdkError.aiModelInstanceRequired, and passing a model instance built directly against a raw AI SDK provider (bypassing ctx.ai) throws SdkError.aiForeignModelRejected, since that instance would carry its own credentials and skip cost tracking.
AI SDK helpers and types (tool, dynamicTool, jsonSchema, zodSchema, stepCountIs, hasToolCall, convertToModelMessages, and the message, stream, and result types) are re-exported from @trayai/helix-sdk, so your project needs no separate ai dependency:
import { tool, stepCountIs } from '@trayai/helix-sdk';
The ai package’s own call functions (generateText, streamText, and so on) are not re-exported. Always call through ctx.ai or ctx.ai(alias).
Supported providers
| Service | Notes |
|---|---|
openai | |
anthropic | |
google | |
mistral | |
cohere | |
openai-compatible | Self-hosted endpoints (vLLM, Ollama, and similar). Use the object form: { service: 'openai-compatible', baseUrl: 'https://...' }. baseUrl must be https:, checked when your config loads. |
Errors
| Error | When it happens |
|---|---|
SdkError.aiProviderNotConfigured | The alias has no matching aiProviders entry |
SdkError.aiUnsupportedService | The alias resolves to a service ctx.ai doesn’t support |
SdkError.aiModelIdRequired | ctx.ai(alias).<method> was called without a string model |
SdkError.aiModelInstanceRequired | A top-level ctx.ai.* function was called with a string instead of a model instance |
SdkError.aiForeignModelRejected | A top-level ctx.ai.* function was called with a model instance built outside ctx.ai(alias) |
Authentication
Like ctx.http.authed and ctx.kv(), ctx.ai requires you to be logged in during local development. Run helix login once, then helix dev; on the deployed platform, no token is needed.