Skip to content
Merged
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, opper, 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.).",
"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, opper, runcrate, 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
6 changes: 3 additions & 3 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, opper, api-route, 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, opper, runcrate, 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`, `opper`, `api-route`, `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`, `opper`, `runcrate`, `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 Expand Up @@ -558,7 +558,7 @@ for a complete local-server configuration.
## Custom HTTP Headers

For OpenAI-compatible providers (`openai`, `github-copilot`, `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`, `opper`, `atlascloud`, `ollama`, and any custom provider using the OpenAI API),
`nebius`, `nvidia`, `minimax`, `baseten`, `daoxe`, `ovhcloud`, `groq`, `fireworks-ai`, `deepseek`, `cerebras`, `togetherai`, `huggingface`, `moonshotai`, `vercel`, `cloudflare-workers-ai`, `cloudflare-ai-gateway`, `requesty`, `openrouter`, `opper`, `runcrate`, `atlascloud`, `ollama`, and any custom provider using the OpenAI API),
`provider_opts.http_headers` adds arbitrary HTTP headers to every outgoing
request:

Expand Down
2 changes: 2 additions & 0 deletions docs/data/nav.yml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@
url: /providers/openrouter/
- title: OVHcloud
url: /providers/ovhcloud/
- title: Runcrate
url: /providers/runcrate/
- title: Together AI
url: /providers/together/
- title: Vercel AI Gateway
Expand Down
1 change: 1 addition & 0 deletions docs/providers/overview/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Use this table to find a built-in provider's config key and authentication metho
| Opper | `opper` | `OPPER_API_KEY` |
| API Route | `api-route` | `API_ROUTE_API_KEY` |
| Atlas Cloud | [`atlascloud`](../atlascloud/index.md) | `ATLASCLOUD_API_KEY` |
| Runcrate | [`runcrate`](../runcrate/index.md) | `RUNCRATE_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`) |
| GitHub Copilot | `github-copilot` | `GITHUB_TOKEN` or `GH_TOKEN` (PAT with `copilot` scope) |
Expand Down
120 changes: 120 additions & 0 deletions docs/providers/runcrate/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
title: "Runcrate"
description: "Use Runcrate models with Docker Agent."
keywords: docker agent, ai agents, model providers, llm, runcrate
weight: 25
canonical: https://docs.docker.com/ai/docker-agent/providers/runcrate/
---

_Use Runcrate models with Docker Agent._

## Overview

