Model providers
Choose a model provider, keep keys in .env, and reach any other provider.
Set model in plico.config.ts. plico validate fails when model.provider is not one of the
providers below and the project has no matching file in providers/.
provider | Key variable | Package to install |
|---|---|---|
anthropic | ANTHROPIC_API_KEY | @ai-sdk/anthropic |
google | GOOGLE_GENERATIVE_AI_API_KEY | @ai-sdk/google |
openai | OPENAI_API_KEY | @ai-sdk/openai |
openai-compatible | OPENAI_API_KEY | none |
The adapter packages are optional peer dependencies, so install only the one you use:
pnpm add @ai-sdk/anthropic. A run that needs a missing package fails with that command.
export default defineConfig({
schemaVersion: 1,
name: "My agent",
model: { provider: "anthropic", name: "claude-sonnet-5-5" },
});Keys and .env
plico run, plico serve and plico readiness load .env from the project folder. A variable already set in
the shell wins over the file. Values are never logged, and plico readiness says when a .env
was loaded. Keep .env out of git.
Set model.apiKeyEnv to read the key from another variable. Set model.baseURL to change the
endpoint. For openai and openai-compatible, OPENAI_BASE_URL is the fallback.
Long conversations
When a thread outgrows the model's context window, the run fails with a clear message to start a new thread or choose a model with a larger context. Plico does not retry this error.
Other providers
openai-compatible reaches any server that speaks the OpenAI chat API:
// OpenRouter
model: { provider: "openai-compatible", name: "anthropic/claude-sonnet-5-5",
baseURL: "https://openrouter.ai/api/v1", apiKeyEnv: "OPENROUTER_API_KEY" }
// LiteLLM proxy
model: { provider: "openai-compatible", name: "my-model",
baseURL: "http://localhost:4000/v1", apiKeyEnv: "LITELLM_API_KEY" }
// Ollama (any non-empty key works)
model: { provider: "openai-compatible", name: "llama3.2",
baseURL: "http://localhost:11434/v1", apiKeyEnv: "OLLAMA_API_KEY" }
// Vercel AI Gateway
model: { provider: "openai-compatible", name: "anthropic/claude-sonnet-5-5",
baseURL: "https://ai-gateway.vercel.sh/v1", apiKeyEnv: "AI_GATEWAY_API_KEY" }
// Groq
model: { provider: "openai-compatible", name: "openai/gpt-oss-20b",
baseURL: "https://api.groq.com/openai/v1", apiKeyEnv: "GROQ_API_KEY" }Reasoning models return their reasoning text. Plico sends it back after a tool call, because some servers need it. A server that rejects it (Groq does) gets one retry without it, and Plico leaves it out for the rest of that run.
For anything else, name the provider after a file in providers/. It exports a function that
returns an AI SDK language model:
import { defineProvider } from "@plico-ai/sdk";
import { createAcme } from "@acme/ai-sdk-provider";
export default defineProvider(({ model, apiKey, baseURL }) =>
createAcme({ apiKey, baseURL })(model),
);model: { provider: "acme", name: "acme-large", apiKeyEnv: "ACME_API_KEY" }Plico wraps the model behind its own model port, so no AI SDK type enters the project contract. Retries stay off inside the adapter; the engine retries the step.