@halo-sdk/adapters 1.0.0 → 1.0.1
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 +70 -2
- package/dist/deepseek.d.ts +4 -4
- package/dist/deepseek.d.ts.map +1 -1
- package/dist/index.cjs +227 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +199 -1
- package/dist/index.js.map +1 -1
- package/package.json +14 -11
- package/dist/deepseek.js +0 -153
- package/dist/deepseek.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
# @halo-sdk/adapters
|
|
2
2
|
|
|
3
|
-
Model adapters for Halo AI SDK.
|
|
3
|
+
Model adapters for Halo AI SDK — provider-specific implementations of the `ModelAdapter` interface.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @halo-sdk/adapters
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires `@halo-sdk/core` as a peer dependency.
|
|
12
|
+
|
|
13
|
+
## DeepSeek Adapter
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { DeepSeekAdapter } from "@halo-sdk/adapters";
|
|
17
|
+
import { Halo } from "@halo-sdk/core";
|
|
18
|
+
|
|
19
|
+
const halo = new Halo({
|
|
20
|
+
adapter: new DeepSeekAdapter({
|
|
21
|
+
apiKey: process.env.DEEPSEEK_API_KEY!,
|
|
22
|
+
model: "deepseek-v4-pro", // optional, defaults to deepseek-v4-flash
|
|
23
|
+
baseUrl: "https://api.deepseek.com", // optional, for proxies or self-hosted
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Prefix Caching
|
|
29
|
+
|
|
30
|
+
DeepSeek automatically caches the stable prefix (system prompt + tools + few-shots). The adapter tracks cache hits and reports them via `agent.stats.caching`:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
console.log(agent.stats.caching);
|
|
34
|
+
// → { totalCacheHitTokens, totalCacheMissTokens, cacheHitRate, estimatedSavingsUsd }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Keep-Alive
|
|
38
|
+
|
|
39
|
+
Server-side KV cache expires after ~5 minutes. Use `agent.keepAlive()` to maintain it:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
const { stop } = agent.keepAlive(120_000); // ping every 2 min
|
|
43
|
+
// ... long task ...
|
|
44
|
+
stop();
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Custom Adapter
|
|
48
|
+
|
|
49
|
+
Implement `ModelAdapter` to support any LLM provider:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import type { ModelAdapter, ModelCapabilities, ChatParams } from "@halo-sdk/core";
|
|
53
|
+
|
|
54
|
+
class MyAdapter implements ModelAdapter {
|
|
55
|
+
readonly modelId = "my-model";
|
|
56
|
+
readonly contextWindow = 128_000;
|
|
57
|
+
readonly capabilities: ModelCapabilities = { toolUse: true, streaming: true };
|
|
58
|
+
|
|
59
|
+
async chat(params: ChatParams) {
|
|
60
|
+
const messages = [...params.prefix, ...params.history];
|
|
61
|
+
// Call your provider's API...
|
|
62
|
+
return { content, toolCalls, usage };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async *stream(params: ChatParams): AsyncGenerator<TurnChunk> {
|
|
66
|
+
// Yield { type: "text-delta", delta } | { type: "tool-call-ready", ... } | { type: "done", usage }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Documentation
|
|
72
|
+
|
|
73
|
+
See the [Halo SDK docs](https://halo-sdk.github.io/halo-ai/en/api-reference/deepseek-adapter) for full API reference.
|
package/dist/deepseek.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ModelAdapter, ModelCapabilities, PricingInfo } from "@halo-sdk/core";
|
|
1
|
+
import type { Usage, TurnChunk, ToolCall, ModelAdapter, ModelCapabilities, PricingInfo, ChatParams } from "@halo-sdk/core";
|
|
3
2
|
export declare class DeepSeekAdapter implements ModelAdapter {
|
|
4
3
|
readonly modelId: string;
|
|
5
4
|
readonly contextWindow = 128000;
|
|
@@ -13,11 +12,12 @@ export declare class DeepSeekAdapter implements ModelAdapter {
|
|
|
13
12
|
model?: string;
|
|
14
13
|
baseUrl?: string;
|
|
15
14
|
});
|
|
16
|
-
chat(
|
|
15
|
+
chat(params: ChatParams): Promise<{
|
|
17
16
|
content: string;
|
|
18
17
|
toolCalls: ToolCall[];
|
|
19
18
|
usage: Usage;
|
|
20
19
|
}>;
|
|
21
|
-
stream(
|
|
20
|
+
stream(params: ChatParams): AsyncGenerator<TurnChunk>;
|
|
21
|
+
private _applyOptions;
|
|
22
22
|
}
|
|
23
23
|
//# sourceMappingURL=deepseek.d.ts.map
|
package/dist/deepseek.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,UAAU,EAEX,MAAM,gBAAgB,CAAC;AAExB,qBAAa,eAAgB,YAAW,YAAY;IAClD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,UAAW;IACjC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAGtC;IAEF,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,WAAW,CAG3B;IAEF,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;gBAEb,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAMhE,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC;QACtC,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,QAAQ,EAAE,CAAC;QACtB,KAAK,EAAE,KAAK,CAAC;KACd,CAAC;IAoDK,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC,SAAS,CAAC;IAiJ5D,OAAO,CAAC,aAAa;CAQtB"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
DeepSeekAdapter: () => DeepSeekAdapter
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/deepseek.ts
|
|
28
|
+
var DeepSeekAdapter = class {
|
|
29
|
+
modelId;
|
|
30
|
+
contextWindow = 128e3;
|
|
31
|
+
capabilities = {
|
|
32
|
+
toolUse: true,
|
|
33
|
+
streaming: true
|
|
34
|
+
};
|
|
35
|
+
/** DeepSeek pricing (USD per 1K tokens). */
|
|
36
|
+
pricing = {
|
|
37
|
+
inputPricePer1k: 27e-5,
|
|
38
|
+
cachedInputPricePer1k: 7e-5
|
|
39
|
+
};
|
|
40
|
+
_apiKey;
|
|
41
|
+
_baseUrl;
|
|
42
|
+
constructor(opts) {
|
|
43
|
+
this._apiKey = opts.apiKey;
|
|
44
|
+
this.modelId = opts.model ?? "deepseek-v4-flash";
|
|
45
|
+
this._baseUrl = (opts.baseUrl ?? "https://api.deepseek.com").replace(/\/+$/, "");
|
|
46
|
+
}
|
|
47
|
+
async chat(params) {
|
|
48
|
+
const { prefix, history, tools, responseFormat, options } = params;
|
|
49
|
+
const messages = [...prefix, ...history];
|
|
50
|
+
const body = {
|
|
51
|
+
model: this.modelId,
|
|
52
|
+
messages,
|
|
53
|
+
stream: false
|
|
54
|
+
};
|
|
55
|
+
if (tools?.length) body.tools = tools;
|
|
56
|
+
if (responseFormat) body.response_format = responseFormat;
|
|
57
|
+
if (options) this._applyOptions(body, options);
|
|
58
|
+
const resp = await fetch(`${this._baseUrl}/chat/completions`, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: {
|
|
61
|
+
Authorization: `Bearer ${this._apiKey}`,
|
|
62
|
+
"Content-Type": "application/json"
|
|
63
|
+
},
|
|
64
|
+
body: JSON.stringify(body)
|
|
65
|
+
});
|
|
66
|
+
if (!resp.ok) {
|
|
67
|
+
throw new Error(`DeepSeek ${resp.status}: ${await resp.text()}`);
|
|
68
|
+
}
|
|
69
|
+
const data = await resp.json();
|
|
70
|
+
const choice = data.choices?.[0]?.message;
|
|
71
|
+
const usageRaw = data.usage;
|
|
72
|
+
const content = choice?.content ?? "";
|
|
73
|
+
const toolCalls = choice?.tool_calls ?? [];
|
|
74
|
+
const promptTokens = usageRaw?.prompt_tokens ?? 0;
|
|
75
|
+
const completionTokens = usageRaw?.completion_tokens ?? 0;
|
|
76
|
+
const cacheHit = usageRaw?.prompt_cache_hit_tokens ?? 0;
|
|
77
|
+
const cacheMiss = usageRaw?.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);
|
|
78
|
+
const usage = {
|
|
79
|
+
promptTokens,
|
|
80
|
+
completionTokens,
|
|
81
|
+
caching: {
|
|
82
|
+
hitTokens: cacheHit,
|
|
83
|
+
missTokens: cacheMiss,
|
|
84
|
+
hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
return { content, toolCalls, usage };
|
|
88
|
+
}
|
|
89
|
+
async *stream(params) {
|
|
90
|
+
const { prefix, history, tools, responseFormat, options } = params;
|
|
91
|
+
const messages = [...prefix, ...history];
|
|
92
|
+
const body = {
|
|
93
|
+
model: this.modelId,
|
|
94
|
+
messages,
|
|
95
|
+
stream: true,
|
|
96
|
+
stream_options: { include_usage: true }
|
|
97
|
+
};
|
|
98
|
+
if (tools?.length) body.tools = tools;
|
|
99
|
+
if (responseFormat) body.response_format = responseFormat;
|
|
100
|
+
if (options) this._applyOptions(body, options);
|
|
101
|
+
const resp = await fetch(`${this._baseUrl}/chat/completions`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: {
|
|
104
|
+
Authorization: `Bearer ${this._apiKey}`,
|
|
105
|
+
"Content-Type": "application/json",
|
|
106
|
+
Accept: "text/event-stream"
|
|
107
|
+
},
|
|
108
|
+
body: JSON.stringify(body)
|
|
109
|
+
});
|
|
110
|
+
if (!resp.ok || !resp.body) {
|
|
111
|
+
throw new Error(`DeepSeek ${resp.status}: ${await resp.text().catch(() => "")}`);
|
|
112
|
+
}
|
|
113
|
+
const reader = resp.body.getReader();
|
|
114
|
+
const decoder = new TextDecoder();
|
|
115
|
+
let buffer = "";
|
|
116
|
+
const tcBuilder = /* @__PURE__ */ new Map();
|
|
117
|
+
const flushToolCalls = async function* () {
|
|
118
|
+
for (const [index, tc] of tcBuilder) {
|
|
119
|
+
if (tc.name) {
|
|
120
|
+
yield {
|
|
121
|
+
type: "tool-call-ready",
|
|
122
|
+
index,
|
|
123
|
+
call: {
|
|
124
|
+
id: tc.id || `call_${index}`,
|
|
125
|
+
type: "function",
|
|
126
|
+
function: { name: tc.name, arguments: tc.arguments }
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
tcBuilder.clear();
|
|
132
|
+
};
|
|
133
|
+
try {
|
|
134
|
+
while (true) {
|
|
135
|
+
const { value, done } = await reader.read();
|
|
136
|
+
if (done) break;
|
|
137
|
+
buffer += decoder.decode(value, { stream: true });
|
|
138
|
+
const lines = buffer.split("\n");
|
|
139
|
+
buffer = lines.pop() ?? "";
|
|
140
|
+
for (const line of lines) {
|
|
141
|
+
const trimmed = line.trim();
|
|
142
|
+
if (!trimmed || !trimmed.startsWith("data: ")) continue;
|
|
143
|
+
const data = trimmed.slice(6);
|
|
144
|
+
if (data === "[DONE]") {
|
|
145
|
+
yield* flushToolCalls();
|
|
146
|
+
yield {
|
|
147
|
+
type: "done",
|
|
148
|
+
usage: { promptTokens: 0, completionTokens: 0 }
|
|
149
|
+
};
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const json = JSON.parse(data);
|
|
154
|
+
const delta = json.choices?.[0]?.delta;
|
|
155
|
+
if (delta?.content) {
|
|
156
|
+
yield {
|
|
157
|
+
type: "text-delta",
|
|
158
|
+
delta: String(delta.content)
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const toolCalls = delta?.tool_calls;
|
|
162
|
+
if (toolCalls) {
|
|
163
|
+
for (let i = 0; i < toolCalls.length; i++) {
|
|
164
|
+
const tc = toolCalls[i];
|
|
165
|
+
const idx = typeof tc.index === "number" ? tc.index : i;
|
|
166
|
+
const existing = tcBuilder.get(idx) ?? {
|
|
167
|
+
name: "",
|
|
168
|
+
arguments: "",
|
|
169
|
+
id: tc.id ?? `call_${idx}`
|
|
170
|
+
};
|
|
171
|
+
if (tc.function?.name) existing.name = String(tc.function.name);
|
|
172
|
+
if (tc.function?.arguments) {
|
|
173
|
+
existing.arguments += String(tc.function.arguments);
|
|
174
|
+
}
|
|
175
|
+
if (tc.id) existing.id = tc.id;
|
|
176
|
+
tcBuilder.set(idx, existing);
|
|
177
|
+
yield {
|
|
178
|
+
type: "tool-call-delta",
|
|
179
|
+
index: idx,
|
|
180
|
+
name: tc.function ? String(tc.function.name ?? "") : void 0,
|
|
181
|
+
argumentsDelta: tc.function ? String(tc.function.arguments ?? "") : void 0
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const usageRaw = json.usage;
|
|
186
|
+
if (usageRaw) {
|
|
187
|
+
const promptTokens = usageRaw.prompt_tokens ?? 0;
|
|
188
|
+
const completionTokens = usageRaw.completion_tokens ?? 0;
|
|
189
|
+
const cacheHit = usageRaw.prompt_cache_hit_tokens ?? 0;
|
|
190
|
+
const cacheMiss = usageRaw.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);
|
|
191
|
+
yield* flushToolCalls();
|
|
192
|
+
yield {
|
|
193
|
+
type: "done",
|
|
194
|
+
usage: {
|
|
195
|
+
promptTokens,
|
|
196
|
+
completionTokens,
|
|
197
|
+
caching: {
|
|
198
|
+
hitTokens: cacheHit,
|
|
199
|
+
missTokens: cacheMiss,
|
|
200
|
+
hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
} catch {
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
yield* flushToolCalls();
|
|
210
|
+
} finally {
|
|
211
|
+
reader.releaseLock();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
_applyOptions(body, options) {
|
|
215
|
+
if (options.temperature !== void 0) body.temperature = options.temperature;
|
|
216
|
+
if (options.topP !== void 0) body.top_p = options.topP;
|
|
217
|
+
if (options.topK !== void 0) body.top_k = options.topK;
|
|
218
|
+
if (options.maxTokens !== void 0) body.max_tokens = options.maxTokens;
|
|
219
|
+
if (options.seed !== void 0) body.seed = options.seed;
|
|
220
|
+
if (options.stop !== void 0) body.stop = options.stop;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
224
|
+
0 && (module.exports = {
|
|
225
|
+
DeepSeekAdapter
|
|
226
|
+
});
|
|
227
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/deepseek.ts"],"sourcesContent":["export { DeepSeekAdapter } from \"./deepseek.js\";\n","import type {\n Usage,\n TurnChunk,\n ToolCall,\n ModelAdapter,\n ModelCapabilities,\n PricingInfo,\n ChatParams,\n ModelCallOptions,\n} from \"@halo-sdk/core\";\n\nexport class DeepSeekAdapter implements ModelAdapter {\n readonly modelId: string;\n readonly contextWindow = 128_000;\n readonly capabilities: ModelCapabilities = {\n toolUse: true,\n streaming: true,\n };\n\n /** DeepSeek pricing (USD per 1K tokens). */\n readonly pricing: PricingInfo = {\n inputPricePer1k: 0.00027,\n cachedInputPricePer1k: 0.00007,\n };\n\n private _apiKey: string;\n private _baseUrl: string;\n\n constructor(opts: { apiKey: string; model?: string; baseUrl?: string }) {\n this._apiKey = opts.apiKey;\n this.modelId = opts.model ?? \"deepseek-v4-flash\";\n this._baseUrl = (opts.baseUrl ?? \"https://api.deepseek.com\").replace(/\\/+$/, \"\");\n }\n\n async chat(params: ChatParams): Promise<{\n content: string;\n toolCalls: ToolCall[];\n usage: Usage;\n }> {\n const { prefix, history, tools, responseFormat, options } = params;\n const messages = [...prefix, ...history];\n const body: Record<string, unknown> = {\n model: this.modelId,\n messages,\n stream: false,\n };\n if (tools?.length) body.tools = tools;\n if (responseFormat) body.response_format = responseFormat;\n if (options) this._applyOptions(body, options);\n\n const resp = await fetch(`${this._baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this._apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n throw new Error(`DeepSeek ${resp.status}: ${await resp.text()}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data: any = await resp.json();\n const choice = data.choices?.[0]?.message;\n const usageRaw = data.usage;\n\n const content: string = choice?.content ?? \"\";\n const toolCalls: ToolCall[] = choice?.tool_calls ?? [];\n\n const promptTokens: number = usageRaw?.prompt_tokens ?? 0;\n const completionTokens: number = usageRaw?.completion_tokens ?? 0;\n const cacheHit: number = usageRaw?.prompt_cache_hit_tokens ?? 0;\n const cacheMiss: number =\n usageRaw?.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);\n\n const usage: Usage = {\n promptTokens,\n completionTokens,\n caching: {\n hitTokens: cacheHit,\n missTokens: cacheMiss,\n hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0,\n },\n };\n\n return { content, toolCalls, usage };\n }\n\n async *stream(params: ChatParams): AsyncGenerator<TurnChunk> {\n const { prefix, history, tools, responseFormat, options } = params;\n const messages = [...prefix, ...history];\n const body: Record<string, unknown> = {\n model: this.modelId,\n messages,\n stream: true,\n stream_options: { include_usage: true },\n };\n if (tools?.length) body.tools = tools;\n if (responseFormat) body.response_format = responseFormat;\n if (options) this._applyOptions(body, options);\n\n const resp = await fetch(`${this._baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this._apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok || !resp.body) {\n throw new Error(`DeepSeek ${resp.status}: ${await resp.text().catch(() => \"\")}`);\n }\n\n const reader = resp.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n // Accumulate streaming tool-call deltas → emit tool-call-ready when complete.\n const tcBuilder = new Map<number, { name: string; arguments: string; id: string }>();\n\n const flushToolCalls = async function* () {\n for (const [index, tc] of tcBuilder) {\n if (tc.name) {\n yield {\n type: \"tool-call-ready\" as const,\n index,\n call: {\n id: tc.id || `call_${index}`,\n type: \"function\" as const,\n function: { name: tc.name, arguments: tc.arguments },\n },\n };\n }\n }\n tcBuilder.clear();\n };\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || !trimmed.startsWith(\"data: \")) continue;\n const data = trimmed.slice(6);\n if (data === \"[DONE]\") {\n yield* flushToolCalls();\n yield {\n type: \"done\",\n usage: { promptTokens: 0, completionTokens: 0 },\n };\n return;\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = JSON.parse(data);\n const delta = json.choices?.[0]?.delta;\n if (delta?.content) {\n yield {\n type: \"text-delta\",\n delta: String(delta.content),\n };\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const toolCalls: any[] | undefined = delta?.tool_calls;\n if (toolCalls) {\n for (let i = 0; i < toolCalls.length; i++) {\n const tc = toolCalls[i]!;\n const idx = typeof tc.index === \"number\" ? tc.index : i;\n const existing = tcBuilder.get(idx) ?? {\n name: \"\",\n arguments: \"\",\n id: tc.id ?? `call_${idx}`,\n };\n if (tc.function?.name) existing.name = String(tc.function.name);\n if (tc.function?.arguments) {\n existing.arguments += String(tc.function.arguments);\n }\n if (tc.id) existing.id = tc.id;\n tcBuilder.set(idx, existing);\n\n yield {\n type: \"tool-call-delta\",\n index: idx,\n name: tc.function ? String(tc.function.name ?? \"\") : undefined,\n argumentsDelta: tc.function ? String(tc.function.arguments ?? \"\") : undefined,\n };\n }\n }\n const usageRaw = json.usage;\n if (usageRaw) {\n const promptTokens = usageRaw.prompt_tokens ?? 0;\n const completionTokens = usageRaw.completion_tokens ?? 0;\n const cacheHit = usageRaw.prompt_cache_hit_tokens ?? 0;\n const cacheMiss =\n usageRaw.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);\n\n // Emit tool-call-ready for all accumulated tool calls\n // before the final done chunk.\n yield* flushToolCalls();\n\n yield {\n type: \"done\",\n usage: {\n promptTokens,\n completionTokens,\n caching: {\n hitTokens: cacheHit,\n missTokens: cacheMiss,\n hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0,\n },\n },\n };\n }\n } catch {\n /* skip malformed SSE frame */\n }\n }\n }\n\n // Stream ended without an explicit usage chunk.\n yield* flushToolCalls();\n } finally {\n reader.releaseLock();\n }\n }\n\n private _applyOptions(body: Record<string, unknown>, options: ModelCallOptions): void {\n if (options.temperature !== undefined) body.temperature = options.temperature;\n if (options.topP !== undefined) body.top_p = options.topP;\n if (options.topK !== undefined) body.top_k = options.topK;\n if (options.maxTokens !== undefined) body.max_tokens = options.maxTokens;\n if (options.seed !== undefined) body.seed = options.seed;\n if (options.stop !== undefined) body.stop = options.stop;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,200 @@
|
|
|
1
|
-
|
|
1
|
+
// src/deepseek.ts
|
|
2
|
+
var DeepSeekAdapter = class {
|
|
3
|
+
modelId;
|
|
4
|
+
contextWindow = 128e3;
|
|
5
|
+
capabilities = {
|
|
6
|
+
toolUse: true,
|
|
7
|
+
streaming: true
|
|
8
|
+
};
|
|
9
|
+
/** DeepSeek pricing (USD per 1K tokens). */
|
|
10
|
+
pricing = {
|
|
11
|
+
inputPricePer1k: 27e-5,
|
|
12
|
+
cachedInputPricePer1k: 7e-5
|
|
13
|
+
};
|
|
14
|
+
_apiKey;
|
|
15
|
+
_baseUrl;
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
this._apiKey = opts.apiKey;
|
|
18
|
+
this.modelId = opts.model ?? "deepseek-v4-flash";
|
|
19
|
+
this._baseUrl = (opts.baseUrl ?? "https://api.deepseek.com").replace(/\/+$/, "");
|
|
20
|
+
}
|
|
21
|
+
async chat(params) {
|
|
22
|
+
const { prefix, history, tools, responseFormat, options } = params;
|
|
23
|
+
const messages = [...prefix, ...history];
|
|
24
|
+
const body = {
|
|
25
|
+
model: this.modelId,
|
|
26
|
+
messages,
|
|
27
|
+
stream: false
|
|
28
|
+
};
|
|
29
|
+
if (tools?.length) body.tools = tools;
|
|
30
|
+
if (responseFormat) body.response_format = responseFormat;
|
|
31
|
+
if (options) this._applyOptions(body, options);
|
|
32
|
+
const resp = await fetch(`${this._baseUrl}/chat/completions`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: `Bearer ${this._apiKey}`,
|
|
36
|
+
"Content-Type": "application/json"
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify(body)
|
|
39
|
+
});
|
|
40
|
+
if (!resp.ok) {
|
|
41
|
+
throw new Error(`DeepSeek ${resp.status}: ${await resp.text()}`);
|
|
42
|
+
}
|
|
43
|
+
const data = await resp.json();
|
|
44
|
+
const choice = data.choices?.[0]?.message;
|
|
45
|
+
const usageRaw = data.usage;
|
|
46
|
+
const content = choice?.content ?? "";
|
|
47
|
+
const toolCalls = choice?.tool_calls ?? [];
|
|
48
|
+
const promptTokens = usageRaw?.prompt_tokens ?? 0;
|
|
49
|
+
const completionTokens = usageRaw?.completion_tokens ?? 0;
|
|
50
|
+
const cacheHit = usageRaw?.prompt_cache_hit_tokens ?? 0;
|
|
51
|
+
const cacheMiss = usageRaw?.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);
|
|
52
|
+
const usage = {
|
|
53
|
+
promptTokens,
|
|
54
|
+
completionTokens,
|
|
55
|
+
caching: {
|
|
56
|
+
hitTokens: cacheHit,
|
|
57
|
+
missTokens: cacheMiss,
|
|
58
|
+
hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return { content, toolCalls, usage };
|
|
62
|
+
}
|
|
63
|
+
async *stream(params) {
|
|
64
|
+
const { prefix, history, tools, responseFormat, options } = params;
|
|
65
|
+
const messages = [...prefix, ...history];
|
|
66
|
+
const body = {
|
|
67
|
+
model: this.modelId,
|
|
68
|
+
messages,
|
|
69
|
+
stream: true,
|
|
70
|
+
stream_options: { include_usage: true }
|
|
71
|
+
};
|
|
72
|
+
if (tools?.length) body.tools = tools;
|
|
73
|
+
if (responseFormat) body.response_format = responseFormat;
|
|
74
|
+
if (options) this._applyOptions(body, options);
|
|
75
|
+
const resp = await fetch(`${this._baseUrl}/chat/completions`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
Authorization: `Bearer ${this._apiKey}`,
|
|
79
|
+
"Content-Type": "application/json",
|
|
80
|
+
Accept: "text/event-stream"
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify(body)
|
|
83
|
+
});
|
|
84
|
+
if (!resp.ok || !resp.body) {
|
|
85
|
+
throw new Error(`DeepSeek ${resp.status}: ${await resp.text().catch(() => "")}`);
|
|
86
|
+
}
|
|
87
|
+
const reader = resp.body.getReader();
|
|
88
|
+
const decoder = new TextDecoder();
|
|
89
|
+
let buffer = "";
|
|
90
|
+
const tcBuilder = /* @__PURE__ */ new Map();
|
|
91
|
+
const flushToolCalls = async function* () {
|
|
92
|
+
for (const [index, tc] of tcBuilder) {
|
|
93
|
+
if (tc.name) {
|
|
94
|
+
yield {
|
|
95
|
+
type: "tool-call-ready",
|
|
96
|
+
index,
|
|
97
|
+
call: {
|
|
98
|
+
id: tc.id || `call_${index}`,
|
|
99
|
+
type: "function",
|
|
100
|
+
function: { name: tc.name, arguments: tc.arguments }
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
tcBuilder.clear();
|
|
106
|
+
};
|
|
107
|
+
try {
|
|
108
|
+
while (true) {
|
|
109
|
+
const { value, done } = await reader.read();
|
|
110
|
+
if (done) break;
|
|
111
|
+
buffer += decoder.decode(value, { stream: true });
|
|
112
|
+
const lines = buffer.split("\n");
|
|
113
|
+
buffer = lines.pop() ?? "";
|
|
114
|
+
for (const line of lines) {
|
|
115
|
+
const trimmed = line.trim();
|
|
116
|
+
if (!trimmed || !trimmed.startsWith("data: ")) continue;
|
|
117
|
+
const data = trimmed.slice(6);
|
|
118
|
+
if (data === "[DONE]") {
|
|
119
|
+
yield* flushToolCalls();
|
|
120
|
+
yield {
|
|
121
|
+
type: "done",
|
|
122
|
+
usage: { promptTokens: 0, completionTokens: 0 }
|
|
123
|
+
};
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const json = JSON.parse(data);
|
|
128
|
+
const delta = json.choices?.[0]?.delta;
|
|
129
|
+
if (delta?.content) {
|
|
130
|
+
yield {
|
|
131
|
+
type: "text-delta",
|
|
132
|
+
delta: String(delta.content)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const toolCalls = delta?.tool_calls;
|
|
136
|
+
if (toolCalls) {
|
|
137
|
+
for (let i = 0; i < toolCalls.length; i++) {
|
|
138
|
+
const tc = toolCalls[i];
|
|
139
|
+
const idx = typeof tc.index === "number" ? tc.index : i;
|
|
140
|
+
const existing = tcBuilder.get(idx) ?? {
|
|
141
|
+
name: "",
|
|
142
|
+
arguments: "",
|
|
143
|
+
id: tc.id ?? `call_${idx}`
|
|
144
|
+
};
|
|
145
|
+
if (tc.function?.name) existing.name = String(tc.function.name);
|
|
146
|
+
if (tc.function?.arguments) {
|
|
147
|
+
existing.arguments += String(tc.function.arguments);
|
|
148
|
+
}
|
|
149
|
+
if (tc.id) existing.id = tc.id;
|
|
150
|
+
tcBuilder.set(idx, existing);
|
|
151
|
+
yield {
|
|
152
|
+
type: "tool-call-delta",
|
|
153
|
+
index: idx,
|
|
154
|
+
name: tc.function ? String(tc.function.name ?? "") : void 0,
|
|
155
|
+
argumentsDelta: tc.function ? String(tc.function.arguments ?? "") : void 0
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const usageRaw = json.usage;
|
|
160
|
+
if (usageRaw) {
|
|
161
|
+
const promptTokens = usageRaw.prompt_tokens ?? 0;
|
|
162
|
+
const completionTokens = usageRaw.completion_tokens ?? 0;
|
|
163
|
+
const cacheHit = usageRaw.prompt_cache_hit_tokens ?? 0;
|
|
164
|
+
const cacheMiss = usageRaw.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);
|
|
165
|
+
yield* flushToolCalls();
|
|
166
|
+
yield {
|
|
167
|
+
type: "done",
|
|
168
|
+
usage: {
|
|
169
|
+
promptTokens,
|
|
170
|
+
completionTokens,
|
|
171
|
+
caching: {
|
|
172
|
+
hitTokens: cacheHit,
|
|
173
|
+
missTokens: cacheMiss,
|
|
174
|
+
hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
} catch {
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
yield* flushToolCalls();
|
|
184
|
+
} finally {
|
|
185
|
+
reader.releaseLock();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
_applyOptions(body, options) {
|
|
189
|
+
if (options.temperature !== void 0) body.temperature = options.temperature;
|
|
190
|
+
if (options.topP !== void 0) body.top_p = options.topP;
|
|
191
|
+
if (options.topK !== void 0) body.top_k = options.topK;
|
|
192
|
+
if (options.maxTokens !== void 0) body.max_tokens = options.maxTokens;
|
|
193
|
+
if (options.seed !== void 0) body.seed = options.seed;
|
|
194
|
+
if (options.stop !== void 0) body.stop = options.stop;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
export {
|
|
198
|
+
DeepSeekAdapter
|
|
199
|
+
};
|
|
2
200
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"sources":["../src/deepseek.ts"],"sourcesContent":["import type {\n Usage,\n TurnChunk,\n ToolCall,\n ModelAdapter,\n ModelCapabilities,\n PricingInfo,\n ChatParams,\n ModelCallOptions,\n} from \"@halo-sdk/core\";\n\nexport class DeepSeekAdapter implements ModelAdapter {\n readonly modelId: string;\n readonly contextWindow = 128_000;\n readonly capabilities: ModelCapabilities = {\n toolUse: true,\n streaming: true,\n };\n\n /** DeepSeek pricing (USD per 1K tokens). */\n readonly pricing: PricingInfo = {\n inputPricePer1k: 0.00027,\n cachedInputPricePer1k: 0.00007,\n };\n\n private _apiKey: string;\n private _baseUrl: string;\n\n constructor(opts: { apiKey: string; model?: string; baseUrl?: string }) {\n this._apiKey = opts.apiKey;\n this.modelId = opts.model ?? \"deepseek-v4-flash\";\n this._baseUrl = (opts.baseUrl ?? \"https://api.deepseek.com\").replace(/\\/+$/, \"\");\n }\n\n async chat(params: ChatParams): Promise<{\n content: string;\n toolCalls: ToolCall[];\n usage: Usage;\n }> {\n const { prefix, history, tools, responseFormat, options } = params;\n const messages = [...prefix, ...history];\n const body: Record<string, unknown> = {\n model: this.modelId,\n messages,\n stream: false,\n };\n if (tools?.length) body.tools = tools;\n if (responseFormat) body.response_format = responseFormat;\n if (options) this._applyOptions(body, options);\n\n const resp = await fetch(`${this._baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this._apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n throw new Error(`DeepSeek ${resp.status}: ${await resp.text()}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data: any = await resp.json();\n const choice = data.choices?.[0]?.message;\n const usageRaw = data.usage;\n\n const content: string = choice?.content ?? \"\";\n const toolCalls: ToolCall[] = choice?.tool_calls ?? [];\n\n const promptTokens: number = usageRaw?.prompt_tokens ?? 0;\n const completionTokens: number = usageRaw?.completion_tokens ?? 0;\n const cacheHit: number = usageRaw?.prompt_cache_hit_tokens ?? 0;\n const cacheMiss: number =\n usageRaw?.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);\n\n const usage: Usage = {\n promptTokens,\n completionTokens,\n caching: {\n hitTokens: cacheHit,\n missTokens: cacheMiss,\n hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0,\n },\n };\n\n return { content, toolCalls, usage };\n }\n\n async *stream(params: ChatParams): AsyncGenerator<TurnChunk> {\n const { prefix, history, tools, responseFormat, options } = params;\n const messages = [...prefix, ...history];\n const body: Record<string, unknown> = {\n model: this.modelId,\n messages,\n stream: true,\n stream_options: { include_usage: true },\n };\n if (tools?.length) body.tools = tools;\n if (responseFormat) body.response_format = responseFormat;\n if (options) this._applyOptions(body, options);\n\n const resp = await fetch(`${this._baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this._apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok || !resp.body) {\n throw new Error(`DeepSeek ${resp.status}: ${await resp.text().catch(() => \"\")}`);\n }\n\n const reader = resp.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n // Accumulate streaming tool-call deltas → emit tool-call-ready when complete.\n const tcBuilder = new Map<number, { name: string; arguments: string; id: string }>();\n\n const flushToolCalls = async function* () {\n for (const [index, tc] of tcBuilder) {\n if (tc.name) {\n yield {\n type: \"tool-call-ready\" as const,\n index,\n call: {\n id: tc.id || `call_${index}`,\n type: \"function\" as const,\n function: { name: tc.name, arguments: tc.arguments },\n },\n };\n }\n }\n tcBuilder.clear();\n };\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || !trimmed.startsWith(\"data: \")) continue;\n const data = trimmed.slice(6);\n if (data === \"[DONE]\") {\n yield* flushToolCalls();\n yield {\n type: \"done\",\n usage: { promptTokens: 0, completionTokens: 0 },\n };\n return;\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = JSON.parse(data);\n const delta = json.choices?.[0]?.delta;\n if (delta?.content) {\n yield {\n type: \"text-delta\",\n delta: String(delta.content),\n };\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const toolCalls: any[] | undefined = delta?.tool_calls;\n if (toolCalls) {\n for (let i = 0; i < toolCalls.length; i++) {\n const tc = toolCalls[i]!;\n const idx = typeof tc.index === \"number\" ? tc.index : i;\n const existing = tcBuilder.get(idx) ?? {\n name: \"\",\n arguments: \"\",\n id: tc.id ?? `call_${idx}`,\n };\n if (tc.function?.name) existing.name = String(tc.function.name);\n if (tc.function?.arguments) {\n existing.arguments += String(tc.function.arguments);\n }\n if (tc.id) existing.id = tc.id;\n tcBuilder.set(idx, existing);\n\n yield {\n type: \"tool-call-delta\",\n index: idx,\n name: tc.function ? String(tc.function.name ?? \"\") : undefined,\n argumentsDelta: tc.function ? String(tc.function.arguments ?? \"\") : undefined,\n };\n }\n }\n const usageRaw = json.usage;\n if (usageRaw) {\n const promptTokens = usageRaw.prompt_tokens ?? 0;\n const completionTokens = usageRaw.completion_tokens ?? 0;\n const cacheHit = usageRaw.prompt_cache_hit_tokens ?? 0;\n const cacheMiss =\n usageRaw.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);\n\n // Emit tool-call-ready for all accumulated tool calls\n // before the final done chunk.\n yield* flushToolCalls();\n\n yield {\n type: \"done\",\n usage: {\n promptTokens,\n completionTokens,\n caching: {\n hitTokens: cacheHit,\n missTokens: cacheMiss,\n hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0,\n },\n },\n };\n }\n } catch {\n /* skip malformed SSE frame */\n }\n }\n }\n\n // Stream ended without an explicit usage chunk.\n yield* flushToolCalls();\n } finally {\n reader.releaseLock();\n }\n }\n\n private _applyOptions(body: Record<string, unknown>, options: ModelCallOptions): void {\n if (options.temperature !== undefined) body.temperature = options.temperature;\n if (options.topP !== undefined) body.top_p = options.topP;\n if (options.topK !== undefined) body.top_k = options.topK;\n if (options.maxTokens !== undefined) body.max_tokens = options.maxTokens;\n if (options.seed !== undefined) body.seed = options.seed;\n if (options.stop !== undefined) body.stop = options.stop;\n }\n}\n"],"mappings":";AAWO,IAAM,kBAAN,MAA8C;AAAA,EAC1C;AAAA,EACA,gBAAgB;AAAA,EAChB,eAAkC;AAAA,IACzC,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AAAA;AAAA,EAGS,UAAuB;AAAA,IAC9B,iBAAiB;AAAA,IACjB,uBAAuB;AAAA,EACzB;AAAA,EAEQ;AAAA,EACA;AAAA,EAER,YAAY,MAA4D;AACtE,SAAK,UAAU,KAAK;AACpB,SAAK,UAAU,KAAK,SAAS;AAC7B,SAAK,YAAY,KAAK,WAAW,4BAA4B,QAAQ,QAAQ,EAAE;AAAA,EACjF;AAAA,EAEA,MAAM,KAAK,QAIR;AACD,UAAM,EAAE,QAAQ,SAAS,OAAO,gBAAgB,QAAQ,IAAI;AAC5D,UAAM,WAAW,CAAC,GAAG,QAAQ,GAAG,OAAO;AACvC,UAAM,OAAgC;AAAA,MACpC,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,QAAQ;AAAA,IACV;AACA,QAAI,OAAO,OAAQ,MAAK,QAAQ;AAChC,QAAI,eAAgB,MAAK,kBAAkB;AAC3C,QAAI,QAAS,MAAK,cAAc,MAAM,OAAO;AAE7C,UAAM,OAAO,MAAM,MAAM,GAAG,KAAK,QAAQ,qBAAqB;AAAA,MAC5D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,OAAO;AAAA,QACrC,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI,MAAM,YAAY,KAAK,MAAM,KAAK,MAAM,KAAK,KAAK,CAAC,EAAE;AAAA,IACjE;AAGA,UAAM,OAAY,MAAM,KAAK,KAAK;AAClC,UAAM,SAAS,KAAK,UAAU,CAAC,GAAG;AAClC,UAAM,WAAW,KAAK;AAEtB,UAAM,UAAkB,QAAQ,WAAW;AAC3C,UAAM,YAAwB,QAAQ,cAAc,CAAC;AAErD,UAAM,eAAuB,UAAU,iBAAiB;AACxD,UAAM,mBAA2B,UAAU,qBAAqB;AAChE,UAAM,WAAmB,UAAU,2BAA2B;AAC9D,UAAM,YACJ,UAAU,4BAA4B,KAAK,IAAI,GAAG,eAAe,QAAQ;AAE3E,UAAM,QAAe;AAAA,MACnB;AAAA,MACA;AAAA,MACA,SAAS;AAAA,QACP,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,SAAS,WAAW,YAAY,IAAI,YAAY,WAAW,aAAa;AAAA,MAC1E;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,WAAW,MAAM;AAAA,EACrC;AAAA,EAEA,OAAO,OAAO,QAA+C;AAC3D,UAAM,EAAE,QAAQ,SAAS,OAAO,gBAAgB,QAAQ,IAAI;AAC5D,UAAM,WAAW,CAAC,GAAG,QAAQ,GAAG,OAAO;AACvC,UAAM,OAAgC;AAAA,MACpC,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,QAAQ;AAAA,MACR,gBAAgB,EAAE,eAAe,KAAK;AAAA,IACxC;AACA,QAAI,OAAO,OAAQ,MAAK,QAAQ;AAChC,QAAI,eAAgB,MAAK,kBAAkB;AAC3C,QAAI,QAAS,MAAK,cAAc,MAAM,OAAO;AAE7C,UAAM,OAAO,MAAM,MAAM,GAAG,KAAK,QAAQ,qBAAqB;AAAA,MAC5D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,OAAO;AAAA,QACrC,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,KAAK,MAAM,CAAC,KAAK,MAAM;AAC1B,YAAM,IAAI,MAAM,YAAY,KAAK,MAAM,KAAK,MAAM,KAAK,KAAK,EAAE,MAAM,MAAM,EAAE,CAAC,EAAE;AAAA,IACjF;AAEA,UAAM,SAAS,KAAK,KAAK,UAAU;AACnC,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,SAAS;AAGb,UAAM,YAAY,oBAAI,IAA6D;AAEnF,UAAM,iBAAiB,mBAAmB;AACxC,iBAAW,CAAC,OAAO,EAAE,KAAK,WAAW;AACnC,YAAI,GAAG,MAAM;AACX,gBAAM;AAAA,YACJ,MAAM;AAAA,YACN;AAAA,YACA,MAAM;AAAA,cACJ,IAAI,GAAG,MAAM,QAAQ,KAAK;AAAA,cAC1B,MAAM;AAAA,cACN,UAAU,EAAE,MAAM,GAAG,MAAM,WAAW,GAAG,UAAU;AAAA,YACrD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,gBAAU,MAAM;AAAA,IAClB;AAEA,QAAI;AACF,aAAO,MAAM;AACX,cAAM,EAAE,OAAO,KAAK,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AACV,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,cAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,iBAAS,MAAM,IAAI,KAAK;AAExB,mBAAW,QAAQ,OAAO;AACxB,gBAAM,UAAU,KAAK,KAAK;AAC1B,cAAI,CAAC,WAAW,CAAC,QAAQ,WAAW,QAAQ,EAAG;AAC/C,gBAAM,OAAO,QAAQ,MAAM,CAAC;AAC5B,cAAI,SAAS,UAAU;AACrB,mBAAO,eAAe;AACtB,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,OAAO,EAAE,cAAc,GAAG,kBAAkB,EAAE;AAAA,YAChD;AACA;AAAA,UACF;AACA,cAAI;AAEF,kBAAM,OAAY,KAAK,MAAM,IAAI;AACjC,kBAAM,QAAQ,KAAK,UAAU,CAAC,GAAG;AACjC,gBAAI,OAAO,SAAS;AAClB,oBAAM;AAAA,gBACJ,MAAM;AAAA,gBACN,OAAO,OAAO,MAAM,OAAO;AAAA,cAC7B;AAAA,YACF;AAEA,kBAAM,YAA+B,OAAO;AAC5C,gBAAI,WAAW;AACb,uBAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,sBAAM,KAAK,UAAU,CAAC;AACtB,sBAAM,MAAM,OAAO,GAAG,UAAU,WAAW,GAAG,QAAQ;AACtD,sBAAM,WAAW,UAAU,IAAI,GAAG,KAAK;AAAA,kBACrC,MAAM;AAAA,kBACN,WAAW;AAAA,kBACX,IAAI,GAAG,MAAM,QAAQ,GAAG;AAAA,gBAC1B;AACA,oBAAI,GAAG,UAAU,KAAM,UAAS,OAAO,OAAO,GAAG,SAAS,IAAI;AAC9D,oBAAI,GAAG,UAAU,WAAW;AAC1B,2BAAS,aAAa,OAAO,GAAG,SAAS,SAAS;AAAA,gBACpD;AACA,oBAAI,GAAG,GAAI,UAAS,KAAK,GAAG;AAC5B,0BAAU,IAAI,KAAK,QAAQ;AAE3B,sBAAM;AAAA,kBACJ,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,MAAM,GAAG,WAAW,OAAO,GAAG,SAAS,QAAQ,EAAE,IAAI;AAAA,kBACrD,gBAAgB,GAAG,WAAW,OAAO,GAAG,SAAS,aAAa,EAAE,IAAI;AAAA,gBACtE;AAAA,cACF;AAAA,YACF;AACA,kBAAM,WAAW,KAAK;AACtB,gBAAI,UAAU;AACZ,oBAAM,eAAe,SAAS,iBAAiB;AAC/C,oBAAM,mBAAmB,SAAS,qBAAqB;AACvD,oBAAM,WAAW,SAAS,2BAA2B;AACrD,oBAAM,YACJ,SAAS,4BAA4B,KAAK,IAAI,GAAG,eAAe,QAAQ;AAI1E,qBAAO,eAAe;AAEtB,oBAAM;AAAA,gBACJ,MAAM;AAAA,gBACN,OAAO;AAAA,kBACL;AAAA,kBACA;AAAA,kBACA,SAAS;AAAA,oBACP,WAAW;AAAA,oBACX,YAAY;AAAA,oBACZ,SAAS,WAAW,YAAY,IAAI,YAAY,WAAW,aAAa;AAAA,kBAC1E;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAGA,aAAO,eAAe;AAAA,IACxB,UAAE;AACA,aAAO,YAAY;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,cAAc,MAA+B,SAAiC;AACpF,QAAI,QAAQ,gBAAgB,OAAW,MAAK,cAAc,QAAQ;AAClE,QAAI,QAAQ,SAAS,OAAW,MAAK,QAAQ,QAAQ;AACrD,QAAI,QAAQ,SAAS,OAAW,MAAK,QAAQ,QAAQ;AACrD,QAAI,QAAQ,cAAc,OAAW,MAAK,aAAa,QAAQ;AAC/D,QAAI,QAAQ,SAAS,OAAW,MAAK,OAAO,QAAQ;AACpD,QAAI,QAAQ,SAAS,OAAW,MAAK,OAAO,QAAQ;AAAA,EACtD;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@halo-sdk/adapters",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Model adapters for Halo AI SDK — DeepSeek API with prefix cache support",
|
|
5
|
-
"license": "MIT",
|
|
6
5
|
"keywords": [
|
|
6
|
+
"adapter",
|
|
7
7
|
"ai",
|
|
8
|
-
"llm",
|
|
9
8
|
"deepseek",
|
|
10
|
-
"
|
|
9
|
+
"llm",
|
|
11
10
|
"prefix-cache"
|
|
12
11
|
],
|
|
12
|
+
"license": "MIT",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "https://github.com/halo-sdk/halo-ai",
|
|
@@ -24,23 +24,26 @@
|
|
|
24
24
|
"exports": {
|
|
25
25
|
".": {
|
|
26
26
|
"types": "./dist/index.d.ts",
|
|
27
|
-
"import": "./dist/index.js"
|
|
27
|
+
"import": "./dist/index.js",
|
|
28
|
+
"require": "./dist/index.cjs"
|
|
28
29
|
}
|
|
29
30
|
},
|
|
30
31
|
"publishConfig": {
|
|
31
32
|
"access": "public"
|
|
32
33
|
},
|
|
33
|
-
"peerDependencies": {
|
|
34
|
-
"@halo-sdk/core": ">=1.0.0"
|
|
35
|
-
},
|
|
36
34
|
"devDependencies": {
|
|
37
35
|
"typescript": "^5.8.0",
|
|
38
36
|
"vitest": "^3.0.0",
|
|
39
|
-
"@halo-sdk/core": "1.0.
|
|
37
|
+
"@halo-sdk/core": "1.0.1"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@halo-sdk/core": ">=1.0.1"
|
|
40
41
|
},
|
|
41
42
|
"scripts": {
|
|
42
|
-
"build": "tsc",
|
|
43
|
-
"dev": "
|
|
43
|
+
"build": "tsc --build --emitDeclarationOnly && tsup",
|
|
44
|
+
"dev": "tsup --watch",
|
|
45
|
+
"clean": "del-cli dist *.tsbuildinfo",
|
|
46
|
+
"publint": "publint",
|
|
44
47
|
"test": "vitest run",
|
|
45
48
|
"test:watch": "vitest"
|
|
46
49
|
}
|
package/dist/deepseek.js
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
export class DeepSeekAdapter {
|
|
2
|
-
modelId;
|
|
3
|
-
contextWindow = 128_000;
|
|
4
|
-
capabilities = {
|
|
5
|
-
toolUse: true,
|
|
6
|
-
streaming: true,
|
|
7
|
-
};
|
|
8
|
-
/** DeepSeek pricing (USD per 1K tokens). */
|
|
9
|
-
pricing = {
|
|
10
|
-
inputPricePer1k: 0.00027,
|
|
11
|
-
cachedInputPricePer1k: 0.00007,
|
|
12
|
-
};
|
|
13
|
-
_apiKey;
|
|
14
|
-
_baseUrl;
|
|
15
|
-
constructor(opts) {
|
|
16
|
-
this._apiKey = opts.apiKey;
|
|
17
|
-
this.modelId = opts.model ?? "deepseek-v4-flash";
|
|
18
|
-
this._baseUrl = (opts.baseUrl ?? "https://api.deepseek.com").replace(/\/+$/, "");
|
|
19
|
-
}
|
|
20
|
-
async chat(prefix, history, tools) {
|
|
21
|
-
const messages = [...prefix, ...history];
|
|
22
|
-
const body = {
|
|
23
|
-
model: this.modelId,
|
|
24
|
-
messages,
|
|
25
|
-
stream: false,
|
|
26
|
-
};
|
|
27
|
-
if (tools?.length)
|
|
28
|
-
body.tools = tools;
|
|
29
|
-
const resp = await fetch(`${this._baseUrl}/chat/completions`, {
|
|
30
|
-
method: "POST",
|
|
31
|
-
headers: {
|
|
32
|
-
Authorization: `Bearer ${this._apiKey}`,
|
|
33
|
-
"Content-Type": "application/json",
|
|
34
|
-
},
|
|
35
|
-
body: JSON.stringify(body),
|
|
36
|
-
});
|
|
37
|
-
if (!resp.ok) {
|
|
38
|
-
throw new Error(`DeepSeek ${resp.status}: ${await resp.text()}`);
|
|
39
|
-
}
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
-
const data = await resp.json();
|
|
42
|
-
const choice = data.choices?.[0]?.message;
|
|
43
|
-
const usageRaw = data.usage;
|
|
44
|
-
const content = choice?.content ?? "";
|
|
45
|
-
const toolCalls = choice?.tool_calls ?? [];
|
|
46
|
-
const promptTokens = usageRaw?.prompt_tokens ?? 0;
|
|
47
|
-
const completionTokens = usageRaw?.completion_tokens ?? 0;
|
|
48
|
-
const cacheHit = usageRaw?.prompt_cache_hit_tokens ?? 0;
|
|
49
|
-
const cacheMiss = usageRaw?.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);
|
|
50
|
-
const usage = {
|
|
51
|
-
promptTokens,
|
|
52
|
-
completionTokens,
|
|
53
|
-
caching: {
|
|
54
|
-
hitTokens: cacheHit,
|
|
55
|
-
missTokens: cacheMiss,
|
|
56
|
-
hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0,
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
return { content, toolCalls, usage };
|
|
60
|
-
}
|
|
61
|
-
async *stream(prefix, history, tools) {
|
|
62
|
-
const messages = [...prefix, ...history];
|
|
63
|
-
const body = {
|
|
64
|
-
model: this.modelId,
|
|
65
|
-
messages,
|
|
66
|
-
stream: true,
|
|
67
|
-
stream_options: { include_usage: true },
|
|
68
|
-
};
|
|
69
|
-
if (tools?.length)
|
|
70
|
-
body.tools = tools;
|
|
71
|
-
const resp = await fetch(`${this._baseUrl}/chat/completions`, {
|
|
72
|
-
method: "POST",
|
|
73
|
-
headers: {
|
|
74
|
-
Authorization: `Bearer ${this._apiKey}`,
|
|
75
|
-
"Content-Type": "application/json",
|
|
76
|
-
Accept: "text/event-stream",
|
|
77
|
-
},
|
|
78
|
-
body: JSON.stringify(body),
|
|
79
|
-
});
|
|
80
|
-
if (!resp.ok || !resp.body) {
|
|
81
|
-
throw new Error(`DeepSeek ${resp.status}: ${await resp.text().catch(() => "")}`);
|
|
82
|
-
}
|
|
83
|
-
const reader = resp.body.getReader();
|
|
84
|
-
const decoder = new TextDecoder();
|
|
85
|
-
let buffer = "";
|
|
86
|
-
try {
|
|
87
|
-
while (true) {
|
|
88
|
-
const { value, done } = await reader.read();
|
|
89
|
-
if (done)
|
|
90
|
-
break;
|
|
91
|
-
buffer += decoder.decode(value, { stream: true });
|
|
92
|
-
const lines = buffer.split("\n");
|
|
93
|
-
buffer = lines.pop() ?? "";
|
|
94
|
-
for (const line of lines) {
|
|
95
|
-
const trimmed = line.trim();
|
|
96
|
-
if (!trimmed || !trimmed.startsWith("data: "))
|
|
97
|
-
continue;
|
|
98
|
-
const data = trimmed.slice(6);
|
|
99
|
-
if (data === "[DONE]") {
|
|
100
|
-
yield { type: "done", usage: { promptTokens: 0, completionTokens: 0 } };
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
try {
|
|
104
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
|
-
const json = JSON.parse(data);
|
|
106
|
-
const delta = json.choices?.[0]?.delta;
|
|
107
|
-
if (delta?.content) {
|
|
108
|
-
yield { type: "text-delta", delta: String(delta.content) };
|
|
109
|
-
}
|
|
110
|
-
const toolCalls = delta?.tool_calls;
|
|
111
|
-
if (toolCalls) {
|
|
112
|
-
for (let i = 0; i < toolCalls.length; i++) {
|
|
113
|
-
const tc = toolCalls[i];
|
|
114
|
-
yield {
|
|
115
|
-
type: "tool-call-delta",
|
|
116
|
-
index: typeof tc.index === "number" ? tc.index : i,
|
|
117
|
-
name: tc.function ? String(tc.function.name ?? "") : undefined,
|
|
118
|
-
argumentsDelta: tc.function ? String(tc.function.arguments ?? "") : undefined,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const usageRaw = json.usage;
|
|
123
|
-
if (usageRaw) {
|
|
124
|
-
const promptTokens = usageRaw.prompt_tokens ?? 0;
|
|
125
|
-
const completionTokens = usageRaw.completion_tokens ?? 0;
|
|
126
|
-
const cacheHit = usageRaw.prompt_cache_hit_tokens ?? 0;
|
|
127
|
-
const cacheMiss = usageRaw.prompt_cache_miss_tokens ?? Math.max(0, promptTokens - cacheHit);
|
|
128
|
-
yield {
|
|
129
|
-
type: "done",
|
|
130
|
-
usage: {
|
|
131
|
-
promptTokens,
|
|
132
|
-
completionTokens,
|
|
133
|
-
caching: {
|
|
134
|
-
hitTokens: cacheHit,
|
|
135
|
-
missTokens: cacheMiss,
|
|
136
|
-
hitRate: cacheHit + cacheMiss > 0 ? cacheHit / (cacheHit + cacheMiss) : 0,
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
/* skip malformed SSE frame */
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
finally {
|
|
149
|
-
reader.releaseLock();
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
//# sourceMappingURL=deepseek.js.map
|
package/dist/deepseek.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deepseek.js","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"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"}
|