[Runcrate](https://www.runcrate.ai/?utm_source=docker-agent&utm_medium=directory&utm_campaign=gpu_pricing)
is a GPU cloud that also serves open models (DeepSeek, GLM, Qwen, gpt-oss and
others) through an OpenAI-compatible API. Docker Agent includes built-in
support for Runcrate as an alias provider.

Some open models come with a limited free allowance for GitHub accounts at
least 30 days old. Once the allowance is used up, or when free capacity is
busy, requests from a workspace with credit are billed to that credit. See
[Runcrate's free inference terms](https://www.runcrate.ai/inference/free?utm_source=docker-agent&utm_medium=directory&utm_campaign=gpu_pricing)
for the current models, limits and prices.

## Setup

1. [Create a Runcrate API key](https://www.runcrate.ai/dashboard/api-keys)
2. Set the environment variable:

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

## Usage

### Inline Syntax

Use a Runcrate model by prefixing its model ID with `runcrate/`:

```yaml
agents:
root:
model: runcrate/deepseek-ai/DeepSeek-V4.1-Flash
description: Assistant using Runcrate
instruction: You are a helpful assistant.
```

Docker Agent splits only the first slash, so model IDs that include an
organization prefix are preserved.

### Named Model

For more control over parameters:

```yaml
models:
runcrate_glm:
provider: runcrate
model: zai-org/GLM-5.3
temperature: 0.7
max_tokens: 8192

agents:
root:
model: runcrate_glm
description: Assistant using Runcrate
instruction: You are a helpful assistant.
```

## Available Models

Some chat model IDs Runcrate serves:

| Model ID | Model |
| --- | --- |
| `deepseek-ai/DeepSeek-V4.1-Flash` | DeepSeek V4.1 Flash (default) |
| `zai-org/GLM-5.3` | GLM-5.3 |
| `Qwen/Qwen3.8-Flash` | Qwen3.8 Flash |
| `openai/gpt-oss-120b` | gpt-oss 120B |

Model IDs are case-sensitive. The live [`/v1/models` endpoint](https://api.runcrate.ai/v1/models)
lists current IDs; it also lists image, video, speech and embedding models,
which this chat provider does not use.

Runcrate is not in the models.dev catalog. Docker Agent does not import metadata
from Runcrate's model list, so it has no catalog-derived pricing or context limits
for these models. Attachment capabilities conservatively fall back to text-only;
image and PDF attachments are dropped, with a warning logged once per model.

If you have verified that your chosen model accepts a particular attachment
type, set `models.<name>.capabilities` to override detection. See
[Attachment Capability Overrides](../../configuration/models/index.md#attachment-capability-overrides)
for all supported flags.

## How It Works

Runcrate is implemented as a built-in alias in Docker Agent:

- **API Type:** OpenAI-compatible Chat Completions (`openai_chatcompletions`)
- **Base URL:** `https://api.runcrate.ai/v1`
- **Token Variable:** `RUNCRATE_API_KEY`

Because Runcrate serves open-weight models whose chat templates can reject
multiple leading system messages, Docker Agent coalesces its per-source system
messages into one.

## Example: Code Assistant

```yaml
agents:
coder:
model: runcrate/deepseek-ai/DeepSeek-V4.1-Flash
description: Code assistant using Runcrate
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 examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ remote MCP endpoints.
| [`daoxe.yaml`](daoxe.yaml) | DaoXE multi-model gateway provider. |
| [`opper.yaml`](opper.yaml) | Opper multi-model gateway provider. |
| [`ovhcloud.yaml`](ovhcloud.yaml) | OVHcloud AI Endpoints provider. |
| [`runcrate.yaml`](runcrate.yaml) | Runcrate open-model host (`runcrate`). |
| [`groq.yaml`](groq.yaml) | Groq fast-inference provider. |
| [`fireworks.yaml`](fireworks.yaml) | Fireworks AI open-model inference (`fireworks-ai`). |
| [`deepseek.yaml`](deepseek.yaml) | DeepSeek chat and reasoning provider. |
Expand Down
17 changes: 17 additions & 0 deletions examples/runcrate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# yaml-language-server: $schema=../agent-schema.json

models:
runcrate_model:
provider: runcrate
model: deepseek-ai/DeepSeek-V4.1-Flash

agents:
root:
model: runcrate_model
description: Assistant using Runcrate
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 @@ -65,6 +65,7 @@ var cloudProviders = []providerConfig{
{"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"},
{"opper", []string{"OPPER_API_KEY"}, "OPPER_API_KEY", "OPPER_API_KEY"},
{"runcrate", []string{"RUNCRATE_API_KEY"}, "RUNCRATE_API_KEY", "RUNCRATE_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"},
{"daoxe", []string{"DAOXE_API_KEY"}, "DAOXE_API_KEY", "DAOXE_API_KEY"},
Expand Down Expand Up @@ -165,6 +166,7 @@ var DefaultModels = map[string]string{
"api-route": "gpt-6.1-sol",
"atlascloud": "qwen/qwen3.8-max",
"opper": "claude-sonnet-4-6",
"runcrate": "deepseek-ai/DeepSeek-V4.1-Flash",
"baseten": "deepseek-ai/DeepSeek-V4-Pro-0813",
"ovhcloud": "Qwen3.5-397B-A17B",
"daoxe": "claude-sonnet-4-6",
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 @@ -95,6 +95,13 @@ func TestAvailableProviders_NoGateway(t *testing.T) {
},
expectedProvider: "opper",
},
{
name: "runcrate api key present",
envVars: map[string]string{
"RUNCRATE_API_KEY": "test-key",
},
expectedProvider: "runcrate",
},
{
name: "baseten api key present",
envVars: map[string]string{
Expand Down Expand Up @@ -352,6 +359,15 @@ func TestAutoModelConfig(t *testing.T) {
expectedModel: "claude-sonnet-4-6",
expectedMaxTokens: 32000,
},
{
name: "runcrate provider",
envVars: map[string]string{
"RUNCRATE_API_KEY": "test-key",
},
expectedProvider: "runcrate",
expectedModel: "deepseek-ai/DeepSeek-V4.1-Flash",
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 @@ -31,6 +31,7 @@ var modelsDevCatalogProviders = map[string]string{
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.
"runcrate": true, // Runcrate 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)
"cloudflare-ai-gateway": true, // multi-provider router; example model ids use the gateway's provider/model form, not guaranteed to match a models.dev id
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 @@ -70,6 +70,11 @@ var Aliases = map[string]Alias{
BaseURL: "https://global.api-route.com/v1",
TokenEnvVar: "API_ROUTE_API_KEY",
},
"runcrate": {
APIType: "openai",
BaseURL: "https://api.runcrate.ai/v1",
TokenEnvVar: "RUNCRATE_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 @@ -41,6 +41,7 @@ func TestCatalogAliases(t *testing.T) {
"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"},
"runcrate": {APIType: "openai", BaseURL: "https://api.runcrate.ai/v1", TokenEnvVar: "RUNCRATE_API_KEY"},
"opper": {APIType: "openai", BaseURL: "https://api.opper.ai/v3/compat", TokenEnvVar: "OPPER_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 @@ -132,6 +133,7 @@ func TestProviderIDsMatchEmbeddedCatalog(t *testing.T) {
"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",
"runcrate": "model IDs come from Runcrate's /v1/models endpoint, not models.dev",
"dmr": "local Docker Model Runner",
"ollama": "local Ollama server",
}
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 @@ -282,6 +282,7 @@ var openModelHostProviders = map[string]bool{
"ovhcloud": true,
"openrouter": true,
"opper": true,
"runcrate": true,
"nebius": true,
"nvidia": true,
"cerebras": true,
Expand Down
11 changes: 11 additions & 0 deletions pkg/model/provider/openai/system_message_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ func TestOpper_MergesConsecutiveSystemMessages(t *testing.T) {
})
}

func TestRuncrate_MergesConsecutiveSystemMessages(t *testing.T) {
t.Parallel()

assertMergesConsecutiveMessages(t, &latest.ModelConfig{
Provider: "runcrate",
Model: "deepseek-ai/DeepSeek-V4.1-Flash",
TokenKey: "MY_TOKEN",
})
}

func TestBaseten_MergesConsecutiveSystemMessages(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -183,6 +193,7 @@ func TestShouldMergeConsecutiveMessages_Gating(t *testing.T) {
{"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},
{"opper, no base_url", &latest.ModelConfig{Provider: "opper", Model: "claude-sonnet-4-6"}, true},
{"runcrate, no base_url", &latest.ModelConfig{Provider: "runcrate", Model: "deepseek-ai/DeepSeek-V4.1-Flash"}, true},
{"ovhcloud", &latest.ModelConfig{Provider: "ovhcloud", Model: "Qwen3.5-397B-A17B"}, true},
{"open-model host alias cerebras", &latest.ModelConfig{Provider: "cerebras", Model: "qwen-3-coder-480b"}, true},
{"open-model host fireworks", &latest.ModelConfig{Provider: "fireworks", Model: "accounts/fireworks/models/kimi-k3"}, 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 @@ -72,6 +72,14 @@ var openAIAliasProviders = []openAIAliasProvider{
greeting: "Hello from Atlas Cloud",
mergesSystemMessages: true,
},
{
provider: "runcrate",
envVar: "RUNCRATE_API_KEY",
testKey: "test-runcrate-key",
model: "deepseek-ai/DeepSeek-V4.1-Flash",
greeting: "Hello from Runcrate",
mergesSystemMessages: true,
},
{
provider: "deepseek",
envVar: "DEEPSEEK_API_KEY",
Expand Down
Loading