Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion agent-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@
"properties": {
"provider": {
"type": "string",
"description": "The underlying provider type. Defaults to \"openai\" when not set. Supported values: openai, anthropic, google, amazon-bedrock, dmr, and any built-in alias (requesty, openrouter, atlascloud, azure, xai, ollama, mistral, baseten, daoxe, ovhcloud, groq, fireworks-ai, deepseek, cerebras, togetherai, huggingface, moonshotai, vercel, cloudflare-workers-ai, cloudflare-ai-gateway, nvidia, github-copilot, chatgpt, opencode, opencode-go, etc.).",
"description": "The underlying provider type. Defaults to \"openai\" when not set. Supported values: openai, anthropic, google, amazon-bedrock, dmr, and any built-in alias (requesty, openrouter, api-route, atlascloud, azure, xai, ollama, mistral, baseten, daoxe, ovhcloud, groq, fireworks-ai, deepseek, cerebras, togetherai, huggingface, moonshotai, vercel, cloudflare-workers-ai, cloudflare-ai-gateway, nvidia, github-copilot, chatgpt, opencode, opencode-go, etc.).",
"examples": [
"openai",
"anthropic",
Expand Down
4 changes: 2 additions & 2 deletions docs/configuration/models/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ models:
first_available: [list] # Optional: candidate model refs, tried in order by available credentials.
# Mutually exclusive with other model settings.
provider: string # Required unless using first_available. One of: openai, anthropic, google, amazon-bedrock,
# dmr, mistral, xai, nebius, nvidia, minimax, baseten, daoxe, ovhcloud, groq, fireworks-ai, deepseek, cerebras, togetherai, huggingface, moonshotai, vercel, cloudflare-workers-ai, cloudflare-ai-gateway, requesty, openrouter, atlascloud,
# dmr, mistral, xai, nebius, nvidia, minimax, baseten, daoxe, ovhcloud, groq, fireworks-ai, deepseek, cerebras, togetherai, huggingface, moonshotai, vercel, cloudflare-workers-ai, cloudflare-ai-gateway, requesty, openrouter, api-route, atlascloud,
# azure, ollama, github-copilot, or a named provider defined
# under the top-level `providers:` section.
model: string # Required: model identifier
Expand Down Expand Up @@ -60,7 +60,7 @@ models:
| Property | Type | Required | Description |
| --------------------- | ---------- | -------- | ------------------------------------------------------------------------------------- |
| `first_available` | array | ✗ | Candidate model references tried in order; selects the first whose credentials are configured. Mutually exclusive with other model settings. |
| `provider` | string | ✓/✗ | Required for regular model definitions; omitted for `first_available` selectors. Provider: `openai`, `anthropic`, `google`, `amazon-bedrock`, `dmr`, `mistral`, `xai`, `nebius`, `nvidia`, `minimax`, `baseten`, `daoxe`, `ovhcloud`, `groq`, `fireworks-ai`, `deepseek`, `cerebras`, `togetherai`, `huggingface`, `moonshotai`, `vercel`, `cloudflare-workers-ai`, `cloudflare-ai-gateway`, `requesty`, `openrouter`, `atlascloud`, `azure`, `ollama`, `github-copilot`, `chatgpt`, `opencode`, `opencode-go`, or any [named provider](../../providers/custom/index.md). |
| `provider` | string | ✓/✗ | Required for regular model definitions; omitted for `first_available` selectors. Provider: `openai`, `anthropic`, `google`, `amazon-bedrock`, `dmr`, `mistral`, `xai`, `nebius`, `nvidia`, `minimax`, `baseten`, `daoxe`, `ovhcloud`, `groq`, `fireworks-ai`, `deepseek`, `cerebras`, `togetherai`, `huggingface`, `moonshotai`, `vercel`, `cloudflare-workers-ai`, `cloudflare-ai-gateway`, `requesty`, `openrouter`, `api-route`, `atlascloud`, `azure`, `ollama`, `github-copilot`, `chatgpt`, `opencode`, `opencode-go`, or any [named provider](../../providers/custom/index.md). |
| `model` | string | ✓/✗ | Required for regular model definitions; omitted for `first_available` selectors. Model name (e.g., `gpt-4o`, `claude-sonnet-4-5`, `gemini-3.5-flash`) |
| `description` | string | ✗ | Informational, human-readable summary of the model's purpose or strengths (e.g., "fast and cheap, good for summaries"). Not sent to the model. Can be combined with `first_available` (a selector's description is kept when it resolves). |
| `temperature` | float | ✗ | Sampling randomness. Range is provider-dependent — typically `0.0–2.0` (Anthropic caps at `1.0`). `0.0` is deterministic. |
Expand Down
2 changes: 2 additions & 0 deletions docs/data/nav.yml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@
url: /providers/overview/
- title: Anthropic
url: /providers/anthropic/
- title: API Route
url: /providers/api-route/
- title: Atlas Cloud
url: /providers/atlascloud/
- title: AWS Bedrock
Expand Down
98 changes: 98 additions & 0 deletions docs/providers/api-route/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
title: "API Route"
description: "Use API Route models with Docker Agent."
keywords: docker agent, ai agents, model providers, llm, api route
weight: 23
canonical: https://docs.docker.com/ai/docker-agent/providers/api-route/
---

_Use API Route models with Docker Agent._

## Overview

[API Route](https://api-route.com) provides access to multiple model families
through an OpenAI-compatible API. Docker Agent includes API Route as a built-in
alias provider using the global endpoint.

## Setup

1. Create an API key in your [API Route account](https://api-route.com).
2. Set the environment variable:

```bash
export API_ROUTE_API_KEY=your-api-key
```

## Usage

### Inline Syntax

```yaml
agents:
root:
model: api-route/gpt-6.1-sol
description: Assistant using API Route
instruction: You are a helpful assistant.
```

### Named Model

```yaml
models:
api_route_model:
provider: api-route
model: gpt-6.1-sol

agents:
root:
model: api_route_model
description: Assistant using API Route
instruction: You are a helpful assistant.
```

## Available Models

The examples use the exact model ID `gpt-6.1-sol`. Retrieve your account's current
model IDs before choosing another model:

```bash
curl https://global.api-route.com/v1/models \
-H "Authorization: Bearer $API_ROUTE_API_KEY"
```

Use an ID from the response unchanged as the `model` value. A catalog listing
does not guarantee that inference is currently available.

API Route is absent from Docker Agent's embedded models.dev catalog. Docker
Agent does not import pricing, context limits or attachment capabilities from
API Route's model list. Attachment detection falls back to text-only, so image
and PDF attachments are dropped with a warning. If you have verified support
for an attachment type on your chosen model and endpoint, set
`models.<name>.capabilities`; see
[Attachment Capability Overrides](../../configuration/models/index.md#attachment-capability-overrides).

## How It Works

- **API type:** OpenAI-compatible Chat Completions (`openai_chatcompletions`)
- **Base URL:** `https://global.api-route.com/v1`
- **Token variable:** `API_ROUTE_API_KEY`

As with other multi-model hosts, Docker Agent combines consecutive system
messages for compatibility with models that require a single leading system
message.

## Example: Code Assistant

```yaml
agents:
coder:
model: api-route/gpt-6.1-sol
description: Code assistant using API Route
instruction: |
You are an expert programmer.
Write clean code and follow language best practices.
toolsets:
- type: filesystem
- type: shell
- type: think
```
1 change: 1 addition & 0 deletions docs/providers/overview/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Use this table to find a built-in provider's config key and authentication metho
| Cloudflare AI Gateway | `cloudflare-ai-gateway` | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_GATEWAY_ID` |
| Requesty | `requesty` | `REQUESTY_API_KEY` |
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` |
| API Route | `api-route` | `API_ROUTE_API_KEY` |
| Atlas Cloud | [`atlascloud`](../atlascloud/index.md) | `ATLASCLOUD_API_KEY` |
| Azure OpenAI | `azure` | `AZURE_API_KEY` + `base_url` (override the key with `token_key`) |
| [Ollama](../local/index.md) | `ollama` | None (local; optional `base_url`) |
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ remote MCP endpoints.
| [`env_placeholders.yaml`](env_placeholders.yaml) | `${env.VAR}` substitution inside the YAML. |
| [`model_env_substitution.yaml`](model_env_substitution.yaml) | `${env.VAR}` substitution in a model's `model` / `base_url`. |
| [`nebius.yaml`](nebius.yaml) | Nebius cloud provider. |
| [`api-route.yaml`](api-route.yaml) | API Route multi-model gateway provider. |
| [`atlascloud.yaml`](atlascloud.yaml) | Atlas Cloud open-model host (`atlascloud`). |
| [`baseten.yaml`](baseten.yaml) | Baseten cloud provider. |
| [`daoxe.yaml`](daoxe.yaml) | DaoXE multi-model gateway provider. |
Expand Down
16 changes: 16 additions & 0 deletions examples/api-route.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# yaml-language-server: $schema=../agent-schema.json

models:
api_route_model:
provider: api-route
model: gpt-6.1-sol

agents:
root:
model: api_route_model
description: Assistant using API Route
instruction: You are a helpful assistant.
toolsets:
- type: filesystem
- type: shell
- type: think
2 changes: 2 additions & 0 deletions pkg/config/auto.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ var cloudProviders = []providerConfig{
}, "GOOGLE_API_KEY (or GEMINI_API_KEY, GOOGLE_GENAI_USE_VERTEXAI)", "GOOGLE_API_KEY"},
{"mistral", []string{"MISTRAL_API_KEY"}, "MISTRAL_API_KEY", "MISTRAL_API_KEY"},
{"openrouter", []string{"OPENROUTER_API_KEY"}, "OPENROUTER_API_KEY", "OPENROUTER_API_KEY"},
{"api-route", []string{"API_ROUTE_API_KEY"}, "API_ROUTE_API_KEY", "API_ROUTE_API_KEY"},
{"atlascloud", []string{"ATLASCLOUD_API_KEY"}, "ATLASCLOUD_API_KEY", "ATLASCLOUD_API_KEY"},
{"baseten", []string{"BASETEN_API_KEY"}, "BASETEN_API_KEY", "BASETEN_API_KEY"},
{"ovhcloud", []string{"OVH_AI_ENDPOINTS_ACCESS_TOKEN"}, "OVH_AI_ENDPOINTS_ACCESS_TOKEN", "OVH_AI_ENDPOINTS_ACCESS_TOKEN"},
Expand Down Expand Up @@ -160,6 +161,7 @@ var DefaultModels = map[string]string{
"dmr": "ai/qwen3:latest",
"mistral": "mistral-small-latest",
"openrouter": "meta-llama/llama-4-maverick",
"api-route": "gpt-6.1-sol",
"atlascloud": "qwen/qwen3.8-max",
"baseten": "deepseek-ai/DeepSeek-V4-Pro",
"ovhcloud": "Qwen3.5-397B-A17B",
Expand Down
16 changes: 16 additions & 0 deletions pkg/config/auto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ func TestAvailableProviders_NoGateway(t *testing.T) {
},
expectedProvider: "openrouter",
},
{
name: "api-route api key present",
envVars: map[string]string{
"API_ROUTE_API_KEY": "test-key",
},
expectedProvider: "api-route",
},
{
name: "atlascloud api key present",
envVars: map[string]string{
Expand Down Expand Up @@ -320,6 +327,15 @@ func TestAutoModelConfig(t *testing.T) {
expectedModel: "meta-llama/llama-4-maverick",
expectedMaxTokens: 32000,
},
{
name: "api-route provider",
envVars: map[string]string{
"API_ROUTE_API_KEY": "test-key",
},
expectedProvider: "api-route",
expectedModel: "gpt-6.1-sol",
expectedMaxTokens: 32000,
},
{
name: "baseten provider",
envVars: map[string]string{
Expand Down
1 change: 1 addition & 0 deletions pkg/config/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var modelsDevCatalogProviders = map[string]string{
// even via modelsDevCatalogProviders above. The test skips models.dev
// lookups for these to avoid false failures.
var modelsDevAbsentProviders = map[string]bool{
"api-route": true, // API Route model IDs come from its own /v1/models endpoint, not models.dev.
"atlascloud": true, // Atlas Cloud model IDs come from its own /v1/models endpoint, not models.dev.
"dmr": true, // Docker Model Runner (local, not in catalog)
"cloudflare-workers-ai": true, // example uses an @cf/... model id not present in the models.dev snapshot (only variant ids like -fp8 are listed)
Expand Down
5 changes: 5 additions & 0 deletions pkg/model/provider/aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ var Aliases = map[string]Alias{
BaseURL: "https://openrouter.ai/api/v1",
TokenEnvVar: "OPENROUTER_API_KEY",
},
"api-route": {
APIType: "openai",
BaseURL: "https://global.api-route.com/v1",
TokenEnvVar: "API_ROUTE_API_KEY",
},
"atlascloud": {
APIType: "openai",
BaseURL: "https://api.atlascloud.ai/v1",
Expand Down
2 changes: 2 additions & 0 deletions pkg/model/provider/aliases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func TestCatalogAliases(t *testing.T) {

expected := map[string]Alias{
"openrouter": {APIType: "openai", BaseURL: "https://openrouter.ai/api/v1", TokenEnvVar: "OPENROUTER_API_KEY"},
"api-route": {APIType: "openai", BaseURL: "https://global.api-route.com/v1", TokenEnvVar: "API_ROUTE_API_KEY"},
"atlascloud": {APIType: "openai", BaseURL: "https://api.atlascloud.ai/v1", TokenEnvVar: "ATLASCLOUD_API_KEY"},
"baseten": {APIType: "openai", BaseURL: "https://inference.baseten.co/v1", TokenEnvVar: "BASETEN_API_KEY"},
"daoxe": {APIType: "openai", BaseURL: "https://api.daoxe.com/v1", TokenEnvVar: "DAOXE_API_KEY"},
Expand Down Expand Up @@ -127,6 +128,7 @@ func TestProviderIDsMatchEmbeddedCatalog(t *testing.T) {
t.Parallel()
db := modelsdev.EmbeddedSnapshot()
absent := map[string]string{
"api-route": "model IDs come from API Route's /v1/models endpoint, not models.dev",
"atlascloud": "model IDs come from Atlas Cloud's /v1/models endpoint, not models.dev",
"chatgpt": "subscription backend, distinct from OpenAI",
"dmr": "local Docker Model Runner",
Expand Down
1 change: 1 addition & 0 deletions pkg/model/provider/openai/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ func (c *Client) convertMessages(ctx context.Context, messages []chat.Message) [
// (openai, mistral, xai, minimax, github-copilot, opencode) tolerate multiple
// system messages and are deliberately absent so their behavior is unchanged.
var openModelHostProviders = map[string]bool{
"api-route": true,
"atlascloud": true,
"baseten": true,
"daoxe": true,
Expand Down
1 change: 1 addition & 0 deletions pkg/model/provider/openai/system_message_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ func TestShouldMergeConsecutiveMessages_Gating(t *testing.T) {
{"open-model host alias openrouter", &latest.ModelConfig{Provider: "openrouter", Model: "qwen/qwen3.6-35b"}, true},
{"open-model host alias atlascloud", &latest.ModelConfig{Provider: "atlascloud", Model: "qwen/qwen3.8-max"}, true},
{"open-model host alias nebius", &latest.ModelConfig{Provider: "nebius", Model: "Qwen/Qwen3"}, true},
{"api-route, no base_url", &latest.ModelConfig{Provider: "api-route", Model: "gpt-6.1-sol"}, true},
{"baseten", &latest.ModelConfig{Provider: "baseten", Model: "zai-org/GLM-5.2"}, true},
{"daoxe, no base_url", &latest.ModelConfig{Provider: "daoxe", Model: "claude-sonnet-4-6"}, true},
{"ovhcloud", &latest.ModelConfig{Provider: "ovhcloud", Model: "Qwen3.5-397B-A17B"}, true},
Expand Down
8 changes: 8 additions & 0 deletions pkg/model/provider/openai_alias_providers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ type openAIAliasProvider struct {
}

var openAIAliasProviders = []openAIAliasProvider{
{
provider: "api-route",
envVar: "API_ROUTE_API_KEY",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated implementer agent — this comment was posted by the implementer bot from Docker Agentic Platform, not by a human developer

F1 (medium): require an explicit opt-in before live inference. This row is also consumed by TestOpenAIAliasProvider_LiveAPI (lines 308–339), which skips only if the credential is absent and then sends a real streamed completion to the built-in endpoint. A contributor who exports API_ROUTE_API_KEY as documented and runs ordinary task test or go test ./... can therefore incur paid inference and network/balance-dependent failures without opting into a live test.

The key-only live-test mechanism predates this PR; this row expands it to API Route. The prior review's safe Task 3.53.1 fake-Go sentinel probe confirmed that exported credentials survive dotenv, so adding an empty .env.test entry alone is insufficient. No live inference was executed for this review.

Please require a separate explicit live-test opt-in, at least for this new provider's live subtest, while keeping mock tests unconditional. Add a regression that verifies credential alone does not enable live inference, without contacting a real backend.

testKey: "test-api-route-key",
model: "gpt-6.1-sol",
greeting: "Hello from API Route",
mergesSystemMessages: true,
},
{
provider: "atlascloud",
envVar: "ATLASCLOUD_API_KEY",
Expand Down
Loading