@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 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 }); // force the thinking flag
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" }); // reasoning auto-true
83
- await model.complete(messages, { reasoning: { effort: "high" } }); // → 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 ../ai-deepseek/src/known-models.ts
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 ../ai-deepseek/src/sdk.ts
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. Sourced from DeepSeek's official pricing table
114
- * (mid-2026); `cachedInput` is the cache-hit input rate. A caller-supplied
115
- * SDK `pricing` registry, or a per-model `pricing`, overrides any entry
116
- * here. Update when DeepSeek revises its published rates.
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-chat": {
120
- input: .14,
121
- output: .28,
122
- cachedInput: .0028
131
+ "deepseek-flash": {
132
+ input: .3,
133
+ output: 1.2,
134
+ cachedInput: .006
123
135
  },
124
- "deepseek-reasoner": {
125
- input: .14,
126
- output: .28,
127
- cachedInput: .0028
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: .14,
131
- output: .28,
132
- cachedInput: .0028
161
+ input: .15,
162
+ output: .6,
163
+ cachedInput: .003
133
164
  },
134
165
  "deepseek-v4-pro": {
135
- input: .435,
136
- output: .87,
137
- cachedInput: .003625
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"}
@@ -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 ../ai-deepseek/src/config.type.d.ts
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":["../../../../../../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"}
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 };
@@ -1,4 +1,4 @@
1
- //#region ../ai-deepseek/src/known-models.d.ts
1
+ //#region ../../packages/ai-deepseek/src/known-models.d.ts
2
2
  /**
3
3
  * Capability inference for DeepSeek chat model ids.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"known-models.d.mts","names":[],"sources":["../../../../../../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"}
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"}
@@ -1,4 +1,4 @@
1
- //#region ../ai-deepseek/src/known-models.ts
1
+ //#region ../../packages/ai-deepseek/src/known-models.ts
2
2
  /**
3
3
  * Capability inference for DeepSeek chat model ids.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"known-models.mjs","names":[],"sources":["../../../../../../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"}
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 ../ai-deepseek/src/sdk.d.ts
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":["../../../../../../ai-deepseek/src/sdk.ts"],"mappings":";;;;;;AA8EA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,WAAA,YAAuB,kBAAA;EA+E2B;EAAA,iBA7E5C,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"}
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 ../ai-deepseek/src/sdk.ts
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. Sourced from DeepSeek's official pricing table
15
- * (mid-2026); `cachedInput` is the cache-hit input rate. A caller-supplied
16
- * SDK `pricing` registry, or a per-model `pricing`, overrides any entry
17
- * here. Update when DeepSeek revises its published rates.
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-chat": {
21
- input: .14,
22
- output: .28,
23
- cachedInput: .0028
32
+ "deepseek-flash": {
33
+ input: .3,
34
+ output: 1.2,
35
+ cachedInput: .006
24
36
  },
25
- "deepseek-reasoner": {
26
- input: .14,
27
- output: .28,
28
- cachedInput: .0028
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: .14,
32
- output: .28,
33
- cachedInput: .0028
62
+ input: .15,
63
+ output: .6,
64
+ cachedInput: .003
34
65
  },
35
66
  "deepseek-v4-pro": {
36
- input: .435,
37
- output: .87,
38
- cachedInput: .003625
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":["../../../../../../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. 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":";;;;;;;;AAoBA,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,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"}
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-chat (non-thinking), deepseek-reasoner (thinking/reasoning), deepseek-v4-flash, deepseek-v4-pro. Triggers: `DeepSeekSDK`, `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"`.'
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" }) // V3 lineage, non-thinking
38
- deepseek.model({ name: "deepseek-reasoner" }) // R1 lineage, reasoning-capable
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 | 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. |
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 | 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. |
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 }) // force thinking flag
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" }); // reasoning auto-true
79
- await model.complete(messages, { reasoning: { effort: "high" } }); // → 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, from DeepSeek's published table), so `usage.cost` is computed out of the box:
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
- const deepseek = new DeepSeekSDK({ apiKey }); // deepseek-chat → { input: 0.14, output: 0.28, cachedInput: 0.0028 }
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
- Override per model or per SDK exactly like the OpenAI adapter. Resolution at `model()` time: per-model `pricing` > SDK `pricing` registry > built-in DeepSeek default > `undefined`.
114
+ Resolution at `model()` time: per-model `pricing` > SDK `pricing` registry > built-in DeepSeek default > `undefined`.
95
115
 
96
- ```ts
97
- new DeepSeekSDK({ apiKey, pricing: { "deepseek-reasoner": { input: 0.55, output: 2.19 } } });
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-chat (non-thinking), deepseek-reasoner (thinking/reasoning), deepseek-v4-flash, deepseek-v4-pro. Triggers: `DeepSeekSDK`, `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"`.
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/ai-deepseek"
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.29.0",
17
- "@warlock.js/logger": "5.29.0"
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.29.0"
21
+ "@warlock.js/ai": "5.31.0"
21
22
  },
22
- "version": "5.29.0",
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-chat (non-thinking), deepseek-reasoner (thinking/reasoning), deepseek-v4-flash, deepseek-v4-pro. Triggers: `DeepSeekSDK`, `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"`.'
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" }) // V3 lineage, non-thinking
30
- deepseek.model({ name: "deepseek-reasoner" }) // R1 lineage, reasoning-capable
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 | 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. |
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 | 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. |
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 }) // force thinking flag
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" }); // reasoning auto-true
71
- await model.complete(messages, { reasoning: { effort: "high" } }); // → 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, from DeepSeek's published table), so `usage.cost` is computed out of the box:
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
- const deepseek = new DeepSeekSDK({ apiKey }); // deepseek-chat → { input: 0.14, output: 0.28, cachedInput: 0.0028 }
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
- Override per model or per SDK exactly like the OpenAI adapter. Resolution at `model()` time: per-model `pricing` > SDK `pricing` registry > built-in DeepSeek default > `undefined`.
106
+ Resolution at `model()` time: per-model `pricing` > SDK `pricing` registry > built-in DeepSeek default > `undefined`.
87
107
 
88
- ```ts
89
- new DeepSeekSDK({ apiKey, pricing: { "deepseek-reasoner": { input: 0.55, output: 2.19 } } });
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.