Files
Read supabase-storage file parts in the AI SDK's experimental_download, store generated files and cache provider file references.
better-supabase/ai-sdk/files connects the AI files
block to the AI SDK. Messages keep supabase-storage:// URLs; the adapter
reads them as the caller when a model needs the bytes.
pnpm add aiDownloads
import { aiFileDownload } from "better-supabase/ai-sdk/files";
import { streamText } from "ai";
const result = streamText({
model,
messages,
experimental_download: aiFileDownload(files),
});aiFileDownload(files) returns the SDK's download function. For a
supabase-storage:// URL it calls files.resolve and files.read as the
caller, so the storage policies decide what the model may see and the
maxBytes limit holds. A file the caller can't read throws an
AiFileDownloadError that carries the DbError. URLs the model fetches
itself are left to the model. Other URLs go to the SDK's createDownload(),
or fail with fallback: false.
Generated files
import { saveGeneratedFiles } from "better-supabase/ai-sdk/files";
const { images } = await generateImage({ model, prompt });
const parts = await saveGeneratedFiles(files, images, {
organizationId,
ownerId: userId,
chatId,
}).orThrow();saveGeneratedFiles stores each file as the service role (files.store)
and returns file parts with supabase-storage:// URLs to put in the
assistant message. It takes anything with uint8Array and mediaType, so
the results of generateImage, generateSpeech and a model's file output
all fit.
Provider files
import { providerFile } from "better-supabase/ai-sdk/files";
const reference = await providerFile(files, fileId, "openai", async (file) => {
const uploaded = await openai.files.create({
file: new File([file.data], file.filename, { type: file.mediaType }),
purpose: "user_data",
});
return { reference: uploaded.id };
}).orThrow();providerFile returns the reference a provider's file API gave for the
file, and uploads the file once through your callback when there is none
or it expired. Pass expiresAt for providers whose files expire, such as
Gemini's 48 hours, and refresh them from a job with
files.providerFiles.expiring().
Last updated on
Durable chat
Answers that run as Workflow SDK workflows with durableChat and durableTurn, tool approvals that wait for hours, stop through a hook, reconnects by chunk index and progress in ai_run_steps.
Embeddings
Embed knowledge with an AI SDK model or Supabase's built-in model, rerank hits, and give the model a search tool that cites its sources.