# Provider detection (/docs/quickstart/provider-detection)



The `createPleachRoute()` handler from `@pleach/core/quickstart`
auto-detects which provider to use based on which env var you set.
This page documents the resolution matrix, the locked default
priority, and how to override it.

## The resolution matrix [#the-resolution-matrix]

The four cases the regression-lock test at
`packages/core/test/quickstart/providerDetection.test.mjs` enforces:

| `OPENROUTER_API_KEY` | `ANTHROPIC_API_KEY` | `detectProvider()` returns      |
| -------------------- | ------------------- | ------------------------------- |
| set                  | unset               | `"openrouter"`                  |
| unset                | set                 | `"anthropic"`                   |
| set                  | set                 | `"anthropic"` (alphabetical)    |
| unset                | unset               | `null` → route returns HTTP 503 |

The third row is the locked behavior consumers most often ask about.
&#x2A;*Default priority is alphabetical, not preference-biased.** Anthropic
precedes OpenRouter alphabetically, so it wins.

This is intentional. The alphabetical default avoids encoding any
OpenRouter-primary preference into the "I just installed Anthropic SDK
and it works" experience. Operators that want a specific priority pass
it explicitly.

## Full default priority [#full-default-priority]

```
anthropic → deepseek → google → mistral → moonshot → openai → openrouter
```

These map to six of the seven `ProviderFamily` values exported from
`@pleach/core/modelfamily` (`xai` has no standalone env-var
detection) plus `openrouter` as a gateway transport.
The resolution matrix itself is host-supplied — reached through the
`AgentAdapter.resolveModel<C>()` seam, not shipped in the package.

Default env-var aliases per provider (from
`DEFAULT_PROVIDER_ENV_VARS`):

| Provider     | Env var(s)                                       |
| ------------ | ------------------------------------------------ |
| `anthropic`  | `ANTHROPIC_API_KEY`                              |
| `deepseek`   | `DEEPSEEK_API_KEY`                               |
| `google`     | `GOOGLE_GENERATIVE_AI_API_KEY`, `GOOGLE_API_KEY` |
| `mistral`    | `MISTRAL_API_KEY`                                |
| `moonshot`   | `MOONSHOT_API_KEY`                               |
| `openai`     | `OPENAI_API_KEY`                                 |
| `openrouter` | `OPENROUTER_API_KEY`                             |

Google ships keys under two names — the newer
`GOOGLE_GENERATIVE_AI_API_KEY` (used by `@google/generative-ai`) and
the legacy `GOOGLE_API_KEY`. The newer name is checked first.

## Custom priority [#custom-priority]

Pass `providers` to override:

```typescript
import { detectProvider } from "@pleach/core/quickstart";

// OpenRouter wins when both keys are set.
const provider = detectProvider({
  providers: ["openrouter", "anthropic", "openai"],
});
```

Pass a subset to restrict detection — providers not in the list are
ignored even if their env vars are set:

```typescript
// Only consider Anthropic and OpenAI. OpenRouter is ignored.
const provider = detectProvider({
  providers: ["anthropic", "openai"],
});
```

## Custom env-var aliases [#custom-env-var-aliases]

Override per-provider env-var names via `envVars`:

```typescript
const provider = detectProvider({
  envVars: {
    anthropic: ["MY_CORP_ANTHROPIC_KEY", "ANTHROPIC_API_KEY"],
  },
});
```

The override replaces the provider's entire alias list. Providers not
in `envVars` inherit defaults.

## Test-friendly: supply a synthetic env [#test-friendly-supply-a-synthetic-env]

By default `detectProvider` reads from `process.env`. Pass `env` to
supply your own map — useful in tests, edge environments, and
custom config sources:

```typescript
const provider = detectProvider({
  env: { ANTHROPIC_API_KEY: "sk-ant-test" },
});
// → "anthropic"
```

Pass `env: {}` to force a "no provider detected" path without
mutating `process.env`.

## Listing all detected providers [#listing-all-detected-providers]

`detectAvailableProviders()` returns every provider with a non-empty
env-var value, in priority order. Useful for diagnostics and for
`createPleachRoute` callers that want to enumerate fallbacks:

```typescript
import { detectAvailableProviders } from "@pleach/core/quickstart";

const available = detectAvailableProviders();
// e.g. ["anthropic", "openrouter"] when both keys are set
```

## Pinning a provider explicitly [#pinning-a-provider-explicitly]

If you want to skip detection entirely, pass `provider` to
`createPleachRoute`:

```typescript
export const POST = createPleachRoute({
  provider: "anthropic",
});
```

Detection is skipped; the route uses Anthropic regardless of which
other env vars are set.

## Honest scope-limit [#honest-scope-limit]

Provider detection works for the seven default providers above.
**Custom providers** (your own gateway, a self-hosted LLM, a
forked SDK) require `orchestratorConfig` on `createPleachRoute` or
direct `SessionRuntime` construction — see
[Upgrading to @pleach/core](/docs/quickstart/upgrading-to-core).

The detection helpers are pure functions over an env map; they do
NOT validate that the key works against the provider. A wrong-key
failure surfaces later as a provider exception inside the stream,
which `ChatStreamError.cause` preserves.

## Where to go next [#where-to-go-next]

<Cards>
  <Card title="Quickstart" href="/docs/quickstart" description="One install, one env var, three files." />

  <Card title="Providers" href="/docs/providers" description="Provider switching, family-strict cascade, model resolution." />

  <Card title="Env vars" href="/docs/env-vars" description="Full env var reference across all SKUs." />

  <Card title="Upgrading to @pleach/core" href="/docs/quickstart/upgrading-to-core" description="When the quickstart surface is too tight." />
</Cards>
