@lovable.dev/ai-gateway
v0.1.6
Published
Server-only SDK for the Lovable AI Gateway
Readme
@lovable.dev/ai-gateway
Server-only SDK for the Lovable AI Gateway. Set LOVABLE_API_KEY in
Node or Deno; LOVABLE_AI_GATEWAY_URL overrides the gateway URL.
import { generateImageStream } from "@lovable.dev/ai-gateway";
const events = await generateImageStream({ model, prompt }, { signal });
return events.toResponse();Each capability exports functions directly through src/index.ts. Calls resolve
their transport through the shared request() function. Pass apiKey in the
optional call options to override the environment credential for that call.
Generate model types
Use npx ai-gateway --help for commands, npx ai-gateway generate --help for
generation options and defaults, and npx ai-gateway --version for the installed
SDK version.
After installing the SDK, run this from the app root with LOVABLE_API_KEY set:
npx ai-gateway generateThe command calls listModels() and writes src/generated/ai-gateway/models.d.ts and
src/generated/ai-gateway/models.d.cts for ESM and CommonJS consumers. It groups
workspace-available model IDs by supported_surfaces. Without --model, only
model–surface combinations with bundled payload types are included. The generated
module augmentation supplies Model, ModelFor<Surface>, and capability unions
such as ImageModels. Ensure the generated files are included by the app's
TypeScript configuration. Re-running replaces the catalog, including removing
models or surface memberships that are no longer returned.
Use npx ai-gateway generate --output <directory> to choose a different output
directory. Relative paths resolve from the app root where the command runs;
absolute paths are also accepted. Each directory receives models.d.ts and
models.d.cts.
Repeat --model <slug> to add models without bundled contracts. Available bundled models remain
included. The generator fetches each selected model's missing surface contracts
through /v1/models/schema, converts them to declarations, and augments the
capability request, response, and event maps in the same output files. Response
and event roots are converted when present; absent output contracts remain unknown. Selecting a bundled model adds
no schema fetch. Unavailable models, missing contracts, and conversion failures
leave the previous declarations unchanged. Re-running without the flags removes
previously generated extra models.
The gateway commits contracts for openai/gpt-6-astra and openai/gpt-6-luna,
covering Chat and Responses requests, buffered results, and SSE events. Astra has
bundled types. Luna exercises dynamic generation with
npx ai-gateway generate --model openai/gpt-6-luna.
The schema route must be deployed, or use LOVABLE_AI_GATEWAY_URL to point at a
local gateway implementing it.
Inference payloads require a model in both the generated surface catalog and the
capability's payload map. The SDK bundles request contracts for 47 models across
65 combinations without availability feature flags, including deprecated models.
Region and retention restrictions remain enforced through workspace discovery and
the gateway. Before generation, request model types are never. Discovery,
video polling, and downloads do not take a model payload.
Generation rejects invalid catalog data and authenticated discovery fallbacks
before changing the existing declarations.
Capability functions
| Capability | Functions | | --- | --- | | models | listModels | | chat | generateChatCompletion, streamChatCompletion | | responses | generateResponse, streamResponse | | messages | generateMessage, streamMessage | | interactions | generateInteraction, streamInteraction | | images | generateImage, generateImageStream, editImage, editImageStream | | embeddings | generateEmbeddings | | speech | generateSpeech, streamSpeech | | transcriptions | transcribeAudio, transcribeAudioStream | | music | generateMusic | | videos | generateVideo, streamVideo, getVideo, downloadVideo | | live | connectLive |
Image edits and transcriptions accept an object containing
Blob/File uploads. The SDK encodes JSON for other inference operations.
Methods select buffered or streaming response modes themselves.
GatewayStream<Event> exposes native JSON SSE events through async iteration
or forwards the original SSE bytes through toResponse(). Choose one consumer;
iteration and forwarding do not duplicate the stream. GatewayBinary exposes
body, contentType, blob(), and toResponse(), also with one consumer.
Both preserve the gateway run ID. Pass CallOptions.runId to group calls.
Video downloads follow the gateway's signed storage redirect without forwarding
gateway credentials. Job polling remains explicit through getVideo().
Payload contracts
Each capability keeps its model-to-fields interface in src/<capability>/payloads.ts.
Requests form a discriminated union: choosing model selects its payload fields.
Shared provider definitions live in src/contracts/. Public request types,
provider field types and interfaces such as ChatFieldsByModel are exported from
the package root.
import { generateResponse } from "@lovable.dev/ai-gateway";
await generateResponse({
model: "openai/gpt-5.4",
input: "Write a short greeting.",
});This call requires that model to be in the generated Responses catalog. Responses
requests omit provider storage and previous-response references; pass prior items
inline. Stream functions own stream and speech stream_format. Upload fields
use Blob or File. Gemini image requests accept native contents or translated
prompt/messages alternatives. Veo uses instances/parameters or the legacy
flat shape; Omni uses Interactions-style input/response_format.
A discovered model without a bundled payload contract cannot be called until a
module augmentation supplies its capability fields. The payload maps are open
interfaces for that extension. Empty maps for Messages, Interactions, Music,
SystemOne and Live have no built-in models. Repeated --model flags fetch additional contracts from the gateway and generate
their payload map additions alongside catalog membership.
Provider schemas describe endpoint families; runtime validation still enforces
numeric limits and other model/provider constraints that TypeScript cannot express.
Every bundled request model has a response entry, and bundled streaming models
have event entries. Open interfaces such as ChatResponseByModel and
ChatEventByModel keep entries separate even when they share wire definitions.
Functions infer their result from payload.model: ChatCompletion<Model>,
ResponsesResponse<Model>, or GatewayStream<EventFor<Surface, Model>>.
ResponseFor<Surface, Model> exposes the corresponding buffered result type.
Dynamic generation augments these maps alongside request fields using the model's
response and event schema roots; it preserves existing static entries. Missing
output contracts return unknown. Binary calls retain GatewayBinary.
Response model IDs can be provider-native strings, and chat output includes gateway
reasoning/image extensions and finish reasons such as no_content. Wire event maps
include failure frames; SDK iteration throws GatewayError instead of yielding them.
Maintain bundled contracts
Add static model entries to the capability payload interfaces and their
response/event contracts to the matching results.ts maps. Builds derive the
runtime bundled catalog from PayloadFieldsBySurface; there is no separate model
list to update.
pnpm generate:contracts regenerates the committed provider definitions from
scripts/contract-sources.json. GitHub sources are pinned by commit; Google's
Interactions spec is checked against a pinned hash. Update pins and review the
capability overlays when contracts change. The generator keeps schema defaults
optional and preserves explicit union member types instead of inferring
discriminators from component names. It removes response-only Interactions
metadata and delegates model literals to the SDK catalog. The local gateway
sources generate response and event definitions from committed model schemas.
Models sharing an output contract reuse one generated definition; result maps
cover every bundled request model. App generation converts missing models’
request, response, and event roots. To refresh the local gateway sources, run
node scripts/generate-contracts.mjs --source gateway, then
pnpm exec oxfmt --write src/contracts/gateway.
Veo wire fields are maintained against Google's typed video parameters and Vertex
serialization functions referenced in the source manifest. Third-party notices
ship in NOTICE. Schema generation is development-only; SDK builds consume the
committed declarations, and app generation fetches committed contracts from the gateway for explicit
model selections. Neither flow asks a provider to infer schemas at runtime.
Transport scope
Model discovery exposes ModelList. The generated catalog lives in app
declarations; bundled payload contracts do not grant workspace access.
Failures use GatewayError subclasses with safe structured diagnostics,
attemptCount, and retryAfter in milliseconds. Read-only calls retry transient
network failures, timeouts, rate limits, and HTTP 500/502/503/504 responses. Generation
calls retry only the gateway’s native rate limit rejection before upstream execution,
and only with a replayable body. Unknown generation outcomes and delivered streams
are never replayed; retryable: false prevents retries.
Per-call options default to maxRetries: 2 and retryWaitBudgetMs: 10000. Backoff
uses full jitter starting at 500 ms, doubling up to 30 seconds, added to a valid
Retry-After minimum. The wait budget accumulates backoff delays and excludes request
execution time. A delay that exceeds the remaining budget returns the last error.
Set maxRetries: 0 to disable retries. Cancellation interrupts pending waits.
SSE iteration normalizes error events and decoding failures; toResponse() forwards native error events
as SSE. Cancellation forwards the caller's abort signal.
connectLive(start, options) opens an authenticated server-side WebSocket to
/v1/live/sessions and resolves after gateway.session.created. Generate the
selected Live model's contracts with ai-gateway generate --model <live-model>.
The startup payload follows the gateway wire format: type: "session.start",
session.model, and transport: { type: "webrtc", sdp: offer }.
The returned session exposes the typed creation event through created, typed
commands through send(), and native server events through single-use async
iteration. The creation event is also the first yielded event. Live command
errors remain events so the app can correlate their client_event_id and
continue the call; connection and decoding failures throw GatewayError during
iteration. A resolved send() confirms local transmission, not provider acceptance.
close() sends session.close once and drains final events for at most 15 seconds.
closed resolves when cleanup finishes; observe iteration for failures and final
usage. Aborting before creation rejects startup; after creation it requests shutdown
and retains the final receiver. Breaking iteration closes the session. Sessions
are never automatically recreated and Live options have no retry settings.
Node uses ws; Cloudflare uses the runtime's fetch upgrade. The app still serves
its browser WebSocket endpoint and keeps cleanup alive with waitUntil. Browser
audio travels directly to the provider through WebRTC. Generate heartbeats only
while browser media and its data channel are connected, then forward them through
send(). The SDK never manufactures browser heartbeats.
Use one server-owned runId across the call and delegated SDK requests. Per-call
metadata adds opaque correlation fields through X-Lovable-AIG-Metadata, such as
live_session_id and delegation_id; exclude prompts, transcripts and credentials.
