@warlock.js/ai-deepseek 5.29.0 → 5.31.0
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/CHANGELOG.md +25 -0
- package/README.md +13 -13
- package/cjs/index.cjs +53 -20
- package/cjs/index.cjs.map +1 -1
- package/esm/config.type.d.mts +1 -1
- package/esm/config.type.d.mts.map +1 -1
- package/esm/index.d.mts +2 -2
- package/esm/index.mjs +2 -2
- package/esm/known-models.d.mts +1 -1
- package/esm/known-models.d.mts.map +1 -1
- package/esm/known-models.mjs +1 -1
- package/esm/known-models.mjs.map +1 -1
- package/esm/sdk.d.mts +31 -3
- package/esm/sdk.d.mts.map +1 -1
- package/esm/sdk.mjs +51 -20
- package/esm/sdk.mjs.map +1 -1
- package/llms-full.txt +61 -27
- package/llms.txt +1 -1
- package/package.json +6 -5
- package/skills/setup-deepseek/SKILL.md +61 -27
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,30 @@ All notable changes to `@warlock.js/ai-deepseek` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
6
|
|
|
7
|
+
## 5.31.0 - 2026-10-18
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- An adapter contract test verifies that aborting `signal` rejects `complete()` and `stream()` on the model and cancels the HTTP request.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Chat calls inherit `providerOptions.openai.body` from the OpenAI adapter, including its protected fields and one-level plain-object merge. Use only this provider's accepted fields when sharing fallback options. Native `countTokens` remains absent; `sdk.count(text)` is an offline estimate.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- `DEEPSEEK_DEFAULT_PRICING` (now exported) matches DeepSeek's price list (2026-10-17) for `deepseek-flash`, `deepseek-v4-flash` and `deepseek-v4-pro`. DeepSeek bills by time of day; the defaults are the peak rates, an upper bound, and `DEEPSEEK_OFF_PEAK_PRICING` holds the off-peak rates.
|
|
20
|
+
|
|
21
|
+
### Upgrading
|
|
22
|
+
|
|
23
|
+
- **BREAKING** `deepseek-chat` and `deepseek-reasoner` (discontinued by DeepSeek) no longer have built-in prices, so a USD budget on them rejects the run as unpriced. Reported costs for the remaining models rise to the peak rates; pass `pricing: DEEPSEEK_OFF_PEAK_PRICING` when you run off-peak.
|
|
24
|
+
|
|
25
|
+
## 5.30.0 - 2026-10-16
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- Lockstep release; package APIs are unchanged.
|
|
30
|
+
|
|
7
31
|
## 5.29.0 - 2026-10-01
|
|
8
32
|
|
|
9
33
|
### Changed
|
|
@@ -75,6 +99,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
75
99
|
### Changed
|
|
76
100
|
|
|
77
101
|
- Lockstep release maintenance and dependency refresh.
|
|
102
|
+
|
|
78
103
|
## 5.20.0 - 2026-09-24
|
|
79
104
|
|
|
80
105
|
### Changed
|
package/README.md
CHANGED
|
@@ -51,12 +51,12 @@ DeepSeekModelConfig {
|
|
|
51
51
|
|
|
52
52
|
## Models
|
|
53
53
|
|
|
54
|
-
| Model | Notes
|
|
55
|
-
| ------------------- |
|
|
56
|
-
| `deepseek-chat` | Non-thinking surface (V3 lineage). Fast, cheap. Reasoning **off**.
|
|
54
|
+
| Model | Notes |
|
|
55
|
+
| ------------------- | --------------------------------------------------------------------------- |
|
|
56
|
+
| `deepseek-chat` | Non-thinking surface (V3 lineage). Fast, cheap. Reasoning **off**. |
|
|
57
57
|
| `deepseek-reasoner` | Thinking surface (R1 lineage). Emits a reasoning channel. Reasoning **on**. |
|
|
58
|
-
| `deepseek-v4-flash` | Newer flash tier. Reasoning **off** by default.
|
|
59
|
-
| `deepseek-v4-pro` | Newer quality tier. Reasoning **on** by default.
|
|
58
|
+
| `deepseek-v4-flash` | Newer flash tier. Reasoning **off** by default. |
|
|
59
|
+
| `deepseek-v4-pro` | Newer quality tier. Reasoning **on** by default. |
|
|
60
60
|
|
|
61
61
|
DeepSeek announced the legacy `deepseek-chat` / `deepseek-reasoner` names retire 2026/07/24 in favor of the `deepseek-v4-*` family; both name sets are understood by the capability inference. `deepseek.model({ name })` accepts any id the upstream serves. `DEEPSEEK_CHAT_MODELS` exports the informational list.
|
|
62
62
|
|
|
@@ -64,23 +64,23 @@ DeepSeek announced the legacy `deepseek-chat` / `deepseek-reasoner` names retire
|
|
|
64
64
|
|
|
65
65
|
Capabilities are inferred from the DeepSeek model **name** (via `inferReasoningCapability` / `inferVisionCapability`) and injected as explicit flags before delegating — an explicit value always wins.
|
|
66
66
|
|
|
67
|
-
| Capability | Default
|
|
68
|
-
| ------------------ |
|
|
69
|
-
| `reasoning` | `true` for `deepseek-reasoner` and the `*-pro` tier; `false` for `deepseek-chat` / `*-flash`.
|
|
70
|
-
| `vision` | `false` for every DeepSeek model — no chat model documents image input (mid-2026).
|
|
67
|
+
| Capability | Default |
|
|
68
|
+
| ------------------ | ---------------------------------------------------------------------------------------------- |
|
|
69
|
+
| `reasoning` | `true` for `deepseek-reasoner` and the `*-pro` tier; `false` for `deepseek-chat` / `*-flash`. |
|
|
70
|
+
| `vision` | `false` for every DeepSeek model — no chat model documents image input (mid-2026). |
|
|
71
71
|
| `structuredOutput` | `true` (inherited from the wrapped OpenAI model), unless `responseFormat` forces a loose mode. |
|
|
72
|
-
| `promptCaching` | `true` (inherited). DeepSeek reports cache hits via `usage.cachedTokens`.
|
|
72
|
+
| `promptCaching` | `true` (inherited). DeepSeek reports cache hits via `usage.cachedTokens`. |
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
|
-
deepseek.model({ name: "deepseek-chat", reasoning: true });
|
|
75
|
+
deepseek.model({ name: "deepseek-chat", reasoning: true }); // force the thinking flag
|
|
76
76
|
deepseek.model({ name: "deepseek-reasoner", reasoning: false }); // suppress it
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
## Reasoning effort
|
|
80
80
|
|
|
81
81
|
```ts
|
|
82
|
-
const model = deepseek.model({ name: "deepseek-reasoner" });
|
|
83
|
-
await model.complete(messages, { reasoning: { effort: "high" } });
|
|
82
|
+
const model = deepseek.model({ name: "deepseek-reasoner" }); // reasoning auto-true
|
|
83
|
+
await model.complete(messages, { reasoning: { effort: "high" } }); // → reasoning_effort: "high"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
`reasoning.effort` maps to the OpenAI-compatible `reasoning_effort` param and is dropped for a non-reasoning model.
|
package/cjs/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
let _warlock_js_ai_openai = require("@warlock.js/ai-openai");
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/ai-deepseek/src/known-models.ts
|
|
5
5
|
/**
|
|
6
6
|
* Capability inference for DeepSeek chat model ids.
|
|
7
7
|
*
|
|
@@ -100,7 +100,7 @@ function inferVisionCapability(modelId) {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
//#endregion
|
|
103
|
-
//#region
|
|
103
|
+
//#region ../../packages/ai-deepseek/src/sdk.ts
|
|
104
104
|
/**
|
|
105
105
|
* DeepSeek's OpenAI-compatible Chat Completions endpoint. Verified against
|
|
106
106
|
* the official API docs (api-docs.deepseek.com, mid-2026).
|
|
@@ -110,31 +110,62 @@ const DEEPSEEK_BASE_URL = "https://api.deepseek.com";
|
|
|
110
110
|
const DEEPSEEK_PROVIDER = "deepseek";
|
|
111
111
|
/**
|
|
112
112
|
* Built-in DeepSeek pricing defaults, in USD per 1,000,000 tokens, keyed
|
|
113
|
-
* by model name
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
113
|
+
* by model name; `cachedInput` is the cache-hit input rate.
|
|
114
|
+
*
|
|
115
|
+
* Source: https://api-docs.deepseek.com/quick_start/pricing, fetched
|
|
116
|
+
* 2026-10-17. DeepSeek bills by time of day: peak hours (01:00–04:00 and
|
|
117
|
+
* 06:00–10:00 UTC, Monday to Friday) cost twice the off-peak rate. A flat
|
|
118
|
+
* `ModelPricing` cannot follow the clock, so these are the **peak** rates —
|
|
119
|
+
* an upper bound that keeps USD budgets safe; off-peak calls really cost
|
|
120
|
+
* half. Pass {@link DEEPSEEK_OFF_PEAK_PRICING} (or your own) as `pricing`
|
|
121
|
+
* when you know you run off-peak.
|
|
122
|
+
*
|
|
123
|
+
* `deepseek-v4-flash` is the legacy name of `deepseek-flash` and bills at
|
|
124
|
+
* the same rate. `deepseek-chat` / `deepseek-reasoner` are gone from the
|
|
125
|
+
* price list (discontinued 2026-07-24) and stay unpriced.
|
|
126
|
+
*
|
|
127
|
+
* A caller-supplied SDK `pricing` registry, or a per-model `pricing`,
|
|
128
|
+
* overrides any entry here.
|
|
117
129
|
*/
|
|
118
130
|
const DEEPSEEK_DEFAULT_PRICING = {
|
|
119
|
-
"deepseek-
|
|
120
|
-
input: .
|
|
121
|
-
output: .
|
|
122
|
-
cachedInput: .
|
|
131
|
+
"deepseek-flash": {
|
|
132
|
+
input: .3,
|
|
133
|
+
output: 1.2,
|
|
134
|
+
cachedInput: .006
|
|
123
135
|
},
|
|
124
|
-
"deepseek-
|
|
125
|
-
input: .
|
|
126
|
-
output: .
|
|
127
|
-
cachedInput: .
|
|
136
|
+
"deepseek-v4-flash": {
|
|
137
|
+
input: .3,
|
|
138
|
+
output: 1.2,
|
|
139
|
+
cachedInput: .006
|
|
140
|
+
},
|
|
141
|
+
"deepseek-v4-pro": {
|
|
142
|
+
input: 1.32,
|
|
143
|
+
output: 3.96,
|
|
144
|
+
cachedInput: .044
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* DeepSeek's off-peak rates (half the peak {@link DEEPSEEK_DEFAULT_PRICING}),
|
|
149
|
+
* same source and date. Opt in per SDK:
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* new DeepSeekSDK({ apiKey, pricing: DEEPSEEK_OFF_PEAK_PRICING });
|
|
153
|
+
*/
|
|
154
|
+
const DEEPSEEK_OFF_PEAK_PRICING = {
|
|
155
|
+
"deepseek-flash": {
|
|
156
|
+
input: .15,
|
|
157
|
+
output: .6,
|
|
158
|
+
cachedInput: .003
|
|
128
159
|
},
|
|
129
160
|
"deepseek-v4-flash": {
|
|
130
|
-
input: .
|
|
131
|
-
output: .
|
|
132
|
-
cachedInput: .
|
|
161
|
+
input: .15,
|
|
162
|
+
output: .6,
|
|
163
|
+
cachedInput: .003
|
|
133
164
|
},
|
|
134
165
|
"deepseek-v4-pro": {
|
|
135
|
-
input: .
|
|
136
|
-
output: .
|
|
137
|
-
cachedInput: .
|
|
166
|
+
input: .66,
|
|
167
|
+
output: 1.98,
|
|
168
|
+
cachedInput: .022
|
|
138
169
|
}
|
|
139
170
|
};
|
|
140
171
|
/**
|
|
@@ -249,6 +280,8 @@ var DeepSeekSDK = class {
|
|
|
249
280
|
|
|
250
281
|
//#endregion
|
|
251
282
|
exports.DEEPSEEK_CHAT_MODELS = DEEPSEEK_CHAT_MODELS;
|
|
283
|
+
exports.DEEPSEEK_DEFAULT_PRICING = DEEPSEEK_DEFAULT_PRICING;
|
|
284
|
+
exports.DEEPSEEK_OFF_PEAK_PRICING = DEEPSEEK_OFF_PEAK_PRICING;
|
|
252
285
|
exports.DeepSeekSDK = DeepSeekSDK;
|
|
253
286
|
exports.inferReasoningCapability = inferReasoningCapability;
|
|
254
287
|
exports.inferVisionCapability = inferVisionCapability;
|
package/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["OpenAISDK"],"sources":["../../../../../../ai-deepseek/src/known-models.ts","../../../../../../ai-deepseek/src/sdk.ts"],"sourcesContent":["/**\n * Capability inference for DeepSeek chat model ids.\n *\n * DeepSeek's API is OpenAI-compatible on the wire (`@warlock.js/ai-deepseek`\n * wraps {@link OpenAISDK}), but its model **names** are not OpenAI names —\n * so OpenAI's own prefix lists (`gpt-4o`, `o3`, …) never match them. This\n * module supplies DeepSeek's OWN name-based inference, which the\n * {@link DeepSeekSDK} injects as explicit capability booleans into the\n * wrapped `openai.model(...)` call (explicit config wins over OpenAI's\n * inference inside `OpenAIModel`).\n *\n * Verified against the official DeepSeek API docs (api-docs.deepseek.com,\n * mid-2026): base URL `https://api.deepseek.com`, OpenAI-compatible Chat\n * Completions. Two reasoning-capable surfaces exist — the legacy\n * `deepseek-reasoner` (thinking mode) and the `*-pro` tier — while\n * `deepseek-chat` is the non-thinking surface. No DeepSeek chat model\n * documents image (vision) input, so vision inference is conservatively\n * `false` for every id.\n */\n\n/**\n * Default DeepSeek chat model ids, surfaced for discovery and docs.\n *\n * - `deepseek-chat` — the non-thinking surface (V3 lineage). Fast, cheap,\n * broad production coverage. Not reasoning-capable.\n * - `deepseek-reasoner` — the thinking surface (R1 lineage). Emits a\n * reasoning channel and accepts the reasoning-effort knob.\n *\n * Both legacy names are scheduled for retirement (2026/07/24 per DeepSeek's\n * deprecation notice) in favor of the `deepseek-v4-*` family\n * (`deepseek-v4-flash`, `deepseek-v4-pro`), which this inference also\n * understands. The list is informational only — `deepseek.model({ name })`\n * accepts any id the upstream serves.\n */\nexport const DEEPSEEK_CHAT_MODELS = [\n \"deepseek-chat\",\n \"deepseek-reasoner\",\n \"deepseek-v4-flash\",\n \"deepseek-v4-pro\",\n] as const;\n\n/**\n * Substrings identifying DeepSeek model ids that expose a reasoning /\n * thinking channel and accept the reasoning-effort knob.\n *\n * - `deepseek-reasoner` — the dedicated thinking surface (R1 lineage).\n * - `-pro` — the V4 quality tier (`deepseek-v4-pro`), which thinks by\n * default per DeepSeek's docs.\n *\n * `deepseek-chat` (the V3 non-thinking surface) and `deepseek-v4-flash`\n * stay `false`. A substring match tolerates date/preview suffixes the\n * provider may append. Override per-model via\n * `deepseek.model({ name, reasoning: true | false })`.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\"deepseek-reasoner\", \"-pro\"];\n\n/**\n * Infer whether a DeepSeek model id is reasoning-capable based on the\n * known substrings. Unknown ids default to `false` so the adapter never\n * forwards an unsupported reasoning param to a non-thinking model.\n *\n * @example\n * inferReasoningCapability(\"deepseek-reasoner\"); // → true\n * inferReasoningCapability(\"deepseek-v4-pro\"); // → true\n * inferReasoningCapability(\"deepseek-chat\"); // → false\n * inferReasoningCapability(\"deepseek-v4-flash\"); // → false\n */\nexport function inferReasoningCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return REASONING_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Substrings identifying DeepSeek model ids that accept image (vision)\n * input.\n *\n * Currently **empty**: as of mid-2026, no DeepSeek chat model documents\n * vision input on the OpenAI-compatible Chat Completions endpoint, so\n * inference returns `false` for every id and passing an image attachment\n * surfaces a clear, agent-side capability error instead of an opaque 400.\n * Append a fragment here (and a paired spec case) the day DeepSeek ships a\n * multimodal chat model. Devs can always opt in per-model via\n * `deepseek.model({ name, vision: true })`.\n */\nconst VISION_CAPABLE_SUBSTRINGS: readonly string[] = [];\n\n/**\n * Infer whether a DeepSeek model id supports vision based on the known\n * substrings. Today this is always `false` (see\n * {@link VISION_CAPABLE_SUBSTRINGS}); kept as a function so the\n * {@link DeepSeekSDK} call site and the override semantics stay identical\n * to the other adapters, ready for a future multimodal id.\n *\n * @example\n * inferVisionCapability(\"deepseek-chat\"); // → false\n * inferVisionCapability(\"deepseek-reasoner\"); // → false\n */\nexport function inferVisionCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n","import type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type {\n DeepSeekEmbedderConfig,\n DeepSeekImageConfig,\n DeepSeekModelConfig,\n DeepSeekSDKConfig,\n} from \"./config.type\";\nimport { inferReasoningCapability, inferVisionCapability } from \"./known-models\";\n\n/**\n * DeepSeek's OpenAI-compatible Chat Completions endpoint. Verified against\n * the official API docs (api-docs.deepseek.com, mid-2026).\n */\nconst DEEPSEEK_BASE_URL = \"https://api.deepseek.com\";\n\n/** Default upstream label for models produced by this SDK. */\nconst DEEPSEEK_PROVIDER = \"deepseek\";\n\n/**\n * Built-in DeepSeek pricing defaults, in USD per 1,000,000 tokens, keyed\n * by model name. Sourced from DeepSeek's official pricing table\n * (mid-2026); `cachedInput` is the cache-hit input rate. A caller-supplied\n * SDK `pricing` registry, or a per-model `pricing`, overrides any entry\n * here. Update when DeepSeek revises its published rates.\n */\nconst DEEPSEEK_DEFAULT_PRICING: Record<string, ModelPricing> = {\n \"deepseek-chat\": { input: 0.14, output: 0.28, cachedInput: 0.0028 },\n \"deepseek-reasoner\": { input: 0.14, output: 0.28, cachedInput: 0.0028 },\n \"deepseek-v4-flash\": { input: 0.14, output: 0.28, cachedInput: 0.0028 },\n \"deepseek-v4-pro\": { input: 0.435, output: 0.87, cachedInput: 0.003625 },\n};\n\n/**\n * DeepSeek-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for DeepSeek models. DeepSeek's API is\n * OpenAI-compatible on the wire, so rather than reimplementing the\n * battle-tested Chat Completions translation, this is a **thin wrapper**\n * over {@link OpenAISDK} from `@warlock.js/ai-openai`: it constructs one\n * internal `OpenAISDK` pinned to DeepSeek's `baseURL` and the `\"deepseek\"`\n * provider label, and delegates `model()` / `embedder()` / `image()` /\n * `count()` straight to it. Construct one `DeepSeekSDK` per account and\n * reuse it everywhere.\n *\n * **What the wrapper adds over a bare `OpenAISDK`.** DeepSeek's model\n * **names** are not OpenAI names, so OpenAI's own vision/reasoning prefix\n * lists never match them. This wrapper injects DeepSeek's OWN capability\n * inference (see `known-models.ts`) and built-in DeepSeek pricing defaults\n * as explicit values on every `model()` call — so `deepseek-reasoner` is\n * correctly flagged reasoning-capable and `deepseek-chat` is not, even\n * though neither matches an OpenAI prefix. An explicit `vision` /\n * `reasoning` / `pricing` you pass per model always wins over these\n * injected defaults.\n *\n * **Responsibility.**\n * - Owns: one long-lived internal `OpenAISDK` (auth, DeepSeek base URL)\n * and DeepSeek's capability + pricing defaults.\n * - Does NOT own: the wire protocol, streaming loop, message/tool\n * translation, or error wrapping — all inherited unchanged from\n * `OpenAISDK` / `OpenAIModel`.\n *\n * @example\n * const deepseek = new DeepSeekSDK({ apiKey: process.env.DEEPSEEK_API_KEY! });\n * const chat = deepseek.model({ name: \"deepseek-chat\" }); // reasoning=false\n * const reasoner = deepseek.model({ name: \"deepseek-reasoner\" }); // reasoning=true\n *\n * @example\n * // Compose into an `ai.deepseek` namespace for ergonomic agent wiring\n * const ai = { agent, tool, deepseek: new DeepSeekSDK({ apiKey }) };\n * const myAgent = ai.agent({ model: ai.deepseek.model({ name: \"deepseek-reasoner\" }) });\n */\nexport class DeepSeekSDK implements SDKAdapterContract {\n /** The wrapped OpenAI-compatible client, pinned to DeepSeek. */\n private readonly openai: OpenAISDK;\n private readonly provider: string;\n private readonly pricing: Record<string, ModelPricing>;\n\n public constructor(config: DeepSeekSDKConfig) {\n const { provider, pricing, baseURL, ...clientOptions } = config;\n\n this.provider = provider ?? DEEPSEEK_PROVIDER;\n // Caller pricing overrides the built-in DeepSeek defaults entry-by-entry.\n this.pricing = { ...DEEPSEEK_DEFAULT_PRICING, ...pricing };\n\n // The internal OpenAISDK carries the DeepSeek base URL + provider label;\n // pricing stays on THIS wrapper so it can be merged with the built-in\n // defaults before each per-model resolution below.\n this.openai = new OpenAISDK({\n ...clientOptions,\n baseURL: baseURL ?? DEEPSEEK_BASE_URL,\n provider: this.provider,\n });\n }\n\n /**\n * Build a `ModelContract` for a DeepSeek model. Delegates to the wrapped\n * `OpenAISDK.model()`, but first injects this provider's defaults:\n * - `vision` / `reasoning` inferred from DeepSeek's model-name lists\n * (`known-models.ts`) — so the right capabilities are set even though\n * the names aren't OpenAI names.\n * - `pricing` resolved from the built-in DeepSeek table merged with any\n * caller-supplied SDK registry.\n *\n * An explicit `vision` / `reasoning` / `pricing` on `config` always wins\n * over the injected default. Everything else (sampling, structured\n * output, streaming, error wrapping) is inherited unchanged from\n * `OpenAIModel`.\n */\n public model(config: DeepSeekModelConfig): ModelContract {\n const resolved: DeepSeekModelConfig = {\n ...config,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n pricing: config.pricing ?? this.pricing[config.name],\n };\n\n return this.openai.model(resolved);\n }\n\n /**\n * Rough offline token-count estimate. Delegated to the wrapped\n * `OpenAISDK.count()` (the core character-heuristic) — good for\n * budgeting/quota guards, not billing.\n */\n public async count(text: string, model?: string): Promise<number> {\n return this.openai.count(text, model);\n }\n\n /**\n * Build an `EmbedderContract`. Delegated verbatim to\n * `OpenAISDK.embedder()`.\n *\n * NOTE: DeepSeek does not officially document an OpenAI-compatible\n * embeddings endpoint (mid-2026); this delegate works against a\n * compatible gateway you point `baseURL` at, but may fail against the\n * stock DeepSeek endpoint. Prefer a dedicated embeddings provider for\n * RAG.\n */\n public embedder(config: DeepSeekEmbedderConfig): EmbedderContract {\n return this.openai.embedder(config);\n }\n\n /**\n * Build an `ImageModelContract`. Delegated verbatim to\n * `OpenAISDK.image()`.\n *\n * NOTE: DeepSeek does not document an image-generation endpoint\n * (mid-2026); provided for adapter parity. A non-image model id is\n * rejected at construction by the wrapped OpenAI image model.\n */\n public image(config: DeepSeekImageConfig): ImageModelContract {\n return this.openai.image(config);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;AAeA,MAAM,+BAA+B,CAAC,qBAAqB,MAAM;;;;;;;;;;;;AAajE,SAAgB,yBAAyB,SAA0B;CACjE,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,6BAA6B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACtF;;;;;;;;;;;;;AAcA,MAAM,4BAA+C,CAAC;;;;;;;;;;;;AAatD,SAAgB,sBAAsB,SAA0B;CAC9D,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,0BAA0B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACnF;;;;;;;;AClFA,MAAM,oBAAoB;;AAG1B,MAAM,oBAAoB;;;;;;;;AAS1B,MAAM,2BAAyD;CAC7D,iBAAiB;EAAE,OAAO;EAAM,QAAQ;EAAM,aAAa;CAAO;CAClE,qBAAqB;EAAE,OAAO;EAAM,QAAQ;EAAM,aAAa;CAAO;CACtE,qBAAqB;EAAE,OAAO;EAAM,QAAQ;EAAM,aAAa;CAAO;CACtE,mBAAmB;EAAE,OAAO;EAAO,QAAQ;EAAM,aAAa;CAAS;AACzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,cAAb,MAAuD;CAMrD,AAAO,YAAY,QAA2B;EAC5C,MAAM,EAAE,UAAU,SAAS,SAAS,GAAG,kBAAkB;EAEzD,KAAK,WAAW,YAAY;EAE5B,KAAK,UAAU;GAAE,GAAG;GAA0B,GAAG;EAAQ;EAKzD,KAAK,SAAS,IAAIA,gCAAU;GAC1B,GAAG;GACH,SAAS,WAAW;GACpB,UAAU,KAAK;EACjB,CAAC;CACH;;;;;;;;;;;;;;;CAgBA,AAAO,MAAM,QAA4C;EACvD,MAAM,WAAgC;GACpC,GAAG;GACH,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;GACnE,SAAS,OAAO,WAAW,KAAK,QAAQ,OAAO;EACjD;EAEA,OAAO,KAAK,OAAO,MAAM,QAAQ;CACnC;;;;;;CAOA,MAAa,MAAM,MAAc,OAAiC;EAChE,OAAO,KAAK,OAAO,MAAM,MAAM,KAAK;CACtC;;;;;;;;;;;CAYA,AAAO,SAAS,QAAkD;EAChE,OAAO,KAAK,OAAO,SAAS,MAAM;CACpC;;;;;;;;;CAUA,AAAO,MAAM,QAAiD;EAC5D,OAAO,KAAK,OAAO,MAAM,MAAM;CACjC;AACF"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["OpenAISDK"],"sources":["../../../../../../../packages/ai-deepseek/src/known-models.ts","../../../../../../../packages/ai-deepseek/src/sdk.ts"],"sourcesContent":["/**\n * Capability inference for DeepSeek chat model ids.\n *\n * DeepSeek's API is OpenAI-compatible on the wire (`@warlock.js/ai-deepseek`\n * wraps {@link OpenAISDK}), but its model **names** are not OpenAI names —\n * so OpenAI's own prefix lists (`gpt-4o`, `o3`, …) never match them. This\n * module supplies DeepSeek's OWN name-based inference, which the\n * {@link DeepSeekSDK} injects as explicit capability booleans into the\n * wrapped `openai.model(...)` call (explicit config wins over OpenAI's\n * inference inside `OpenAIModel`).\n *\n * Verified against the official DeepSeek API docs (api-docs.deepseek.com,\n * mid-2026): base URL `https://api.deepseek.com`, OpenAI-compatible Chat\n * Completions. Two reasoning-capable surfaces exist — the legacy\n * `deepseek-reasoner` (thinking mode) and the `*-pro` tier — while\n * `deepseek-chat` is the non-thinking surface. No DeepSeek chat model\n * documents image (vision) input, so vision inference is conservatively\n * `false` for every id.\n */\n\n/**\n * Default DeepSeek chat model ids, surfaced for discovery and docs.\n *\n * - `deepseek-chat` — the non-thinking surface (V3 lineage). Fast, cheap,\n * broad production coverage. Not reasoning-capable.\n * - `deepseek-reasoner` — the thinking surface (R1 lineage). Emits a\n * reasoning channel and accepts the reasoning-effort knob.\n *\n * Both legacy names are scheduled for retirement (2026/07/24 per DeepSeek's\n * deprecation notice) in favor of the `deepseek-v4-*` family\n * (`deepseek-v4-flash`, `deepseek-v4-pro`), which this inference also\n * understands. The list is informational only — `deepseek.model({ name })`\n * accepts any id the upstream serves.\n */\nexport const DEEPSEEK_CHAT_MODELS = [\n \"deepseek-chat\",\n \"deepseek-reasoner\",\n \"deepseek-v4-flash\",\n \"deepseek-v4-pro\",\n] as const;\n\n/**\n * Substrings identifying DeepSeek model ids that expose a reasoning /\n * thinking channel and accept the reasoning-effort knob.\n *\n * - `deepseek-reasoner` — the dedicated thinking surface (R1 lineage).\n * - `-pro` — the V4 quality tier (`deepseek-v4-pro`), which thinks by\n * default per DeepSeek's docs.\n *\n * `deepseek-chat` (the V3 non-thinking surface) and `deepseek-v4-flash`\n * stay `false`. A substring match tolerates date/preview suffixes the\n * provider may append. Override per-model via\n * `deepseek.model({ name, reasoning: true | false })`.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\"deepseek-reasoner\", \"-pro\"];\n\n/**\n * Infer whether a DeepSeek model id is reasoning-capable based on the\n * known substrings. Unknown ids default to `false` so the adapter never\n * forwards an unsupported reasoning param to a non-thinking model.\n *\n * @example\n * inferReasoningCapability(\"deepseek-reasoner\"); // → true\n * inferReasoningCapability(\"deepseek-v4-pro\"); // → true\n * inferReasoningCapability(\"deepseek-chat\"); // → false\n * inferReasoningCapability(\"deepseek-v4-flash\"); // → false\n */\nexport function inferReasoningCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return REASONING_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Substrings identifying DeepSeek model ids that accept image (vision)\n * input.\n *\n * Currently **empty**: as of mid-2026, no DeepSeek chat model documents\n * vision input on the OpenAI-compatible Chat Completions endpoint, so\n * inference returns `false` for every id and passing an image attachment\n * surfaces a clear, agent-side capability error instead of an opaque 400.\n * Append a fragment here (and a paired spec case) the day DeepSeek ships a\n * multimodal chat model. Devs can always opt in per-model via\n * `deepseek.model({ name, vision: true })`.\n */\nconst VISION_CAPABLE_SUBSTRINGS: readonly string[] = [];\n\n/**\n * Infer whether a DeepSeek model id supports vision based on the known\n * substrings. Today this is always `false` (see\n * {@link VISION_CAPABLE_SUBSTRINGS}); kept as a function so the\n * {@link DeepSeekSDK} call site and the override semantics stay identical\n * to the other adapters, ready for a future multimodal id.\n *\n * @example\n * inferVisionCapability(\"deepseek-chat\"); // → false\n * inferVisionCapability(\"deepseek-reasoner\"); // → false\n */\nexport function inferVisionCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n","import type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type {\n DeepSeekEmbedderConfig,\n DeepSeekImageConfig,\n DeepSeekModelConfig,\n DeepSeekSDKConfig,\n} from \"./config.type\";\nimport { inferReasoningCapability, inferVisionCapability } from \"./known-models\";\n\n/**\n * DeepSeek's OpenAI-compatible Chat Completions endpoint. Verified against\n * the official API docs (api-docs.deepseek.com, mid-2026).\n */\nconst DEEPSEEK_BASE_URL = \"https://api.deepseek.com\";\n\n/** Default upstream label for models produced by this SDK. */\nconst DEEPSEEK_PROVIDER = \"deepseek\";\n\n/**\n * Built-in DeepSeek pricing defaults, in USD per 1,000,000 tokens, keyed\n * by model name; `cachedInput` is the cache-hit input rate.\n *\n * Source: https://api-docs.deepseek.com/quick_start/pricing, fetched\n * 2026-10-17. DeepSeek bills by time of day: peak hours (01:00–04:00 and\n * 06:00–10:00 UTC, Monday to Friday) cost twice the off-peak rate. A flat\n * `ModelPricing` cannot follow the clock, so these are the **peak** rates —\n * an upper bound that keeps USD budgets safe; off-peak calls really cost\n * half. Pass {@link DEEPSEEK_OFF_PEAK_PRICING} (or your own) as `pricing`\n * when you know you run off-peak.\n *\n * `deepseek-v4-flash` is the legacy name of `deepseek-flash` and bills at\n * the same rate. `deepseek-chat` / `deepseek-reasoner` are gone from the\n * price list (discontinued 2026-07-24) and stay unpriced.\n *\n * A caller-supplied SDK `pricing` registry, or a per-model `pricing`,\n * overrides any entry here.\n */\nexport const DEEPSEEK_DEFAULT_PRICING: Readonly<Record<string, ModelPricing>> = {\n \"deepseek-flash\": { input: 0.3, output: 1.2, cachedInput: 0.006 },\n \"deepseek-v4-flash\": { input: 0.3, output: 1.2, cachedInput: 0.006 },\n \"deepseek-v4-pro\": { input: 1.32, output: 3.96, cachedInput: 0.044 },\n};\n\n/**\n * DeepSeek's off-peak rates (half the peak {@link DEEPSEEK_DEFAULT_PRICING}),\n * same source and date. Opt in per SDK:\n *\n * @example\n * new DeepSeekSDK({ apiKey, pricing: DEEPSEEK_OFF_PEAK_PRICING });\n */\nexport const DEEPSEEK_OFF_PEAK_PRICING: Readonly<Record<string, ModelPricing>> = {\n \"deepseek-flash\": { input: 0.15, output: 0.6, cachedInput: 0.003 },\n \"deepseek-v4-flash\": { input: 0.15, output: 0.6, cachedInput: 0.003 },\n \"deepseek-v4-pro\": { input: 0.66, output: 1.98, cachedInput: 0.022 },\n};\n\n/**\n * DeepSeek-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for DeepSeek models. DeepSeek's API is\n * OpenAI-compatible on the wire, so rather than reimplementing the\n * battle-tested Chat Completions translation, this is a **thin wrapper**\n * over {@link OpenAISDK} from `@warlock.js/ai-openai`: it constructs one\n * internal `OpenAISDK` pinned to DeepSeek's `baseURL` and the `\"deepseek\"`\n * provider label, and delegates `model()` / `embedder()` / `image()` /\n * `count()` straight to it. Construct one `DeepSeekSDK` per account and\n * reuse it everywhere.\n *\n * **What the wrapper adds over a bare `OpenAISDK`.** DeepSeek's model\n * **names** are not OpenAI names, so OpenAI's own vision/reasoning prefix\n * lists never match them. This wrapper injects DeepSeek's OWN capability\n * inference (see `known-models.ts`) and built-in DeepSeek pricing defaults\n * as explicit values on every `model()` call — so `deepseek-reasoner` is\n * correctly flagged reasoning-capable and `deepseek-chat` is not, even\n * though neither matches an OpenAI prefix. An explicit `vision` /\n * `reasoning` / `pricing` you pass per model always wins over these\n * injected defaults.\n *\n * **Responsibility.**\n * - Owns: one long-lived internal `OpenAISDK` (auth, DeepSeek base URL)\n * and DeepSeek's capability + pricing defaults.\n * - Does NOT own: the wire protocol, streaming loop, message/tool\n * translation, or error wrapping — all inherited unchanged from\n * `OpenAISDK` / `OpenAIModel`.\n *\n * @example\n * const deepseek = new DeepSeekSDK({ apiKey: process.env.DEEPSEEK_API_KEY! });\n * const chat = deepseek.model({ name: \"deepseek-chat\" }); // reasoning=false\n * const reasoner = deepseek.model({ name: \"deepseek-reasoner\" }); // reasoning=true\n *\n * @example\n * // Compose into an `ai.deepseek` namespace for ergonomic agent wiring\n * const ai = { agent, tool, deepseek: new DeepSeekSDK({ apiKey }) };\n * const myAgent = ai.agent({ model: ai.deepseek.model({ name: \"deepseek-reasoner\" }) });\n */\nexport class DeepSeekSDK implements SDKAdapterContract {\n /** The wrapped OpenAI-compatible client, pinned to DeepSeek. */\n private readonly openai: OpenAISDK;\n private readonly provider: string;\n private readonly pricing: Record<string, ModelPricing>;\n\n public constructor(config: DeepSeekSDKConfig) {\n const { provider, pricing, baseURL, ...clientOptions } = config;\n\n this.provider = provider ?? DEEPSEEK_PROVIDER;\n // Caller pricing overrides the built-in DeepSeek defaults entry-by-entry.\n this.pricing = { ...DEEPSEEK_DEFAULT_PRICING, ...pricing };\n\n // The internal OpenAISDK carries the DeepSeek base URL + provider label;\n // pricing stays on THIS wrapper so it can be merged with the built-in\n // defaults before each per-model resolution below.\n this.openai = new OpenAISDK({\n ...clientOptions,\n baseURL: baseURL ?? DEEPSEEK_BASE_URL,\n provider: this.provider,\n });\n }\n\n /**\n * Build a `ModelContract` for a DeepSeek model. Delegates to the wrapped\n * `OpenAISDK.model()`, but first injects this provider's defaults:\n * - `vision` / `reasoning` inferred from DeepSeek's model-name lists\n * (`known-models.ts`) — so the right capabilities are set even though\n * the names aren't OpenAI names.\n * - `pricing` resolved from the built-in DeepSeek table merged with any\n * caller-supplied SDK registry.\n *\n * An explicit `vision` / `reasoning` / `pricing` on `config` always wins\n * over the injected default. Everything else (sampling, structured\n * output, streaming, error wrapping) is inherited unchanged from\n * `OpenAIModel`.\n */\n public model(config: DeepSeekModelConfig): ModelContract {\n const resolved: DeepSeekModelConfig = {\n ...config,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n pricing: config.pricing ?? this.pricing[config.name],\n };\n\n return this.openai.model(resolved);\n }\n\n /**\n * Rough offline token-count estimate. Delegated to the wrapped\n * `OpenAISDK.count()` (the core character-heuristic) — good for\n * budgeting/quota guards, not billing.\n */\n public async count(text: string, model?: string): Promise<number> {\n return this.openai.count(text, model);\n }\n\n /**\n * Build an `EmbedderContract`. Delegated verbatim to\n * `OpenAISDK.embedder()`.\n *\n * NOTE: DeepSeek does not officially document an OpenAI-compatible\n * embeddings endpoint (mid-2026); this delegate works against a\n * compatible gateway you point `baseURL` at, but may fail against the\n * stock DeepSeek endpoint. Prefer a dedicated embeddings provider for\n * RAG.\n */\n public embedder(config: DeepSeekEmbedderConfig): EmbedderContract {\n return this.openai.embedder(config);\n }\n\n /**\n * Build an `ImageModelContract`. Delegated verbatim to\n * `OpenAISDK.image()`.\n *\n * NOTE: DeepSeek does not document an image-generation endpoint\n * (mid-2026); provided for adapter parity. A non-image model id is\n * rejected at construction by the wrapped OpenAI image model.\n */\n public image(config: DeepSeekImageConfig): ImageModelContract {\n return this.openai.image(config);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;AAeA,MAAM,+BAA+B,CAAC,qBAAqB,MAAM;;;;;;;;;;;;AAajE,SAAgB,yBAAyB,SAA0B;CACjE,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,6BAA6B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACtF;;;;;;;;;;;;;AAcA,MAAM,4BAA+C,CAAC;;;;;;;;;;;;AAatD,SAAgB,sBAAsB,SAA0B;CAC9D,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,0BAA0B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACnF;;;;;;;;AClFA,MAAM,oBAAoB;;AAG1B,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;AAqB1B,MAAa,2BAAmE;CAC9E,kBAAkB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAM;CAChE,qBAAqB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAM;CACnE,mBAAmB;EAAE,OAAO;EAAM,QAAQ;EAAM,aAAa;CAAM;AACrE;;;;;;;;AASA,MAAa,4BAAoE;CAC/E,kBAAkB;EAAE,OAAO;EAAM,QAAQ;EAAK,aAAa;CAAM;CACjE,qBAAqB;EAAE,OAAO;EAAM,QAAQ;EAAK,aAAa;CAAM;CACpE,mBAAmB;EAAE,OAAO;EAAM,QAAQ;EAAM,aAAa;CAAM;AACrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,cAAb,MAAuD;CAMrD,AAAO,YAAY,QAA2B;EAC5C,MAAM,EAAE,UAAU,SAAS,SAAS,GAAG,kBAAkB;EAEzD,KAAK,WAAW,YAAY;EAE5B,KAAK,UAAU;GAAE,GAAG;GAA0B,GAAG;EAAQ;EAKzD,KAAK,SAAS,IAAIA,gCAAU;GAC1B,GAAG;GACH,SAAS,WAAW;GACpB,UAAU,KAAK;EACjB,CAAC;CACH;;;;;;;;;;;;;;;CAgBA,AAAO,MAAM,QAA4C;EACvD,MAAM,WAAgC;GACpC,GAAG;GACH,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;GACnE,SAAS,OAAO,WAAW,KAAK,QAAQ,OAAO;EACjD;EAEA,OAAO,KAAK,OAAO,MAAM,QAAQ;CACnC;;;;;;CAOA,MAAa,MAAM,MAAc,OAAiC;EAChE,OAAO,KAAK,OAAO,MAAM,MAAM,KAAK;CACtC;;;;;;;;;;;CAYA,AAAO,SAAS,QAAkD;EAChE,OAAO,KAAK,OAAO,SAAS,MAAM;CACpC;;;;;;;;;CAUA,AAAO,MAAM,QAAiD;EAC5D,OAAO,KAAK,OAAO,MAAM,MAAM;CACjC;AACF"}
|
package/esm/config.type.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OpenAISDKConfig } from "@warlock.js/ai-openai";
|
|
2
2
|
import { EmbedderConfig, ImageModelConfig, ModelConfig } from "@warlock.js/ai";
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/ai-deepseek/src/config.type.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* Per-model `response_format` override forwarded to the wrapped OpenAI
|
|
7
7
|
* model. Mirrors the OpenAI adapter's union (DeepSeek speaks the same
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.type.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"config.type.d.mts","names":[],"sources":["../../../../../../../packages/ai-deepseek/src/config.type.ts"],"mappings":";;;;;;AAaA;;;;AAAkC;AAsClC;;;KAtCY,sBAAA;;;;;;AAiDF;AAoBV;;;;;;;;;;;;;AAsCO;AAcP;;;;AAAmD;AAWnD;;;;AAAkD;;;;;;;KA9FtC,iBAAA,GAAoB,IAAI,CAAC,eAAA;;;;;;EAMnC,OAAA;;;;;EAKA,QAAA;AAAA;;;;;;;;;;;;;;;;;;KAoBU,mBAAA,GAAsB,WAAA;;;;;;;EAOhC,MAAA;;;;;;;;EAQA,SAAA;;;;;;EAMA,gBAAA;;;;;;;EAOA,cAAA,GAAiB,sBAAsB;;;;;EAKvC,GAAA;;;;;EAKA,KAAA;AAAA;;;;;;;;;;;;KAcU,sBAAA,GAAyB,cAAc;;;;;;;;;;KAWvC,mBAAA,GAAsB,gBAAgB"}
|
package/esm/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { DeepSeekEmbedderConfig, DeepSeekImageConfig, DeepSeekModelConfig, DeepSeekSDKConfig } from "./config.type.mjs";
|
|
2
|
-
import { DeepSeekSDK } from "./sdk.mjs";
|
|
2
|
+
import { DEEPSEEK_DEFAULT_PRICING, DEEPSEEK_OFF_PEAK_PRICING, DeepSeekSDK } from "./sdk.mjs";
|
|
3
3
|
import { DEEPSEEK_CHAT_MODELS, inferReasoningCapability, inferVisionCapability } from "./known-models.mjs";
|
|
4
|
-
export { DEEPSEEK_CHAT_MODELS, type DeepSeekEmbedderConfig, type DeepSeekImageConfig, type DeepSeekModelConfig, DeepSeekSDK, type DeepSeekSDKConfig, inferReasoningCapability, inferVisionCapability };
|
|
4
|
+
export { DEEPSEEK_CHAT_MODELS, DEEPSEEK_DEFAULT_PRICING, DEEPSEEK_OFF_PEAK_PRICING, type DeepSeekEmbedderConfig, type DeepSeekImageConfig, type DeepSeekModelConfig, DeepSeekSDK, type DeepSeekSDKConfig, inferReasoningCapability, inferVisionCapability };
|
package/esm/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { DEEPSEEK_CHAT_MODELS, inferReasoningCapability, inferVisionCapability } from "./known-models.mjs";
|
|
2
|
-
import { DeepSeekSDK } from "./sdk.mjs";
|
|
2
|
+
import { DEEPSEEK_DEFAULT_PRICING, DEEPSEEK_OFF_PEAK_PRICING, DeepSeekSDK } from "./sdk.mjs";
|
|
3
3
|
|
|
4
|
-
export { DEEPSEEK_CHAT_MODELS, DeepSeekSDK, inferReasoningCapability, inferVisionCapability };
|
|
4
|
+
export { DEEPSEEK_CHAT_MODELS, DEEPSEEK_DEFAULT_PRICING, DEEPSEEK_OFF_PEAK_PRICING, DeepSeekSDK, inferReasoningCapability, inferVisionCapability };
|
package/esm/known-models.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"known-models.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"known-models.d.mts","names":[],"sources":["../../../../../../../packages/ai-deepseek/src/known-models.ts"],"mappings":";;AAkCA;;;;AAKU;AA4BV;;;;AAAwD;AA+BxD;;;;AAAqD;;;;;;;;;;;;;;;;;;cAhExC,oBAAA;;;;;;;;;;;;iBAiCG,wBAAA,CAAyB,OAAe;;;;;;;;;;;;iBA+BxC,qBAAA,CAAsB,OAAe"}
|
package/esm/known-models.mjs
CHANGED
package/esm/known-models.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"known-models.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"known-models.mjs","names":[],"sources":["../../../../../../../packages/ai-deepseek/src/known-models.ts"],"sourcesContent":["/**\n * Capability inference for DeepSeek chat model ids.\n *\n * DeepSeek's API is OpenAI-compatible on the wire (`@warlock.js/ai-deepseek`\n * wraps {@link OpenAISDK}), but its model **names** are not OpenAI names —\n * so OpenAI's own prefix lists (`gpt-4o`, `o3`, …) never match them. This\n * module supplies DeepSeek's OWN name-based inference, which the\n * {@link DeepSeekSDK} injects as explicit capability booleans into the\n * wrapped `openai.model(...)` call (explicit config wins over OpenAI's\n * inference inside `OpenAIModel`).\n *\n * Verified against the official DeepSeek API docs (api-docs.deepseek.com,\n * mid-2026): base URL `https://api.deepseek.com`, OpenAI-compatible Chat\n * Completions. Two reasoning-capable surfaces exist — the legacy\n * `deepseek-reasoner` (thinking mode) and the `*-pro` tier — while\n * `deepseek-chat` is the non-thinking surface. No DeepSeek chat model\n * documents image (vision) input, so vision inference is conservatively\n * `false` for every id.\n */\n\n/**\n * Default DeepSeek chat model ids, surfaced for discovery and docs.\n *\n * - `deepseek-chat` — the non-thinking surface (V3 lineage). Fast, cheap,\n * broad production coverage. Not reasoning-capable.\n * - `deepseek-reasoner` — the thinking surface (R1 lineage). Emits a\n * reasoning channel and accepts the reasoning-effort knob.\n *\n * Both legacy names are scheduled for retirement (2026/07/24 per DeepSeek's\n * deprecation notice) in favor of the `deepseek-v4-*` family\n * (`deepseek-v4-flash`, `deepseek-v4-pro`), which this inference also\n * understands. The list is informational only — `deepseek.model({ name })`\n * accepts any id the upstream serves.\n */\nexport const DEEPSEEK_CHAT_MODELS = [\n \"deepseek-chat\",\n \"deepseek-reasoner\",\n \"deepseek-v4-flash\",\n \"deepseek-v4-pro\",\n] as const;\n\n/**\n * Substrings identifying DeepSeek model ids that expose a reasoning /\n * thinking channel and accept the reasoning-effort knob.\n *\n * - `deepseek-reasoner` — the dedicated thinking surface (R1 lineage).\n * - `-pro` — the V4 quality tier (`deepseek-v4-pro`), which thinks by\n * default per DeepSeek's docs.\n *\n * `deepseek-chat` (the V3 non-thinking surface) and `deepseek-v4-flash`\n * stay `false`. A substring match tolerates date/preview suffixes the\n * provider may append. Override per-model via\n * `deepseek.model({ name, reasoning: true | false })`.\n */\nconst REASONING_CAPABLE_SUBSTRINGS = [\"deepseek-reasoner\", \"-pro\"];\n\n/**\n * Infer whether a DeepSeek model id is reasoning-capable based on the\n * known substrings. Unknown ids default to `false` so the adapter never\n * forwards an unsupported reasoning param to a non-thinking model.\n *\n * @example\n * inferReasoningCapability(\"deepseek-reasoner\"); // → true\n * inferReasoningCapability(\"deepseek-v4-pro\"); // → true\n * inferReasoningCapability(\"deepseek-chat\"); // → false\n * inferReasoningCapability(\"deepseek-v4-flash\"); // → false\n */\nexport function inferReasoningCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return REASONING_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n\n/**\n * Substrings identifying DeepSeek model ids that accept image (vision)\n * input.\n *\n * Currently **empty**: as of mid-2026, no DeepSeek chat model documents\n * vision input on the OpenAI-compatible Chat Completions endpoint, so\n * inference returns `false` for every id and passing an image attachment\n * surfaces a clear, agent-side capability error instead of an opaque 400.\n * Append a fragment here (and a paired spec case) the day DeepSeek ships a\n * multimodal chat model. Devs can always opt in per-model via\n * `deepseek.model({ name, vision: true })`.\n */\nconst VISION_CAPABLE_SUBSTRINGS: readonly string[] = [];\n\n/**\n * Infer whether a DeepSeek model id supports vision based on the known\n * substrings. Today this is always `false` (see\n * {@link VISION_CAPABLE_SUBSTRINGS}); kept as a function so the\n * {@link DeepSeekSDK} call site and the override semantics stay identical\n * to the other adapters, ready for a future multimodal id.\n *\n * @example\n * inferVisionCapability(\"deepseek-chat\"); // → false\n * inferVisionCapability(\"deepseek-reasoner\"); // → false\n */\nexport function inferVisionCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return VISION_CAPABLE_SUBSTRINGS.some((fragment) => normalized.includes(fragment));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,uBAAuB;CAClC;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;AAeA,MAAM,+BAA+B,CAAC,qBAAqB,MAAM;;;;;;;;;;;;AAajE,SAAgB,yBAAyB,SAA0B;CACjE,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,6BAA6B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACtF;;;;;;;;;;;;;AAcA,MAAM,4BAA+C,CAAC;;;;;;;;;;;;AAatD,SAAgB,sBAAsB,SAA0B;CAC9D,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,0BAA0B,MAAM,aAAa,WAAW,SAAS,QAAQ,CAAC;AACnF"}
|
package/esm/sdk.d.mts
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
1
|
import { DeepSeekEmbedderConfig, DeepSeekImageConfig, DeepSeekModelConfig, DeepSeekSDKConfig } from "./config.type.mjs";
|
|
2
|
-
import { EmbedderContract, ImageModelContract, ModelContract, SDKAdapterContract } from "@warlock.js/ai";
|
|
2
|
+
import { EmbedderContract, ImageModelContract, ModelContract, ModelPricing, SDKAdapterContract } from "@warlock.js/ai";
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/ai-deepseek/src/sdk.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Built-in DeepSeek pricing defaults, in USD per 1,000,000 tokens, keyed
|
|
7
|
+
* by model name; `cachedInput` is the cache-hit input rate.
|
|
8
|
+
*
|
|
9
|
+
* Source: https://api-docs.deepseek.com/quick_start/pricing, fetched
|
|
10
|
+
* 2026-10-17. DeepSeek bills by time of day: peak hours (01:00–04:00 and
|
|
11
|
+
* 06:00–10:00 UTC, Monday to Friday) cost twice the off-peak rate. A flat
|
|
12
|
+
* `ModelPricing` cannot follow the clock, so these are the **peak** rates —
|
|
13
|
+
* an upper bound that keeps USD budgets safe; off-peak calls really cost
|
|
14
|
+
* half. Pass {@link DEEPSEEK_OFF_PEAK_PRICING} (or your own) as `pricing`
|
|
15
|
+
* when you know you run off-peak.
|
|
16
|
+
*
|
|
17
|
+
* `deepseek-v4-flash` is the legacy name of `deepseek-flash` and bills at
|
|
18
|
+
* the same rate. `deepseek-chat` / `deepseek-reasoner` are gone from the
|
|
19
|
+
* price list (discontinued 2026-07-24) and stay unpriced.
|
|
20
|
+
*
|
|
21
|
+
* A caller-supplied SDK `pricing` registry, or a per-model `pricing`,
|
|
22
|
+
* overrides any entry here.
|
|
23
|
+
*/
|
|
24
|
+
declare const DEEPSEEK_DEFAULT_PRICING: Readonly<Record<string, ModelPricing>>;
|
|
25
|
+
/**
|
|
26
|
+
* DeepSeek's off-peak rates (half the peak {@link DEEPSEEK_DEFAULT_PRICING}),
|
|
27
|
+
* same source and date. Opt in per SDK:
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* new DeepSeekSDK({ apiKey, pricing: DEEPSEEK_OFF_PEAK_PRICING });
|
|
31
|
+
*/
|
|
32
|
+
declare const DEEPSEEK_OFF_PEAK_PRICING: Readonly<Record<string, ModelPricing>>;
|
|
5
33
|
/**
|
|
6
34
|
* DeepSeek-backed implementation of `SDKAdapterContract`.
|
|
7
35
|
*
|
|
@@ -90,5 +118,5 @@ declare class DeepSeekSDK implements SDKAdapterContract {
|
|
|
90
118
|
image(config: DeepSeekImageConfig): ImageModelContract;
|
|
91
119
|
}
|
|
92
120
|
//#endregion
|
|
93
|
-
export { DeepSeekSDK };
|
|
121
|
+
export { DEEPSEEK_DEFAULT_PRICING, DEEPSEEK_OFF_PEAK_PRICING, DeepSeekSDK };
|
|
94
122
|
//# sourceMappingURL=sdk.d.mts.map
|
package/esm/sdk.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../../packages/ai-deepseek/src/sdk.ts"],"mappings":";;;;;;AA4CA;;;;;;;;;;;;AAA2E;AAa3E;;;;cAba,wBAAA,EAA0B,QAAA,CAAS,MAAA,SAAe,YAAA;;;;;;;;cAalD,yBAAA,EAA2B,QAAA,CAAS,MAAA,SAAe,YAAA;AA6ChE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+E+D;AA/E/D,cAAa,WAAA,YAAuB,kBAAA;;mBAEjB,MAAA;EAAA,iBACA,QAAA;EAAA,iBACA,OAAA;cAEE,MAAA,EAAQ,iBAAA;;;;;;;;;;;;;;;EA+BpB,KAAA,CAAM,MAAA,EAAQ,mBAAA,GAAsB,aAAA;;;;;;EAgB9B,KAAA,CAAM,IAAA,UAAc,KAAA,YAAiB,OAAA;;;;;;;;;;;EAc3C,QAAA,CAAS,MAAA,EAAQ,sBAAA,GAAyB,gBAAA;;;;;;;;;EAY1C,KAAA,CAAM,MAAA,EAAQ,mBAAA,GAAsB,kBAAA;AAAA"}
|
package/esm/sdk.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { inferReasoningCapability, inferVisionCapability } from "./known-models.mjs";
|
|
2
2
|
import { OpenAISDK } from "@warlock.js/ai-openai";
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/ai-deepseek/src/sdk.ts
|
|
5
5
|
/**
|
|
6
6
|
* DeepSeek's OpenAI-compatible Chat Completions endpoint. Verified against
|
|
7
7
|
* the official API docs (api-docs.deepseek.com, mid-2026).
|
|
@@ -11,31 +11,62 @@ const DEEPSEEK_BASE_URL = "https://api.deepseek.com";
|
|
|
11
11
|
const DEEPSEEK_PROVIDER = "deepseek";
|
|
12
12
|
/**
|
|
13
13
|
* Built-in DeepSeek pricing defaults, in USD per 1,000,000 tokens, keyed
|
|
14
|
-
* by model name
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* by model name; `cachedInput` is the cache-hit input rate.
|
|
15
|
+
*
|
|
16
|
+
* Source: https://api-docs.deepseek.com/quick_start/pricing, fetched
|
|
17
|
+
* 2026-10-17. DeepSeek bills by time of day: peak hours (01:00–04:00 and
|
|
18
|
+
* 06:00–10:00 UTC, Monday to Friday) cost twice the off-peak rate. A flat
|
|
19
|
+
* `ModelPricing` cannot follow the clock, so these are the **peak** rates —
|
|
20
|
+
* an upper bound that keeps USD budgets safe; off-peak calls really cost
|
|
21
|
+
* half. Pass {@link DEEPSEEK_OFF_PEAK_PRICING} (or your own) as `pricing`
|
|
22
|
+
* when you know you run off-peak.
|
|
23
|
+
*
|
|
24
|
+
* `deepseek-v4-flash` is the legacy name of `deepseek-flash` and bills at
|
|
25
|
+
* the same rate. `deepseek-chat` / `deepseek-reasoner` are gone from the
|
|
26
|
+
* price list (discontinued 2026-07-24) and stay unpriced.
|
|
27
|
+
*
|
|
28
|
+
* A caller-supplied SDK `pricing` registry, or a per-model `pricing`,
|
|
29
|
+
* overrides any entry here.
|
|
18
30
|
*/
|
|
19
31
|
const DEEPSEEK_DEFAULT_PRICING = {
|
|
20
|
-
"deepseek-
|
|
21
|
-
input: .
|
|
22
|
-
output: .
|
|
23
|
-
cachedInput: .
|
|
32
|
+
"deepseek-flash": {
|
|
33
|
+
input: .3,
|
|
34
|
+
output: 1.2,
|
|
35
|
+
cachedInput: .006
|
|
24
36
|
},
|
|
25
|
-
"deepseek-
|
|
26
|
-
input: .
|
|
27
|
-
output: .
|
|
28
|
-
cachedInput: .
|
|
37
|
+
"deepseek-v4-flash": {
|
|
38
|
+
input: .3,
|
|
39
|
+
output: 1.2,
|
|
40
|
+
cachedInput: .006
|
|
41
|
+
},
|
|
42
|
+
"deepseek-v4-pro": {
|
|
43
|
+
input: 1.32,
|
|
44
|
+
output: 3.96,
|
|
45
|
+
cachedInput: .044
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* DeepSeek's off-peak rates (half the peak {@link DEEPSEEK_DEFAULT_PRICING}),
|
|
50
|
+
* same source and date. Opt in per SDK:
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* new DeepSeekSDK({ apiKey, pricing: DEEPSEEK_OFF_PEAK_PRICING });
|
|
54
|
+
*/
|
|
55
|
+
const DEEPSEEK_OFF_PEAK_PRICING = {
|
|
56
|
+
"deepseek-flash": {
|
|
57
|
+
input: .15,
|
|
58
|
+
output: .6,
|
|
59
|
+
cachedInput: .003
|
|
29
60
|
},
|
|
30
61
|
"deepseek-v4-flash": {
|
|
31
|
-
input: .
|
|
32
|
-
output: .
|
|
33
|
-
cachedInput: .
|
|
62
|
+
input: .15,
|
|
63
|
+
output: .6,
|
|
64
|
+
cachedInput: .003
|
|
34
65
|
},
|
|
35
66
|
"deepseek-v4-pro": {
|
|
36
|
-
input: .
|
|
37
|
-
output: .
|
|
38
|
-
cachedInput: .
|
|
67
|
+
input: .66,
|
|
68
|
+
output: 1.98,
|
|
69
|
+
cachedInput: .022
|
|
39
70
|
}
|
|
40
71
|
};
|
|
41
72
|
/**
|
|
@@ -149,5 +180,5 @@ var DeepSeekSDK = class {
|
|
|
149
180
|
};
|
|
150
181
|
|
|
151
182
|
//#endregion
|
|
152
|
-
export { DeepSeekSDK };
|
|
183
|
+
export { DEEPSEEK_DEFAULT_PRICING, DEEPSEEK_OFF_PEAK_PRICING, DeepSeekSDK };
|
|
153
184
|
//# sourceMappingURL=sdk.mjs.map
|
package/esm/sdk.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../../packages/ai-deepseek/src/sdk.ts"],"sourcesContent":["import type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type {\n DeepSeekEmbedderConfig,\n DeepSeekImageConfig,\n DeepSeekModelConfig,\n DeepSeekSDKConfig,\n} from \"./config.type\";\nimport { inferReasoningCapability, inferVisionCapability } from \"./known-models\";\n\n/**\n * DeepSeek's OpenAI-compatible Chat Completions endpoint. Verified against\n * the official API docs (api-docs.deepseek.com, mid-2026).\n */\nconst DEEPSEEK_BASE_URL = \"https://api.deepseek.com\";\n\n/** Default upstream label for models produced by this SDK. */\nconst DEEPSEEK_PROVIDER = \"deepseek\";\n\n/**\n * Built-in DeepSeek pricing defaults, in USD per 1,000,000 tokens, keyed\n * by model name; `cachedInput` is the cache-hit input rate.\n *\n * Source: https://api-docs.deepseek.com/quick_start/pricing, fetched\n * 2026-10-17. DeepSeek bills by time of day: peak hours (01:00–04:00 and\n * 06:00–10:00 UTC, Monday to Friday) cost twice the off-peak rate. A flat\n * `ModelPricing` cannot follow the clock, so these are the **peak** rates —\n * an upper bound that keeps USD budgets safe; off-peak calls really cost\n * half. Pass {@link DEEPSEEK_OFF_PEAK_PRICING} (or your own) as `pricing`\n * when you know you run off-peak.\n *\n * `deepseek-v4-flash` is the legacy name of `deepseek-flash` and bills at\n * the same rate. `deepseek-chat` / `deepseek-reasoner` are gone from the\n * price list (discontinued 2026-07-24) and stay unpriced.\n *\n * A caller-supplied SDK `pricing` registry, or a per-model `pricing`,\n * overrides any entry here.\n */\nexport const DEEPSEEK_DEFAULT_PRICING: Readonly<Record<string, ModelPricing>> = {\n \"deepseek-flash\": { input: 0.3, output: 1.2, cachedInput: 0.006 },\n \"deepseek-v4-flash\": { input: 0.3, output: 1.2, cachedInput: 0.006 },\n \"deepseek-v4-pro\": { input: 1.32, output: 3.96, cachedInput: 0.044 },\n};\n\n/**\n * DeepSeek's off-peak rates (half the peak {@link DEEPSEEK_DEFAULT_PRICING}),\n * same source and date. Opt in per SDK:\n *\n * @example\n * new DeepSeekSDK({ apiKey, pricing: DEEPSEEK_OFF_PEAK_PRICING });\n */\nexport const DEEPSEEK_OFF_PEAK_PRICING: Readonly<Record<string, ModelPricing>> = {\n \"deepseek-flash\": { input: 0.15, output: 0.6, cachedInput: 0.003 },\n \"deepseek-v4-flash\": { input: 0.15, output: 0.6, cachedInput: 0.003 },\n \"deepseek-v4-pro\": { input: 0.66, output: 1.98, cachedInput: 0.022 },\n};\n\n/**\n * DeepSeek-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for DeepSeek models. DeepSeek's API is\n * OpenAI-compatible on the wire, so rather than reimplementing the\n * battle-tested Chat Completions translation, this is a **thin wrapper**\n * over {@link OpenAISDK} from `@warlock.js/ai-openai`: it constructs one\n * internal `OpenAISDK` pinned to DeepSeek's `baseURL` and the `\"deepseek\"`\n * provider label, and delegates `model()` / `embedder()` / `image()` /\n * `count()` straight to it. Construct one `DeepSeekSDK` per account and\n * reuse it everywhere.\n *\n * **What the wrapper adds over a bare `OpenAISDK`.** DeepSeek's model\n * **names** are not OpenAI names, so OpenAI's own vision/reasoning prefix\n * lists never match them. This wrapper injects DeepSeek's OWN capability\n * inference (see `known-models.ts`) and built-in DeepSeek pricing defaults\n * as explicit values on every `model()` call — so `deepseek-reasoner` is\n * correctly flagged reasoning-capable and `deepseek-chat` is not, even\n * though neither matches an OpenAI prefix. An explicit `vision` /\n * `reasoning` / `pricing` you pass per model always wins over these\n * injected defaults.\n *\n * **Responsibility.**\n * - Owns: one long-lived internal `OpenAISDK` (auth, DeepSeek base URL)\n * and DeepSeek's capability + pricing defaults.\n * - Does NOT own: the wire protocol, streaming loop, message/tool\n * translation, or error wrapping — all inherited unchanged from\n * `OpenAISDK` / `OpenAIModel`.\n *\n * @example\n * const deepseek = new DeepSeekSDK({ apiKey: process.env.DEEPSEEK_API_KEY! });\n * const chat = deepseek.model({ name: \"deepseek-chat\" }); // reasoning=false\n * const reasoner = deepseek.model({ name: \"deepseek-reasoner\" }); // reasoning=true\n *\n * @example\n * // Compose into an `ai.deepseek` namespace for ergonomic agent wiring\n * const ai = { agent, tool, deepseek: new DeepSeekSDK({ apiKey }) };\n * const myAgent = ai.agent({ model: ai.deepseek.model({ name: \"deepseek-reasoner\" }) });\n */\nexport class DeepSeekSDK implements SDKAdapterContract {\n /** The wrapped OpenAI-compatible client, pinned to DeepSeek. */\n private readonly openai: OpenAISDK;\n private readonly provider: string;\n private readonly pricing: Record<string, ModelPricing>;\n\n public constructor(config: DeepSeekSDKConfig) {\n const { provider, pricing, baseURL, ...clientOptions } = config;\n\n this.provider = provider ?? DEEPSEEK_PROVIDER;\n // Caller pricing overrides the built-in DeepSeek defaults entry-by-entry.\n this.pricing = { ...DEEPSEEK_DEFAULT_PRICING, ...pricing };\n\n // The internal OpenAISDK carries the DeepSeek base URL + provider label;\n // pricing stays on THIS wrapper so it can be merged with the built-in\n // defaults before each per-model resolution below.\n this.openai = new OpenAISDK({\n ...clientOptions,\n baseURL: baseURL ?? DEEPSEEK_BASE_URL,\n provider: this.provider,\n });\n }\n\n /**\n * Build a `ModelContract` for a DeepSeek model. Delegates to the wrapped\n * `OpenAISDK.model()`, but first injects this provider's defaults:\n * - `vision` / `reasoning` inferred from DeepSeek's model-name lists\n * (`known-models.ts`) — so the right capabilities are set even though\n * the names aren't OpenAI names.\n * - `pricing` resolved from the built-in DeepSeek table merged with any\n * caller-supplied SDK registry.\n *\n * An explicit `vision` / `reasoning` / `pricing` on `config` always wins\n * over the injected default. Everything else (sampling, structured\n * output, streaming, error wrapping) is inherited unchanged from\n * `OpenAIModel`.\n */\n public model(config: DeepSeekModelConfig): ModelContract {\n const resolved: DeepSeekModelConfig = {\n ...config,\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n pricing: config.pricing ?? this.pricing[config.name],\n };\n\n return this.openai.model(resolved);\n }\n\n /**\n * Rough offline token-count estimate. Delegated to the wrapped\n * `OpenAISDK.count()` (the core character-heuristic) — good for\n * budgeting/quota guards, not billing.\n */\n public async count(text: string, model?: string): Promise<number> {\n return this.openai.count(text, model);\n }\n\n /**\n * Build an `EmbedderContract`. Delegated verbatim to\n * `OpenAISDK.embedder()`.\n *\n * NOTE: DeepSeek does not officially document an OpenAI-compatible\n * embeddings endpoint (mid-2026); this delegate works against a\n * compatible gateway you point `baseURL` at, but may fail against the\n * stock DeepSeek endpoint. Prefer a dedicated embeddings provider for\n * RAG.\n */\n public embedder(config: DeepSeekEmbedderConfig): EmbedderContract {\n return this.openai.embedder(config);\n }\n\n /**\n * Build an `ImageModelContract`. Delegated verbatim to\n * `OpenAISDK.image()`.\n *\n * NOTE: DeepSeek does not document an image-generation endpoint\n * (mid-2026); provided for adapter parity. A non-image model id is\n * rejected at construction by the wrapped OpenAI image model.\n */\n public image(config: DeepSeekImageConfig): ImageModelContract {\n return this.openai.image(config);\n }\n}\n"],"mappings":";;;;;;;;AAoBA,MAAM,oBAAoB;;AAG1B,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;AAqB1B,MAAa,2BAAmE;CAC9E,kBAAkB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAM;CAChE,qBAAqB;EAAE,OAAO;EAAK,QAAQ;EAAK,aAAa;CAAM;CACnE,mBAAmB;EAAE,OAAO;EAAM,QAAQ;EAAM,aAAa;CAAM;AACrE;;;;;;;;AASA,MAAa,4BAAoE;CAC/E,kBAAkB;EAAE,OAAO;EAAM,QAAQ;EAAK,aAAa;CAAM;CACjE,qBAAqB;EAAE,OAAO;EAAM,QAAQ;EAAK,aAAa;CAAM;CACpE,mBAAmB;EAAE,OAAO;EAAM,QAAQ;EAAM,aAAa;CAAM;AACrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,cAAb,MAAuD;CAMrD,AAAO,YAAY,QAA2B;EAC5C,MAAM,EAAE,UAAU,SAAS,SAAS,GAAG,kBAAkB;EAEzD,KAAK,WAAW,YAAY;EAE5B,KAAK,UAAU;GAAE,GAAG;GAA0B,GAAG;EAAQ;EAKzD,KAAK,SAAS,IAAI,UAAU;GAC1B,GAAG;GACH,SAAS,WAAW;GACpB,UAAU,KAAK;EACjB,CAAC;CACH;;;;;;;;;;;;;;;CAgBA,AAAO,MAAM,QAA4C;EACvD,MAAM,WAAgC;GACpC,GAAG;GACH,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;GACnE,SAAS,OAAO,WAAW,KAAK,QAAQ,OAAO;EACjD;EAEA,OAAO,KAAK,OAAO,MAAM,QAAQ;CACnC;;;;;;CAOA,MAAa,MAAM,MAAc,OAAiC;EAChE,OAAO,KAAK,OAAO,MAAM,MAAM,KAAK;CACtC;;;;;;;;;;;CAYA,AAAO,SAAS,QAAkD;EAChE,OAAO,KAAK,OAAO,SAAS,MAAM;CACpC;;;;;;;;;CAUA,AAAO,MAAM,QAAiD;EAC5D,OAAO,KAAK,OAAO,MAAM,MAAM;CACjC;AACF"}
|
package/llms-full.txt
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
name: setup-deepseek
|
|
11
|
-
description: 'Wire @warlock.js/ai-deepseek — new DeepSeekSDK({apiKey, baseURL?, provider?, pricing?}) for DeepSeek''s OpenAI-compatible API, .model({name, reasoning?, vision?, structuredOutput?, responseFormat?}) for ModelContract. Thin wrapper over @warlock.js/ai-openai''s OpenAISDK pinned to https://api.deepseek.com with provider "deepseek"; injects DeepSeek-specific reasoning/vision inference + built-in pricing. Models: deepseek-
|
|
11
|
+
description: 'Wire @warlock.js/ai-deepseek — new DeepSeekSDK({apiKey, baseURL?, provider?, pricing?}) for DeepSeek''s OpenAI-compatible API, .model({name, reasoning?, vision?, structuredOutput?, responseFormat?}) for ModelContract. Thin wrapper over @warlock.js/ai-openai''s OpenAISDK pinned to https://api.deepseek.com with provider "deepseek"; injects DeepSeek-specific reasoning/vision inference + built-in pricing. Models: deepseek-flash / deepseek-v4-flash, deepseek-v4-pro, legacy deepseek-chat / deepseek-reasoner. Built-in peak-rate pricing (DEEPSEEK_DEFAULT_PRICING) and an opt-in off-peak table (DEEPSEEK_OFF_PEAK_PRICING). Triggers: `DeepSeekSDK`, `DEEPSEEK_DEFAULT_PRICING`, `DEEPSEEK_OFF_PEAK_PRICING`, `deepseek-chat`, `deepseek-reasoner`, `deepseek-v4`, `api.deepseek.com`, `DEEPSEEK_API_KEY`, reasoning effort on deepseek; "wire deepseek into a warlock agent", "use deepseek-reasoner", "configure deepseek-chat", "route a warlock agent through deepseek". Skip: OpenAI/Azure/OpenRouter — `@warlock.js/ai-openai`; agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; raw deepseek HTTP / the `openai` SDK directly. Typical import `import { DeepSeekSDK } from "@warlock.js/ai-deepseek"`.'
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# `@warlock.js/ai-deepseek`
|
|
@@ -34,38 +34,38 @@ new DeepSeekSDK({ apiKey, baseURL: "https://my-gateway/deepseek", provider: "dee
|
|
|
34
34
|
## Producing a model
|
|
35
35
|
|
|
36
36
|
```ts
|
|
37
|
-
deepseek.model({ name: "deepseek-chat" })
|
|
38
|
-
deepseek.model({ name: "deepseek-reasoner" })
|
|
39
|
-
deepseek.model({ name: "deepseek-chat", temperature: 0.2 })
|
|
37
|
+
deepseek.model({ name: "deepseek-chat" }); // V3 lineage, non-thinking
|
|
38
|
+
deepseek.model({ name: "deepseek-reasoner" }); // R1 lineage, reasoning-capable
|
|
39
|
+
deepseek.model({ name: "deepseek-chat", temperature: 0.2 });
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
|
|
43
43
|
|
|
44
44
|
## Models
|
|
45
45
|
|
|
46
|
-
| Model
|
|
47
|
-
|
|
|
48
|
-
| `deepseek-chat`
|
|
49
|
-
| `deepseek-reasoner` | Thinking surface (R1 lineage). Emits a reasoning channel. Reasoning **on**.
|
|
50
|
-
| `deepseek-v4-flash` | Newer flash tier. Reasoning **off** by default.
|
|
51
|
-
| `deepseek-v4-pro`
|
|
46
|
+
| Model | Notes |
|
|
47
|
+
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
48
|
+
| `deepseek-chat` | Non-thinking surface (V3 lineage). Fast, cheap, broad coverage. Reasoning **off**. |
|
|
49
|
+
| `deepseek-reasoner` | Thinking surface (R1 lineage). Emits a reasoning channel. Reasoning **on**. |
|
|
50
|
+
| `deepseek-v4-flash` | Newer flash tier. Reasoning **off** by default. |
|
|
51
|
+
| `deepseek-v4-pro` | Newer quality tier. Reasoning **on** by default. |
|
|
52
52
|
|
|
53
53
|
DeepSeek announced the legacy `deepseek-chat` / `deepseek-reasoner` names retire 2026/07/24 in favor of the `deepseek-v4-*` family; both name sets are understood by the capability inference. `deepseek.model({ name })` accepts any id the upstream serves.
|
|
54
54
|
|
|
55
55
|
## Capabilities — what's auto-set
|
|
56
56
|
|
|
57
|
-
| Flag
|
|
58
|
-
|
|
|
59
|
-
| `reasoning`
|
|
60
|
-
| `vision`
|
|
61
|
-
| `structuredOutput` | `true` (inherited from the wrapped OpenAI model), unless `responseFormat` is set to a loose mode.
|
|
62
|
-
| `promptCaching`
|
|
57
|
+
| Flag | Default |
|
|
58
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
59
|
+
| `reasoning` | Inferred from the DeepSeek model name. `true` for `deepseek-reasoner` and the `*-pro` tier; `false` for `deepseek-chat` / `*-flash`. Drives whether the reasoning-effort knob is forwarded. |
|
|
60
|
+
| `vision` | `false` for every DeepSeek model — no DeepSeek chat model documents image input (mid-2026). |
|
|
61
|
+
| `structuredOutput` | `true` (inherited from the wrapped OpenAI model), unless `responseFormat` is set to a loose mode. |
|
|
62
|
+
| `promptCaching` | `true` (inherited). DeepSeek reports cache hits via `usage.cachedTokens`, the same shape as OpenAI. |
|
|
63
63
|
|
|
64
64
|
**Override any flag explicitly** via `.model({ name, reasoning?, vision?, structuredOutput? })` — an explicit value always wins over the injected inference.
|
|
65
65
|
|
|
66
66
|
```ts
|
|
67
|
-
deepseek.model({ name: "deepseek-chat", reasoning: true })
|
|
68
|
-
deepseek.model({ name: "deepseek-reasoner", reasoning: false }) // suppress it
|
|
67
|
+
deepseek.model({ name: "deepseek-chat", reasoning: true }); // force thinking flag
|
|
68
|
+
deepseek.model({ name: "deepseek-reasoner", reasoning: false }); // suppress it
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
## Uses the OpenAI-compatible endpoint
|
|
@@ -75,8 +75,8 @@ Everything on the wire — Chat Completions request/response shape, streaming lo
|
|
|
75
75
|
Structured output, reasoning effort, and streaming therefore behave exactly as documented for the OpenAI adapter:
|
|
76
76
|
|
|
77
77
|
```ts
|
|
78
|
-
const model = deepseek.model({ name: "deepseek-reasoner" });
|
|
79
|
-
await model.complete(messages, { reasoning: { effort: "high" } });
|
|
78
|
+
const model = deepseek.model({ name: "deepseek-reasoner" }); // reasoning auto-true
|
|
79
|
+
await model.complete(messages, { reasoning: { effort: "high" } }); // → reasoning_effort: "high"
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
## Embeddings & images
|
|
@@ -85,21 +85,41 @@ await model.complete(messages, { reasoning: { effort: "high" } }); // → reaso
|
|
|
85
85
|
|
|
86
86
|
## Pricing
|
|
87
87
|
|
|
88
|
-
The adapter ships **built-in DeepSeek pricing defaults** (USD per 1M tokens
|
|
88
|
+
The adapter ships **built-in DeepSeek pricing defaults** (`DEEPSEEK_DEFAULT_PRICING`, USD per 1M tokens; `cachedInput` is the cache-hit rate), so `usage.cost` is computed out of the box — on agent reports and on each `model.complete()` / streaming `done` usage.
|
|
89
|
+
|
|
90
|
+
DeepSeek bills by time of day: peak hours (01:00–04:00 and 06:00–10:00 UTC, Monday to Friday) cost twice the off-peak rate. A flat `ModelPricing` cannot follow the clock, so the defaults are the **peak** rates — an upper bound that keeps USD budgets safe; off-peak calls really cost half. Opt into `DEEPSEEK_OFF_PEAK_PRICING` when you know you run off-peak.
|
|
89
91
|
|
|
90
92
|
```ts
|
|
91
|
-
|
|
93
|
+
import { totalCost } from "@warlock.js/ai";
|
|
94
|
+
import {
|
|
95
|
+
DEEPSEEK_DEFAULT_PRICING,
|
|
96
|
+
DEEPSEEK_OFF_PEAK_PRICING,
|
|
97
|
+
DeepSeekSDK,
|
|
98
|
+
} from "@warlock.js/ai-deepseek";
|
|
99
|
+
|
|
100
|
+
const deepseek = new DeepSeekSDK({ apiKey: process.env.DEEPSEEK_API_KEY ?? "" });
|
|
101
|
+
DEEPSEEK_DEFAULT_PRICING["deepseek-flash"]; // { input: 0.3, output: 1.2, cachedInput: 0.006 } — peak
|
|
102
|
+
|
|
103
|
+
const offPeak = new DeepSeekSDK({
|
|
104
|
+
apiKey: process.env.DEEPSEEK_API_KEY ?? "",
|
|
105
|
+
pricing: DEEPSEEK_OFF_PEAK_PRICING, // { input: 0.15, output: 0.6, cachedInput: 0.003 } for flash
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const { usage } = await offPeak
|
|
109
|
+
.model({ name: "deepseek-v4-pro" })
|
|
110
|
+
.complete([{ role: "user", content: "hi" }]);
|
|
111
|
+
console.log(usage.cachedTokens, totalCost(usage.cost));
|
|
92
112
|
```
|
|
93
113
|
|
|
94
|
-
|
|
114
|
+
Resolution at `model()` time: per-model `pricing` > SDK `pricing` registry > built-in DeepSeek default > `undefined`.
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
116
|
+
- **Source.** https://api-docs.deepseek.com/quick_start/pricing, fetched 2026-10-17. Covered: `deepseek-flash`, `deepseek-v4-flash` (its legacy name, same rate) and `deepseek-v4-pro`.
|
|
117
|
+
- **Unpriced:** `deepseek-chat` / `deepseek-reasoner` are gone from the price list (announced for discontinuation on 2026-07-24) — pass `pricing` if a gateway still serves them.
|
|
118
|
+
- **Usage semantics.** DeepSeek's `prompt_tokens` equals cache hits + misses and `prompt_tokens_details.cached_tokens` mirrors `prompt_cache_hit_tokens`, so the usage is `inputIncludesCache: true` and hits bill at `cachedInput`. DeepSeek caches automatically on disk and takes no request hint, so `promptCacheKey` is never sent.
|
|
99
119
|
|
|
100
120
|
## Errors
|
|
101
121
|
|
|
102
|
-
Raw errors surface through the wrapped OpenAI adapter's wrapper into the typed `@warlock.js/ai` `AIError` hierarchy — see the `handle-ai-errors` topic of the `warlock-js-ai` skill.
|
|
122
|
+
Raw errors surface through the wrapped OpenAI adapter's wrapper into the typed `@warlock.js/ai` `AIError` hierarchy — see the `handle-ai-errors` topic of the `warlock-js-ai` skill. DeepSeek documents 503 as "Server Overloaded" (https://api-docs.deepseek.com/quick_start/error_codes); it maps to `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`). Every wrapped error carries `status`, `retryable` and `billed` (`false` for 401 / 402 / 403, otherwise `"unknown"`).
|
|
103
123
|
|
|
104
124
|
## When NOT to use this skill
|
|
105
125
|
|
|
@@ -113,4 +133,18 @@ Raw errors surface through the wrapped OpenAI adapter's wrapper into the typed `
|
|
|
113
133
|
- The `run-ai-agent` topic of the `warlock-js-ai` skill — passing the model into `ai.agent({...})`.
|
|
114
134
|
- The `pick-ai-provider` topic of the `warlock-js-ai` skill — adapter comparison.
|
|
115
135
|
|
|
136
|
+
## Provider body options and token estimates
|
|
137
|
+
|
|
138
|
+
This adapter delegates Chat Completions to the OpenAI adapter, so
|
|
139
|
+
`providerOptions.openai.body` adds native Chat request fields. Other provider
|
|
140
|
+
keys are ignored. Plain-object fields merge one level deep with neutral options;
|
|
141
|
+
caller-provided keys win, while arrays, scalars and `null` replace the field.
|
|
142
|
+
The OpenAI adapter's protected conversation, tool and transport fields remain
|
|
143
|
+
protected here too. Send only fields supported by this provider; do not reuse
|
|
144
|
+
OpenAI-only bodies across a mixed-provider fallback chain.
|
|
145
|
+
|
|
146
|
+
Models from this adapter have no native `countTokens` method. Check
|
|
147
|
+
`model.countTokens` before using an optional native counting capability;
|
|
148
|
+
`sdk.count(text)` is a separate offline estimate.
|
|
149
|
+
|
|
116
150
|
|
package/llms.txt
CHANGED
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
|
|
7
7
|
## Skills
|
|
8
8
|
|
|
9
|
-
- [setup-deepseek](@warlock.js/ai-deepseek/setup-deepseek/SKILL.md): Wire @warlock.js/ai-deepseek — new DeepSeekSDK({apiKey, baseURL?, provider?, pricing?}) for DeepSeek's OpenAI-compatible API, .model({name, reasoning?, vision?, structuredOutput?, responseFormat?}) for ModelContract. Thin wrapper over @warlock.js/ai-openai's OpenAISDK pinned to https://api.deepseek.com with provider "deepseek"; injects DeepSeek-specific reasoning/vision inference + built-in pricing. Models: deepseek-
|
|
9
|
+
- [setup-deepseek](@warlock.js/ai-deepseek/setup-deepseek/SKILL.md): Wire @warlock.js/ai-deepseek — new DeepSeekSDK({apiKey, baseURL?, provider?, pricing?}) for DeepSeek's OpenAI-compatible API, .model({name, reasoning?, vision?, structuredOutput?, responseFormat?}) for ModelContract. Thin wrapper over @warlock.js/ai-openai's OpenAISDK pinned to https://api.deepseek.com with provider "deepseek"; injects DeepSeek-specific reasoning/vision inference + built-in pricing. Models: deepseek-flash / deepseek-v4-flash, deepseek-v4-pro, legacy deepseek-chat / deepseek-reasoner. Built-in peak-rate pricing (DEEPSEEK_DEFAULT_PRICING) and an opt-in off-peak table (DEEPSEEK_OFF_PEAK_PRICING). Triggers: `DeepSeekSDK`, `DEEPSEEK_DEFAULT_PRICING`, `DEEPSEEK_OFF_PEAK_PRICING`, `deepseek-chat`, `deepseek-reasoner`, `deepseek-v4`, `api.deepseek.com`, `DEEPSEEK_API_KEY`, reasoning effort on deepseek; "wire deepseek into a warlock agent", "use deepseek-reasoner", "configure deepseek-chat", "route a warlock agent through deepseek". Skip: OpenAI/Azure/OpenRouter — `@warlock.js/ai-openai`; agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; raw deepseek HTTP / the `openai` SDK directly. Typical import `import { DeepSeekSDK } from "@warlock.js/ai-deepseek"`.
|
package/package.json
CHANGED
|
@@ -10,16 +10,17 @@
|
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "https://github.com/warlockjs/
|
|
13
|
+
"url": "git+https://github.com/warlockjs/framework.git",
|
|
14
|
+
"directory": "packages/ai-deepseek"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
|
-
"@warlock.js/ai-openai": "5.
|
|
17
|
-
"@warlock.js/logger": "5.
|
|
17
|
+
"@warlock.js/ai-openai": "5.31.0",
|
|
18
|
+
"@warlock.js/logger": "5.31.0"
|
|
18
19
|
},
|
|
19
20
|
"peerDependencies": {
|
|
20
|
-
"@warlock.js/ai": "5.
|
|
21
|
+
"@warlock.js/ai": "5.31.0"
|
|
21
22
|
},
|
|
22
|
-
"version": "5.
|
|
23
|
+
"version": "5.31.0",
|
|
23
24
|
"main": "./cjs/index.cjs",
|
|
24
25
|
"module": "./esm/index.mjs",
|
|
25
26
|
"types": "./esm/index.d.mts",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-deepseek
|
|
3
|
-
description: 'Wire @warlock.js/ai-deepseek — new DeepSeekSDK({apiKey, baseURL?, provider?, pricing?}) for DeepSeek''s OpenAI-compatible API, .model({name, reasoning?, vision?, structuredOutput?, responseFormat?}) for ModelContract. Thin wrapper over @warlock.js/ai-openai''s OpenAISDK pinned to https://api.deepseek.com with provider "deepseek"; injects DeepSeek-specific reasoning/vision inference + built-in pricing. Models: deepseek-
|
|
3
|
+
description: 'Wire @warlock.js/ai-deepseek — new DeepSeekSDK({apiKey, baseURL?, provider?, pricing?}) for DeepSeek''s OpenAI-compatible API, .model({name, reasoning?, vision?, structuredOutput?, responseFormat?}) for ModelContract. Thin wrapper over @warlock.js/ai-openai''s OpenAISDK pinned to https://api.deepseek.com with provider "deepseek"; injects DeepSeek-specific reasoning/vision inference + built-in pricing. Models: deepseek-flash / deepseek-v4-flash, deepseek-v4-pro, legacy deepseek-chat / deepseek-reasoner. Built-in peak-rate pricing (DEEPSEEK_DEFAULT_PRICING) and an opt-in off-peak table (DEEPSEEK_OFF_PEAK_PRICING). Triggers: `DeepSeekSDK`, `DEEPSEEK_DEFAULT_PRICING`, `DEEPSEEK_OFF_PEAK_PRICING`, `deepseek-chat`, `deepseek-reasoner`, `deepseek-v4`, `api.deepseek.com`, `DEEPSEEK_API_KEY`, reasoning effort on deepseek; "wire deepseek into a warlock agent", "use deepseek-reasoner", "configure deepseek-chat", "route a warlock agent through deepseek". Skip: OpenAI/Azure/OpenRouter — `@warlock.js/ai-openai`; agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; raw deepseek HTTP / the `openai` SDK directly. Typical import `import { DeepSeekSDK } from "@warlock.js/ai-deepseek"`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `@warlock.js/ai-deepseek`
|
|
@@ -26,38 +26,38 @@ new DeepSeekSDK({ apiKey, baseURL: "https://my-gateway/deepseek", provider: "dee
|
|
|
26
26
|
## Producing a model
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
|
-
deepseek.model({ name: "deepseek-chat" })
|
|
30
|
-
deepseek.model({ name: "deepseek-reasoner" })
|
|
31
|
-
deepseek.model({ name: "deepseek-chat", temperature: 0.2 })
|
|
29
|
+
deepseek.model({ name: "deepseek-chat" }); // V3 lineage, non-thinking
|
|
30
|
+
deepseek.model({ name: "deepseek-reasoner" }); // R1 lineage, reasoning-capable
|
|
31
|
+
deepseek.model({ name: "deepseek-chat", temperature: 0.2 });
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
|
|
35
35
|
|
|
36
36
|
## Models
|
|
37
37
|
|
|
38
|
-
| Model
|
|
39
|
-
|
|
|
40
|
-
| `deepseek-chat`
|
|
41
|
-
| `deepseek-reasoner` | Thinking surface (R1 lineage). Emits a reasoning channel. Reasoning **on**.
|
|
42
|
-
| `deepseek-v4-flash` | Newer flash tier. Reasoning **off** by default.
|
|
43
|
-
| `deepseek-v4-pro`
|
|
38
|
+
| Model | Notes |
|
|
39
|
+
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
40
|
+
| `deepseek-chat` | Non-thinking surface (V3 lineage). Fast, cheap, broad coverage. Reasoning **off**. |
|
|
41
|
+
| `deepseek-reasoner` | Thinking surface (R1 lineage). Emits a reasoning channel. Reasoning **on**. |
|
|
42
|
+
| `deepseek-v4-flash` | Newer flash tier. Reasoning **off** by default. |
|
|
43
|
+
| `deepseek-v4-pro` | Newer quality tier. Reasoning **on** by default. |
|
|
44
44
|
|
|
45
45
|
DeepSeek announced the legacy `deepseek-chat` / `deepseek-reasoner` names retire 2026/07/24 in favor of the `deepseek-v4-*` family; both name sets are understood by the capability inference. `deepseek.model({ name })` accepts any id the upstream serves.
|
|
46
46
|
|
|
47
47
|
## Capabilities — what's auto-set
|
|
48
48
|
|
|
49
|
-
| Flag
|
|
50
|
-
|
|
|
51
|
-
| `reasoning`
|
|
52
|
-
| `vision`
|
|
53
|
-
| `structuredOutput` | `true` (inherited from the wrapped OpenAI model), unless `responseFormat` is set to a loose mode.
|
|
54
|
-
| `promptCaching`
|
|
49
|
+
| Flag | Default |
|
|
50
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| `reasoning` | Inferred from the DeepSeek model name. `true` for `deepseek-reasoner` and the `*-pro` tier; `false` for `deepseek-chat` / `*-flash`. Drives whether the reasoning-effort knob is forwarded. |
|
|
52
|
+
| `vision` | `false` for every DeepSeek model — no DeepSeek chat model documents image input (mid-2026). |
|
|
53
|
+
| `structuredOutput` | `true` (inherited from the wrapped OpenAI model), unless `responseFormat` is set to a loose mode. |
|
|
54
|
+
| `promptCaching` | `true` (inherited). DeepSeek reports cache hits via `usage.cachedTokens`, the same shape as OpenAI. |
|
|
55
55
|
|
|
56
56
|
**Override any flag explicitly** via `.model({ name, reasoning?, vision?, structuredOutput? })` — an explicit value always wins over the injected inference.
|
|
57
57
|
|
|
58
58
|
```ts
|
|
59
|
-
deepseek.model({ name: "deepseek-chat", reasoning: true })
|
|
60
|
-
deepseek.model({ name: "deepseek-reasoner", reasoning: false }) // suppress it
|
|
59
|
+
deepseek.model({ name: "deepseek-chat", reasoning: true }); // force thinking flag
|
|
60
|
+
deepseek.model({ name: "deepseek-reasoner", reasoning: false }); // suppress it
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
## Uses the OpenAI-compatible endpoint
|
|
@@ -67,8 +67,8 @@ Everything on the wire — Chat Completions request/response shape, streaming lo
|
|
|
67
67
|
Structured output, reasoning effort, and streaming therefore behave exactly as documented for the OpenAI adapter:
|
|
68
68
|
|
|
69
69
|
```ts
|
|
70
|
-
const model = deepseek.model({ name: "deepseek-reasoner" });
|
|
71
|
-
await model.complete(messages, { reasoning: { effort: "high" } });
|
|
70
|
+
const model = deepseek.model({ name: "deepseek-reasoner" }); // reasoning auto-true
|
|
71
|
+
await model.complete(messages, { reasoning: { effort: "high" } }); // → reasoning_effort: "high"
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
## Embeddings & images
|
|
@@ -77,21 +77,41 @@ await model.complete(messages, { reasoning: { effort: "high" } }); // → reaso
|
|
|
77
77
|
|
|
78
78
|
## Pricing
|
|
79
79
|
|
|
80
|
-
The adapter ships **built-in DeepSeek pricing defaults** (USD per 1M tokens
|
|
80
|
+
The adapter ships **built-in DeepSeek pricing defaults** (`DEEPSEEK_DEFAULT_PRICING`, USD per 1M tokens; `cachedInput` is the cache-hit rate), so `usage.cost` is computed out of the box — on agent reports and on each `model.complete()` / streaming `done` usage.
|
|
81
|
+
|
|
82
|
+
DeepSeek bills by time of day: peak hours (01:00–04:00 and 06:00–10:00 UTC, Monday to Friday) cost twice the off-peak rate. A flat `ModelPricing` cannot follow the clock, so the defaults are the **peak** rates — an upper bound that keeps USD budgets safe; off-peak calls really cost half. Opt into `DEEPSEEK_OFF_PEAK_PRICING` when you know you run off-peak.
|
|
81
83
|
|
|
82
84
|
```ts
|
|
83
|
-
|
|
85
|
+
import { totalCost } from "@warlock.js/ai";
|
|
86
|
+
import {
|
|
87
|
+
DEEPSEEK_DEFAULT_PRICING,
|
|
88
|
+
DEEPSEEK_OFF_PEAK_PRICING,
|
|
89
|
+
DeepSeekSDK,
|
|
90
|
+
} from "@warlock.js/ai-deepseek";
|
|
91
|
+
|
|
92
|
+
const deepseek = new DeepSeekSDK({ apiKey: process.env.DEEPSEEK_API_KEY ?? "" });
|
|
93
|
+
DEEPSEEK_DEFAULT_PRICING["deepseek-flash"]; // { input: 0.3, output: 1.2, cachedInput: 0.006 } — peak
|
|
94
|
+
|
|
95
|
+
const offPeak = new DeepSeekSDK({
|
|
96
|
+
apiKey: process.env.DEEPSEEK_API_KEY ?? "",
|
|
97
|
+
pricing: DEEPSEEK_OFF_PEAK_PRICING, // { input: 0.15, output: 0.6, cachedInput: 0.003 } for flash
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const { usage } = await offPeak
|
|
101
|
+
.model({ name: "deepseek-v4-pro" })
|
|
102
|
+
.complete([{ role: "user", content: "hi" }]);
|
|
103
|
+
console.log(usage.cachedTokens, totalCost(usage.cost));
|
|
84
104
|
```
|
|
85
105
|
|
|
86
|
-
|
|
106
|
+
Resolution at `model()` time: per-model `pricing` > SDK `pricing` registry > built-in DeepSeek default > `undefined`.
|
|
87
107
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
108
|
+
- **Source.** https://api-docs.deepseek.com/quick_start/pricing, fetched 2026-10-17. Covered: `deepseek-flash`, `deepseek-v4-flash` (its legacy name, same rate) and `deepseek-v4-pro`.
|
|
109
|
+
- **Unpriced:** `deepseek-chat` / `deepseek-reasoner` are gone from the price list (announced for discontinuation on 2026-07-24) — pass `pricing` if a gateway still serves them.
|
|
110
|
+
- **Usage semantics.** DeepSeek's `prompt_tokens` equals cache hits + misses and `prompt_tokens_details.cached_tokens` mirrors `prompt_cache_hit_tokens`, so the usage is `inputIncludesCache: true` and hits bill at `cachedInput`. DeepSeek caches automatically on disk and takes no request hint, so `promptCacheKey` is never sent.
|
|
91
111
|
|
|
92
112
|
## Errors
|
|
93
113
|
|
|
94
|
-
Raw errors surface through the wrapped OpenAI adapter's wrapper into the typed `@warlock.js/ai` `AIError` hierarchy — see the `handle-ai-errors` topic of the `warlock-js-ai` skill.
|
|
114
|
+
Raw errors surface through the wrapped OpenAI adapter's wrapper into the typed `@warlock.js/ai` `AIError` hierarchy — see the `handle-ai-errors` topic of the `warlock-js-ai` skill. DeepSeek documents 503 as "Server Overloaded" (https://api-docs.deepseek.com/quick_start/error_codes); it maps to `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`). Every wrapped error carries `status`, `retryable` and `billed` (`false` for 401 / 402 / 403, otherwise `"unknown"`).
|
|
95
115
|
|
|
96
116
|
## When NOT to use this skill
|
|
97
117
|
|
|
@@ -104,3 +124,17 @@ Raw errors surface through the wrapped OpenAI adapter's wrapper into the typed `
|
|
|
104
124
|
- The `setup-openai` topic of the `warlock-js-ai-openai` skill — the wrapped adapter; all wire-level behavior.
|
|
105
125
|
- The `run-ai-agent` topic of the `warlock-js-ai` skill — passing the model into `ai.agent({...})`.
|
|
106
126
|
- The `pick-ai-provider` topic of the `warlock-js-ai` skill — adapter comparison.
|
|
127
|
+
|
|
128
|
+
## Provider body options and token estimates
|
|
129
|
+
|
|
130
|
+
This adapter delegates Chat Completions to the OpenAI adapter, so
|
|
131
|
+
`providerOptions.openai.body` adds native Chat request fields. Other provider
|
|
132
|
+
keys are ignored. Plain-object fields merge one level deep with neutral options;
|
|
133
|
+
caller-provided keys win, while arrays, scalars and `null` replace the field.
|
|
134
|
+
The OpenAI adapter's protected conversation, tool and transport fields remain
|
|
135
|
+
protected here too. Send only fields supported by this provider; do not reuse
|
|
136
|
+
OpenAI-only bodies across a mixed-provider fallback chain.
|
|
137
|
+
|
|
138
|
+
Models from this adapter have no native `countTokens` method. Check
|
|
139
|
+
`model.countTokens` before using an optional native counting capability;
|
|
140
|
+
`sdk.count(text)` is a separate offline estimate.
|