keel
Model

Connecting providers

Configure provider SDKs, credentials, and model options.

Keel ships adapters for Anthropic, OpenAI, and Gemini. Each translates Keel's model input and transcript into its provider's API and normalizes the result. All three stream: text deltas reach the wire as the provider produces them, and each adapter's generate is implemented by collecting its own stream, so both paths share one contract mapping.

Install the provider SDK

Install only the SDKs your application uses:

npm install @anthropic-ai/sdk  # Anthropic
npm install openai             # OpenAI
npm install @google/genai      # Gemini
pnpm add @anthropic-ai/sdk
pnpm add openai
pnpm add @google/genai
yarn add @anthropic-ai/sdk
yarn add openai
yarn add @google/genai
bun add @anthropic-ai/sdk
bun add openai
bun add @google/genai

Use a provider class

Every provider class and factory requires an explicit model. Omitting it is a TypeScript error and throws KeelError at runtime for JavaScript callers. Keel never selects a default model, so library upgrades cannot silently change your selection.

Choose a known model. Keel resolves its context window, maximum supported output, and tool capabilities from a versioned local catalog:

import { OpenAIProvider } from "@keel-dev/core/providers/openai";

const primary = new OpenAIProvider({
  apiKey: process.env.OPENAI_API_KEY,
  model: "gpt-5.1",
});
Import under @keel-dev/core/providers/ClassEquivalent factoryConventional key variable
anthropicAnthropicProvideranthropic(options)ANTHROPIC_API_KEY
openaiOpenAIProvideropenai(options)OPENAI_API_KEY
geminiGeminiProvidergemini(options)GEMINI_API_KEY

The last column is a naming convention, not a lookup: Keel never reads environment variables. The adapter uses only the apiKey option you pass — your application loads its environment (or secret store) and supplies the value explicitly, as in the example above. A tier constructed without an apiKey is declared loudly: defineChain warns at definition time, naming the conventional variable, and at execution the tier reports unavailable so the chain falls through to the next tier.

The classes wrap the provider SDKs and normalize messages, tool calls, usage, and errors for the chain. Two behaviors of that wrapping are worth knowing:

  • The SDK never retries underneath Keel. Each SDK client is constructed with maxRetries: 0. Keel's chain is the single retry authority; a second retry loop inside the SDK would multiply attempts invisibly. See Retry and fallback.
  • A refused model ID fails fast, then re-probes. When the API rejects the configured model (not found), the adapter reports bad-request, warns, and keeps failing fast for 60 seconds before asking the API again — no hammering, and no permanent per-process latch. Fix the model ID in the chain definition.

Understand the defaults

The initial catalog includes claude-opus-5, claude-haiku-4-5 (and its 20251001 snapshot), gpt-5.1, and gemini-2.5-pro.

Keep the selected ID in version-controlled configuration so changes can be reviewed. An explicit ID is not necessarily an immutable provider snapshot: use a versioned snapshot ID where the provider offers one. Keel cannot prevent a provider from changing what an alias or custom deployment points to.

provider.capabilities describes the model's supported limits. provider.windowTokens and provider.maxOutputTokens are the selected application ceilings. The default output ceiling is 8,192 tokens, reduced when the model or selected window supports less. Override these options to use a smaller window or another output ceiling within the model's capacity.

The catalog is a local snapshot exposed as MODEL_CATALOG and MODEL_CATALOG_VERSION. It performs no live discovery and does not establish account access or pricing. Supply optional pricing separately.

Use a model outside the catalog

A new model on a supported provider does not need a new adapter. Declare its capabilities explicitly with customModel:

import { customModel } from "@keel-dev/core";
import { OpenAIProvider } from "@keel-dev/core/providers/openai";

const model = customModel({
  provider: "openai",
  id: "my-new-model", // Replace with your provider's model ID.
  windowTokens: 32_000,
  maxOutputTokens: 4_000,
  supportsTools: true,
  canForceTool: true,
});

const fallback = new OpenAIProvider({
  apiKey: process.env.OPENAI_API_KEY,
  model,
});

These limits are illustrative. Use the capabilities of your actual model or deployment. Custom models use the selected provider's existing SDK and request format; another API protocol requires a custom adapter.

Unknown string IDs and mismatched provider definitions produce TypeScript errors. JavaScript callers receive configuration errors too. Token limits must be positive safe integers, output must fit the window, and forced tool selection requires tool support. Keel never guesses limits from an unknown model name.

Keep local and deployed configuration separate

The bundled examples can run without keys using deterministic adapters. A deployed live chain should use the configured provider tiers and report exhaustion if they all fail. Adding a scripted greeting as a final production fallback would conceal the failure behind a canned response.

Studio's key panel is a local development path: its key settings use browser storage, and provider calls run from the browser. The Anthropic and OpenAI SDKs refuse browser execution unless you opt in, so those two adapters accept a browser: true option that sets the SDK's dangerouslyAllowBrowser flag; the Gemini adapter needs no such option. Reserve browser: true for local development, and supply production credentials on your server rather than distributing them to app users:

import { AnthropicProvider } from "@keel-dev/core/providers/anthropic";

// Local development only — never ship a key to app users.
// `keys` comes from your app's local key handling (Studio's key panel
// hands your `createApp(cfg)` its LiveKeys the same way).
export function localTier(keys: { anthropic: string }) {
  return new AnthropicProvider({
    apiKey: keys.anthropic,
    model: "claude-haiku-4-5",
    browser: true,
  });
}

Inspect in Studio

Load your locally configured app in Studio. Watch WIRE while a turn runs — a streaming tier's text arrives as deltas — and inspect MODEL for the adapter ID and finish reason. If no live tier executes, check the credential warnings and fallback events before changing the agent's prompt.

Next: Retry and fallback.