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
6 changes: 6 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,12 @@
# Set base URL to enable (default: http://localhost:8000/v1)
# VLLM_BASE_URL=http://localhost:8000/v1

# SGLang (OpenAI-compatible server)
# SGLANG_API_KEY is optional; set it only if launch_server uses --api-key.
# SGLANG_API_KEY=token-abc123
# Set base URL to enable (default: http://localhost:30000/v1)
# SGLANG_BASE_URL=http://localhost:30000/v1

# LM Studio (local, OpenAI-compatible server)
# LM Studio speaks the OpenAI API (/v1/chat/completions, /v1/embeddings) and has
# NO native Ollama API. Attach it to the openai type via a suffix so it gets a
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const client = new Anthropic({
GoModel supports OpenAI, Anthropic, Cohere, Google Gemini, Vertex AI, DeepSeek,
Groq, Fireworks AI, Meta (Muse Spark), OpenRouter, Z.ai, xAI (Grok), Alibaba
Cloud Model Studio (Bailian), Kilo AI, MiniMax, Xiaomi MiMo, OpenCode Go, Azure
OpenAI, Oracle, Ollama, vLLM, Amazon Bedrock Runtime, Amazon Bedrock Mantle, and
OpenAI, Oracle, Ollama, SGLang, vLLM, Amazon Bedrock Runtime, Amazon Bedrock Mantle, and
all OpenAI-compatible providers.

See the [Providers Overview](https://gomodel.enterpilot.io/docs/providers/overview?utm_source=readme) for the full
Expand Down
8 changes: 7 additions & 1 deletion config/config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ server:
enable_passthrough_routes: true # expose /p/{provider}/{endpoint} passthrough routes
allow_passthrough_v1_alias: true # allow /p/{provider}/v1/... while keeping /p/{provider}/... canonical
user_path_header: "X-GoModel-User-Path" # env: USER_PATH_HEADER; inbound header used for user_path scoping
enabled_passthrough_providers: ["openai", "anthropic", "cohere", "openrouter", "kilo", "zai", "vllm", "deepseek", "bailian"] # providers enabled on /p/{provider}/...
enabled_passthrough_providers: ["openai", "anthropic", "cohere", "openrouter", "kilo", "zai", "sglang", "vllm", "deepseek", "bailian"] # providers enabled on /p/{provider}/...
realtime_enabled: true # env: REALTIME_ENABLED; expose /v1/realtime websocket and /p/{provider}/v1/realtime upgrades (OpenAI only)
pid_file: "data/gomodel.pid" # env: PID_FILE; where the running gateway records its process id so `gomodel --reload` can find it. Set per instance when several gateways share a host; empty writes no pid file and disables --reload; changing it needs a restart, not a reload

Expand Down Expand Up @@ -418,6 +418,12 @@ providers:
# Optional: set this only when vllm serve was started with --api-key.
# api_key: "token-abc123"

sglang:
type: sglang
base_url: "http://localhost:30000/v1"
# Optional: set this only when launch_server uses --api-key.
# api_key: "token-abc123"

# Custom OpenAI-compatible provider
# my-provider:
# type: openai
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func buildDefaultConfig() *Config {
"openrouter",
"kilo",
"zai",
"sglang",
"vllm",
"deepseek",
},
Expand Down
5 changes: 3 additions & 2 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func clearProviderEnvVars(t *testing.T) {
"AZURE_API_KEY", "AZURE_BASE_URL", "AZURE_API_VERSION", "AZURE_MODELS",
"ORACLE_API_KEY", "ORACLE_BASE_URL", "ORACLE_MODELS",
"VLLM_API_KEY", "VLLM_BASE_URL", "VLLM_MODELS",
"SGLANG_API_KEY", "SGLANG_BASE_URL", "SGLANG_MODELS",
"OLLAMA_API_KEY", "OLLAMA_BASE_URL", "OLLAMA_MODELS",
} {
t.Setenv(key, "")
Expand Down Expand Up @@ -124,7 +125,7 @@ func TestBuildDefaultConfig(t *testing.T) {
if !cfg.Server.AllowPassthroughV1Alias {
t.Error("expected Server.AllowPassthroughV1Alias=true")
}
if got, want := cfg.Server.EnabledPassthroughProviders, []string{"openai", "anthropic", "openrouter", "kilo", "zai", "vllm", "deepseek"}; !reflect.DeepEqual(got, want) {
if got, want := cfg.Server.EnabledPassthroughProviders, []string{"openai", "anthropic", "openrouter", "kilo", "zai", "sglang", "vllm", "deepseek"}; !reflect.DeepEqual(got, want) {
t.Errorf("expected Server.EnabledPassthroughProviders=%v, got %v", want, got)
}
if cfg.Models.ConfiguredProviderModelsMode != ConfiguredProviderModelsModeFallback {
Expand Down Expand Up @@ -1201,7 +1202,7 @@ func TestLoad_ConfigExample_UsesNestedModelCacheSettings(t *testing.T) {
t.Fatalf("expected Cache.Model.Redis to be nil in example config, got %+v", result.Config.Cache.Model.Redis)
}
gotProviders := result.Config.Server.EnabledPassthroughProviders
wantProviders := []string{"openai", "anthropic", "cohere", "openrouter", "kilo", "zai", "vllm", "deepseek", "bailian"}
wantProviders := []string{"openai", "anthropic", "cohere", "openrouter", "kilo", "zai", "sglang", "vllm", "deepseek", "bailian"}
if !reflect.DeepEqual(gotProviders, wantProviders) {
t.Fatalf("Server.EnabledPassthroughProviders = %v, want %v", gotProviders, wantProviders)
}
Expand Down
2 changes: 1 addition & 1 deletion config/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type ServerConfig struct {
UserPathHeader string `yaml:"user_path_header" env:"USER_PATH_HEADER"`
// EnabledPassthroughProviders lists the provider types enabled on
// /p/{provider}/... passthrough routes. Default:
// ["openai", "anthropic", "openrouter", "kilo", "zai", "vllm", "deepseek"].
// ["openai", "anthropic", "openrouter", "kilo", "zai", "sglang", "vllm", "deepseek"].
EnabledPassthroughProviders []string `yaml:"enabled_passthrough_providers" env:"ENABLED_PASSTHROUGH_PROVIDERS"`
// RealtimeEnabled exposes the realtime (speech-to-speech) websocket endpoint
// at /v1/realtime and the /p/{provider}/v1/realtime passthrough upgrade.
Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/config-yaml.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ must use the same suffix for each instance: for example, pair
`gcp_adc`.

Configured provider model lists can stay in env via `<PROVIDER>_MODELS`, for
example `OPENROUTER_MODELS`, `ORACLE_MODELS`, `AZURE_MODELS`, or `VLLM_MODELS`.
example `OPENROUTER_MODELS`, `ORACLE_MODELS`, `AZURE_MODELS`, `SGLANG_MODELS`, or `VLLM_MODELS`.
Set `CONFIGURED_PROVIDER_MODELS_MODE=fallback` (default) to use those lists only
when upstream `/models` fails or is empty, or `allowlist` to expose only the
configured models for providers that define a list and skip their upstream
Expand Down
14 changes: 12 additions & 2 deletions docs/advanced/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,14 @@ Set these to automatically register providers. No YAML configuration required.
| `AZURE_API_KEY` | Azure OpenAI (`AZURE_BASE_URL` also required) |
| `ORACLE_API_KEY` | Oracle GenAI (`ORACLE_BASE_URL` also required) |
| `OLLAMA_BASE_URL` | Ollama (no API key needed) |
| `SGLANG_BASE_URL` | SGLang (no API key needed unless upstream requires) |
| `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`). 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`. Kilo AI defaults to `https://api.kilo.ai/api/gateway` and can be overridden with `KILO_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`. Kilo AI defaults to `https://api.kilo.ai/api/gateway` and can be overridden with `KILO_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. SGLang defaults to `http://localhost:30000/v1` when `SGLANG_API_KEY` is set, but keyless deployments should set `SGLANG_BASE_URL` explicitly to register the provider. vLLM follows the same pattern at `http://localhost:8000/v1`. 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`,
`AZURE_MODELS`, or `VLLM_MODELS`. By default,
`AZURE_MODELS`, `SGLANG_MODELS`, or `VLLM_MODELS`. By default,
`CONFIGURED_PROVIDER_MODELS_MODE=fallback` uses configured lists only when
upstream `/models` fails, returns nil, or returns an empty list. Set
`CONFIGURED_PROVIDER_MODELS_MODE=allowlist` to expose only configured models for
Expand Down Expand Up @@ -420,6 +421,8 @@ export OPENROUTER_MODELS="openai/gpt-oss-120b,anthropic/claude-sonnet-4"
export KILO_MODELS="anthropic/claude-sonnet-4.5,openai/gpt-5.5"
export CONFIGURED_PROVIDER_MODELS_MODE="fallback" # fallback or allowlist
export OLLAMA_BASE_URL="http://localhost:11434/v1" # Registers "ollama" provider
export SGLANG_BASE_URL="http://localhost:30000/v1" # Registers keyless "sglang" provider
# Optional: export SGLANG_API_KEY="token-abc123"
export VLLM_BASE_URL="http://localhost:8000/v1" # Registers keyless "vllm" provider
# Optional: export VLLM_API_KEY="token-abc123"
```
Expand Down Expand Up @@ -501,6 +504,13 @@ providers:
# api_key is optional; set it only when vllm serve uses --api-key.
# api_key: "token-abc123"

# Add an SGLang OpenAI-compatible server
sglang:
type: sglang
base_url: "http://localhost:30000/v1"
# api_key is optional; set it only when launch_server uses --api-key.
# api_key: "token-abc123"

# Configure a model list for fallback or allowlist mode
gemini:
type: gemini
Expand Down
1 change: 1 addition & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
"providers/xiaomi",
"providers/minimax",
"providers/opencode-go",
"providers/sglang",
"providers/vllm",
"providers/multiple-ollama",
"providers/kimicode",
Expand Down
4 changes: 2 additions & 2 deletions docs/features/passthrough-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ from passthrough requests before forwarding them upstream.

Passthrough is intentionally narrow while the API is in beta.

- `openai`, `anthropic`, `openrouter`, `kilo`, `zai`, `vllm`, and `deepseek` are enabled by
- `openai`, `anthropic`, `openrouter`, `kilo`, `zai`, `sglang`, `vllm`, and `deepseek` are enabled by
default.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- GoModel does not translate passthrough request bodies or response bodies.
- Provider-native error bodies and status codes are proxied instead of converted
Expand All @@ -146,7 +146,7 @@ Passthrough routes are enabled by default:
```env
ENABLE_PASSTHROUGH_ROUTES=true
ALLOW_PASSTHROUGH_V1_ALIAS=true
ENABLED_PASSTHROUGH_PROVIDERS=openai,anthropic,openrouter,kilo,zai,vllm,deepseek
ENABLED_PASSTHROUGH_PROVIDERS=openai,anthropic,openrouter,kilo,zai,sglang,vllm,deepseek
```

Set `ENABLED_PASSTHROUGH_PROVIDERS` to the provider types you want to expose.
5 changes: 3 additions & 2 deletions docs/guides/production.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,9 @@ call the gateway directly. Add the headers at your proxy if you need that.
**GoModel runs fully air-gapped.** There is no telemetry, no phone-home, no
update check, and no license check. The admin dashboard is embedded in the
binary and its fonts are vendored, so the UI loads no CDN assets. Paired with
local model servers such as [Ollama](/providers/multiple-ollama) or
[vLLM](/providers/vllm), the gateway needs no route to the public internet.
local model servers such as [Ollama](/providers/multiple-ollama),
[SGLang](/providers/sglang), or [vLLM](/providers/vllm), the gateway needs no
route to the public internet.

There is exactly one outbound call that is not to a configured provider: the
model metadata registry at `MODEL_LIST_URL`, which supplies pricing, context
Expand Down
5 changes: 4 additions & 1 deletion docs/providers/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ support, not every individual model capability exposed by an upstream provider.
| Azure OpenAI | `AZURE_API_KEY` + `AZURE_BASE_URL` (`AZURE_API_VERSION` optional) | `gpt-5` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | [Azure OpenAI](/providers/azure) |
| Oracle GenAI | `ORACLE_API_KEY` + `ORACLE_BASE_URL` | `openai.gpt-oss-120b` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | [Oracle GenAI](/providers/oracle) |
| Ollama | `OLLAMA_BASE_URL` | `llama3.2` | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | [Ollama](/providers/multiple-ollama) |
| SGLang | `SGLANG_BASE_URL` (`SGLANG_API_KEY` optional) | `Qwen/Qwen2.5-0.5B-Instruct` | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | [SGLang](/providers/sglang) |
| vLLM | `VLLM_BASE_URL` (`VLLM_API_KEY` optional) | `meta-llama/Llama-3.1-8B-Instruct` | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | [vLLM](/providers/vllm) |
| Amazon Bedrock | `BEDROCK_BASE_URL` (region or endpoint) + AWS credentials | `anthropic.claude-3-5-haiku-20241022-v1:0` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | [Amazon Bedrock](/providers/bedrock) |
| Amazon Bedrock Mantle | `BEDROCK_MANTLE_API_KEY` or AWS credentials | `openai.gpt-5.6-sol` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | [Bedrock Mantle](/providers/bedrock-mantle) |
Expand Down Expand Up @@ -122,6 +123,8 @@ support, not every individual model capability exposed by an upstream provider.
for providers that define a list, skipping their upstream `/models` calls.
- **vLLM** — set `VLLM_API_KEY` only if the upstream server was started with
`--api-key`.
- **SGLang** — set `SGLANG_API_KEY` only if the upstream server was started
with `--api-key`; otherwise `SGLANG_BASE_URL` is enough.
- **Multiple API keys for one provider** — set `OPENAI_API_KEY_2`,
`OPENAI_API_KEY_3`, and so on to spread sessions across keys while keeping
each conversation on one key for prompt-cache affinity. See
Expand Down Expand Up @@ -154,7 +157,7 @@ These are the providers most users hit friction on:
- **Anthropic** — reasoning effort maps to Claude's adaptive thinking and
effort control, which differ across model generations.
- **DeepSeek** — reasoning effort mapping quirks for DeepSeek V4.
- **Ollama / vLLM** — local-model hosting with optional multi-instance setup
- **Ollama / SGLang / vLLM** — local-model hosting with optional multi-instance setup
through suffixed env vars and provider-qualified model IDs.
- **Xiaomi MiMo** — thinking mode on by default, a `[1m]` context suffix, and
TTS/ASR that run through chat completions rather than native audio endpoints.
Expand Down
125 changes: 125 additions & 0 deletions docs/providers/sglang.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
title: "SGLang"
description: "Route OpenAI-compatible GoModel requests to one or more self-hosted SGLang servers."
icon: "server"
keywords: ["SGLang", "self-hosted", "Hugging Face models", "OpenAI-compatible server"]
---

GoModel talks to SGLang through its OpenAI-compatible `/v1` API and exposes
SGLang-native endpoints through provider passthrough. Hugging Face model IDs
with slashes work because GoModel splits provider-qualified selectors on the
first slash only.

Start SGLang first:

```bash
python -m sglang.launch_server \
--model-path Qwen/Qwen2.5-0.5B-Instruct \
--host 0.0.0.0 \
--port 30000
# Add --api-key token-abc123 if the server should require bearer auth.
```

See SGLang's [OpenAI-compatible API documentation](https://docs.sglang.io/docs/basic_usage/openai_api_completions)
for current launch and accelerator-specific options.

## Configure

```bash
SGLANG_BASE_URL=http://host.docker.internal:30000/v1 # include /v1
# SGLANG_API_KEY=token-abc123 # only with --api-key
GOMODEL_MASTER_KEY=change-me
```

<Note>
These examples assume GoModel runs in Docker and SGLang runs on the host. If
both run in the same Docker or Kubernetes network, use the SGLang service
name. If GoModel runs directly on the host, use
`http://localhost:30000/v1`.
</Note>

## Run GoModel

<CodeGroup>

```bash Docker (.env file)
docker run --rm -p 8080:8080 --env-file .env enterpilot/gomodel
```

```bash Docker (inline -e)
docker run --rm -p 8080:8080 \
-e GOMODEL_MASTER_KEY="change-me" \
-e SGLANG_BASE_URL="http://host.docker.internal:30000/v1" \
enterpilot/gomodel
```

```bash Binary (make build)
make build
./bin/gomodel
```

</CodeGroup>

## Verify

```bash
curl -s http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer change-me" \
-H "Content-Type: application/json" \
-d '{
"model": "sglang/Qwen/Qwen2.5-0.5B-Instruct",
"messages": [{"role": "user", "content": "Reply with exactly ok."}],
"max_tokens": 8
}'
```

`GET /v1/models` returns SGLang model IDs prefixed by provider name, for
example `sglang/Qwen/Qwen2.5-0.5B-Instruct`.

## Multiple SGLang instances

Use suffixed environment variables to register more than one instance without
YAML:

```bash
SGLANG_BASE_URL=http://host.docker.internal:30000/v1
SGLANG_TEST_BASE_URL=http://host.docker.internal:30001/v1
```

This registers `sglang` and `sglang-test`. The suffix is lowercased and
underscores become hyphens.

## Native passthrough

Passthrough is enabled by default. Root-relative SGLang endpoints such as
`/generate` are sent without the configured `/v1` prefix:

```bash
curl -s http://localhost:8080/p/sglang/generate \
-H "Authorization: Bearer change-me" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello",
"sampling_params": {"max_new_tokens": 8}
}'
```

Keep the explicit `v1/` segment for SGLang endpoints that include it, such as
`/v1/rerank` or `/v1/tokenize`:

```text
/p/sglang/v1/rerank
/p/sglang/v1/tokenize
```

GoModel strips client authorization before forwarding and applies
`SGLANG_API_KEY` when configured.

## Capability notes

- Chat completions, streaming, model listing, Responses, and embeddings use
SGLang's OpenAI-compatible API.
- Embeddings and model-specific features depend on the model loaded by SGLang.
- Native batch, file, and stored-response lifecycle interfaces are not yet
exposed as typed GoModel provider capabilities; use passthrough where the
installed SGLang version supports them.
Loading