@openclaw/deepseek-provider 2026.10.10-beta.5 → 2026.11.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/.setup/{models-D843Tvyg.mjs → openclaw.plugin-CmWHGGeY.mjs} +24 -22
- package/dist/.source-module-urls/4b346188900dd8d01f5d5f8baca1f9af648850415a0a1346f45749910375d843.json +1 -0
- package/dist/api.js +1 -1
- package/dist/index.js +9 -8
- package/dist/model-credential.js +22 -0
- package/dist/models.js +17 -1
- package/dist/onboard.js +3 -3
- package/dist/provider-catalog.js +3 -4
- package/dist/provider-discovery.js +1 -2
- package/dist/provider-policy-api.js +3 -33
- package/dist/stream.js +2 -3
- package/dist/thinking.js +2 -3
- package/dist/web-search-contract-api.js +1 -0
- package/dist/web-search-provider.js +58 -0
- package/dist/web-search-provider.runtime.js +98 -0
- package/openclaw.plugin.json +36 -2
- package/package.json +4 -4
- package/dist/.source-module-urls/711aaf42931af9b0593c1c7a68146b3f73c995a5d94b804ef8cfffbf23f39d1f.json +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# OpenClaw DeepSeek Provider
|
|
2
2
|
|
|
3
|
-
Official OpenClaw provider plugin for DeepSeek.
|
|
3
|
+
Official OpenClaw provider plugin for DeepSeek models and web search.
|
|
4
|
+
|
|
5
|
+
Select `tools.web.search.provider: "deepseek"` to search with any model. Search
|
|
6
|
+
uses `DEEPSEEK_API_KEY`, a plugin search key, or the configured model-provider key
|
|
7
|
+
while that provider and its models use DeepSeek's API; see the setup documentation
|
|
8
|
+
for credential precedence and query limits.
|
|
4
9
|
|
|
5
10
|
Install from OpenClaw:
|
|
6
11
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
//#region extensions/deepseek/openclaw.plugin.json
|
|
1
|
+
// extensions/deepseek/openclaw.plugin.json
|
|
3
2
|
var openclaw_plugin_default = {
|
|
4
3
|
id: "deepseek",
|
|
5
4
|
categories: ["models"],
|
|
@@ -7,7 +6,10 @@ var openclaw_plugin_default = {
|
|
|
7
6
|
enabledByDefault: true,
|
|
8
7
|
providerCatalogEntry: "./provider-discovery.ts",
|
|
9
8
|
providers: ["deepseek"],
|
|
10
|
-
contracts: {
|
|
9
|
+
contracts: {
|
|
10
|
+
"usageProviders": ["deepseek"],
|
|
11
|
+
"webSearchProviders": ["deepseek"]
|
|
12
|
+
},
|
|
11
13
|
providerEndpoints: [{
|
|
12
14
|
"endpointClass": "deepseek-native",
|
|
13
15
|
"hosts": ["api.deepseek.com"]
|
|
@@ -19,6 +21,7 @@ var openclaw_plugin_default = {
|
|
|
19
21
|
"baseUrl": "https://api.deepseek.com",
|
|
20
22
|
"api": "openai-completions",
|
|
21
23
|
"defaultModel": "deepseek-v4-pro",
|
|
24
|
+
"family": "deepseek",
|
|
22
25
|
"models": [
|
|
23
26
|
{
|
|
24
27
|
"id": "deepseek-v4-flash",
|
|
@@ -125,23 +128,22 @@ var openclaw_plugin_default = {
|
|
|
125
128
|
configSchema: {
|
|
126
129
|
"type": "object",
|
|
127
130
|
"additionalProperties": false,
|
|
128
|
-
"properties": {
|
|
129
|
-
|
|
131
|
+
"properties": { "webSearch": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"additionalProperties": false,
|
|
134
|
+
"properties": { "apiKey": { "type": ["string", "object"] } }
|
|
135
|
+
} }
|
|
136
|
+
},
|
|
137
|
+
uiHints: { "webSearch.apiKey": {
|
|
138
|
+
"label": "DeepSeek Search API Key",
|
|
139
|
+
"help": "DeepSeek API key. Falls back to DEEPSEEK_API_KEY, then to models.providers.deepseek.apiKey while that provider and its models use https://api.deepseek.com.",
|
|
140
|
+
"sensitive": true
|
|
141
|
+
} },
|
|
142
|
+
configGroups: [{
|
|
143
|
+
"id": "web-search",
|
|
144
|
+
"title": "Web search",
|
|
145
|
+
"order": 10,
|
|
146
|
+
"properties": ["webSearch"]
|
|
147
|
+
}]
|
|
130
148
|
};
|
|
131
|
-
|
|
132
|
-
//#region extensions/deepseek/models.ts
|
|
133
|
-
const DEEPSEEK_MANIFEST_CATALOG = openclaw_plugin_default.modelCatalog.providers.deepseek;
|
|
134
|
-
const DEEPSEEK_BASE_URL = DEEPSEEK_MANIFEST_CATALOG.baseUrl;
|
|
135
|
-
const DEEPSEEK_MODEL_CATALOG = buildManifestModelProviderConfig({
|
|
136
|
-
providerId: "deepseek",
|
|
137
|
-
catalog: DEEPSEEK_MANIFEST_CATALOG
|
|
138
|
-
}).models.map((model) => Object.assign(model, { api: "openai-completions" }));
|
|
139
|
-
const DEEPSEEK_V4_MODEL_IDS = new Set(DEEPSEEK_MODEL_CATALOG.map((model) => model.id).filter((id) => id === "deepseek-flash" || id.startsWith("deepseek-v4-")));
|
|
140
|
-
function isDeepSeekV4ModelId(modelId) {
|
|
141
|
-
return DEEPSEEK_V4_MODEL_IDS.has(modelId.toLowerCase());
|
|
142
|
-
}
|
|
143
|
-
function isDeepSeekV4ModelRef(model) {
|
|
144
|
-
return model.provider === "deepseek" && typeof model.id === "string" && isDeepSeekV4ModelId(model.id);
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
147
|
-
export { openclaw_plugin_default as a, isDeepSeekV4ModelRef as i, DEEPSEEK_MODEL_CATALOG as n, isDeepSeekV4ModelId as r, DEEPSEEK_BASE_URL as t };
|
|
149
|
+
export { openclaw_plugin_default as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"entries":[{"output":"api.js","source":"extensions/deepseek/api.ts"},{"output":"index.js","source":"extensions/deepseek/index.ts"},{"output":"model-credential.js","source":"extensions/deepseek/model-credential.ts"},{"output":"models.js","source":"extensions/deepseek/models.ts"},{"output":"onboard.js","source":"extensions/deepseek/onboard.ts"},{"output":"provider-catalog.js","source":"extensions/deepseek/provider-catalog.ts"},{"output":"provider-discovery.js","source":"extensions/deepseek/provider-discovery.ts"},{"output":"provider-policy-api.js","source":"extensions/deepseek/provider-policy-api.ts"},{"output":"stream.js","source":"extensions/deepseek/stream.ts"},{"output":"thinking.js","source":"extensions/deepseek/thinking.ts"},{"output":"web-search-contract-api.js","source":"extensions/deepseek/web-search-contract-api.ts"},{"output":"web-search-provider.js","source":"extensions/deepseek/web-search-provider.ts"},{"output":"web-search-provider.runtime.js","source":"extensions/deepseek/web-search-provider.runtime.ts"}],"chunks":[{"output":".setup/openclaw.plugin-CmWHGGeY.mjs","sha256":"5d49086775c117889c0da60f93e8059571cec5502f77c5bc87b2e694ee1d6bab","facadeSource":null,"sources":["extensions/deepseek/openclaw.plugin.json"]},{"output":"api.js","sha256":"e2750717df20042eb482577777c8d2cfbf8122334b1bed3185ffa95fe09aba4d","facadeSource":"extensions/deepseek/api.ts","sources":[]},{"output":"index.js","sha256":"a51eb7227b1e7c35276afe38368edc5c588840d35029f08bfcf49b3972f8fae1","facadeSource":"extensions/deepseek/index.ts","sources":["extensions/deepseek/index.ts"]},{"output":"model-credential.js","sha256":"9200c0f610a1d388a5db5ee7fe0edf71e124b14bd3b04fa5d16fa06bda2a7cf7","facadeSource":"extensions/deepseek/model-credential.ts","sources":["extensions/deepseek/model-credential.ts"]},{"output":"models.js","sha256":"2e0735f3b071ae101a17978927ca93b48a46815d9742baac05f17a8463245ec0","facadeSource":"extensions/deepseek/models.ts","sources":["extensions/deepseek/models.ts"]},{"output":"onboard.js","sha256":"c83ac3ea1688857053f642029ef7c640a9279ea1c96fad257c4b8df35dc879fd","facadeSource":"extensions/deepseek/onboard.ts","sources":["extensions/deepseek/onboard.ts"]},{"output":"provider-catalog.js","sha256":"1f3ffb0852fe10e5a9e8a2ff3870dd5ce21f7089107274bb94c4fb50c8107a7e","facadeSource":"extensions/deepseek/provider-catalog.ts","sources":["extensions/deepseek/provider-catalog.ts"]},{"output":"provider-discovery.js","sha256":"37031a296833f55692f3513e0ca17a0f47529e1cb0f08e9a1033112447456209","facadeSource":"extensions/deepseek/provider-discovery.ts","sources":["extensions/deepseek/provider-discovery.ts"]},{"output":"provider-policy-api.js","sha256":"ea3b8633424ee63de51d1997cae90b80d5d2a6ed5ae7e33b46d8e9eb2843f7ba","facadeSource":"extensions/deepseek/provider-policy-api.ts","sources":["extensions/deepseek/provider-policy-api.ts"]},{"output":"stream.js","sha256":"3f59495c0d02b0efd82396f4d37ec114055086d33144bececbef52c5dd21cc39","facadeSource":"extensions/deepseek/stream.ts","sources":["extensions/deepseek/stream.ts"]},{"output":"thinking.js","sha256":"c2c4a0237dc245e08b6b39913b8c60487c12b2cc42c89b33e7c9981618b4d3bc","facadeSource":"extensions/deepseek/thinking.ts","sources":["extensions/deepseek/thinking.ts"]},{"output":"web-search-contract-api.js","sha256":"f774674c8df1ea6c885c38d64ed270d6c666d877b31d75c50957535f5af80455","facadeSource":"extensions/deepseek/web-search-contract-api.ts","sources":[]},{"output":"web-search-provider.js","sha256":"1006927ad948b6c3ddea34697e82e878a909ffcccd625e123d308231411128b4","facadeSource":"extensions/deepseek/web-search-provider.ts","sources":["extensions/deepseek/web-search-provider.ts"]},{"output":"web-search-provider.runtime.js","sha256":"ca516c5e0e7b1028c8f0f8b0ffba88c0fa0aed814e5c126a51f019e9c5469bf3","facadeSource":"extensions/deepseek/web-search-provider.runtime.ts","sources":["extensions/deepseek/web-search-provider.runtime.ts"]}],"unrenderedSources":["extensions/deepseek/api.ts","extensions/deepseek/web-search-contract-api.ts"]}
|
package/dist/api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEEPSEEK_BASE_URL, DEEPSEEK_MODEL_CATALOG } from "./models.js";
|
|
2
2
|
import { buildDeepSeekProvider } from "./provider-catalog.js";
|
|
3
3
|
import { createDeepSeekV4ThinkingWrapper } from "./stream.js";
|
|
4
4
|
export { DEEPSEEK_BASE_URL, DEEPSEEK_MODEL_CATALOG, buildDeepSeekProvider, createDeepSeekV4ThinkingWrapper };
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as openclaw_plugin_default } from "./.setup/openclaw.plugin-CmWHGGeY.mjs";
|
|
2
2
|
import { applyDeepSeekConfig } from "./onboard.js";
|
|
3
3
|
import { buildDeepSeekProvider } from "./provider-catalog.js";
|
|
4
4
|
import { createDeepSeekV4ThinkingWrapper } from "./stream.js";
|
|
5
5
|
import { resolveDeepSeekV4ThinkingProfile } from "./thinking.js";
|
|
6
|
+
import { createDeepSeekWebSearchProvider } from "./web-search-provider.js";
|
|
6
7
|
import { readConfiguredProviderCatalogEntries } from "openclaw/plugin-sdk/provider-catalog-shared";
|
|
7
8
|
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
|
|
8
9
|
import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared";
|
|
9
10
|
import { buildProviderToolCompatFamilyHooks } from "openclaw/plugin-sdk/provider-tools";
|
|
10
|
-
import { fetchDeepSeekUsage } from "openclaw/plugin-sdk/provider-usage";
|
|
11
|
-
|
|
11
|
+
import { fetchDeepSeekUsage, resolveProviderUsageApiKeyAuth } from "openclaw/plugin-sdk/provider-usage";
|
|
12
|
+
// extensions/deepseek/index.ts
|
|
12
13
|
const PROVIDER_ID = "deepseek";
|
|
13
14
|
var deepseek_default = defineSingleProviderPluginEntry({
|
|
14
15
|
id: PROVIDER_ID,
|
|
15
16
|
name: "DeepSeek Provider",
|
|
16
17
|
description: "Bundled DeepSeek provider plugin",
|
|
17
18
|
manifest: openclaw_plugin_default,
|
|
19
|
+
register(api) {
|
|
20
|
+
api.registerReload({ hotPrefixes: ["plugins.entries.deepseek.config.webSearch.apiKey"] });
|
|
21
|
+
api.registerWebSearchProvider(createDeepSeekWebSearchProvider());
|
|
22
|
+
},
|
|
18
23
|
provider: {
|
|
19
24
|
label: "DeepSeek",
|
|
20
25
|
docsPath: "/providers/deepseek",
|
|
@@ -38,12 +43,8 @@ var deepseek_default = defineSingleProviderPluginEntry({
|
|
|
38
43
|
wrapStreamFn: (ctx) => createDeepSeekV4ThinkingWrapper(ctx.streamFn, ctx.thinkingLevel),
|
|
39
44
|
resolveThinkingProfile: ({ modelId }) => resolveDeepSeekV4ThinkingProfile(modelId),
|
|
40
45
|
isModernModelRef: ({ modelId }) => Boolean(resolveDeepSeekV4ThinkingProfile(modelId)),
|
|
41
|
-
resolveUsageAuth:
|
|
42
|
-
const apiKey = (await ctx.resolveApiKeyCandidatesFromConfigAndStore?.({ envDirect: [ctx.env.DEEPSEEK_API_KEY] }))?.[0];
|
|
43
|
-
return apiKey ? { token: apiKey } : null;
|
|
44
|
-
},
|
|
46
|
+
resolveUsageAuth: (ctx) => resolveProviderUsageApiKeyAuth(ctx, [ctx.env.DEEPSEEK_API_KEY]),
|
|
45
47
|
fetchUsageSnapshot: async (ctx) => await fetchDeepSeekUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn)
|
|
46
48
|
}
|
|
47
49
|
});
|
|
48
|
-
//#endregion
|
|
49
50
|
export { deepseek_default as default };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { t as openclaw_plugin_default } from "./.setup/openclaw.plugin-CmWHGGeY.mjs";
|
|
2
|
+
import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
|
|
3
|
+
// extensions/deepseek/model-credential.ts
|
|
4
|
+
const DEEPSEEK_API_ORIGIN = new URL(openclaw_plugin_default.modelCatalog.providers.deepseek.baseUrl).origin;
|
|
5
|
+
function isDeepSeekApiUrl(value) {
|
|
6
|
+
const baseUrl = value?.trim();
|
|
7
|
+
if (!baseUrl) return true;
|
|
8
|
+
const url = URL.parse(baseUrl);
|
|
9
|
+
if (!url || url.protocol !== "https:" || url.username || url.password) return false;
|
|
10
|
+
url.hostname = url.hostname.replace(/\.$/, "");
|
|
11
|
+
return url.origin === DEEPSEEK_API_ORIGIN;
|
|
12
|
+
}
|
|
13
|
+
/** Raw model-provider key (SecretRefs intact) when DeepSeek search may reuse it. */
|
|
14
|
+
function resolveDeepSeekModelKeyFallback(config) {
|
|
15
|
+
const value = config?.models?.providers?.deepseek?.apiKey;
|
|
16
|
+
if (value === void 0) return;
|
|
17
|
+
return Object.entries(config?.models?.providers ?? {}).filter(([id]) => normalizeProviderId(id) === "deepseek").every(([, entry]) => isDeepSeekApiUrl(entry.baseUrl) && (entry.models ?? []).every((model) => isDeepSeekApiUrl(model.baseUrl))) ? {
|
|
18
|
+
path: "models.providers.deepseek.apiKey",
|
|
19
|
+
value
|
|
20
|
+
} : void 0;
|
|
21
|
+
}
|
|
22
|
+
export { resolveDeepSeekModelKeyFallback };
|
package/dist/models.js
CHANGED
|
@@ -1 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import { t as openclaw_plugin_default } from "./.setup/openclaw.plugin-CmWHGGeY.mjs";
|
|
2
|
+
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
|
3
|
+
// extensions/deepseek/models.ts
|
|
4
|
+
const DEEPSEEK_MANIFEST_CATALOG = openclaw_plugin_default.modelCatalog.providers.deepseek;
|
|
5
|
+
const DEEPSEEK_BASE_URL = DEEPSEEK_MANIFEST_CATALOG.baseUrl;
|
|
6
|
+
const DEEPSEEK_MODEL_CATALOG = buildManifestModelProviderConfig({
|
|
7
|
+
providerId: "deepseek",
|
|
8
|
+
catalog: DEEPSEEK_MANIFEST_CATALOG
|
|
9
|
+
}).models.map((model) => Object.assign(model, { api: "openai-completions" }));
|
|
10
|
+
const DEEPSEEK_V4_MODEL_IDS = new Set(DEEPSEEK_MODEL_CATALOG.map((model) => model.id).filter((id) => id === "deepseek-flash" || id.startsWith("deepseek-v4-")));
|
|
11
|
+
function isDeepSeekV4ModelId(modelId) {
|
|
12
|
+
return DEEPSEEK_V4_MODEL_IDS.has(modelId.toLowerCase());
|
|
13
|
+
}
|
|
14
|
+
function isDeepSeekV4ModelRef(model) {
|
|
15
|
+
return model.provider === "deepseek" && isDeepSeekV4ModelId(model.id);
|
|
16
|
+
}
|
|
17
|
+
export { DEEPSEEK_BASE_URL, DEEPSEEK_MODEL_CATALOG, isDeepSeekV4ModelId, isDeepSeekV4ModelRef };
|
package/dist/onboard.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as openclaw_plugin_default } from "./.setup/openclaw.plugin-CmWHGGeY.mjs";
|
|
2
|
+
import { DEEPSEEK_BASE_URL, DEEPSEEK_MODEL_CATALOG } from "./models.js";
|
|
2
3
|
import { readManifestProviderDefaultModelRef } from "openclaw/plugin-sdk/provider-catalog-shared";
|
|
3
4
|
import { createProviderConnectionPresetAppliers } from "openclaw/plugin-sdk/provider-onboard";
|
|
4
|
-
|
|
5
|
+
// extensions/deepseek/onboard.ts
|
|
5
6
|
const DEEPSEEK_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(openclaw_plugin_default, "deepseek");
|
|
6
7
|
const { applyConfig: applyDeepSeekConfig } = createProviderConnectionPresetAppliers({
|
|
7
8
|
primaryModelRef: DEEPSEEK_DEFAULT_MODEL_REF,
|
|
@@ -16,5 +17,4 @@ const { applyConfig: applyDeepSeekConfig } = createProviderConnectionPresetAppli
|
|
|
16
17
|
}]
|
|
17
18
|
})
|
|
18
19
|
});
|
|
19
|
-
//#endregion
|
|
20
20
|
export { applyDeepSeekConfig };
|
package/dist/provider-catalog.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { DEEPSEEK_BASE_URL, DEEPSEEK_MODEL_CATALOG } from "./models.js";
|
|
2
|
+
// extensions/deepseek/provider-catalog.ts
|
|
3
3
|
function buildDeepSeekProvider() {
|
|
4
4
|
return {
|
|
5
5
|
baseUrl: DEEPSEEK_BASE_URL,
|
|
6
6
|
api: "openai-completions",
|
|
7
|
-
models:
|
|
7
|
+
models: DEEPSEEK_MODEL_CATALOG
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
|
-
//#endregion
|
|
11
10
|
export { buildDeepSeekProvider };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildDeepSeekProvider } from "./provider-catalog.js";
|
|
2
|
-
|
|
2
|
+
// extensions/deepseek/provider-discovery.ts
|
|
3
3
|
const deepSeekProviderDiscovery = {
|
|
4
4
|
id: "deepseek",
|
|
5
5
|
label: "DeepSeek",
|
|
@@ -10,5 +10,4 @@ const deepSeekProviderDiscovery = {
|
|
|
10
10
|
run: async () => ({ provider: buildDeepSeekProvider() })
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
|
-
//#endregion
|
|
14
13
|
export { deepSeekProviderDiscovery as default };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEEPSEEK_MODEL_CATALOG } from "./models.js";
|
|
2
2
|
import { resolveDeepSeekV4ThinkingProfile } from "./thinking.js";
|
|
3
|
-
|
|
3
|
+
// extensions/deepseek/provider-policy-api.ts
|
|
4
4
|
const PREVIOUS_BUNDLED_METADATA = {
|
|
5
5
|
"deepseek-v4-flash": {
|
|
6
6
|
contextWindow: 1e6,
|
|
@@ -21,34 +21,8 @@ const PREVIOUS_BUNDLED_METADATA = {
|
|
|
21
21
|
cacheRead: .145,
|
|
22
22
|
cacheWrite: 0
|
|
23
23
|
}
|
|
24
|
-
},
|
|
25
|
-
"deepseek-chat": {
|
|
26
|
-
contextWindow: 131072,
|
|
27
|
-
maxTokens: 8192,
|
|
28
|
-
cost: {
|
|
29
|
-
input: .28,
|
|
30
|
-
output: .42,
|
|
31
|
-
cacheRead: .028,
|
|
32
|
-
cacheWrite: 0
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
"deepseek-reasoner": {
|
|
36
|
-
contextWindow: 131072,
|
|
37
|
-
maxTokens: 65536,
|
|
38
|
-
cost: {
|
|
39
|
-
input: .28,
|
|
40
|
-
output: .42,
|
|
41
|
-
cacheRead: .028,
|
|
42
|
-
cacheWrite: 0
|
|
43
|
-
}
|
|
44
24
|
}
|
|
45
25
|
};
|
|
46
|
-
const ZERO_COST = {
|
|
47
|
-
input: 0,
|
|
48
|
-
output: 0,
|
|
49
|
-
cacheRead: 0,
|
|
50
|
-
cacheWrite: 0
|
|
51
|
-
};
|
|
52
26
|
function isPositiveNumber(value) {
|
|
53
27
|
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
54
28
|
}
|
|
@@ -63,12 +37,9 @@ function hasSameCost(left, right) {
|
|
|
63
37
|
if (Object.hasOwn(cost, "tieredPricing")) return false;
|
|
64
38
|
return cost.input === right.input && cost.output === right.output && cost.cacheRead === right.cacheRead && cost.cacheWrite === right.cacheWrite;
|
|
65
39
|
}
|
|
66
|
-
function isShippedZeroCostAliasSnapshot(raw, previous) {
|
|
67
|
-
return (raw.id === "deepseek-chat" || raw.id === "deepseek-reasoner") && raw.contextWindow === previous?.contextWindow && raw.maxTokens === previous?.maxTokens && hasSameCost(raw.cost, ZERO_COST);
|
|
68
|
-
}
|
|
69
40
|
function isPreviousBundledMetadataSnapshot(raw, previous) {
|
|
70
41
|
if (!previous) return false;
|
|
71
|
-
return raw.contextWindow === previous.contextWindow && raw.maxTokens === previous.maxTokens &&
|
|
42
|
+
return raw.contextWindow === previous.contextWindow && raw.maxTokens === previous.maxTokens && hasSameCost(raw.cost, previous.cost);
|
|
72
43
|
}
|
|
73
44
|
/**
|
|
74
45
|
* Provider policy surface for DeepSeek.
|
|
@@ -104,5 +75,4 @@ function normalizeConfig(params) {
|
|
|
104
75
|
function resolveThinkingProfile(params) {
|
|
105
76
|
return params.provider.trim().toLowerCase() === "deepseek" ? resolveDeepSeekV4ThinkingProfile(params.modelId) : null;
|
|
106
77
|
}
|
|
107
|
-
//#endregion
|
|
108
78
|
export { normalizeConfig, resolveThinkingProfile };
|
package/dist/stream.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isDeepSeekV4ModelRef } from "./models.js";
|
|
2
2
|
import { createDeepSeekV4OpenAICompatibleThinkingWrapper } from "openclaw/plugin-sdk/provider-stream-shared";
|
|
3
|
-
|
|
3
|
+
// extensions/deepseek/stream.ts
|
|
4
4
|
function createDeepSeekV4ThinkingWrapper(baseStreamFn, thinkingLevel) {
|
|
5
5
|
return createDeepSeekV4OpenAICompatibleThinkingWrapper({
|
|
6
6
|
baseStreamFn,
|
|
@@ -8,5 +8,4 @@ function createDeepSeekV4ThinkingWrapper(baseStreamFn, thinkingLevel) {
|
|
|
8
8
|
shouldPatchModel: isDeepSeekV4ModelRef
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
|
-
//#endregion
|
|
12
11
|
export { createDeepSeekV4ThinkingWrapper };
|
package/dist/thinking.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { isDeepSeekV4ModelId } from "./models.js";
|
|
2
|
+
// extensions/deepseek/thinking.ts
|
|
3
3
|
const DEEPSEEK_V4_THINKING_PROFILE = {
|
|
4
4
|
levels: [
|
|
5
5
|
"off",
|
|
@@ -15,5 +15,4 @@ const DEEPSEEK_V4_THINKING_PROFILE = {
|
|
|
15
15
|
function resolveDeepSeekV4ThinkingProfile(modelId) {
|
|
16
16
|
return isDeepSeekV4ModelId(modelId) ? DEEPSEEK_V4_THINKING_PROFILE : void 0;
|
|
17
17
|
}
|
|
18
|
-
//#endregion
|
|
19
18
|
export { resolveDeepSeekV4ThinkingProfile };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createDeepSeekWebSearchProvider } from "./web-search-provider.js";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { resolveDeepSeekModelKeyFallback } from "./model-credential.js";
|
|
2
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
3
|
+
import { createWebSearchProviderContractFields } from "openclaw/plugin-sdk/provider-web-search-contract";
|
|
4
|
+
// extensions/deepseek/web-search-provider.ts
|
|
5
|
+
const CREDENTIAL_PATH = "plugins.entries.deepseek.config.webSearch.apiKey";
|
|
6
|
+
const loadRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime.js"));
|
|
7
|
+
function createDeepSeekWebSearchProvider() {
|
|
8
|
+
return {
|
|
9
|
+
id: "deepseek",
|
|
10
|
+
label: "DeepSeek",
|
|
11
|
+
hint: "Structured search results from DeepSeek's search engine",
|
|
12
|
+
onboardingScopes: ["text-inference"],
|
|
13
|
+
credentialLabel: "DeepSeek API key",
|
|
14
|
+
envVars: ["DEEPSEEK_API_KEY"],
|
|
15
|
+
placeholder: "sk-...",
|
|
16
|
+
signupUrl: "https://platform.deepseek.com/api_keys",
|
|
17
|
+
docsUrl: "https://docs.openclaw.ai/providers/deepseek#web-search",
|
|
18
|
+
autoDetectOrder: 80,
|
|
19
|
+
credentialPath: CREDENTIAL_PATH,
|
|
20
|
+
...createWebSearchProviderContractFields({
|
|
21
|
+
credentialPath: CREDENTIAL_PATH,
|
|
22
|
+
searchCredential: {
|
|
23
|
+
type: "scoped",
|
|
24
|
+
scopeId: "deepseek"
|
|
25
|
+
},
|
|
26
|
+
configuredCredential: { pluginId: "deepseek" },
|
|
27
|
+
selectionPluginId: "deepseek"
|
|
28
|
+
}),
|
|
29
|
+
getConfiguredCredentialFallback: resolveDeepSeekModelKeyFallback,
|
|
30
|
+
createTool: (ctx) => ({
|
|
31
|
+
description: "Search the web using DeepSeek. Returns titles, URLs, and model-oriented summaries. Queries support site:, -site:, lang:, after:, before:, and quoted phrases; maximum 128 Unicode characters.",
|
|
32
|
+
parameters: {
|
|
33
|
+
type: "object",
|
|
34
|
+
required: ["query"],
|
|
35
|
+
properties: {
|
|
36
|
+
query: {
|
|
37
|
+
type: "string",
|
|
38
|
+
minLength: 1,
|
|
39
|
+
maxLength: 128,
|
|
40
|
+
description: "Search query, including any search operators."
|
|
41
|
+
},
|
|
42
|
+
count: {
|
|
43
|
+
type: "integer",
|
|
44
|
+
minimum: 1,
|
|
45
|
+
maximum: 10,
|
|
46
|
+
description: "Number of results (1-10; default 5)."
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
execute: async (args, context) => {
|
|
51
|
+
context?.signal?.throwIfAborted();
|
|
52
|
+
const { executeDeepSeekSearch } = await loadRuntime();
|
|
53
|
+
return executeDeepSeekSearch(ctx, args, context?.signal);
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export { createDeepSeekWebSearchProvider };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { resolveDeepSeekModelKeyFallback } from "./model-credential.js";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { readProviderJsonObjectResponse } from "openclaw/plugin-sdk/provider-http";
|
|
4
|
+
import { DEFAULT_SEARCH_COUNT, MAX_SEARCH_COUNT, buildSearchCacheKey, mergeScopedSearchConfig, postTrustedWebToolsJson, readCachedSearchPayload, readConfiguredSecretString, readPositiveIntegerParam, readProviderEnvValue, readStringParam, resolveProviderWebSearchPluginConfig, resolveSearchCacheTtlMs, resolveSearchCount, resolveSearchTimeoutSeconds, writeCachedSearchPayload } from "openclaw/plugin-sdk/provider-web-search";
|
|
5
|
+
import { asNonArrayRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
|
+
// extensions/deepseek/web-search-provider.runtime.ts
|
|
7
|
+
const SEARCH_URL = "https://api.deepseek.com/v1/tools/search";
|
|
8
|
+
async function executeDeepSeekSearch(ctx, args, signal) {
|
|
9
|
+
signal?.throwIfAborted();
|
|
10
|
+
const query = readStringParam(args, "query", { required: true });
|
|
11
|
+
if (Array.from(query).length > 128) return {
|
|
12
|
+
error: "invalid_query",
|
|
13
|
+
message: "DeepSeek search queries must contain 1 to 128 Unicode characters. Shorten the query; it has not been sent."
|
|
14
|
+
};
|
|
15
|
+
const unsupported = [
|
|
16
|
+
"country",
|
|
17
|
+
"language",
|
|
18
|
+
"freshness",
|
|
19
|
+
"date_after",
|
|
20
|
+
"date_before",
|
|
21
|
+
"search_lang",
|
|
22
|
+
"ui_lang",
|
|
23
|
+
"domain_filter",
|
|
24
|
+
"max_tokens",
|
|
25
|
+
"max_tokens_per_page"
|
|
26
|
+
].find((key) => args[key] !== void 0);
|
|
27
|
+
if (unsupported) return {
|
|
28
|
+
error: "unsupported_filter",
|
|
29
|
+
message: `DeepSeek does not support the ${unsupported} parameter. Put site:, -site:, lang:, after:, or before: operators directly in query instead.`
|
|
30
|
+
};
|
|
31
|
+
const searchConfig = mergeScopedSearchConfig(ctx.searchConfig, "deepseek", resolveProviderWebSearchPluginConfig(ctx.config, "deepseek"));
|
|
32
|
+
const deepseek = asNonArrayRecord(searchConfig?.deepseek);
|
|
33
|
+
const modelKey = resolveDeepSeekModelKeyFallback(ctx.config);
|
|
34
|
+
const apiKey = readConfiguredSecretString(deepseek.apiKey, "plugins.entries.deepseek.config.webSearch.apiKey") ?? readProviderEnvValue(["DEEPSEEK_API_KEY"]) ?? (modelKey ? readConfiguredSecretString(modelKey.value, modelKey.path) : void 0);
|
|
35
|
+
if (!apiKey) return {
|
|
36
|
+
error: "missing_deepseek_api_key",
|
|
37
|
+
message: "web_search (deepseek) needs a DeepSeek API key. Configure plugins.entries.deepseek.config.webSearch.apiKey or set DEEPSEEK_API_KEY; for chat, DEEPSEEK_API_KEY outranks models.providers.deepseek.apiKey unless models.providers.deepseek.auth is \"api-key\". models.providers.deepseek.apiKey is reused only while that provider and its models use https://api.deepseek.com. Use web_fetch for a specific URL if you do not want to configure search.",
|
|
38
|
+
docs: "https://docs.openclaw.ai/providers/deepseek#web-search"
|
|
39
|
+
};
|
|
40
|
+
const count = resolveSearchCount(readPositiveIntegerParam(args, "count", {
|
|
41
|
+
max: MAX_SEARCH_COUNT,
|
|
42
|
+
message: "count must be an integer from 1 to 10."
|
|
43
|
+
}) ?? searchConfig?.maxResults, DEFAULT_SEARCH_COUNT);
|
|
44
|
+
const credentialScope = createHash("sha256").update(apiKey).digest("hex");
|
|
45
|
+
const cacheKey = buildSearchCacheKey(["deepseek", JSON.stringify([
|
|
46
|
+
query,
|
|
47
|
+
count,
|
|
48
|
+
credentialScope
|
|
49
|
+
])]);
|
|
50
|
+
const ttlMs = resolveSearchCacheTtlMs(searchConfig);
|
|
51
|
+
const cached = readCachedSearchPayload(cacheKey, ttlMs);
|
|
52
|
+
if (cached) return cached;
|
|
53
|
+
const start = Date.now();
|
|
54
|
+
let omittedResults = false;
|
|
55
|
+
const results = await postTrustedWebToolsJson({
|
|
56
|
+
url: SEARCH_URL,
|
|
57
|
+
apiKey,
|
|
58
|
+
timeoutSeconds: resolveSearchTimeoutSeconds(searchConfig),
|
|
59
|
+
signal,
|
|
60
|
+
body: {
|
|
61
|
+
query,
|
|
62
|
+
count,
|
|
63
|
+
need_content: false
|
|
64
|
+
},
|
|
65
|
+
errorLabel: "DeepSeek"
|
|
66
|
+
}, async (response) => {
|
|
67
|
+
const data = await readProviderJsonObjectResponse(response, "DeepSeek API error");
|
|
68
|
+
if (!Array.isArray(data.results)) throw new Error("DeepSeek API error: malformed JSON response");
|
|
69
|
+
return data.results.slice(0, count).flatMap((entry) => {
|
|
70
|
+
const result = asNonArrayRecord(entry);
|
|
71
|
+
const url = normalizeOptionalString(result.url);
|
|
72
|
+
const parsed = url && url.length <= 2048 ? URL.parse(url) : null;
|
|
73
|
+
if (!parsed || !["http:", "https:"].includes(parsed.protocol) || parsed.href.length > 2048) {
|
|
74
|
+
omittedResults = true;
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
return [{
|
|
78
|
+
title: normalizeOptionalString(result.title) ?? "",
|
|
79
|
+
url: parsed.href,
|
|
80
|
+
snippet: normalizeOptionalString(result.summary) ?? normalizeOptionalString(result.snippet),
|
|
81
|
+
published: normalizeOptionalString(result.date),
|
|
82
|
+
siteName: normalizeOptionalString(result.site_name)
|
|
83
|
+
}];
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
signal?.throwIfAborted();
|
|
87
|
+
const payload = {
|
|
88
|
+
query,
|
|
89
|
+
provider: "deepseek",
|
|
90
|
+
count: results.length,
|
|
91
|
+
results,
|
|
92
|
+
tookMs: Date.now() - start,
|
|
93
|
+
...omittedResults ? { truncated: true } : {}
|
|
94
|
+
};
|
|
95
|
+
writeCachedSearchPayload(cacheKey, payload, ttlMs);
|
|
96
|
+
return payload;
|
|
97
|
+
}
|
|
98
|
+
export { executeDeepSeekSearch };
|
package/openclaw.plugin.json
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"contracts": {
|
|
15
15
|
"usageProviders": [
|
|
16
16
|
"deepseek"
|
|
17
|
+
],
|
|
18
|
+
"webSearchProviders": [
|
|
19
|
+
"deepseek"
|
|
17
20
|
]
|
|
18
21
|
},
|
|
19
22
|
"providerEndpoints": [
|
|
@@ -40,6 +43,7 @@
|
|
|
40
43
|
"baseUrl": "https://api.deepseek.com",
|
|
41
44
|
"api": "openai-completions",
|
|
42
45
|
"defaultModel": "deepseek-v4-pro",
|
|
46
|
+
"family": "deepseek",
|
|
43
47
|
"models": [
|
|
44
48
|
{
|
|
45
49
|
"id": "deepseek-v4-flash",
|
|
@@ -167,6 +171,36 @@
|
|
|
167
171
|
"configSchema": {
|
|
168
172
|
"type": "object",
|
|
169
173
|
"additionalProperties": false,
|
|
170
|
-
"properties": {
|
|
171
|
-
|
|
174
|
+
"properties": {
|
|
175
|
+
"webSearch": {
|
|
176
|
+
"type": "object",
|
|
177
|
+
"additionalProperties": false,
|
|
178
|
+
"properties": {
|
|
179
|
+
"apiKey": {
|
|
180
|
+
"type": [
|
|
181
|
+
"string",
|
|
182
|
+
"object"
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"uiHints": {
|
|
190
|
+
"webSearch.apiKey": {
|
|
191
|
+
"label": "DeepSeek Search API Key",
|
|
192
|
+
"help": "DeepSeek API key. Falls back to DEEPSEEK_API_KEY, then to models.providers.deepseek.apiKey while that provider and its models use https://api.deepseek.com.",
|
|
193
|
+
"sensitive": true
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"configGroups": [
|
|
197
|
+
{
|
|
198
|
+
"id": "web-search",
|
|
199
|
+
"title": "Web search",
|
|
200
|
+
"order": 10,
|
|
201
|
+
"properties": [
|
|
202
|
+
"webSearch"
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
]
|
|
172
206
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/deepseek-provider",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.11.5-beta.1",
|
|
4
4
|
"description": "OpenClaw DeepSeek provider plugin.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"minHostVersion": ">=2026.6.8"
|
|
19
19
|
},
|
|
20
20
|
"compat": {
|
|
21
|
-
"pluginApi": ">=2026.
|
|
21
|
+
"pluginApi": ">=2026.11.5-beta.1"
|
|
22
22
|
},
|
|
23
23
|
"build": {
|
|
24
|
-
"openclawVersion": "2026.
|
|
24
|
+
"openclawVersion": "2026.11.5-beta.1",
|
|
25
25
|
"bundledDist": false
|
|
26
26
|
},
|
|
27
27
|
"release": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"assets/activity.svg"
|
|
41
41
|
],
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"openclaw": ">=2026.
|
|
43
|
+
"openclaw": ">=2026.11.5-beta.1"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"openclaw": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"entries":[{"output":"api.js","source":"extensions/deepseek/api.ts"},{"output":"index.js","source":"extensions/deepseek/index.ts"},{"output":"models.js","source":"extensions/deepseek/models.ts"},{"output":"onboard.js","source":"extensions/deepseek/onboard.ts"},{"output":"provider-catalog.js","source":"extensions/deepseek/provider-catalog.ts"},{"output":"provider-discovery.js","source":"extensions/deepseek/provider-discovery.ts"},{"output":"provider-policy-api.js","source":"extensions/deepseek/provider-policy-api.ts"},{"output":"stream.js","source":"extensions/deepseek/stream.ts"},{"output":"thinking.js","source":"extensions/deepseek/thinking.ts"}],"chunks":[{"output":".setup/models-D843Tvyg.mjs","sha256":"d5b24405ea7091d1fa59357cdce41dfd848289e65f14bb94de2b9ffac5d68f83","facadeSource":null,"sources":["extensions/deepseek/models.ts","extensions/deepseek/openclaw.plugin.json"]},{"output":"api.js","sha256":"c366bae61e81cf65942f8dce7aff9fb544a8ecbea3472c344645b5357a498373","facadeSource":"extensions/deepseek/api.ts","sources":[]},{"output":"index.js","sha256":"ccbd617a48cd055dfe5ae365c45059ca76842dc292c09138d29257bc024dcfef","facadeSource":"extensions/deepseek/index.ts","sources":["extensions/deepseek/index.ts"]},{"output":"models.js","sha256":"cca4a1e221c85a76e59c94a0c8169f24c45269c45203ab9192c8d93a9633b06e","facadeSource":"extensions/deepseek/models.ts","sources":[]},{"output":"onboard.js","sha256":"c2ae5b3ad3b1238cbcdc532aadb80232e98b756694592229272dcd2fb7a1c22f","facadeSource":"extensions/deepseek/onboard.ts","sources":["extensions/deepseek/onboard.ts"]},{"output":"provider-catalog.js","sha256":"da71b33a1eac62d9ab3699ec3412dee16759597e997ddd589fe241441dbb8b26","facadeSource":"extensions/deepseek/provider-catalog.ts","sources":["extensions/deepseek/provider-catalog.ts"]},{"output":"provider-discovery.js","sha256":"b92bb7dbb5768d5bbb65aa5c699573615f8da532e51229175f6eb921c3e8c010","facadeSource":"extensions/deepseek/provider-discovery.ts","sources":["extensions/deepseek/provider-discovery.ts"]},{"output":"provider-policy-api.js","sha256":"2c285c22023e46d95efd367d06215189a130f67b9e89c9fd678f9cf8afd58b84","facadeSource":"extensions/deepseek/provider-policy-api.ts","sources":["extensions/deepseek/provider-policy-api.ts"]},{"output":"stream.js","sha256":"875ec93067872ae4c08dffe061628b70c0425d71f6af51db4a592dfc1924ef67","facadeSource":"extensions/deepseek/stream.ts","sources":["extensions/deepseek/stream.ts"]},{"output":"thinking.js","sha256":"f8cf8a8e19e51a51330b38eb773db7ac8deb7493fdbb3cd4da7016f6672f81f5","facadeSource":"extensions/deepseek/thinking.ts","sources":["extensions/deepseek/thinking.ts"]}],"unrenderedSources":["extensions/deepseek/api.ts"]}
|