feat: add deepseek provider

This commit is contained in:
07akioni
2026-03-16 19:52:47 +08:00
parent 64c69c3fc9
commit 570b0ea92a
14 changed files with 295 additions and 0 deletions

4
.github/labeler.yml vendored
View File

@@ -234,6 +234,10 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/byteplus/**"
"extensions: deepseek":
- changed-files:
- any-glob-to-any-file:
- "extensions/deepseek/**"
"extensions: anthropic":
- changed-files:
- any-glob-to-any-file:

View File

@@ -1106,6 +1106,7 @@
"providers/cloudflare-ai-gateway",
"providers/claude-max-api-proxy",
"providers/deepgram",
"providers/deepseek",
"providers/github-copilot",
"providers/huggingface",
"providers/kilocode",

View File

@@ -0,0 +1,63 @@
---
summary: "DeepSeek setup (auth + model selection)"
read_when:
- You want to use DeepSeek with OpenClaw
- You need the API key env var or CLI auth choice
---
# DeepSeek
[DeepSeek](https://www.deepseek.com) provides powerful AI models with an OpenAI-compatible API.
- Provider: `deepseek`
- Auth: `DEEPSEEK_API_KEY`
- API: OpenAI-compatible
## Quick start
1. Set the API key (recommended: store it for the Gateway):
```bash
openclaw setup --wizard --auth-choice deepseek-api-key
```
2. Set a default model:
```json5
{
agents: {
defaults: {
model: { primary: "deepseek/deepseek-chat" },
},
},
}
```
## Non-interactive example
```bash
openclaw setup --wizard --non-interactive \
--mode local \
--auth-choice deepseek-api-key \
--deepseek-api-key "$DEEPSEEK_API_KEY"
```
This will set `deepseek/deepseek-chat` as the default model.
## Environment note
If the Gateway runs as a daemon (launchd/systemd), make sure `DEEPSEEK_API_KEY`
is available to that process (for example, in `~/.openclaw/.env` or via
`env.shellEnv`).
## Available models
| Model ID | Name | Type | Context |
| ------------------- | ------------------------ | --------- | ------- |
| `deepseek-chat` | DeepSeek Chat (V3.2) | General | 128K |
| `deepseek-reasoner` | DeepSeek Reasoner (V3.2) | Reasoning | 128K |
- **deepseek-chat** corresponds to DeepSeek-V3.2 in non-thinking mode.
- **deepseek-reasoner** corresponds to DeepSeek-V3.2 in thinking mode with chain-of-thought reasoning.
Get your API key at [platform.deepseek.com](https://platform.deepseek.com/api_keys).

View File

@@ -0,0 +1,55 @@
import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core";
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth";
import { buildSingleProviderApiKeyCatalog } from "openclaw/plugin-sdk/provider-catalog";
import { applyDeepSeekConfig, DEEPSEEK_DEFAULT_MODEL_REF } from "./onboard.js";
import { buildDeepSeekProvider } from "./provider-catalog.js";
const PROVIDER_ID = "deepseek";
const deepseekPlugin = {
id: PROVIDER_ID,
name: "DeepSeek Provider",
description: "Bundled DeepSeek provider plugin",
configSchema: emptyPluginConfigSchema(),
register(api: OpenClawPluginApi) {
api.registerProvider({
id: PROVIDER_ID,
label: "DeepSeek",
docsPath: "/providers/deepseek",
envVars: ["DEEPSEEK_API_KEY"],
auth: [
createProviderApiKeyAuthMethod({
providerId: PROVIDER_ID,
methodId: "api-key",
label: "DeepSeek API key",
hint: "API key",
optionKey: "deepseekApiKey",
flagName: "--deepseek-api-key",
envVar: "DEEPSEEK_API_KEY",
promptMessage: "Enter DeepSeek API key",
defaultModel: DEEPSEEK_DEFAULT_MODEL_REF,
expectedProviders: ["deepseek"],
applyConfig: (cfg) => applyDeepSeekConfig(cfg),
wizard: {
choiceId: "deepseek-api-key",
choiceLabel: "DeepSeek API key",
groupId: "deepseek",
groupLabel: "DeepSeek",
groupHint: "API key",
},
}),
],
catalog: {
order: "simple",
run: (ctx) =>
buildSingleProviderApiKeyCatalog({
ctx,
providerId: PROVIDER_ID,
buildProvider: buildDeepSeekProvider,
}),
},
});
},
};
export default deepseekPlugin;

View File

@@ -0,0 +1,35 @@
import {
buildDeepSeekModelDefinition,
DEEPSEEK_BASE_URL,
DEEPSEEK_MODEL_CATALOG,
} from "openclaw/plugin-sdk/provider-models";
import {
applyAgentDefaultModelPrimary,
applyProviderConfigWithModelCatalog,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
export const DEEPSEEK_DEFAULT_MODEL_REF = "deepseek/deepseek-chat";
export function applyDeepSeekProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
const models = { ...cfg.agents?.defaults?.models };
models[DEEPSEEK_DEFAULT_MODEL_REF] = {
...models[DEEPSEEK_DEFAULT_MODEL_REF],
alias: models[DEEPSEEK_DEFAULT_MODEL_REF]?.alias ?? "DeepSeek",
};
return applyProviderConfigWithModelCatalog(cfg, {
agentModels: models,
providerId: "deepseek",
api: "openai-completions",
baseUrl: DEEPSEEK_BASE_URL,
catalogModels: DEEPSEEK_MODEL_CATALOG.map(buildDeepSeekModelDefinition),
});
}
export function applyDeepSeekConfig(cfg: OpenClawConfig): OpenClawConfig {
return applyAgentDefaultModelPrimary(
applyDeepSeekProviderConfig(cfg),
DEEPSEEK_DEFAULT_MODEL_REF,
);
}

View File

@@ -0,0 +1,27 @@
{
"id": "deepseek",
"providers": ["deepseek"],
"providerAuthEnvVars": {
"deepseek": ["DEEPSEEK_API_KEY"]
},
"providerAuthChoices": [
{
"provider": "deepseek",
"method": "api-key",
"choiceId": "deepseek-api-key",
"choiceLabel": "DeepSeek API key",
"groupId": "deepseek",
"groupLabel": "DeepSeek",
"groupHint": "API key",
"optionKey": "deepseekApiKey",
"cliFlag": "--deepseek-api-key",
"cliOption": "--deepseek-api-key <key>",
"cliDescription": "DeepSeek API key"
}
],
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {}
}
}

View File

@@ -0,0 +1,12 @@
{
"name": "@openclaw/deepseek-provider",
"version": "2026.3.14",
"private": true,
"description": "OpenClaw DeepSeek provider plugin",
"type": "module",
"openclaw": {
"extensions": [
"./index.ts"
]
}
}

View File

@@ -0,0 +1,14 @@
import {
buildDeepSeekModelDefinition,
DEEPSEEK_BASE_URL,
DEEPSEEK_MODEL_CATALOG,
type ModelProviderConfig,
} from "openclaw/plugin-sdk/provider-models";
export function buildDeepSeekProvider(): ModelProviderConfig {
return {
baseUrl: DEEPSEEK_BASE_URL,
api: "openai-completions",
models: DEEPSEEK_MODEL_CATALOG.map(buildDeepSeekModelDefinition),
};
}

View File

@@ -0,0 +1,46 @@
import type { ModelDefinitionConfig } from "../config/types.models.js";
export const DEEPSEEK_BASE_URL = "https://api.deepseek.com";
const DEEPSEEK_DEFAULT_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
};
export const DEEPSEEK_MODEL_CATALOG: ModelDefinitionConfig[] = [
{
id: "deepseek-chat",
name: "DeepSeek Chat",
reasoning: false,
input: ["text"],
contextWindow: 131072,
maxTokens: 8192,
cost: DEEPSEEK_DEFAULT_COST,
},
{
id: "deepseek-reasoner",
name: "DeepSeek Reasoner",
reasoning: true,
input: ["text"],
contextWindow: 131072,
maxTokens: 8192,
cost: DEEPSEEK_DEFAULT_COST,
},
];
export function buildDeepSeekModelDefinition(
model: (typeof DEEPSEEK_MODEL_CATALOG)[number],
): ModelDefinitionConfig {
return {
id: model.id,
name: model.name,
api: "openai-completions",
reasoning: model.reasoning,
input: model.input,
cost: model.cost,
contextWindow: model.contextWindow,
maxTokens: model.maxTokens,
};
}

View File

@@ -0,0 +1,27 @@
import { describe, expect, it } from "vitest";
import { buildDeepSeekProvider } from "./models-config.providers.static.js";
describe("DeepSeek provider", () => {
it("should build deepseek provider with correct configuration", () => {
const provider = buildDeepSeekProvider();
expect(provider.baseUrl).toBe("https://api.deepseek.com");
expect(provider.api).toBe("openai-completions");
expect(provider.models).toBeDefined();
expect(provider.models.length).toBeGreaterThan(0);
});
it("should include both deepseek-chat and deepseek-reasoner models", () => {
const provider = buildDeepSeekProvider();
const modelIds = provider.models.map((m) => m.id);
expect(modelIds).toContain("deepseek-chat");
expect(modelIds).toContain("deepseek-reasoner");
});
it("should mark deepseek-reasoner as a reasoning model", () => {
const provider = buildDeepSeekProvider();
const reasoner = provider.models.find((m) => m.id === "deepseek-reasoner");
const chat = provider.models.find((m) => m.id === "deepseek-chat");
expect(reasoner?.reasoning).toBe(true);
expect(chat?.reasoning).toBe(false);
});
});

View File

@@ -2,6 +2,7 @@ export {
buildBytePlusCodingProvider,
buildBytePlusProvider,
} from "../../extensions/byteplus/provider-catalog.js";
export { buildDeepSeekProvider } from "../../extensions/deepseek/provider-catalog.js";
export { buildKimiCodingProvider } from "../../extensions/kimi-coding/provider-catalog.js";
export { buildKilocodeProvider } from "../../extensions/kilocode/provider-catalog.js";
export {

View File

@@ -10,6 +10,7 @@ export type BuiltInAuthChoice =
| "claude-cli"
| "token"
| "chutes"
| "deepseek-api-key"
| "openai-codex"
| "openai-api-key"
| "openrouter-api-key"
@@ -58,6 +59,7 @@ export type BuiltInAuthChoiceGroupId =
| "openai"
| "anthropic"
| "chutes"
| "deepseek"
| "google"
| "copilot"
| "openrouter"
@@ -115,6 +117,7 @@ export type OnboardOptions = {
/** API key persistence mode for setup flows (default: plaintext). */
secretInputMode?: SecretInputMode;
anthropicApiKey?: string;
deepseekApiKey?: string;
openaiApiKey?: string;
mistralApiKey?: string;
openrouterApiKey?: string;

