@arikusi/deepseek-mcp-server 1.0.3 → 1.1.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 +36 -1
- package/README.md +111 -23
- package/dist/config.d.ts +42 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +63 -0
- package/dist/config.js.map +1 -0
- package/dist/cost.d.ts +24 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +34 -0
- package/dist/cost.js.map +1 -0
- package/dist/deepseek-client.d.ts +2 -3
- package/dist/deepseek-client.d.ts.map +1 -1
- package/dist/deepseek-client.js +72 -13
- package/dist/deepseek-client.js.map +1 -1
- package/dist/index.js +191 -80
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +258 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +56 -0
- package/dist/schemas.js.map +1 -0
- package/dist/types.d.ts +57 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -4
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,39 @@ 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.1.0] - 2026-02-10
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- **Function Calling Support**: Full OpenAI-compatible function calling via `tools` and `tool_choice` parameters
|
|
23
|
+
- Define up to 128 tool definitions with JSON Schema parameters
|
|
24
|
+
- Control tool behavior with `tool_choice`: auto, none, required, or specific function
|
|
25
|
+
- Tool call results formatted in response with call IDs and arguments
|
|
26
|
+
- Streaming + function calling works together (delta accumulation)
|
|
27
|
+
- `tool` message role for sending tool results back
|
|
28
|
+
- **Centralized Config System** (`src/config.ts`)
|
|
29
|
+
- Zod-validated configuration from environment variables
|
|
30
|
+
- `DEEPSEEK_BASE_URL`: Custom API endpoint (default: `https://api.deepseek.com`)
|
|
31
|
+
- `SHOW_COST_INFO`: Toggle cost display in responses (default: true)
|
|
32
|
+
- `REQUEST_TIMEOUT`: API request timeout in ms (default: 60000)
|
|
33
|
+
- `MAX_RETRIES`: Maximum API retry count (default: 2)
|
|
34
|
+
- **Test Suite**: 85 tests with Vitest
|
|
35
|
+
- Config, Cost, Schemas, Client, and Function Calling tests
|
|
36
|
+
- 80%+ code coverage with v8 provider
|
|
37
|
+
- `npm test`, `npm run test:watch`, `npm run test:coverage` scripts
|
|
38
|
+
- **2 New Prompt Templates** (total: 12)
|
|
39
|
+
- `function_call_debug`: Debug function calling issues
|
|
40
|
+
- `create_function_schema`: Generate JSON Schema from natural language
|
|
41
|
+
- CI coverage job in GitHub Actions
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- **Project Structure**: Modularized codebase
|
|
45
|
+
- `src/config.ts`: Centralized configuration
|
|
46
|
+
- `src/cost.ts`: Cost calculation (extracted from index.ts)
|
|
47
|
+
- `src/schemas.ts`: Zod validation schemas (extracted from index.ts)
|
|
48
|
+
- `DeepSeekClient` constructor now uses centralized config (no manual apiKey passing)
|
|
49
|
+
- Server version bumped to 1.1.0
|
|
50
|
+
- Updated `deepseek_chat` tool description to mention function calling
|
|
51
|
+
|
|
19
52
|
## [1.0.3] - 2025-02-07
|
|
20
53
|
|
|
21
54
|
### Added
|
|
@@ -91,6 +124,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
91
124
|
|
|
92
125
|
## Version History
|
|
93
126
|
|
|
127
|
+
- **1.1.0** (2026-02-10): Function calling, config system, test suite
|
|
94
128
|
- **1.0.3** (2025-02-07): Cost tracking and prompt templates
|
|
95
129
|
- **1.0.0** (2025-01-13): Initial public release
|
|
96
130
|
- **0.1.0** (Development): Internal development version
|
|
@@ -101,7 +135,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
101
135
|
- [GitHub repository](https://github.com/arikusi/deepseek-mcp-server)
|
|
102
136
|
- [Issue tracker](https://github.com/arikusi/deepseek-mcp-server/issues)
|
|
103
137
|
|
|
104
|
-
[Unreleased]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.0
|
|
138
|
+
[Unreleased]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.1.0...HEAD
|
|
139
|
+
[1.1.0]: https://github.com/arikusi/deepseek-mcp-server/compare/v1.0.3...v1.1.0
|
|
105
140
|
[1.0.3]: https://github.com/arikusi/deepseek-mcp-server/releases/tag/v1.0.3
|
|
106
141
|
[1.0.0]: https://github.com/arikusi/deepseek-mcp-server/releases/tag/v1.0.0
|
|
107
142
|
[0.1.0]: https://github.com/arikusi/deepseek-mcp-server/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -14,9 +14,9 @@ A Model Context Protocol (MCP) server that integrates DeepSeek AI models with MC
|
|
|
14
14
|
- Gemini CLI (if MCP support is available)
|
|
15
15
|
- Any MCP-compatible client
|
|
16
16
|
|
|
17
|
-
>
|
|
17
|
+
> **Note**: This is an unofficial community project and is not affiliated with DeepSeek.
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Quick Start
|
|
20
20
|
|
|
21
21
|
### For Claude Code
|
|
22
22
|
|
|
@@ -42,19 +42,22 @@ gemini mcp add deepseek npx @arikusi/deepseek-mcp-server -e DEEPSEEK_API_KEY=you
|
|
|
42
42
|
|
|
43
43
|
**Get your API key:** [https://platform.deepseek.com](https://platform.deepseek.com)
|
|
44
44
|
|
|
45
|
-
That's it! Your MCP client can now use DeepSeek models!
|
|
45
|
+
That's it! Your MCP client can now use DeepSeek models!
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
49
|
## Features
|
|
50
50
|
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
51
|
+
- **DeepSeek Chat**: Fast and capable general-purpose model
|
|
52
|
+
- **DeepSeek Reasoner (R1)**: Advanced reasoning with chain-of-thought explanations
|
|
53
|
+
- **Function Calling**: OpenAI-compatible tool use with up to 128 tool definitions
|
|
54
|
+
- **Cost Tracking**: Automatic cost calculation for every request (USD)
|
|
55
|
+
- **Configurable**: Environment-based configuration with validation
|
|
56
|
+
- **12 Prompt Templates**: Pre-built templates for debugging, code review, function calling, and more
|
|
57
|
+
- **Streaming Support**: Real-time response generation
|
|
58
|
+
- **Tested**: 85 tests with 80%+ code coverage
|
|
59
|
+
- **Type-Safe**: Full TypeScript implementation
|
|
60
|
+
- **MCP Compatible**: Works with any MCP-compatible CLI (Claude Code, Gemini CLI, etc.)
|
|
58
61
|
|
|
59
62
|
## Installation
|
|
60
63
|
|
|
@@ -130,22 +133,26 @@ If your MCP client doesn't support the `add` command, manually add to your confi
|
|
|
130
133
|
|
|
131
134
|
### `deepseek_chat`
|
|
132
135
|
|
|
133
|
-
Chat with DeepSeek AI models with automatic cost tracking.
|
|
136
|
+
Chat with DeepSeek AI models with automatic cost tracking and function calling support.
|
|
134
137
|
|
|
135
138
|
**Parameters:**
|
|
136
139
|
|
|
137
140
|
- `messages` (required): Array of conversation messages
|
|
138
|
-
- `role`: "system" | "user" | "assistant"
|
|
141
|
+
- `role`: "system" | "user" | "assistant" | "tool"
|
|
139
142
|
- `content`: Message text
|
|
143
|
+
- `tool_call_id` (optional): Required for tool role messages
|
|
140
144
|
- `model` (optional): "deepseek-chat" (default) or "deepseek-reasoner"
|
|
141
145
|
- `temperature` (optional): 0-2, controls randomness (default: 1.0)
|
|
142
146
|
- `max_tokens` (optional): Maximum tokens to generate
|
|
143
147
|
- `stream` (optional): Enable streaming mode (default: false)
|
|
148
|
+
- `tools` (optional): Array of tool definitions for function calling (max 128)
|
|
149
|
+
- `tool_choice` (optional): "auto" | "none" | "required" | `{type: "function", function: {name: "..."}}`
|
|
144
150
|
|
|
145
151
|
**Response includes:**
|
|
146
152
|
- Content with formatting
|
|
153
|
+
- Function call results (if tools were used)
|
|
147
154
|
- Request information (tokens, model, cost in USD)
|
|
148
|
-
- Structured data with `cost_usd`
|
|
155
|
+
- Structured data with `cost_usd` and `tool_calls` fields
|
|
149
156
|
|
|
150
157
|
**Example:**
|
|
151
158
|
|
|
@@ -179,9 +186,44 @@ Chat with DeepSeek AI models with automatic cost tracking.
|
|
|
179
186
|
|
|
180
187
|
The reasoner model will show its thinking process in `<thinking>` tags followed by the final answer.
|
|
181
188
|
|
|
189
|
+
**Function Calling Example:**
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"messages": [
|
|
194
|
+
{
|
|
195
|
+
"role": "user",
|
|
196
|
+
"content": "What's the weather in Istanbul?"
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
"tools": [
|
|
200
|
+
{
|
|
201
|
+
"type": "function",
|
|
202
|
+
"function": {
|
|
203
|
+
"name": "get_weather",
|
|
204
|
+
"description": "Get current weather for a location",
|
|
205
|
+
"parameters": {
|
|
206
|
+
"type": "object",
|
|
207
|
+
"properties": {
|
|
208
|
+
"location": {
|
|
209
|
+
"type": "string",
|
|
210
|
+
"description": "City name"
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"required": ["location"]
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
],
|
|
218
|
+
"tool_choice": "auto"
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
When the model decides to call a function, the response includes `tool_calls` with the function name and arguments. You can then send the result back using a `tool` role message with the matching `tool_call_id`.
|
|
223
|
+
|
|
182
224
|
## Available Prompts
|
|
183
225
|
|
|
184
|
-
Pre-built prompt templates for common tasks:
|
|
226
|
+
Pre-built prompt templates for common tasks (12 total):
|
|
185
227
|
|
|
186
228
|
### Core Reasoning
|
|
187
229
|
- **debug_with_reasoning**: Debug code with step-by-step analysis
|
|
@@ -197,6 +239,10 @@ Pre-built prompt templates for common tasks:
|
|
|
197
239
|
- **cost_comparison**: Compare LLM costs for tasks
|
|
198
240
|
- **pair_programming**: Interactive coding with explanations
|
|
199
241
|
|
|
242
|
+
### Function Calling
|
|
243
|
+
- **function_call_debug**: Debug function calling issues with tool definitions and messages
|
|
244
|
+
- **create_function_schema**: Generate JSON Schema for function calling from natural language
|
|
245
|
+
|
|
200
246
|
Each prompt is optimized for the DeepSeek Reasoner model to provide detailed reasoning.
|
|
201
247
|
|
|
202
248
|
## Models
|
|
@@ -216,6 +262,26 @@ Each prompt is optimized for the DeepSeek Reasoner model to provide detailed rea
|
|
|
216
262
|
- **Special**: Provides chain-of-thought reasoning
|
|
217
263
|
- **Output**: Both reasoning process and final answer
|
|
218
264
|
|
|
265
|
+
## Configuration
|
|
266
|
+
|
|
267
|
+
The server is configured via environment variables. All settings except `DEEPSEEK_API_KEY` are optional.
|
|
268
|
+
|
|
269
|
+
| Variable | Default | Description |
|
|
270
|
+
|----------|---------|-------------|
|
|
271
|
+
| `DEEPSEEK_API_KEY` | (required) | Your DeepSeek API key |
|
|
272
|
+
| `DEEPSEEK_BASE_URL` | `https://api.deepseek.com` | Custom API endpoint |
|
|
273
|
+
| `SHOW_COST_INFO` | `true` | Show cost info in responses |
|
|
274
|
+
| `REQUEST_TIMEOUT` | `60000` | Request timeout in milliseconds |
|
|
275
|
+
| `MAX_RETRIES` | `2` | Maximum retry count for failed requests |
|
|
276
|
+
|
|
277
|
+
**Example with custom config:**
|
|
278
|
+
```bash
|
|
279
|
+
claude mcp add -s user deepseek npx @arikusi/deepseek-mcp-server \
|
|
280
|
+
-e DEEPSEEK_API_KEY=your-key \
|
|
281
|
+
-e SHOW_COST_INFO=false \
|
|
282
|
+
-e REQUEST_TIMEOUT=30000
|
|
283
|
+
```
|
|
284
|
+
|
|
219
285
|
## Development
|
|
220
286
|
|
|
221
287
|
### Project Structure
|
|
@@ -223,10 +289,19 @@ Each prompt is optimized for the DeepSeek Reasoner model to provide detailed rea
|
|
|
223
289
|
```
|
|
224
290
|
deepseek-mcp-server/
|
|
225
291
|
├── src/
|
|
226
|
-
│ ├── index.ts
|
|
227
|
-
│ ├── deepseek-client.ts
|
|
228
|
-
│
|
|
229
|
-
├──
|
|
292
|
+
│ ├── index.ts # Main MCP server, tool & prompt registration
|
|
293
|
+
│ ├── deepseek-client.ts # DeepSeek API wrapper (OpenAI SDK)
|
|
294
|
+
│ ├── config.ts # Centralized config with Zod validation
|
|
295
|
+
│ ├── cost.ts # Cost calculation and formatting
|
|
296
|
+
│ ├── schemas.ts # Zod input validation schemas
|
|
297
|
+
│ ├── types.ts # TypeScript type definitions
|
|
298
|
+
│ ├── config.test.ts # Config tests
|
|
299
|
+
│ ├── cost.test.ts # Cost tests
|
|
300
|
+
│ ├── schemas.test.ts # Schema validation tests
|
|
301
|
+
│ ├── deepseek-client.test.ts # Client tests
|
|
302
|
+
│ └── function-calling.test.ts # Function calling tests
|
|
303
|
+
├── dist/ # Compiled JavaScript
|
|
304
|
+
├── vitest.config.ts # Test configuration
|
|
230
305
|
├── package.json
|
|
231
306
|
├── tsconfig.json
|
|
232
307
|
└── README.md
|
|
@@ -244,6 +319,19 @@ npm run build
|
|
|
244
319
|
npm run watch
|
|
245
320
|
```
|
|
246
321
|
|
|
322
|
+
### Testing
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
# Run all tests
|
|
326
|
+
npm test
|
|
327
|
+
|
|
328
|
+
# Watch mode
|
|
329
|
+
npm run test:watch
|
|
330
|
+
|
|
331
|
+
# With coverage report
|
|
332
|
+
npm run test:coverage
|
|
333
|
+
```
|
|
334
|
+
|
|
247
335
|
### Testing Locally
|
|
248
336
|
|
|
249
337
|
```bash
|
|
@@ -357,10 +445,10 @@ MIT License - see [LICENSE](LICENSE) file for details
|
|
|
357
445
|
|
|
358
446
|
## Support
|
|
359
447
|
|
|
360
|
-
-
|
|
361
|
-
-
|
|
362
|
-
-
|
|
363
|
-
-
|
|
448
|
+
- [Documentation](https://github.com/arikusi/deepseek-mcp-server#readme)
|
|
449
|
+
- [Bug Reports](https://github.com/arikusi/deepseek-mcp-server/issues)
|
|
450
|
+
- [Discussions](https://github.com/arikusi/deepseek-mcp-server/discussions)
|
|
451
|
+
- Contact: [GitHub Issues](https://github.com/arikusi/deepseek-mcp-server/issues)
|
|
364
452
|
|
|
365
453
|
## Resources
|
|
366
454
|
|
|
@@ -376,6 +464,6 @@ MIT License - see [LICENSE](LICENSE) file for details
|
|
|
376
464
|
|
|
377
465
|
---
|
|
378
466
|
|
|
379
|
-
**Made
|
|
467
|
+
**Made by [@arikusi](https://github.com/arikusi)**
|
|
380
468
|
|
|
381
469
|
This is an unofficial community project and is not affiliated with DeepSeek.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Configuration
|
|
3
|
+
* Loads and validates configuration from environment variables
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
declare const ConfigSchema: z.ZodObject<{
|
|
7
|
+
apiKey: z.ZodString;
|
|
8
|
+
baseUrl: z.ZodDefault<z.ZodString>;
|
|
9
|
+
showCostInfo: z.ZodDefault<z.ZodBoolean>;
|
|
10
|
+
requestTimeout: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
maxRetries: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
apiKey: string;
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
showCostInfo: boolean;
|
|
16
|
+
requestTimeout: number;
|
|
17
|
+
maxRetries: number;
|
|
18
|
+
}, {
|
|
19
|
+
apiKey: string;
|
|
20
|
+
baseUrl?: string | undefined;
|
|
21
|
+
showCostInfo?: boolean | undefined;
|
|
22
|
+
requestTimeout?: number | undefined;
|
|
23
|
+
maxRetries?: number | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
export type Config = z.infer<typeof ConfigSchema>;
|
|
26
|
+
/**
|
|
27
|
+
* Load configuration from environment variables.
|
|
28
|
+
* Validates with Zod and caches the result.
|
|
29
|
+
* Exits process if validation fails (e.g., missing API key).
|
|
30
|
+
*/
|
|
31
|
+
export declare function loadConfig(): Config;
|
|
32
|
+
/**
|
|
33
|
+
* Get the cached configuration.
|
|
34
|
+
* Throws if loadConfig() hasn't been called yet.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getConfig(): Config;
|
|
37
|
+
/**
|
|
38
|
+
* Reset cached configuration (for testing).
|
|
39
|
+
*/
|
|
40
|
+
export declare function resetConfig(): void;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +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;AAExB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;EAMhB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAIlD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CA8BnC;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAKlC;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Configuration
|
|
3
|
+
* Loads and validates configuration from environment variables
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
const ConfigSchema = z.object({
|
|
7
|
+
apiKey: z.string().min(1, 'DEEPSEEK_API_KEY is required'),
|
|
8
|
+
baseUrl: z.string().url().default('https://api.deepseek.com'),
|
|
9
|
+
showCostInfo: z.boolean().default(true),
|
|
10
|
+
requestTimeout: z.number().positive().default(60000),
|
|
11
|
+
maxRetries: z.number().min(0).max(10).default(2),
|
|
12
|
+
});
|
|
13
|
+
let cachedConfig = null;
|
|
14
|
+
/**
|
|
15
|
+
* Load configuration from environment variables.
|
|
16
|
+
* Validates with Zod and caches the result.
|
|
17
|
+
* Exits process if validation fails (e.g., missing API key).
|
|
18
|
+
*/
|
|
19
|
+
export function loadConfig() {
|
|
20
|
+
const raw = {
|
|
21
|
+
apiKey: process.env.DEEPSEEK_API_KEY || '',
|
|
22
|
+
baseUrl: process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com',
|
|
23
|
+
showCostInfo: process.env.SHOW_COST_INFO !== 'false',
|
|
24
|
+
requestTimeout: process.env.REQUEST_TIMEOUT
|
|
25
|
+
? parseInt(process.env.REQUEST_TIMEOUT, 10)
|
|
26
|
+
: 60000,
|
|
27
|
+
maxRetries: process.env.MAX_RETRIES
|
|
28
|
+
? parseInt(process.env.MAX_RETRIES, 10)
|
|
29
|
+
: 2,
|
|
30
|
+
};
|
|
31
|
+
const result = ConfigSchema.safeParse(raw);
|
|
32
|
+
if (!result.success) {
|
|
33
|
+
console.error('Error: Configuration validation failed');
|
|
34
|
+
const issues = result.error.issues;
|
|
35
|
+
for (const issue of issues) {
|
|
36
|
+
console.error(` - ${issue.path.join('.')}: ${issue.message}`);
|
|
37
|
+
}
|
|
38
|
+
if (!raw.apiKey) {
|
|
39
|
+
console.error('Please set your DeepSeek API key:');
|
|
40
|
+
console.error(' export DEEPSEEK_API_KEY="your-api-key-here"');
|
|
41
|
+
}
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
cachedConfig = result.data;
|
|
45
|
+
return cachedConfig;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get the cached configuration.
|
|
49
|
+
* Throws if loadConfig() hasn't been called yet.
|
|
50
|
+
*/
|
|
51
|
+
export function getConfig() {
|
|
52
|
+
if (!cachedConfig) {
|
|
53
|
+
throw new Error('Config not loaded. Call loadConfig() first.');
|
|
54
|
+
}
|
|
55
|
+
return cachedConfig;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reset cached configuration (for testing).
|
|
59
|
+
*/
|
|
60
|
+
export function resetConfig() {
|
|
61
|
+
cachedConfig = null;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,8BAA8B,CAAC;IACzD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,0BAA0B,CAAC;IAC7D,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACpD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;CACjD,CAAC,CAAC;AAIH,IAAI,YAAY,GAAkB,IAAI,CAAC;AAEvC;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG;QACV,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE;QAC1C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,0BAA0B;QACpE,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,OAAO;QACpD,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;YACzC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,CAAC;YAC3C,CAAC,CAAC,KAAK;QACT,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;YACjC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;YACvC,CAAC,CAAC,CAAC;KACN,CAAC;IAEF,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAE3C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACnD,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;IAC3B,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,YAAY,GAAG,IAAI,CAAC;AACtB,CAAC"}
|
package/dist/cost.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Calculation Module
|
|
3
|
+
* Handles pricing and cost formatting for DeepSeek API requests
|
|
4
|
+
*/
|
|
5
|
+
/** DeepSeek pricing per 1M tokens (USD) */
|
|
6
|
+
export declare const PRICING: {
|
|
7
|
+
readonly 'deepseek-chat': {
|
|
8
|
+
readonly prompt: 0.14;
|
|
9
|
+
readonly completion: 0.28;
|
|
10
|
+
};
|
|
11
|
+
readonly 'deepseek-reasoner': {
|
|
12
|
+
readonly prompt: 0.55;
|
|
13
|
+
readonly completion: 2.19;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Calculate cost for a request based on token usage
|
|
18
|
+
*/
|
|
19
|
+
export declare function calculateCost(promptTokens: number, completionTokens: number, model: string): number;
|
|
20
|
+
/**
|
|
21
|
+
* Format cost as readable USD string
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatCost(cost: number): string;
|
|
24
|
+
//# sourceMappingURL=cost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2CAA2C;AAC3C,eAAO,MAAM,OAAO;;;;;;;;;CASV,CAAC;AAEX;;GAEG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,MAAM,GACZ,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/C"}
|
package/dist/cost.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Calculation Module
|
|
3
|
+
* Handles pricing and cost formatting for DeepSeek API requests
|
|
4
|
+
*/
|
|
5
|
+
/** DeepSeek pricing per 1M tokens (USD) */
|
|
6
|
+
export const PRICING = {
|
|
7
|
+
'deepseek-chat': {
|
|
8
|
+
prompt: 0.14,
|
|
9
|
+
completion: 0.28,
|
|
10
|
+
},
|
|
11
|
+
'deepseek-reasoner': {
|
|
12
|
+
prompt: 0.55,
|
|
13
|
+
completion: 2.19,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Calculate cost for a request based on token usage
|
|
18
|
+
*/
|
|
19
|
+
export function calculateCost(promptTokens, completionTokens, model) {
|
|
20
|
+
const modelPricing = PRICING[model] || PRICING['deepseek-chat'];
|
|
21
|
+
const promptCost = (promptTokens / 1_000_000) * modelPricing.prompt;
|
|
22
|
+
const completionCost = (completionTokens / 1_000_000) * modelPricing.completion;
|
|
23
|
+
return promptCost + completionCost;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Format cost as readable USD string
|
|
27
|
+
*/
|
|
28
|
+
export function formatCost(cost) {
|
|
29
|
+
if (cost < 0.01) {
|
|
30
|
+
return `$${cost.toFixed(4)}`;
|
|
31
|
+
}
|
|
32
|
+
return `$${cost.toFixed(2)}`;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=cost.js.map
|
package/dist/cost.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.js","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2CAA2C;AAC3C,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,eAAe,EAAE;QACf,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,IAAI;KACjB;IACD,mBAAmB,EAAE;QACnB,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,IAAI;KACjB;CACO,CAAC;AAEX;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,YAAoB,EACpB,gBAAwB,EACxB,KAAa;IAEb,MAAM,YAAY,GAChB,OAAO,CAAC,KAA6B,CAAC,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;IAErE,MAAM,UAAU,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC;IACpE,MAAM,cAAc,GAClB,CAAC,gBAAgB,GAAG,SAAS,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC;IAE3D,OAAO,UAAU,GAAG,cAAc,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;QAChB,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/B,CAAC"}
|
|
@@ -5,15 +5,14 @@
|
|
|
5
5
|
import type { ChatCompletionParams, ChatCompletionResponse } from './types.js';
|
|
6
6
|
export declare class DeepSeekClient {
|
|
7
7
|
private client;
|
|
8
|
-
|
|
9
|
-
constructor(apiKey: string);
|
|
8
|
+
constructor();
|
|
10
9
|
/**
|
|
11
10
|
* Create a chat completion (non-streaming)
|
|
12
11
|
*/
|
|
13
12
|
createChatCompletion(params: ChatCompletionParams): Promise<ChatCompletionResponse>;
|
|
14
13
|
/**
|
|
15
14
|
* Create a streaming chat completion
|
|
16
|
-
* Returns the full text after streaming completes
|
|
15
|
+
* Returns the full text after streaming completes (buffered)
|
|
17
16
|
*/
|
|
18
17
|
createStreamingChatCompletion(params: ChatCompletionParams): Promise<ChatCompletionResponse>;
|
|
19
18
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepseek-client.d.ts","sourceRoot":"","sources":["../src/deepseek-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"deepseek-client.d.ts","sourceRoot":"","sources":["../src/deepseek-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EAEvB,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;;IAavB;;OAEG;IACG,oBAAoB,CACxB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,sBAAsB,CAAC;IAkElC;;;OAGG;IACG,6BAA6B,CACjC,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,sBAAsB,CAAC;IAyHlC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAazC"}
|
package/dist/deepseek-client.js
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
* Wrapper around OpenAI SDK for DeepSeek API
|
|
4
4
|
*/
|
|
5
5
|
import OpenAI from 'openai';
|
|
6
|
+
import { getConfig } from './config.js';
|
|
6
7
|
export class DeepSeekClient {
|
|
7
8
|
client;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (!apiKey) {
|
|
11
|
-
throw new Error('DeepSeek API key is required');
|
|
12
|
-
}
|
|
9
|
+
constructor() {
|
|
10
|
+
const config = getConfig();
|
|
13
11
|
this.client = new OpenAI({
|
|
14
|
-
apiKey,
|
|
15
|
-
baseURL:
|
|
12
|
+
apiKey: config.apiKey,
|
|
13
|
+
baseURL: config.baseUrl,
|
|
14
|
+
timeout: config.requestTimeout,
|
|
15
|
+
maxRetries: config.maxRetries,
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
@@ -20,7 +20,9 @@ export class DeepSeekClient {
|
|
|
20
20
|
*/
|
|
21
21
|
async createChatCompletion(params) {
|
|
22
22
|
try {
|
|
23
|
-
|
|
23
|
+
// Build request params - using 'any' for OpenAI SDK compatibility
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
+
const requestParams = {
|
|
24
26
|
model: params.model,
|
|
25
27
|
messages: params.messages,
|
|
26
28
|
temperature: params.temperature ?? 1.0,
|
|
@@ -30,7 +32,14 @@ export class DeepSeekClient {
|
|
|
30
32
|
presence_penalty: params.presence_penalty,
|
|
31
33
|
stop: params.stop,
|
|
32
34
|
stream: false,
|
|
33
|
-
}
|
|
35
|
+
};
|
|
36
|
+
if (params.tools?.length) {
|
|
37
|
+
requestParams.tools = params.tools;
|
|
38
|
+
}
|
|
39
|
+
if (params.tool_choice !== undefined) {
|
|
40
|
+
requestParams.tool_choice = params.tool_choice;
|
|
41
|
+
}
|
|
42
|
+
const response = await this.client.chat.completions.create(requestParams);
|
|
34
43
|
const choice = response.choices[0];
|
|
35
44
|
if (!choice) {
|
|
36
45
|
throw new Error('No response from DeepSeek API');
|
|
@@ -39,6 +48,15 @@ export class DeepSeekClient {
|
|
|
39
48
|
const reasoning_content = 'reasoning_content' in choice.message
|
|
40
49
|
? choice.message.reasoning_content
|
|
41
50
|
: undefined;
|
|
51
|
+
// Extract tool_calls if present
|
|
52
|
+
const tool_calls = choice.message.tool_calls?.map((tc) => ({
|
|
53
|
+
id: tc.id,
|
|
54
|
+
type: 'function',
|
|
55
|
+
function: {
|
|
56
|
+
name: tc.function.name,
|
|
57
|
+
arguments: tc.function.arguments,
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
42
60
|
return {
|
|
43
61
|
content: choice.message.content || '',
|
|
44
62
|
reasoning_content,
|
|
@@ -49,6 +67,7 @@ export class DeepSeekClient {
|
|
|
49
67
|
total_tokens: response.usage?.total_tokens || 0,
|
|
50
68
|
},
|
|
51
69
|
finish_reason: choice.finish_reason || 'stop',
|
|
70
|
+
tool_calls: tool_calls?.length ? tool_calls : undefined,
|
|
52
71
|
};
|
|
53
72
|
}
|
|
54
73
|
catch (error) {
|
|
@@ -58,11 +77,13 @@ export class DeepSeekClient {
|
|
|
58
77
|
}
|
|
59
78
|
/**
|
|
60
79
|
* Create a streaming chat completion
|
|
61
|
-
* Returns the full text after streaming completes
|
|
80
|
+
* Returns the full text after streaming completes (buffered)
|
|
62
81
|
*/
|
|
63
82
|
async createStreamingChatCompletion(params) {
|
|
64
83
|
try {
|
|
65
|
-
|
|
84
|
+
// Build request params - using 'any' for OpenAI SDK compatibility
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
|
+
const requestParams = {
|
|
66
87
|
model: params.model,
|
|
67
88
|
messages: params.messages,
|
|
68
89
|
temperature: params.temperature ?? 1.0,
|
|
@@ -72,7 +93,14 @@ export class DeepSeekClient {
|
|
|
72
93
|
presence_penalty: params.presence_penalty,
|
|
73
94
|
stop: params.stop,
|
|
74
95
|
stream: true,
|
|
75
|
-
}
|
|
96
|
+
};
|
|
97
|
+
if (params.tools?.length) {
|
|
98
|
+
requestParams.tools = params.tools;
|
|
99
|
+
}
|
|
100
|
+
if (params.tool_choice !== undefined) {
|
|
101
|
+
requestParams.tool_choice = params.tool_choice;
|
|
102
|
+
}
|
|
103
|
+
const stream = await this.client.chat.completions.create(requestParams);
|
|
76
104
|
let fullContent = '';
|
|
77
105
|
let reasoningContent = '';
|
|
78
106
|
let modelName = params.model;
|
|
@@ -82,6 +110,8 @@ export class DeepSeekClient {
|
|
|
82
110
|
completion_tokens: 0,
|
|
83
111
|
total_tokens: 0,
|
|
84
112
|
};
|
|
113
|
+
// Tool calls accumulation (index-based)
|
|
114
|
+
const toolCallsMap = new Map();
|
|
85
115
|
// Collect all chunks
|
|
86
116
|
for await (const chunk of stream) {
|
|
87
117
|
const choice = chunk.choices[0];
|
|
@@ -92,9 +122,31 @@ export class DeepSeekClient {
|
|
|
92
122
|
fullContent += choice.delta.content;
|
|
93
123
|
}
|
|
94
124
|
// Collect reasoning content (for deepseek-reasoner)
|
|
95
|
-
if ('reasoning_content' in choice.delta) {
|
|
125
|
+
if ('reasoning_content' in (choice.delta || {})) {
|
|
96
126
|
reasoningContent += choice.delta.reasoning_content || '';
|
|
97
127
|
}
|
|
128
|
+
// Accumulate tool_calls deltas
|
|
129
|
+
if (choice.delta?.tool_calls) {
|
|
130
|
+
for (const tc of choice.delta.tool_calls) {
|
|
131
|
+
const existing = toolCallsMap.get(tc.index);
|
|
132
|
+
if (existing) {
|
|
133
|
+
if (tc.function?.name)
|
|
134
|
+
existing.function.name += tc.function.name;
|
|
135
|
+
if (tc.function?.arguments)
|
|
136
|
+
existing.function.arguments += tc.function.arguments;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
toolCallsMap.set(tc.index, {
|
|
140
|
+
id: tc.id || '',
|
|
141
|
+
type: 'function',
|
|
142
|
+
function: {
|
|
143
|
+
name: tc.function?.name || '',
|
|
144
|
+
arguments: tc.function?.arguments || '',
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
98
150
|
// Get finish reason
|
|
99
151
|
if (choice.finish_reason) {
|
|
100
152
|
finishReason = choice.finish_reason;
|
|
@@ -108,12 +160,19 @@ export class DeepSeekClient {
|
|
|
108
160
|
usage = chunk.usage;
|
|
109
161
|
}
|
|
110
162
|
}
|
|
163
|
+
// Convert tool calls map to sorted array
|
|
164
|
+
const toolCalls = toolCallsMap.size > 0
|
|
165
|
+
? Array.from(toolCallsMap.entries())
|
|
166
|
+
.sort(([a], [b]) => a - b)
|
|
167
|
+
.map(([, tc]) => tc)
|
|
168
|
+
: undefined;
|
|
111
169
|
return {
|
|
112
170
|
content: fullContent,
|
|
113
171
|
reasoning_content: reasoningContent || undefined,
|
|
114
172
|
model: modelName,
|
|
115
173
|
usage,
|
|
116
174
|
finish_reason: finishReason,
|
|
175
|
+
tool_calls: toolCalls,
|
|
117
176
|
};
|
|
118
177
|
}
|
|
119
178
|
catch (error) {
|