How Model Aliases Work in DS2API for OpenAI, Claude, and Gemini Compatibility
DS2API uses a two-layer model alias system that maps OpenAI, Claude, and Gemini model names to native DeepSeek model IDs, allowing seamless cross-provider compatibility without changing request payloads.
The model aliases in DS2API enable the API gateway to accept requests using external provider naming conventions while routing everything to a DeepSeek backend. This architecture decouples the consumer-facing model identifiers from the actual inference engine, supporting runtime customization through configuration overlays.
The Model Alias Architecture
DS2API implements alias resolution through a hierarchical lookup system defined in internal/config/models.go. The design separates static defaults from dynamic runtime overrides, ensuring that operators can customize mappings without rebuilding the binary.
Default Alias Table
The system ships with a comprehensive built-in mapping called DefaultModelAliases that covers major providers:
- OpenAI GPT family:
"gpt-4"maps to"deepseek-v4-flash" - Claude models:
"claude-sonnet-4-6"maps to"deepseek-v4-flash"(lines 35-48) - Gemini variants:
"gemini-pro"maps to"deepseek-v4-pro", while"gemini-flash-latest"maps to"deepseek-v4-flash"(lines 66-82)
These mappings reside in internal/config/models.go and load into memory at startup, providing immediate compatibility for common model identifiers.
Runtime Configuration Overrides
Operators can extend or override the default table through the config.json configuration file under the ModelAliases key. The admin API handlers in internal/httpapi/admin/settings/handler_settings_parse.go (lines 119-138) parse JSON payloads containing a "model_aliases" field and merge them into the running configuration.
{
"model_aliases": {
"my-custom-gpt": "deepseek-v4-pro",
"experimental-claude": "deepseek-v4-flash"
}
}
This runtime merging allows hot-swapping alias definitions without service restarts.
How Alias Resolution Works
The resolution algorithm implemented in config.ResolveModel follows an eight-step precedence chain to determine the final DeepSeek model ID:
- Normalize the request string (trim whitespace, convert to lowercase)
- Reject retired historical model names via
isRetiredHistoricalModel - Return immediately if the request already matches a valid DeepSeek model
- Build lookup map starting with defaults, then overlay runtime aliases from
store.ModelAliases() - Map if valid when the request exists in the alias table and points to a supported DeepSeek model
- Validate prefix for strings starting with
"deepseek-"that weren't recognized (treat as invalid) - Heuristic resolution for unknown families based on substrings (vision, reasoning, search)
- Fallback to
"deepseek-v4-flash"for any other recognized family
The function signature in internal/config/models.go (lines 89-108) accepts a ModelAliasReader interface and the requested model string:
// internal/config/models.go
func ResolveModel(store ModelAliasReader, req string) (string, bool) {
// Normalization and lookup logic
}
Provider-Specific Integration
Each supported provider leverages the same resolution core, ensuring consistent behavior across different API endpoints.
OpenAI GPT Compatibility
When requests arrive with OpenAI-style model names like gpt-4-turbo or gpt-3.5-turbo, DS2API consults the alias table and translates these to their DeepSeek counterparts before forwarding to the inference engine. The mapping handles both current and legacy OpenAI model naming conventions.
Claude Conversion Layer
The Claude-specific handler in internal/claudeconv/convert.go explicitly calls the resolver to translate Anthropic model names:
// internal/claudeconv/convert.go
func ConvertClaudeToDeepSeek(req map[string]any, aliasProvider config.ModelAliasReader, defaultClaudeModel string) map[string]any {
model := req["model"].(string)
dsModel, ok := config.ResolveModel(aliasProvider, model)
if !ok {
// Handle resolution failure
}
// Build DeepSeek-compatible payload
out := map[string]any{
"model": dsModel,
"messages": convertedMessages,
}
return out
}
This conversion happens early in the request lifecycle, ensuring that downstream DeepSeek handling remains provider-agnostic.
Gemini Support
Gemini endpoints utilize the same ResolveModel function. When a request specifies gemini-pro or gemini-flash-latest, the resolver maps these to deepseek-v4-pro or deepseek-v4-flash respectively. The Gemini handlers require no special-case conversion logic beyond this resolution step.
Runtime Alias Management
The administrative API surface exposes endpoints for dynamic alias configuration. Handlers in internal/httpapi/admin/settings/handler_settings_*.go process JSON updates containing the "model_aliases" key:
// internal/httpapi/admin/settings/handler_settings_parse.go
func parseModelAliases(input []byte) (map[string]string, error) {
var cfg struct {
ModelAliases map[string]string `json:"model_aliases"`
}
if err := json.Unmarshal(input, &cfg); err != nil {
return nil, err
}
return cfg.ModelAliases, nil
}
Once parsed, these aliases populate the configuration store that ResolveModel queries during subsequent requests.
Custom Alias Resolution Example
To programmatically resolve a Claude model name without custom aliases:
package main
import (
"fmt"
"ds2api/internal/config"
)
func main() {
// Passing nil for store uses only default aliases
model, ok := config.ResolveModel(nil, "claude-sonnet-4-6")
if ok {
fmt.Println("Resolved to DeepSeek model:", model)
// Output: deepseek-v4-flash
}
}
When runtime aliases exist, pass the configuration store instead of nil to include custom mappings in the resolution chain.
Summary
- DS2API treats DeepSeek as the native backend but accepts OpenAI, Claude, and Gemini model names through an alias abstraction layer.
- Default mappings live in
internal/config/models.gocovering major provider model families. - Runtime overrides via
config.jsonor admin APIs allow operators to customize aliases without redeployment. - Resolution precedence follows an eight-step algorithm in
config.ResolveModel, handling normalization, validation, and fallback logic. - Provider handlers in
internal/claudeconv/convert.goand Gemini HTTP routes call the centralized resolver, keeping provider-specific code minimal.
Frequently Asked Questions
How do I add a custom model alias in DS2API?
Submit a PATCH request to the admin settings endpoint with a JSON body containing the "model_aliases" field, or define mappings in your config.json file under the ModelAliases key. The system merges these with default aliases in internal/config/models.go, with runtime values taking precedence.
What happens if I request an unsupported model name?
If config.ResolveModel cannot find the requested name in the alias table or recognize it as a valid DeepSeek model, it returns false for the second boolean parameter. The API handler typically responds with a 400 error indicating an unsupported model, unless the name matches heuristics for vision or reasoning models that trigger fallback logic.
Why does DS2API map everything to DeepSeek models instead of supporting multiple backends?
DS2API architecture standardizes on DeepSeek as the inference engine to simplify deployment and optimization. The alias system provides cross-provider compatibility for callers already integrated with OpenAI, Claude, or Gemini SDKs, allowing them to migrate to DS2API without changing their model naming conventions or request formatting.
Can I override the default OpenAI or Claude mappings?
Yes. Runtime aliases defined in config.json or via the admin API (handled in internal/httpapi/admin/settings/handler_settings_parse.go) override the default mappings from DefaultModelAliases. This allows you to redirect common model names like "gpt-4" to different DeepSeek variants or custom deployment endpoints.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →