@arikusi/deepseek-mcp-server 1.2.0 → 1.3.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +79 -8
  3. package/dist/circuit-breaker.d.ts +37 -0
  4. package/dist/circuit-breaker.d.ts.map +1 -0
  5. package/dist/circuit-breaker.js +101 -0
  6. package/dist/circuit-breaker.js.map +1 -0
  7. package/dist/config.d.ts +9 -0
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +10 -0
  10. package/dist/config.js.map +1 -1
  11. package/dist/deepseek-client.d.ts +23 -5
  12. package/dist/deepseek-client.d.ts.map +1 -1
  13. package/dist/deepseek-client.js +221 -119
  14. package/dist/deepseek-client.js.map +1 -1
  15. package/dist/errors.d.ts +13 -0
  16. package/dist/errors.d.ts.map +1 -1
  17. package/dist/errors.js +18 -0
  18. package/dist/errors.js.map +1 -1
  19. package/dist/index.js +5 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/resources/config.d.ts +7 -0
  22. package/dist/resources/config.d.ts.map +1 -0
  23. package/dist/resources/config.js +44 -0
  24. package/dist/resources/config.js.map +1 -0
  25. package/dist/resources/index.d.ts +7 -0
  26. package/dist/resources/index.d.ts.map +1 -0
  27. package/dist/resources/index.js +13 -0
  28. package/dist/resources/index.js.map +1 -0
  29. package/dist/resources/models.d.ts +7 -0
  30. package/dist/resources/models.d.ts.map +1 -0
  31. package/dist/resources/models.js +62 -0
  32. package/dist/resources/models.js.map +1 -0
  33. package/dist/resources/usage.d.ts +7 -0
  34. package/dist/resources/usage.d.ts.map +1 -0
  35. package/dist/resources/usage.js +31 -0
  36. package/dist/resources/usage.js.map +1 -0
  37. package/dist/schemas.d.ts +13 -0
  38. package/dist/schemas.d.ts.map +1 -1
  39. package/dist/schemas.js +6 -0
  40. package/dist/schemas.js.map +1 -1
  41. package/dist/session.d.ts +68 -0
  42. package/dist/session.d.ts.map +1 -0
  43. package/dist/session.js +184 -0
  44. package/dist/session.js.map +1 -0
  45. package/dist/tools/deepseek-chat.d.ts +1 -0
  46. package/dist/tools/deepseek-chat.d.ts.map +1 -1
  47. package/dist/tools/deepseek-chat.js +50 -7
  48. package/dist/tools/deepseek-chat.js.map +1 -1
  49. package/dist/tools/deepseek-sessions.d.ts +7 -0
  50. package/dist/tools/deepseek-sessions.d.ts.map +1 -0
  51. package/dist/tools/deepseek-sessions.js +101 -0
  52. package/dist/tools/deepseek-sessions.js.map +1 -0
  53. package/dist/tools/index.d.ts.map +1 -1
  54. package/dist/tools/index.js +2 -0
  55. package/dist/tools/index.js.map +1 -1
  56. package/dist/types.d.ts +55 -0
  57. package/dist/types.d.ts.map +1 -1
  58. package/dist/types.js.map +1 -1
  59. package/dist/usage-tracker.d.ts +40 -0
  60. package/dist/usage-tracker.d.ts.map +1 -0
  61. package/dist/usage-tracker.js +76 -0
  62. package/dist/usage-tracker.js.map +1 -0
  63. package/package.json +5 -2
package/CHANGELOG.md CHANGED
@@ -16,6 +16,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
16
  ### Fixed
17
17
  - Nothing yet
18
18
 
19
+ ## [1.3.0] - 2026-03-04
20
+
21
+ ### Added
22
+ - **Multi-Turn Sessions**: `session_id` parameter on `deepseek_chat` for multi-turn conversations. Session history is stored in memory and automatically prepended to requests. Sessions have configurable TTL and max count.
23
+ - **Session Management Tool**: `deepseek_sessions` tool with `list`, `delete`, and `clear` actions for managing active sessions.
24
+ - **Circuit Breaker**: Protects against cascading API failures. After 5 consecutive failures, fast-fails for 30 seconds, then probes for recovery.
25
+ - **Model Fallback**: Automatic fallback between `deepseek-chat` and `deepseek-reasoner` on retryable errors (429, 503, timeout). Configurable via `FALLBACK_ENABLED`.
26
+ - **MCP Resources**: 3 read-only resources following MCP Resources spec:
27
+ - `deepseek://models`: Model list with capabilities, context limits, and pricing
28
+ - `deepseek://config`: Current server configuration (API key masked)
29
+ - `deepseek://usage`: Real-time usage statistics (requests, tokens, costs, sessions)
30
+ - **Usage Tracker**: Global usage statistics tracking across all requests.
31
+ - **New Error Classes**: `FallbackExhaustedError`, `CircuitBreakerOpenError` for resilience error handling.
32
+ - **New Config**: `SESSION_TTL_MINUTES` (default: 30), `MAX_SESSIONS` (default: 100), `FALLBACK_ENABLED` (default: true).
33
+ - **198 Tests**: Up from 150, covering sessions, circuit breaker, fallback, and MCP resources.
34
+
35
+ ### Changed
36
+ - `deepseek-client.ts` now wraps API calls in circuit breaker and supports automatic model fallback.
37
+ - `deepseek_chat` tool description updated to mention sessions, fallback, and circuit breaker.
38
+ - `tools/index.ts` now registers both `deepseek_chat` and `deepseek_sessions` tools.
39
+ - `index.ts` now registers MCP resources via `registerAllResources()`.
40
+
19
41
  ## [1.2.0] - 2026-02-26
20
42
 
21
43
  ### Added
@@ -171,6 +193,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
171
193
 
172
194
  ## Version History
173
195
 
196
+ - **1.3.0** (2026-03-04): Sessions, circuit breaker, model fallback, MCP resources, 198 tests
174
197
  - **1.2.0** (2026-02-26): DeepSeek V3.2 support — thinking mode, JSON mode, cache-aware pricing, 150 tests
175
198
  - **1.1.1** (2026-02-11): Modular architecture, type safety, security fixes, 126 tests
176
199
  - **1.1.0** (2026-02-10): Function calling, config system, test suite
@@ -184,7 +207,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
184
207
  - [GitHub repository](https://github.com/arikusi/deepseek-mcp-server)
185
208
  - [Issue tracker](https://github.com/arikusi/deepseek-mcp-server/issues)
186
209
 
187
- [Unreleased]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.2.0...HEAD
210
+ [Unreleased]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.3.0...HEAD
211
+ [1.3.0]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.2.0...v1.3.0
188
212
  [1.2.0]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.1.1...v1.2.0
189
213
  [1.1.1]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.1.0...v1.1.1
190
214
  [1.1.0]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.0.3...v1.1.0
package/README.md CHANGED
@@ -7,12 +7,12 @@
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://www.typescriptlang.org/)
8
8
  [![Build Status](https://github.com/arikusi/deepseek-mcp-server/workflows/CI/badge.svg)](https://github.com/arikusi/deepseek-mcp-server/actions)
9
9
 
10
- A Model Context Protocol (MCP) server that integrates DeepSeek AI models with MCP-compatible clients. Access DeepSeek's powerful chat and reasoning models directly from your development environment.
10
+ A Model Context Protocol (MCP) server that integrates DeepSeek AI models with MCP-compatible clients. Access DeepSeek's powerful chat and reasoning models with multi-turn sessions, automatic model fallback, and MCP Resources directly from your development environment.
11
11
 
12
12
  **Compatible with:**
13
13
  - Claude Code CLI
14
- - Gemini CLI (if MCP support is available)
15
- - Any MCP-compatible client
14
+ - Gemini CLI
15
+ - Any MCP-compatible client (Cursor, Windsurf, etc.)
16
16
 
17
17
  > **Note**: This is an unofficial community project and is not affiliated with DeepSeek.
18
18
 
@@ -49,14 +49,18 @@ That's it! Your MCP client can now use DeepSeek models!
49
49
  ## Features
50
50
 
51
51
  - **DeepSeek V3.2**: Both models now run DeepSeek-V3.2 (since Sept 2025)
52
+ - **Multi-Turn Sessions**: Conversation context preserved across requests via `session_id` parameter
53
+ - **Model Fallback & Circuit Breaker**: Automatic fallback between models with circuit breaker protection against cascading failures
54
+ - **MCP Resources**: `deepseek://models`, `deepseek://config`, `deepseek://usage` — query model info, config, and usage stats
52
55
  - **Thinking Mode**: Enable enhanced reasoning on deepseek-chat with `thinking: {type: "enabled"}`
53
56
  - **JSON Output Mode**: Structured JSON responses with `json_mode: true`
54
57
  - **Function Calling**: OpenAI-compatible tool use with up to 128 tool definitions
55
58
  - **Cache-Aware Cost Tracking**: Automatic cost calculation with cache hit/miss breakdown
59
+ - **Session Management Tool**: List, delete, and clear sessions via `deepseek_sessions` tool
56
60
  - **Configurable**: Environment-based configuration with validation
57
61
  - **12 Prompt Templates**: Pre-built templates for debugging, code review, function calling, and more
58
62
  - **Streaming Support**: Real-time response generation
59
- - **Tested**: 150 tests with 90%+ code coverage
63
+ - **Tested**: 198 tests with 90%+ code coverage
60
64
  - **Type-Safe**: Full TypeScript implementation
61
65
  - **MCP Compatible**: Works with any MCP-compatible CLI (Claude Code, Gemini CLI, etc.)
62
66
 
@@ -98,7 +102,7 @@ npm run build
98
102
 
99
103
  ## Usage
100
104
 
101
- Once configured, your MCP client will have access to the `deepseek_chat` tool and can use DeepSeek models.
105
+ Once configured, your MCP client will have access to `deepseek_chat` and `deepseek_sessions` tools, plus 3 MCP resources.
102
106
 
103
107
  **Example prompts:**
104
108
  ```
@@ -150,6 +154,7 @@ Chat with DeepSeek AI models with automatic cost tracking and function calling s
150
154
  - `tool_choice` (optional): "auto" | "none" | "required" | `{type: "function", function: {name: "..."}}`
151
155
  - `thinking` (optional): Enable thinking mode `{type: "enabled"}` for enhanced reasoning
152
156
  - `json_mode` (optional): Enable JSON output mode (supported by both models)
157
+ - `session_id` (optional): Session ID for multi-turn conversations. Previous context is automatically prepended.
153
158
 
154
159
  **Response includes:**
155
160
  - Content with formatting
@@ -258,6 +263,60 @@ When thinking mode is enabled, `temperature`, `top_p`, `frequency_penalty`, and
258
263
 
259
264
  JSON mode ensures the model outputs valid JSON. Include the word "json" in your prompt for best results. Supported by both `deepseek-chat` and `deepseek-reasoner`.
260
265
 
266
+ **Multi-Turn Session Example:**
267
+
268
+ ```json
269
+ {
270
+ "messages": [
271
+ {
272
+ "role": "user",
273
+ "content": "What is the capital of France?"
274
+ }
275
+ ],
276
+ "session_id": "my-session-1"
277
+ }
278
+ ```
279
+
280
+ Use the same `session_id` across requests to maintain conversation context. The server stores messages in memory and automatically prepends history to each request.
281
+
282
+ ### `deepseek_sessions`
283
+
284
+ Manage conversation sessions.
285
+
286
+ **Parameters:**
287
+ - `action` (required): "list" | "clear" | "delete"
288
+ - `session_id` (optional): Required when action is "delete"
289
+
290
+ **Examples:**
291
+ ```json
292
+ {"action": "list"}
293
+ {"action": "delete", "session_id": "my-session-1"}
294
+ {"action": "clear"}
295
+ ```
296
+
297
+ ## Available Resources
298
+
299
+ MCP Resources provide read-only data about the server:
300
+
301
+ | Resource URI | Description |
302
+ |-------------|-------------|
303
+ | `deepseek://models` | Available models with capabilities, context limits, and pricing |
304
+ | `deepseek://config` | Current server configuration (API key masked) |
305
+ | `deepseek://usage` | Real-time usage statistics (requests, tokens, costs, sessions) |
306
+
307
+ ## Model Fallback & Circuit Breaker
308
+
309
+ When a model fails with a retryable error (429, 503, timeout), the server automatically falls back to the other model:
310
+ - `deepseek-chat` fails → tries `deepseek-reasoner`
311
+ - `deepseek-reasoner` fails → tries `deepseek-chat`
312
+
313
+ The circuit breaker protects against cascading failures:
314
+ - After 5 consecutive failures, the circuit **opens** (fast-fail mode)
315
+ - After 30 seconds, it enters **half-open** state and sends a probe request
316
+ - If the probe succeeds, the circuit **closes** and normal operation resumes
317
+
318
+ Fallback can be disabled with `FALLBACK_ENABLED=false`.
319
+
261
320
  ## Available Prompts
262
321
 
263
322
  Pre-built prompt templates for common tasks (12 total):
@@ -320,6 +379,9 @@ The server is configured via environment variables. All settings except `DEEPSEE
320
379
  | `MAX_RETRIES` | `2` | Maximum retry count for failed requests |
321
380
  | `SKIP_CONNECTION_TEST` | `false` | Skip startup API connection test |
322
381
  | `MAX_MESSAGE_LENGTH` | `100000` | Maximum message content length (characters) |
382
+ | `SESSION_TTL_MINUTES` | `30` | Session time-to-live in minutes |
383
+ | `MAX_SESSIONS` | `100` | Maximum number of concurrent sessions |
384
+ | `FALLBACK_ENABLED` | `true` | Enable automatic model fallback on errors |
323
385
 
324
386
  **Example with custom config:**
325
387
  ```bash
@@ -336,17 +398,26 @@ claude mcp add -s user deepseek npx @arikusi/deepseek-mcp-server \
336
398
  ```
337
399
  deepseek-mcp-server/
338
400
  ├── src/
339
- │ ├── index.ts # Entry point, bootstrap (~80 lines)
401
+ │ ├── index.ts # Entry point, bootstrap
340
402
  │ ├── server.ts # McpServer factory (auto-version)
341
- │ ├── deepseek-client.ts # DeepSeek API wrapper (OpenAI SDK)
403
+ │ ├── deepseek-client.ts # DeepSeek API wrapper (circuit breaker + fallback)
342
404
  │ ├── config.ts # Centralized config with Zod validation
343
405
  │ ├── cost.ts # Cost calculation and formatting
344
406
  │ ├── schemas.ts # Zod input validation schemas
345
407
  │ ├── types.ts # TypeScript types + type guards
346
408
  │ ├── errors.ts # Custom error classes
409
+ │ ├── session.ts # In-memory session store (multi-turn)
410
+ │ ├── circuit-breaker.ts # Circuit breaker pattern
411
+ │ ├── usage-tracker.ts # Usage statistics tracker
347
412
  │ ├── tools/
348
- │ │ ├── deepseek-chat.ts # deepseek_chat tool handler
413
+ │ │ ├── deepseek-chat.ts # deepseek_chat tool (sessions + fallback)
414
+ │ │ ├── deepseek-sessions.ts # deepseek_sessions tool
349
415
  │ │ └── index.ts # Tool registration aggregator
416
+ │ ├── resources/
417
+ │ │ ├── models.ts # deepseek://models resource
418
+ │ │ ├── config.ts # deepseek://config resource
419
+ │ │ ├── usage.ts # deepseek://usage resource
420
+ │ │ └── index.ts # Resource registration aggregator
350
421
  │ └── prompts/
351
422
  │ ├── core.ts # 5 core reasoning prompts
352
423
  │ ├── advanced.ts # 5 advanced prompts
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Circuit Breaker Pattern
3
+ * Prevents cascading failures by fast-failing when the API is unhealthy
4
+ *
5
+ * States:
6
+ * CLOSED → normal operation, requests pass through
7
+ * OPEN → API is unhealthy, requests are immediately rejected
8
+ * HALF_OPEN → testing if API has recovered with a single probe request
9
+ */
10
+ import type { CircuitBreakerStatus } from './types.js';
11
+ export declare class CircuitBreaker {
12
+ private readonly threshold;
13
+ private readonly openTimeout;
14
+ private state;
15
+ private failureCount;
16
+ private lastFailureTime;
17
+ private halfOpenInProgress;
18
+ constructor(threshold?: number, openTimeout?: number);
19
+ /**
20
+ * Execute a function through the circuit breaker.
21
+ * - CLOSED: pass through, track failures
22
+ * - OPEN: reject immediately (fast-fail) unless timeout elapsed → HALF_OPEN
23
+ * - HALF_OPEN: allow one probe request
24
+ */
25
+ execute<T>(fn: () => Promise<T>): Promise<T>;
26
+ /**
27
+ * Get current circuit breaker status
28
+ */
29
+ getStatus(): CircuitBreakerStatus;
30
+ /**
31
+ * Manually reset the circuit breaker to CLOSED state
32
+ */
33
+ reset(): void;
34
+ private onSuccess;
35
+ private onFailure;
36
+ }
37
+ //# sourceMappingURL=circuit-breaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAuB,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE5E,qBAAa,cAAc;IAOvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAP9B,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,kBAAkB,CAAS;gBAGhB,SAAS,GAAE,MAAU,EACrB,WAAW,GAAE,MAAc;IAG9C;;;;;OAKG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA+BlD;;OAEG;IACH,SAAS,IAAI,oBAAoB;IAiBjC;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,SAAS;CAYlB"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Circuit Breaker Pattern
3
+ * Prevents cascading failures by fast-failing when the API is unhealthy
4
+ *
5
+ * States:
6
+ * CLOSED → normal operation, requests pass through
7
+ * OPEN → API is unhealthy, requests are immediately rejected
8
+ * HALF_OPEN → testing if API has recovered with a single probe request
9
+ */
10
+ import { CircuitBreakerOpenError } from './errors.js';
11
+ export class CircuitBreaker {
12
+ threshold;
13
+ openTimeout;
14
+ state = 'CLOSED';
15
+ failureCount = 0;
16
+ lastFailureTime = 0;
17
+ halfOpenInProgress = false;
18
+ constructor(threshold = 5, openTimeout = 30000) {
19
+ this.threshold = threshold;
20
+ this.openTimeout = openTimeout;
21
+ }
22
+ /**
23
+ * Execute a function through the circuit breaker.
24
+ * - CLOSED: pass through, track failures
25
+ * - OPEN: reject immediately (fast-fail) unless timeout elapsed → HALF_OPEN
26
+ * - HALF_OPEN: allow one probe request
27
+ */
28
+ async execute(fn) {
29
+ if (this.state === 'OPEN') {
30
+ // Check if enough time has elapsed to try half-open
31
+ if (Date.now() - this.lastFailureTime >= this.openTimeout) {
32
+ this.state = 'HALF_OPEN';
33
+ this.halfOpenInProgress = false;
34
+ }
35
+ else {
36
+ throw new CircuitBreakerOpenError();
37
+ }
38
+ }
39
+ if (this.state === 'HALF_OPEN' && this.halfOpenInProgress) {
40
+ throw new CircuitBreakerOpenError('Circuit breaker is half-open — probe request in progress');
41
+ }
42
+ if (this.state === 'HALF_OPEN') {
43
+ this.halfOpenInProgress = true;
44
+ }
45
+ try {
46
+ const result = await fn();
47
+ this.onSuccess();
48
+ return result;
49
+ }
50
+ catch (error) {
51
+ this.onFailure();
52
+ throw error;
53
+ }
54
+ }
55
+ /**
56
+ * Get current circuit breaker status
57
+ */
58
+ getStatus() {
59
+ // Auto-transition from OPEN to HALF_OPEN if timeout elapsed
60
+ if (this.state === 'OPEN' &&
61
+ Date.now() - this.lastFailureTime >= this.openTimeout) {
62
+ this.state = 'HALF_OPEN';
63
+ this.halfOpenInProgress = false;
64
+ }
65
+ return {
66
+ state: this.state,
67
+ failureCount: this.failureCount,
68
+ lastFailureTime: this.lastFailureTime,
69
+ };
70
+ }
71
+ /**
72
+ * Manually reset the circuit breaker to CLOSED state
73
+ */
74
+ reset() {
75
+ this.state = 'CLOSED';
76
+ this.failureCount = 0;
77
+ this.lastFailureTime = 0;
78
+ this.halfOpenInProgress = false;
79
+ }
80
+ onSuccess() {
81
+ if (this.state === 'HALF_OPEN') {
82
+ // Probe succeeded → close circuit
83
+ this.state = 'CLOSED';
84
+ this.halfOpenInProgress = false;
85
+ }
86
+ this.failureCount = 0;
87
+ }
88
+ onFailure() {
89
+ this.failureCount++;
90
+ this.lastFailureTime = Date.now();
91
+ if (this.state === 'HALF_OPEN') {
92
+ // Probe failed → re-open
93
+ this.state = 'OPEN';
94
+ this.halfOpenInProgress = false;
95
+ }
96
+ else if (this.failureCount >= this.threshold) {
97
+ this.state = 'OPEN';
98
+ }
99
+ }
100
+ }
101
+ //# sourceMappingURL=circuit-breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -11,6 +11,9 @@ declare const ConfigSchema: z.ZodObject<{
11
11
  maxRetries: z.ZodDefault<z.ZodNumber>;
12
12
  skipConnectionTest: z.ZodDefault<z.ZodBoolean>;
13
13
  maxMessageLength: z.ZodDefault<z.ZodNumber>;
14
+ sessionTtlMinutes: z.ZodDefault<z.ZodNumber>;
15
+ maxSessions: z.ZodDefault<z.ZodNumber>;
16
+ fallbackEnabled: z.ZodDefault<z.ZodBoolean>;
14
17
  }, "strip", z.ZodTypeAny, {
15
18
  apiKey: string;
16
19
  baseUrl: string;
@@ -19,6 +22,9 @@ declare const ConfigSchema: z.ZodObject<{
19
22
  maxRetries: number;
20
23
  skipConnectionTest: boolean;
21
24
  maxMessageLength: number;
25
+ sessionTtlMinutes: number;
26
+ maxSessions: number;
27
+ fallbackEnabled: boolean;
22
28
  }, {
23
29
  apiKey: string;
24
30
  baseUrl?: string | undefined;
@@ -27,6 +33,9 @@ declare const ConfigSchema: z.ZodObject<{
27
33
  maxRetries?: number | undefined;
28
34
  skipConnectionTest?: boolean | undefined;
29
35
  maxMessageLength?: number | undefined;
36
+ sessionTtlMinutes?: number | undefined;
37
+ maxSessions?: number | undefined;
38
+ fallbackEnabled?: boolean | undefined;
30
39
  }>;
31
40
  export type Config = z.infer<typeof ConfigSchema>;
32
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;EAQhB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAIlD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAqCnC;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAKlC;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWhB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAIlD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CA4CnC;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAKlC;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
package/dist/config.js CHANGED
@@ -12,6 +12,9 @@ const ConfigSchema = z.object({
12
12
  maxRetries: z.number().min(0).max(10).default(2),
13
13
  skipConnectionTest: z.boolean().default(false),
14
14
  maxMessageLength: z.number().positive().default(100_000),
15
+ sessionTtlMinutes: z.number().positive().default(30),
16
+ maxSessions: z.number().positive().default(100),
17
+ fallbackEnabled: z.boolean().default(true),
15
18
  });
16
19
  let cachedConfig = null;
17
20
  /**
@@ -34,6 +37,13 @@ export function loadConfig() {
34
37
  maxMessageLength: process.env.MAX_MESSAGE_LENGTH
35
38
  ? parseInt(process.env.MAX_MESSAGE_LENGTH, 10)
36
39
  : 100_000,
40
+ sessionTtlMinutes: process.env.SESSION_TTL_MINUTES
41
+ ? parseInt(process.env.SESSION_TTL_MINUTES, 10)
42
+ : 30,
43
+ maxSessions: process.env.MAX_SESSIONS
44
+ ? parseInt(process.env.MAX_SESSIONS, 10)
45
+ : 100,
46
+ fallbackEnabled: process.env.FALLBACK_ENABLED !== 'false',
37
47
  };
38
48
  const result = ConfigSchema.safeParse(raw);
39
49
  if (!result.success) {
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,21 @@
1
1
  /**
2
2
  * DeepSeek API Client
3
3
  * Wrapper around OpenAI SDK for DeepSeek API
4
+ * Features: circuit breaker protection, automatic model fallback
4
5
  */
5
- import type { ChatCompletionParams, ChatCompletionResponse } from './types.js';
6
+ import type { ChatCompletionParams, ChatCompletionResponse, FallbackInfo } from './types.js';
7
+ /** Extended response with optional fallback info */
8
+ export interface ChatCompletionResponseWithFallback extends ChatCompletionResponse {
9
+ fallback?: FallbackInfo;
10
+ }
6
11
  export declare class DeepSeekClient {
7
12
  private client;
13
+ private circuitBreaker;
8
14
  constructor();
15
+ /**
16
+ * Get circuit breaker status
17
+ */
18
+ getCircuitBreakerStatus(): import("./types.js").CircuitBreakerStatus;
9
19
  /**
10
20
  * Build request params shared between streaming and non-streaming
11
21
  */
@@ -15,14 +25,22 @@ export declare class DeepSeekClient {
15
25
  */
16
26
  private wrapError;
17
27
  /**
18
- * Create a chat completion (non-streaming)
28
+ * Parse raw API response into ChatCompletionResponse
19
29
  */
20
- createChatCompletion(params: ChatCompletionParams): Promise<ChatCompletionResponse>;
30
+ private parseResponse;
21
31
  /**
22
- * Create a streaming chat completion
32
+ * Create a chat completion (non-streaming) with circuit breaker and fallback
33
+ */
34
+ createChatCompletion(params: ChatCompletionParams): Promise<ChatCompletionResponseWithFallback>;
35
+ /**
36
+ * Create a streaming chat completion with circuit breaker and fallback
23
37
  * Returns the full text after streaming completes (buffered)
24
38
  */
25
- createStreamingChatCompletion(params: ChatCompletionParams): Promise<ChatCompletionResponse>;
39
+ createStreamingChatCompletion(params: ChatCompletionParams): Promise<ChatCompletionResponseWithFallback>;
40
+ /**
41
+ * Internal streaming implementation
42
+ */
43
+ private streamInternal;
26
44
  /**
27
45
  * Test API connection
28
46
  */
@@ -1 +1 @@
1
- {"version":3,"file":"deepseek-client.d.ts","sourceRoot":"","sources":["../src/deepseek-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EAKvB,MAAM,YAAY,CAAC;AAWpB,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;;IAavB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyD1B;;OAEG;IACH,OAAO,CAAC,SAAS;IAOjB;;OAEG;IACG,oBAAoB,CACxB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,sBAAsB,CAAC;IA+ClC;;;OAGG;IACG,6BAA6B,CACjC,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,sBAAsB,CAAC;IA0GlC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAazC"}
1
+ {"version":3,"file":"deepseek-client.d.ts","sourceRoot":"","sources":["../src/deepseek-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EAItB,YAAY,EAEb,MAAM,YAAY,CAAC;AAiBpB,oDAAoD;AACpD,MAAM,WAAW,kCAAmC,SAAQ,sBAAsB;IAChF,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAwBD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,cAAc,CAAiB;;IAevC;;OAEG;IACH,uBAAuB;IAIvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyD1B;;OAEG;IACH,OAAO,CAAC,SAAS;IASjB;;OAEG;IACH,OAAO,CAAC,aAAa;IAoCrB;;OAEG;IACG,oBAAoB,CACxB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,kCAAkC,CAAC;IAoD9C;;;OAGG;IACG,6BAA6B,CACjC,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,kCAAkC,CAAC;IAwC9C;;OAEG;YACW,cAAc;IA4F5B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAazC"}