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
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</p>

<p align="center">
A fast and lightweight AI gateway written in Go, providing a unified OpenAI-compatible API for OpenAI, Anthropic, Gemini, xAI, Groq, OpenRouter, Z.ai, Azure OpenAI, Oracle, Ollama, and more.
A fast and lightweight AI gateway written in Go, providing a unified OpenAI-compatible API for OpenAI, Anthropic, Gemini, DeepSeek, xAI, Groq, OpenRouter, Z.ai, Azure OpenAI, Oracle, Ollama, and more.
</p>

<a href="docs/dashboard.gif">
Expand Down Expand Up @@ -51,6 +51,7 @@ docker run --rm -p 8080:8080 \
-e OPENAI_API_KEY="your-openai-key" \
-e ANTHROPIC_API_KEY="your-anthropic-key" \
-e GEMINI_API_KEY="your-gemini-key" \
-e DEEPSEEK_API_KEY="your-deepseek-key" \
-e GROQ_API_KEY="your-groq-key" \
-e OPENROUTER_API_KEY="your-openrouter-key" \
-e ZAI_API_KEY="your-zai-key" \
Expand Down Expand Up @@ -90,6 +91,7 @@ Example model identifiers are illustrative and subject to change; consult provid
| OpenAI | `OPENAI_API_KEY` | `gpt-5.5` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Anthropic | `ANTHROPIC_API_KEY` | `claude-sonnet-4-20250514` | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
| Google Gemini | `GEMINI_API_KEY` | `gemini-2.5-flash` | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| DeepSeek | `DEEPSEEK_API_KEY` | `deepseek-v4-pro` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Groq | `GROQ_API_KEY` | `llama-3.3-70b-versatile` | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| OpenRouter | `OPENROUTER_API_KEY` | `google/gemini-2.5-flash` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Z.ai | `ZAI_API_KEY` (`ZAI_BASE_URL` optional) | `glm-5.1` | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
Expand All @@ -105,7 +107,9 @@ For Z.ai's GLM Coding Plan, set `ZAI_BASE_URL=https://api.z.ai/api/coding/paas/v
Configured model lists are available for every provider with
`<PROVIDER>_MODELS`, for example
`OPENROUTER_MODELS=openai/gpt-oss-120b,anthropic/claude-sonnet-4` or
`ORACLE_MODELS=openai.gpt-oss-120b,xai.grok-3`. By default,
`ORACLE_MODELS=openai.gpt-oss-120b,xai.grok-3`. DeepSeek defaults to
`https://api.deepseek.com`; set `DEEPSEEK_BASE_URL` only when using a compatible
proxy or alternate DeepSeek endpoint. By default,
`CONFIGURED_PROVIDER_MODELS_MODE=fallback` uses those lists only when upstream
`/models` is unavailable or empty. Set `CONFIGURED_PROVIDER_MODELS_MODE=allowlist`
to expose only configured models for providers that define a list, skipping
Expand Down Expand Up @@ -288,7 +292,7 @@ See [DEVELOPMENT.md](docs/DEVELOPMENT.md) for testing, linting, and pre-commit s
### Must Have

