@molecule/api-ai-deepseek 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +70 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -3,17 +3,17 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-10-
|
|
6
|
+
Generated: 2026-10-16T23:28:16.072Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-ai-deepseek
|
|
10
10
|
|
|
11
|
+
DeepSeek AI provider for molecule.dev.
|
|
12
|
+
|
|
11
13
|
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
12
14
|
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
13
15
|
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
14
16
|
|
|
15
|
-
DeepSeek AI provider for molecule.dev.
|
|
16
|
-
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
19
|
```typescript
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EACV,UAAU,EAIV,SAAS,EAET,UAAU,EAGX,MAAM,kBAAkB,CAAA;AASzB,OAAO,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAsGhD,8DAA8D;AAC9D,eAAO,MAAM,8BAA8B,QAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EACV,UAAU,EAIV,SAAS,EAET,UAAU,EAGX,MAAM,kBAAkB,CAAA;AASzB,OAAO,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAsGhD,8DAA8D;AAC9D,eAAO,MAAM,8BAA8B,QAAS,CAAA;AAgGpD;;;;GAIG;AACH,cAAM,sBAAuB,YAAW,UAAU;IAChD,QAAQ,CAAC,IAAI,cAAa;IAC1B,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,WAAW,CAAC,CAAqB;IACzC,OAAO,CAAC,aAAa,CAAC,CAAuB;IAC7C,OAAO,CAAC,mBAAmB,CAAQ;IACnC,OAAO,CAAC,sBAAsB,CAAQ;gBAE1B,MAAM,GAAE,cAAmB;IAwBvC;;;;;OAKG;IACI,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC;IAiRzD;;;;;;;;;OASG;YACW,2BAA2B;IA0EzC;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB;IA2BzB;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc;IAgFtB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IAWnB;;;;;OAKG;IACH,OAAO,CAAE,yBAAyB;IAuDlC;;;;;;;;;;;;OAYG;YACY,sBAAsB;IA2GrC;;;;;;;;;;OAUG;IACH,OAAO,CAAE,eAAe;CA0LzB;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,+BAAyB,CAAA;AAExD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,UAAU,CAElE"}
|
package/dist/provider.js
CHANGED
|
@@ -33,6 +33,12 @@ export const DEFAULT_FIRST_TOKEN_TIMEOUT_MS = 45_000;
|
|
|
33
33
|
const DEFAULT_STREAM_SILENCE_TIMEOUT_MS = 60_000;
|
|
34
34
|
/** Node's `setTimeout` ceiling: a larger delay is clamped to 1 ms, i.e. instant. */
|
|
35
35
|
const MAX_TIMER_MS = 2_147_483_647;
|
|
36
|
+
/**
|
|
37
|
+
* How many stop sequences DeepSeek accepts in one request ("Up to 16 sequences
|
|
38
|
+
* where the API will stop generating further tokens", create-chat-completion).
|
|
39
|
+
* A longer list is sent truncated rather than refused by the API.
|
|
40
|
+
*/
|
|
41
|
+
const MAX_STOP_SEQUENCES = 16;
|
|
36
42
|
/**
|
|
37
43
|
* Resolve a stream bound from the config, then the environment, then the
|
|
38
44
|
* default. A value that is not a positive finite number is IGNORED rather than
|
|
@@ -144,6 +150,16 @@ class DeepseekAIProviderImpl {
|
|
|
144
150
|
const model = this.modelMap[canonicalModel] ?? canonicalModel;
|
|
145
151
|
const maxTokens = params.maxTokens ?? this.maxTokens;
|
|
146
152
|
const messages = this.formatMessages(params.messages, params.system);
|
|
153
|
+
// Stop sequences, capped at the API's own limit. Verified honoured by the
|
|
154
|
+
// native endpoint on 2026-10-17: with `stop: ['<analysis>']` a reply that
|
|
155
|
+
// would have opened with that tag streamed nothing at all, and one that
|
|
156
|
+
// reached it mid-answer ended there with the tag dropped from the text.
|
|
157
|
+
const stop = (params.stop ?? []).filter((s) => s.length > 0).slice(0, MAX_STOP_SEQUENCES);
|
|
158
|
+
if ((params.stop?.length ?? 0) > MAX_STOP_SEQUENCES) {
|
|
159
|
+
logger.warn('DeepSeek takes at most 16 stop sequences — the rest were dropped', {
|
|
160
|
+
requested: params.stop?.length,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
147
163
|
const body = {
|
|
148
164
|
// Abuse attribution (see ChatParams.endUserId): OpenAI-compatible APIs
|
|
149
165
|
// scope enforcement by `user`, so an abusive tenant can be actioned
|
|
@@ -157,6 +173,7 @@ class DeepseekAIProviderImpl {
|
|
|
157
173
|
messages,
|
|
158
174
|
stream: params.stream !== false,
|
|
159
175
|
...(params.stream !== false ? { stream_options: { include_usage: true } } : {}),
|
|
176
|
+
...(stop.length > 0 ? { stop } : {}),
|
|
160
177
|
};
|
|
161
178
|
// Tools: merge custom tools (function format) and server tools
|
|
162
179
|
const functions = params.tools?.length ? this.formatTools(params.tools) : [];
|
|
@@ -281,18 +298,44 @@ class DeepseekAIProviderImpl {
|
|
|
281
298
|
detail = errorBody;
|
|
282
299
|
}
|
|
283
300
|
logger.error('DeepSeek API error', { status: response.status, detail, errorBody });
|
|
301
|
+
// The status ladder decides what the CALLER can do, so every branch
|
|
302
|
+
// must stay distinguishable downstream: the turn classifier keys on
|
|
303
|
+
// these sentences, and an exhausted account must never read as
|
|
304
|
+
// "try again" (2026-10-20: a −$0.09 DeepSeek account answered 402 on
|
|
305
|
+
// every request and each one surfaced as the generic error — sixteen
|
|
306
|
+
// benchmark runs died at their first request, indistinguishable from
|
|
307
|
+
// an outage and each given a retry that could never succeed).
|
|
284
308
|
const clientMessage = response.status === 429
|
|
285
309
|
? 'AI rate limit exceeded. Please try again shortly.'
|
|
286
310
|
: response.status === 401
|
|
287
|
-
?
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
311
|
+
? // The status rides in the text: the turn classifier is
|
|
312
|
+
// text-only, and an auth failure must classify `auth`
|
|
313
|
+
// (never retried) — not the unknown bucket's pity retry.
|
|
314
|
+
'AI service configuration error (HTTP 401) — the API key was rejected.'
|
|
315
|
+
: response.status === 402 ||
|
|
316
|
+
/insufficient balance|credit balance|payment required/i.test(detail)
|
|
317
|
+
? // An exhausted account is a platform billing condition, not a
|
|
318
|
+
// request problem and not a transient outage — no retry can
|
|
319
|
+
// restore a negative balance.
|
|
320
|
+
'AI service is unavailable — provider credit balance too low.'
|
|
321
|
+
: response.status === 400 &&
|
|
322
|
+
/prompt is too long|too many tokens|token.*limit|context.*length/i.test(detail)
|
|
323
|
+
? "Conversation too long for the model's context window. Use /compact to free space, or start a new conversation."
|
|
324
|
+
: response.status === 400
|
|
325
|
+
? 'AI request was invalid — check the model and request parameters.'
|
|
326
|
+
: response.status === 500 ||
|
|
327
|
+
response.status === 502 ||
|
|
328
|
+
response.status === 503 ||
|
|
329
|
+
response.status === 504 ||
|
|
330
|
+
response.status === 529
|
|
331
|
+
? // The outage statuses the turn classifier reads as transient —
|
|
332
|
+
// one shared sentence, so a provider shed rides the retry
|
|
333
|
+
// ladder instead of killing the turn (was: 503 only).
|
|
334
|
+
'AI service is temporarily overloaded. Please try again in a moment.'
|
|
335
|
+
: // Anything else still names its status, so a never-before-seen
|
|
336
|
+
// code is classifiable (and 5xx-shaped ones ride `http 5xx`
|
|
337
|
+
// into the transient class) instead of a bare "try again".
|
|
338
|
+
`AI service error (HTTP ${response.status}). Please try again.`;
|
|
296
339
|
yield { type: 'error', message: clientMessage, errorKey: 'ai.error.apiError' };
|
|
297
340
|
return;
|
|
298
341
|
}
|
|
@@ -804,11 +847,24 @@ class DeepseekAIProviderImpl {
|
|
|
804
847
|
code: streamError.code,
|
|
805
848
|
message: streamError.message,
|
|
806
849
|
});
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
850
|
+
// Same distinctions as the pre-flight ladder, in the same precedence
|
|
851
|
+
// the turn classifier applies (rate → auth → context → balance →
|
|
852
|
+
// transient): an exhausted account is a billing state (never
|
|
853
|
+
// transient, never "try again"), an auth failure stays `auth`, a
|
|
854
|
+
// context overflow stays recoverable. There is no HTTP status here —
|
|
855
|
+
// the stream answered 200 — so each class keys on the provider's own
|
|
856
|
+
// wording, plus numeric codes some hosts send as `code`.
|
|
857
|
+
const clientMessage = /rate.?limit|\b429\b|quota/i.test(detail)
|
|
858
|
+
? 'AI rate limit exceeded. Please try again shortly.'
|
|
859
|
+
: /\b401\b|authentication|unauthorized/i.test(detail)
|
|
860
|
+
? 'AI service authentication/configuration error — the API key was rejected.'
|
|
861
|
+
: /context.?length|context.?window|too long|too many tokens|token.?limit/i.test(detail)
|
|
862
|
+
? "Conversation too long for the model's context window. Use /compact to free space, or start a new conversation."
|
|
863
|
+
: /insufficient balance|credit balance|payment required|\b402\b/i.test(detail)
|
|
864
|
+
? 'AI service is unavailable — provider credit balance too low.'
|
|
865
|
+
: /overload|capacity|\b(?:500|502|503|504|529)\b/i.test(detail)
|
|
866
|
+
? 'AI service is temporarily overloaded. Please try again in a moment.'
|
|
867
|
+
: 'AI service error. Please try again.';
|
|
812
868
|
yield { type: 'error', message: clientMessage, errorKey: 'ai.error.apiError' };
|
|
813
869
|
continue;
|
|
814
870
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molecule/api-ai-deepseek",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "DeepSeek AI provider for molecule.dev",
|
|
5
5
|
"homepage": "https://www.molecule.dev/packages/api-ai-deepseek",
|
|
6
6
|
"type": "module",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"directory": "packages/api/bonds/ai/deepseek"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@molecule/api-ai": "1.3.
|
|
36
|
+
"@molecule/api-ai": "1.3.4",
|
|
37
37
|
"@molecule/api-bond": "1.0.2",
|
|
38
38
|
"@types/node": "26.1.2",
|
|
39
39
|
"typescript": "6.0.3",
|