@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 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
- - `DeepSeekAdapter` — DeepSeek API adapter with prefix cache support
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.
@@ -1,5 +1,4 @@
1
- import type { ChatMessage, ToolCall, ToolSpec, Usage, TurnChunk } from "@halo-sdk/core";
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(prefix: ChatMessage[], history: ChatMessage[], tools?: ToolSpec[]): Promise<{
15
+ chat(params: ChatParams): Promise<{
17
16
  content: string;
18
17
  toolCalls: ToolCall[];
19
18
  usage: Usage;
20
19
  }>;
21
- stream(prefix: ChatMessage[], history: ChatMessage[], tools?: ToolSpec[]): AsyncGenerator<TurnChunk>;
20
+ stream(params: ChatParams): AsyncGenerator<TurnChunk>;
21
+ private _applyOptions;
22
22
  }
23
23
  //# sourceMappingURL=deepseek.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEnF,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,CACR,MAAM,EAAE,WAAW,EAAE,EACrB,OAAO,EAAE,WAAW,EAAE,EACtB,KAAK,CAAC,EAAE,QAAQ,EAAE,GACjB,OAAO,CAAC;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,QAAQ,EAAE,CAAC;QACtB,KAAK,EAAE,KAAK,CAAC;KACd,CAAC;IAiDK,MAAM,CACX,MAAM,EAAE,WAAW,EAAE,EACrB,OAAO,EAAE,WAAW,EAAE,EACtB,KAAK,CAAC,EAAE,QAAQ,EAAE,GACjB,cAAc,CAAC,SAAS,CAAC;CA4F7B"}
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
- export { DeepSeekAdapter } from "./deepseek.js";
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.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
- "adapter",
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.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": "tsc --watch",
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"deepseek.js","sourceRoot":"","sources":["../src/deepseek.ts"],"names":[],"mappings":"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"}