- [ ] Intelligent routing
- [ ] Broader provider support: Oracle model configuration via environment variables, plus Cohere, Command A, Operational, and DeepSeek V3
- [ ] Broader provider support: Cohere, Command A, and Operational
- [ ] Budget management with limits per `user_path` and/or API key
- [ ] Editable model pricing for accurate cost tracking and budgeting
- [ ] Full support for the OpenAI `/responses` and `/conversations` lifecycle
Expand Down
2 changes: 1 addition & 1 deletion cmd/gomodel/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4355,7 +4355,7 @@ var SwaggerInfo = &swag.Spec{
BasePath: "/",
Schemes: []string{"http"},
Title: "GoModel API",
Description: "High-performance AI gateway routing requests to multiple LLM providers (OpenAI, Anthropic, Gemini, Groq, OpenRouter, Z.ai, xAI, Oracle, Ollama). Drop-in OpenAI-compatible API.",
Description: "High-performance AI gateway routing requests to multiple LLM providers (OpenAI, Anthropic, Gemini, Groq, OpenRouter, DeepSeek, Z.ai, xAI, MiniMax, Oracle, Ollama). Drop-in OpenAI-compatible API.",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
Expand Down
4 changes: 3 additions & 1 deletion cmd/gomodel/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"gomodel/internal/providers"
"gomodel/internal/providers/anthropic"
"gomodel/internal/providers/azure"
"gomodel/internal/providers/deepseek"
"gomodel/internal/providers/gemini"
"gomodel/internal/providers/groq"
"gomodel/internal/providers/minimax"
Expand Down Expand Up @@ -73,7 +74,7 @@ func startApplication(application lifecycleApp, addr string) error {

// @title GoModel API
// @version 1.0
// @description High-performance AI gateway routing requests to multiple LLM providers (OpenAI, Anthropic, Gemini, Groq, OpenRouter, Z.ai, xAI, MiniMax, Oracle, Ollama). Drop-in OpenAI-compatible API.
// @description High-performance AI gateway routing requests to multiple LLM providers (OpenAI, Anthropic, Gemini, Groq, OpenRouter, DeepSeek, Z.ai, xAI, MiniMax, Oracle, Ollama). Drop-in OpenAI-compatible API.
// @BasePath /
// @schemes http
// @securityDefinitions.apikey BearerAuth
Expand Down Expand Up @@ -119,6 +120,7 @@ func main() {
factory.Add(azure.Registration)
factory.Add(oracle.Registration)
factory.Add(anthropic.Registration)
factory.Add(deepseek.Registration)
factory.Add(gemini.Registration)
factory.Add(groq.Registration)
factory.Add(minimax.Registration)
Expand Down
7 changes: 4 additions & 3 deletions config/config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,11 @@ providers:
# - openai.gpt-oss-120b
# - xai.grok-3

# Example: DeepSeek (OpenAI-compatible)
# Example: DeepSeek. GoModel translates /v1/responses requests to DeepSeek
# chat completions because DeepSeek does not expose a native Responses API.
# deepseek:
# type: "openai"
# base_url: "https://api.deepseek.com/v1"
# type: "deepseek"
# base_url: "https://api.deepseek.com"
# api_key: "${DEEPSEEK_API_KEY}"

# Example: local Ollama server with explicit per-model metadata.
Expand Down
1 change: 1 addition & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func clearProviderEnvVars(t *testing.T) {
"OPENAI_API_KEY", "OPENAI_BASE_URL", "OPENAI_MODELS",
"ANTHROPIC_API_KEY", "ANTHROPIC_BASE_URL", "ANTHROPIC_MODELS",
"GEMINI_API_KEY", "GEMINI_BASE_URL", "GEMINI_MODELS",
"DEEPSEEK_API_KEY", "DEEPSEEK_BASE_URL", "DEEPSEEK_MODELS",
"XAI_API_KEY", "XAI_BASE_URL", "XAI_MODELS",
"GROQ_API_KEY", "GROQ_BASE_URL", "GROQ_MODELS",
"OPENROUTER_API_KEY", "OPENROUTER_BASE_URL", "OPENROUTER_MODELS", "OPENROUTER_SITE_URL", "OPENROUTER_APP_NAME",
Expand Down
2 changes: 1 addition & 1 deletion docs/about/roadmap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ icon: "list-todo"
### Must Have

- [ ] Intelligent routing
- [ ] Broader provider support: Oracle model configuration via environment variables, plus Cohere, Command A, Operational, and DeepSeek V3
- [ ] Broader provider support: Cohere, Command A, and Operational
- [ ] Budget management with limits per `user_path` and/or API key
- [ ] Editable model pricing for accurate cost tracking and budgeting
- [ ] Full support for the OpenAI `/responses` and `/conversations` lifecycle
Expand Down
2 changes: 1 addition & 1 deletion docs/adr/0001-explicit-provider-registration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Context

GoModel supports multiple LLM providers, including OpenAI, Anthropic, Gemini, xAI, Groq, OpenRouter, Z.ai, Azure OpenAI, Oracle, Ollama, and custom OpenAI-compatible endpoints. Each provider must be registered with the factory before use.
GoModel supports multiple LLM providers, including OpenAI, Anthropic, Gemini, DeepSeek, xAI, Groq, OpenRouter, Z.ai, Azure OpenAI, Oracle, Ollama, and custom OpenAI-compatible endpoints. Each provider must be registered with the factory before use.

## Decision

Expand Down
10 changes: 9 additions & 1 deletion docs/advanced/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ Set these to automatically register providers. No YAML configuration required.
| `OPENAI_API_KEY` | OpenAI |
| `ANTHROPIC_API_KEY` | Anthropic |
| `GEMINI_API_KEY` | Google Gemini |
| `DEEPSEEK_API_KEY` | DeepSeek |
| `OPENROUTER_API_KEY` | OpenRouter |
| `ZAI_API_KEY` | Z.ai |
| `XAI_API_KEY` | xAI (Grok) |
Expand All @@ -190,7 +191,7 @@ Set these to automatically register providers. No YAML configuration required.
| `OLLAMA_BASE_URL` | Ollama (no API key needed) |
| `VLLM_BASE_URL` | vLLM (no API key needed unless upstream requires) |

Most providers can use a custom base URL via `<PROVIDER>_BASE_URL` (for example `OPENAI_BASE_URL`). OpenRouter defaults to `https://openrouter.ai/api/v1` and can be overridden with `OPENROUTER_BASE_URL`. Z.ai defaults to `https://api.z.ai/api/paas/v4`; set `ZAI_BASE_URL=https://api.z.ai/api/coding/paas/v4` for the GLM Coding Plan endpoint. vLLM defaults to `http://localhost:8000/v1` when `VLLM_API_KEY` is set, but keyless deployments should set `VLLM_BASE_URL` explicitly to register the provider. Azure uses `AZURE_BASE_URL` for its deployment base URL and accepts an optional `AZURE_API_VERSION` override; otherwise it defaults to `2024-10-21`. Oracle requires `ORACLE_BASE_URL` because its OpenAI-compatible endpoint is region-specific.
Most providers can use a custom base URL via `<PROVIDER>_BASE_URL` (for example `OPENAI_BASE_URL`). DeepSeek defaults to `https://api.deepseek.com`; set `DEEPSEEK_BASE_URL` only for a compatible proxy or alternate DeepSeek endpoint. OpenRouter defaults to `https://openrouter.ai/api/v1` and can be overridden with `OPENROUTER_BASE_URL`. Z.ai defaults to `https://api.z.ai/api/paas/v4`; set `ZAI_BASE_URL=https://api.z.ai/api/coding/paas/v4` for the GLM Coding Plan endpoint. vLLM defaults to `http://localhost:8000/v1` when `VLLM_API_KEY` is set, but keyless deployments should set `VLLM_BASE_URL` explicitly to register the provider. Azure uses `AZURE_BASE_URL` for its deployment base URL and accepts an optional `AZURE_API_VERSION` override; otherwise it defaults to `2024-10-21`. Oracle requires `ORACLE_BASE_URL` because its OpenAI-compatible endpoint is region-specific.

Every provider type also accepts a comma-separated configured model list via
`<PROVIDER>_MODELS`, for example `OPENROUTER_MODELS`, `ORACLE_MODELS`,
Expand Down Expand Up @@ -311,6 +312,7 @@ The simplest way to add providers. GoModel checks for well-known API key environ
export OPENAI_API_KEY="sk-..." # Registers "openai" provider
export ANTHROPIC_API_KEY="sk-ant-..." # Registers "anthropic" provider
export GEMINI_API_KEY="..." # Registers "gemini" provider
export DEEPSEEK_API_KEY="..." # Registers "deepseek" provider
export XAI_API_KEY="..." # Registers "xai" provider
export GROQ_API_KEY="gsk_..." # Registers "groq" provider
export OPENROUTER_API_KEY="sk-or-..." # Registers "openrouter" provider
Expand Down Expand Up @@ -381,6 +383,12 @@ providers:
- openai.gpt-oss-120b
- xai.grok-3

# Add DeepSeek. GoModel translates /v1/responses to DeepSeek chat completions.
deepseek:
type: deepseek
base_url: "https://api.deepseek.com"
api_key: "..."

# Add a vLLM OpenAI-compatible server
vllm:
type: vllm
Expand Down
1 change: 1 addition & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"pages": [
"guides/openclaw",
"guides/oracle",
"guides/deepseek",
"guides/vllm",
"guides/multiple-ollama",
"guides/claude-code",
Expand Down
13 changes: 7 additions & 6 deletions docs/getting-started/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ icon: "rocket"
## Run GoModel in 30 Seconds

GoModel is an OpenAI-compatible AI gateway. You can connect one endpoint and
route traffic across OpenAI, Anthropic, Gemini, xAI, Groq, OpenRouter, Z.ai,
Azure OpenAI, Oracle, Ollama, and more while keeping auth, audit logs, and admin
visibility in one place.
route traffic across OpenAI, Anthropic, Gemini, DeepSeek, xAI, Groq, OpenRouter,
Z.ai, Azure OpenAI, Oracle, Ollama, and more while keeping auth, audit logs, and
admin visibility in one place.

### 1. Start GoModel

Expand All @@ -26,9 +26,10 @@ docker run --rm -p 8080:8080 \

<Note>
Set at least one provider credential or base URL
(`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`,
`GROQ_API_KEY`, `OPENROUTER_API_KEY`, `ZAI_API_KEY`, `AZURE_API_KEY` +
`AZURE_BASE_URL`, `ORACLE_API_KEY` + `ORACLE_BASE_URL`,
(`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`,
`DEEPSEEK_API_KEY`, `XAI_API_KEY`, `GROQ_API_KEY`, `OPENROUTER_API_KEY`,
`ZAI_API_KEY`, `AZURE_API_KEY` + `AZURE_BASE_URL`,
`ORACLE_API_KEY` + `ORACLE_BASE_URL`,
`OLLAMA_BASE_URL`) or GoModel will have no models to route. GoModel also
works well with additional OpenAI-compatible providers out of the box.
</Note>
Expand Down
38 changes: 37 additions & 1 deletion docs/guides/codex.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Responses API.

Flow:

`Codex -> GoModel -> OpenAI`
`Codex -> GoModel -> upstream model provider`

## Before you start

Expand Down Expand Up @@ -97,6 +97,42 @@ The validated result was:
ok
```

## DeepSeek V4

Codex sends `POST /v1/responses`. DeepSeek exposes chat completions instead of
a native Responses API, so configure the first-class DeepSeek provider and let
GoModel translate the request.

```yaml
providers:
deepseek:
type: deepseek
base_url: "https://api.deepseek.com"
api_key: "${DEEPSEEK_API_KEY}"
```

If you previously configured DeepSeek as `type: openai`, change it to
`type: deepseek` for Codex. The generic OpenAI provider forwards `/responses`
upstream, while the DeepSeek provider translates `/responses` to
`/chat/completions`.

See the [DeepSeek guide](/guides/deepseek) for the full reasoning effort
mapping table (DeepSeek V4 only accepts `high` and `max`, so GoModel maps
`low` and `medium` up to `high`).

Then use the DeepSeek model name in Codex:

```toml
model_provider = "gomodel"
model = "deepseek-v4-pro"

[model_providers.gomodel]
name = "GoModel"
base_url = "http://localhost:8080/v1"
env_key = "OPENAI_API_KEY"
wire_api = "responses"
```

## 5. Check the traffic in GoModel

Open the GoModel dashboard audit logs:
Expand Down
67 changes: 67 additions & 0 deletions docs/guides/deepseek.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
title: "GoModel & DeepSeek"
description: "Configure DeepSeek V4 in GoModel and understand how reasoning effort is mapped to DeepSeek's reasoning_effort field."
icon: "brain"
---

GoModel routes to DeepSeek through DeepSeek's chat completions API. DeepSeek
does not expose a native Responses API, so GoModel translates `/v1/responses`
requests to `/chat/completions` automatically.

## 1. Configure DeepSeek

Env-only is enough:

```bash
export DEEPSEEK_API_KEY="..."
```

Or in `config.yaml` (not recommended):

```yaml
providers:
deepseek:
type: deepseek
base_url: "https://api.deepseek.com"
api_key: "${DEEPSEEK_API_KEY}"
```

<Note>
If you previously configured DeepSeek as `type: openai`, switch it to `type:
deepseek` so GoModel translates `/v1/responses` and remaps reasoning effort.
The generic OpenAI provider does neither.
</Note>

## 2. Reasoning effort mapping

DeepSeek V4 reasoning models accept `reasoning_effort` as a top-level string
with two levels: `high` and `max`. GoModel accepts the standard OpenAI-style
levels and remaps them:

| Client sends | DeepSeek receives |
| --------------- | ----------------- |
| `low` | `high` |
| `medium` | `high` |
| `high` | `high` |
| `xhigh` / `max` | `max` |
| anything else | passed through |

`low` and `medium` are mapped up to `high` because DeepSeek's reasoning models
do not accept lower levels. If you want to avoid reasoning entirely, omit the
`reasoning` field instead of passing `low`.

GoModel rewrites the request body so DeepSeek sees a top-level
`reasoning_effort: "..."` instead of OpenAI's nested
`"reasoning": {"effort": "..."}` shape. No client change is required.

## Current support

Integrated:

- chat completions and streaming
- Responses API and streaming (translated to chat completions)
- model listing through `/models`

Not supported by DeepSeek:

- embeddings (returns an `invalid_request_error`)
2 changes: 1 addition & 1 deletion docs/openapi.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"openapi": "3.0.0",
"info": {
"description": "High-performance AI gateway routing requests to multiple LLM providers (OpenAI, Anthropic, Gemini, Groq, OpenRouter, Z.ai, xAI, MiniMax, Oracle, Ollama). Drop-in OpenAI-compatible API.",
"description": "High-performance AI gateway routing requests to multiple LLM providers (OpenAI, Anthropic, Gemini, Groq, OpenRouter, DeepSeek, Z.ai, xAI, MiniMax, Oracle, Ollama). Drop-in OpenAI-compatible API.",
"title": "GoModel API",
"contact": {},
"version": "1.0"
Expand Down
2 changes: 1 addition & 1 deletion helm/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
apiVersion: v2
name: gomodel
description: High-performance AI gateway for multiple LLM providers (OpenAI, Anthropic, Gemini, Groq, Z.ai, xAI)
description: High-performance AI gateway for multiple LLM providers (OpenAI, Anthropic, Gemini, DeepSeek, Groq, Z.ai, xAI)
type: application
version: 0.1.0
appVersion: "1.0.0"
Expand Down
2 changes: 1 addition & 1 deletion helm/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# GoModel Helm Chart

High-performance AI gateway for multiple LLM providers (OpenAI, Anthropic, Gemini, Groq, Z.ai, xAI, Oracle).
High-performance AI gateway for multiple LLM providers (OpenAI, Anthropic, Gemini, DeepSeek, Groq, Z.ai, xAI, Oracle).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify whether the Helm chart actually exposes DeepSeek settings.
rg -n -C2 'deepseek|DEEPSEEK|providers\.deepseek' helm

Repository: ENTERPILOT/GoModel

Length of output: 44


Remove DeepSeek from the provider list in line 3.

The README advertises DeepSeek support, but the Helm chart does not expose any DeepSeek configuration (no providers.deepseek.* or DEEPSEEK_* settings found in helm/). Operators cannot configure this provider from Helm, so remove it from the description to match what the chart actually supports.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@helm/README.md` at line 3, Update the provider list string in helm/README.md
by removing "DeepSeek" from the comma-separated providers on the line that
currently reads "High-performance AI gateway for multiple LLM providers (OpenAI,
Anthropic, Gemini, DeepSeek, Groq, Z.ai, xAI, Oracle)"; edit that phrase to
exclude DeepSeek and adjust punctuation/spacing so the list remains
grammatically correct (e.g., "OpenAI, Anthropic, Gemini, Groq, Z.ai, xAI,
Oracle"). Ensure no other README lines advertise DeepSeek support.


## Prerequisites

Expand Down
23 changes: 23 additions & 0 deletions internal/providers/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ var testDiscoveryConfigs = map[string]DiscoveryConfig{
"gemini": {
DefaultBaseURL: "https://generativelanguage.googleapis.com/v1beta/openai",
},
"deepseek": {
DefaultBaseURL: "https://api.deepseek.com",
},
"xai": {
DefaultBaseURL: "https://api.x.ai/v1",
},
Expand Down Expand Up @@ -402,6 +405,26 @@ func TestApplyProviderEnvVars_DiscoversOpenRouterFromAPIKey(t *testing.T) {
}
}

func TestApplyProviderEnvVars_DiscoversDeepSeekFromAPIKey(t *testing.T) {
t.Setenv("DEEPSEEK_API_KEY", "deepseek-key")

got := applyProviderEnvVars(map[string]config.RawProviderConfig{}, testDiscoveryConfigs)

p, exists := got["deepseek"]
if !exists {
t.Fatal("expected deepseek to be discovered from env var")
}
if p.APIKey != "deepseek-key" {
t.Errorf("APIKey = %q, want deepseek-key", p.APIKey)
}
if p.Type != "deepseek" {
t.Errorf("Type = %q, want deepseek", p.Type)
}
if p.BaseURL != testDiscoveryConfigs["deepseek"].DefaultBaseURL {
t.Errorf("BaseURL = %q, want %q", p.BaseURL, testDiscoveryConfigs["deepseek"].DefaultBaseURL)
}
}

func TestApplyProviderEnvVars_DiscoversZAIFromAPIKey(t *testing.T) {
t.Setenv("ZAI_API_KEY", "zai-key")

Expand Down
Loading
Loading