View File

@@ -41,6 +41,11 @@ export {
SYNTHETIC_DEFAULT_MODEL_REF,
SYNTHETIC_MODEL_CATALOG,
} from "../agents/synthetic-models.js";
export {
buildDeepSeekModelDefinition,
DEEPSEEK_BASE_URL,
DEEPSEEK_MODEL_CATALOG,
} from "../agents/deepseek-models.js";
export {
buildTogetherModelDefinition,
TOGETHER_BASE_URL,

View File

@@ -2,6 +2,7 @@ import ANTHROPIC_MANIFEST from "../../extensions/anthropic/openclaw.plugin.json"
import BYTEPLUS_MANIFEST from "../../extensions/byteplus/openclaw.plugin.json" with { type: "json" };
import CLOUDFLARE_AI_GATEWAY_MANIFEST from "../../extensions/cloudflare-ai-gateway/openclaw.plugin.json" with { type: "json" };
import COPILOT_PROXY_MANIFEST from "../../extensions/copilot-proxy/openclaw.plugin.json" with { type: "json" };
import DEEPSEEK_MANIFEST from "../../extensions/deepseek/openclaw.plugin.json" with { type: "json" };
import GITHUB_COPILOT_MANIFEST from "../../extensions/github-copilot/openclaw.plugin.json" with { type: "json" };
import GOOGLE_MANIFEST from "../../extensions/google/openclaw.plugin.json" with { type: "json" };
import HUGGINGFACE_MANIFEST from "../../extensions/huggingface/openclaw.plugin.json" with { type: "json" };
@@ -63,6 +64,7 @@ export const BUNDLED_PROVIDER_AUTH_ENV_VAR_CANDIDATES = collectBundledProviderAu
BYTEPLUS_MANIFEST,
CLOUDFLARE_AI_GATEWAY_MANIFEST,
COPILOT_PROXY_MANIFEST,
DEEPSEEK_MANIFEST,
GITHUB_COPILOT_MANIFEST,
GOOGLE_MANIFEST,
HUGGINGFACE_MANIFEST,