dsh-multi-router 0.5.9 → 0.6.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +46 -6
  3. package/THIRD_PARTY_NOTICES.md +4 -0
  4. package/cordis.patch.yml +2 -2
  5. package/lib/accounts.js +4 -4
  6. package/lib/api-service.js +11 -0
  7. package/lib/api-service.js.map +7 -0
  8. package/lib/{chunk-U2MU2M5C.js → chunk-2LH6TD2U.js} +25 -115
  9. package/lib/chunk-2LH6TD2U.js.map +7 -0
  10. package/lib/chunk-4V52V5GO.js +105 -0
  11. package/lib/chunk-4V52V5GO.js.map +7 -0
  12. package/lib/chunk-625KMEYS.js +332 -0
  13. package/lib/chunk-625KMEYS.js.map +7 -0
  14. package/lib/{chunk-P43AWJ4Q.js → chunk-BSAI3SW5.js} +3 -3
  15. package/lib/{chunk-J3XO7RTF.js → chunk-DZ4ZUAYH.js} +50 -6
  16. package/lib/chunk-DZ4ZUAYH.js.map +7 -0
  17. package/lib/{chunk-MCHV2R25.js → chunk-NGVWVIBM.js} +22 -6
  18. package/lib/chunk-NGVWVIBM.js.map +7 -0
  19. package/lib/{chunk-FTM7RHQV.js → chunk-OK2T2UAZ.js} +4 -4
  20. package/lib/{chunk-S6ZQ45SS.js → chunk-VZPXRK7Q.js} +3 -3
  21. package/lib/{chunk-I4EW5TI7.js → chunk-ZQZSXCVR.js} +164 -48
  22. package/lib/chunk-ZQZSXCVR.js.map +7 -0
  23. package/lib/cli.js +7 -6
  24. package/lib/cli.js.map +1 -1
  25. package/lib/client.js +462 -44
  26. package/lib/client.js.map +2 -2
  27. package/lib/clients.js +9 -5
  28. package/lib/{host-v0.5.9.js → host-v0.6.1.js} +19 -13
  29. package/lib/host.js +19 -13
  30. package/lib/index.js +19 -13
  31. package/lib/index.js.map +2 -2
  32. package/lib/manager.js +11 -7
  33. package/lib/router.js +2 -2
  34. package/lib/shim.js +3 -3
  35. package/package.json +1 -1
  36. package/lib/chunk-I4EW5TI7.js.map +0 -7
  37. package/lib/chunk-J3XO7RTF.js.map +0 -7
  38. package/lib/chunk-MCHV2R25.js.map +0 -7
  39. package/lib/chunk-U2MU2M5C.js.map +0 -7
  40. /package/lib/{chunk-P43AWJ4Q.js.map → chunk-BSAI3SW5.js.map} +0 -0
  41. /package/lib/{chunk-FTM7RHQV.js.map → chunk-OK2T2UAZ.js.map} +0 -0
  42. /package/lib/{chunk-S6ZQ45SS.js.map → chunk-VZPXRK7Q.js.map} +0 -0
@@ -0,0 +1,105 @@
1
+ // upstream/trae/src/sse.ts
2
+ var SseDecoder = class {
3
+ buffer = "";
4
+ event;
5
+ id;
6
+ retry;
7
+ data = [];
8
+ push(chunk) {
9
+ this.buffer += chunk;
10
+ const events = [];
11
+ while (true) {
12
+ const match = /\r?\n/.exec(this.buffer);
13
+ if (match === null || match.index === void 0) break;
14
+ const line = this.buffer.slice(0, match.index);
15
+ this.buffer = this.buffer.slice(match.index + match[0].length);
16
+ const emitted = this.consumeLine(line);
17
+ if (emitted !== void 0) events.push(emitted);
18
+ }
19
+ return events;
20
+ }
21
+ finish() {
22
+ const events = [];
23
+ if (this.buffer !== "") {
24
+ const emitted = this.consumeLine(this.buffer);
25
+ this.buffer = "";
26
+ if (emitted !== void 0) events.push(emitted);
27
+ }
28
+ const final = this.dispatch();
29
+ if (final !== void 0) events.push(final);
30
+ return events;
31
+ }
32
+ consumeLine(line) {
33
+ if (line === "") return this.dispatch();
34
+ if (line.startsWith(":")) return void 0;
35
+ const colon = line.indexOf(":");
36
+ const field = colon === -1 ? line : line.slice(0, colon);
37
+ let value = colon === -1 ? "" : line.slice(colon + 1);
38
+ if (value.startsWith(" ")) value = value.slice(1);
39
+ if (field === "event") this.event = value;
40
+ else if (field === "data") this.data.push(value);
41
+ else if (field === "id" && !value.includes("\0")) this.id = value;
42
+ else if (field === "retry" && /^\d+$/.test(value)) this.retry = Number(value);
43
+ return void 0;
44
+ }
45
+ dispatch() {
46
+ if (this.data.length === 0) {
47
+ this.event = void 0;
48
+ this.retry = void 0;
49
+ return void 0;
50
+ }
51
+ const result = {
52
+ ...this.event === void 0 || this.event === "" ? {} : { event: this.event },
53
+ data: this.data.join("\n"),
54
+ ...this.id === void 0 ? {} : { id: this.id },
55
+ ...this.retry === void 0 ? {} : { retry: this.retry }
56
+ };
57
+ this.event = void 0;
58
+ this.retry = void 0;
59
+ this.data = [];
60
+ return result;
61
+ }
62
+ };
63
+ function decodeTraeEvent(event) {
64
+ if (event.data === "[DONE]") return { type: "done", finishReason: "stop" };
65
+ let payload;
66
+ try {
67
+ payload = JSON.parse(event.data);
68
+ } catch {
69
+ return { type: "unknown", ...event.event === void 0 ? {} : { event: event.event }, data: event.data };
70
+ }
71
+ const record = typeof payload === "object" && payload !== null && !Array.isArray(payload) ? payload : {};
72
+ if (event.event === "request_wait_in_queue") {
73
+ return { type: "queue", ...typeof record["position"] === "number" ? { position: record["position"] } : {} };
74
+ }
75
+ if (event.event === "progress_notice") return { type: "progress", notice: payload };
76
+ if (event.event === "token_usage") {
77
+ return {
78
+ type: "usage",
79
+ ...typeof record["prompt_tokens"] === "number" ? { inputTokens: record["prompt_tokens"] } : {},
80
+ ...typeof record["completion_tokens"] === "number" ? { outputTokens: record["completion_tokens"] } : {},
81
+ ...typeof record["total_tokens"] === "number" ? { totalTokens: record["total_tokens"] } : {},
82
+ ...typeof record["reasoning_tokens"] === "number" ? { reasoningTokens: record["reasoning_tokens"] } : {},
83
+ ...typeof record["cache_read_input_tokens"] === "number" ? { cacheReadTokens: record["cache_read_input_tokens"] } : {},
84
+ ...typeof record["cache_creation_input_tokens"] === "number" ? { cacheWriteTokens: record["cache_creation_input_tokens"] } : {}
85
+ };
86
+ }
87
+ if (event.event === "done" || typeof record["finish_reason"] === "string" && record["response"] === void 0) {
88
+ return { type: "done", finishReason: typeof record["finish_reason"] === "string" ? record["finish_reason"] : "stop" };
89
+ }
90
+ if (event.event === "output" || record["response"] !== void 0 || record["reasoning_content"] !== void 0) {
91
+ return {
92
+ type: "delta",
93
+ text: typeof record["response"] === "string" ? record["response"] : "",
94
+ ...typeof record["reasoning_content"] === "string" ? { reasoning: record["reasoning_content"] } : {},
95
+ ...record["tool_calls"] === void 0 || record["tool_calls"] === null ? {} : { toolCalls: record["tool_calls"] }
96
+ };
97
+ }
98
+ return { type: "unknown", ...event.event === void 0 ? {} : { event: event.event }, data: payload };
99
+ }
100
+
101
+ export {
102
+ SseDecoder,
103
+ decodeTraeEvent
104
+ };
105
+ //# sourceMappingURL=chunk-4V52V5GO.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../upstream/trae/src/sse.ts"],
4
+ "sourcesContent": ["export interface SseEvent {\n event?: string\n data: string\n id?: string\n retry?: number\n}\n\n/** Incremental SSE decoder supporting CRLF, chunk splits and multi-line data. */\nexport class SseDecoder {\n private buffer = ''\n private event: string | undefined\n private id: string | undefined\n private retry: number | undefined\n private data: string[] = []\n\n push(chunk: string): SseEvent[] {\n this.buffer += chunk\n const events: SseEvent[] = []\n while (true) {\n const match = /\\r?\\n/.exec(this.buffer)\n if (match === null || match.index === undefined) break\n const line = this.buffer.slice(0, match.index)\n this.buffer = this.buffer.slice(match.index + match[0].length)\n const emitted = this.consumeLine(line)\n if (emitted !== undefined) events.push(emitted)\n }\n return events\n }\n\n finish(): SseEvent[] {\n const events: SseEvent[] = []\n if (this.buffer !== '') {\n const emitted = this.consumeLine(this.buffer)\n this.buffer = ''\n if (emitted !== undefined) events.push(emitted)\n }\n const final = this.dispatch()\n if (final !== undefined) events.push(final)\n return events\n }\n\n private consumeLine(line: string): SseEvent | undefined {\n if (line === '') return this.dispatch()\n if (line.startsWith(':')) return undefined\n const colon = line.indexOf(':')\n const field = colon === -1 ? line : line.slice(0, colon)\n let value = colon === -1 ? '' : line.slice(colon + 1)\n if (value.startsWith(' ')) value = value.slice(1)\n if (field === 'event') this.event = value\n else if (field === 'data') this.data.push(value)\n else if (field === 'id' && !value.includes('\\0')) this.id = value\n else if (field === 'retry' && /^\\d+$/.test(value)) this.retry = Number(value)\n return undefined\n }\n\n private dispatch(): SseEvent | undefined {\n if (this.data.length === 0) {\n this.event = undefined\n this.retry = undefined\n return undefined\n }\n const result: SseEvent = {\n ...this.event === undefined || this.event === '' ? {} : { event: this.event },\n data: this.data.join('\\n'),\n ...this.id === undefined ? {} : { id: this.id },\n ...this.retry === undefined ? {} : { retry: this.retry },\n }\n this.event = undefined\n this.retry = undefined\n this.data = []\n return result\n }\n}\n\nexport type TraeStreamEvent =\n | { type: 'queue'; position?: number }\n | { type: 'progress'; notice: unknown }\n | { type: 'delta'; text: string; reasoning?: string; toolCalls?: unknown }\n | {\n type: 'usage'\n inputTokens?: number\n outputTokens?: number\n totalTokens?: number\n reasoningTokens?: number\n /**\n * Trae's prompt-cache accounting (`cache_read_input_tokens` /\n * `cache_creation_input_tokens` on the `token_usage` event). Verified\n * 2026-09-22 (docs/ISSUE10_DIAGNOSIS.md): a byte-identical 9224-token\n * prompt reports `prompt_tokens: 9224` while `cache_read_input_tokens`\n * rises to 9216, so these are a *subset* of `prompt_tokens` \u2014 the OpenAI\n * convention, not Anthropic's exclusive one. Forwarding them as\n * `cached_tokens` is therefore arithmetically correct.\n */\n cacheReadTokens?: number\n cacheWriteTokens?: number\n }\n | { type: 'done'; finishReason: string }\n | { type: 'unknown'; event?: string; data: unknown }\n\nexport function decodeTraeEvent(event: SseEvent): TraeStreamEvent {\n if (event.data === '[DONE]') return { type: 'done', finishReason: 'stop' }\n let payload: unknown\n try { payload = JSON.parse(event.data) as unknown } catch { return { type: 'unknown', ...event.event === undefined ? {} : { event: event.event }, data: event.data } }\n const record = typeof payload === 'object' && payload !== null && !Array.isArray(payload) ? payload as Record<string, unknown> : {}\n if (event.event === 'request_wait_in_queue') {\n return { type: 'queue', ...typeof record['position'] === 'number' ? { position: record['position'] } : {} }\n }\n if (event.event === 'progress_notice') return { type: 'progress', notice: payload }\n if (event.event === 'token_usage') {\n return {\n type: 'usage',\n ...typeof record['prompt_tokens'] === 'number' ? { inputTokens: record['prompt_tokens'] } : {},\n ...typeof record['completion_tokens'] === 'number' ? { outputTokens: record['completion_tokens'] } : {},\n ...typeof record['total_tokens'] === 'number' ? { totalTokens: record['total_tokens'] } : {},\n ...typeof record['reasoning_tokens'] === 'number' ? { reasoningTokens: record['reasoning_tokens'] } : {},\n ...typeof record['cache_read_input_tokens'] === 'number' ? { cacheReadTokens: record['cache_read_input_tokens'] } : {},\n ...typeof record['cache_creation_input_tokens'] === 'number' ? { cacheWriteTokens: record['cache_creation_input_tokens'] } : {},\n }\n }\n if (event.event === 'done' || typeof record['finish_reason'] === 'string' && record['response'] === undefined) {\n return { type: 'done', finishReason: typeof record['finish_reason'] === 'string' ? record['finish_reason'] : 'stop' }\n }\n if (event.event === 'output' || record['response'] !== undefined || record['reasoning_content'] !== undefined) {\n return {\n type: 'delta',\n text: typeof record['response'] === 'string' ? record['response'] : '',\n ...typeof record['reasoning_content'] === 'string' ? { reasoning: record['reasoning_content'] } : {},\n ...record['tool_calls'] === undefined || record['tool_calls'] === null ? {} : { toolCalls: record['tool_calls'] },\n }\n }\n return { type: 'unknown', ...event.event === undefined ? {} : { event: event.event }, data: payload }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,332 @@
1
+ import {
2
+ SseDecoder
3
+ } from "./chunk-4V52V5GO.js";
4
+ import {
5
+ hostIsLoopback
6
+ } from "./chunk-DNQPZMPF.js";
7
+ import {
8
+ RouteError,
9
+ abortable
10
+ } from "./chunk-DZ4ZUAYH.js";
11
+ import {
12
+ REASONING_EFFORTS,
13
+ beijingDay,
14
+ writePrivateJson
15
+ } from "./chunk-NGVWVIBM.js";
16
+
17
+ // src/api-service.mjs
18
+ import { createServer } from "node:http";
19
+ import { randomBytes, randomUUID, createHash, timingSafeEqual } from "node:crypto";
20
+ import { readFile } from "node:fs/promises";
21
+ import { networkInterfaces } from "node:os";
22
+ import { Readable } from "node:stream";
23
+ import { pipeline } from "node:stream/promises";
24
+ import { withFileLock } from "@deepseek-ai/dsh-atomic-write";
25
+ var defaults = () => ({ version: 1, enabled: false, port: 8787, allowLan: false, modelIds: null, key: null });
26
+ var revision = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
27
+ var fail = (status, code) => {
28
+ throw new RouteError(status, code);
29
+ };
30
+ var json = (res, status, value) => {
31
+ res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff" });
32
+ res.end(JSON.stringify(value));
33
+ };
34
+ function validate(value) {
35
+ if (!value || value.version !== 1 || typeof value.enabled !== "boolean" || typeof value.allowLan !== "boolean" || !Number.isInteger(value.port) || value.port < 1024 || value.port > 65535 || value.modelIds !== null && (!Array.isArray(value.modelIds) || value.modelIds.length > 1e3 || value.modelIds.some((id) => typeof id !== "string" || !/^[\w.-]{1,128}$/.test(id))) || value.key !== null && !/^sk-dsh-[A-Za-z0-9_-]{43}$/.test(value.key) || value.enabled && !value.key) throw Error("API \u8BBE\u7F6E\u65E0\u6548\uFF1A\u7AEF\u53E3\u9700\u4E3A 1024\u201365535\uFF0C\u542F\u7528\u524D\u8BF7\u751F\u6210 API Key\u3002");
36
+ return value;
37
+ }
38
+ var ApiService = class {
39
+ constructor(file, manager) {
40
+ this.file = file;
41
+ this.manager = manager;
42
+ this.settings = defaults();
43
+ this.phase = "stopped";
44
+ this.controllers = /* @__PURE__ */ new Set();
45
+ this.queue = Promise.resolve();
46
+ }
47
+ async load() {
48
+ this.configError = false;
49
+ try {
50
+ this.settings = validate(JSON.parse(await readFile(this.file, "utf8")));
51
+ } catch (e) {
52
+ if (e.code !== "ENOENT") {
53
+ this.configError = true;
54
+ this.phase = "error";
55
+ this.error = "API \u914D\u7F6E\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u670D\u52A1\u672A\u542F\u52A8\u3002\u8BF7\u91CD\u65B0\u4FDD\u5B58\u8BBE\u7F6E\u3002";
56
+ }
57
+ }
58
+ }
59
+ choices() {
60
+ return this.manager.adapterModels().filter((m) => !m.freeOnly || m.dynamicFree);
61
+ }
62
+ models() {
63
+ return this.choices().filter((m) => this.settings.modelIds === null ? m.visible !== false : this.settings.modelIds.includes(m.id));
64
+ }
65
+ state() {
66
+ const { key, ...settings } = this.settings;
67
+ const port = this.server?.address()?.port ?? settings.port;
68
+ const events = this.manager.telemetry.data.events.filter((e) => e.source === "api" && beijingDay(e.at) === beijingDay(Date.now()));
69
+ const addresses = settings.allowLan ? [...new Set(Object.values(networkInterfaces()).flat().filter((a) => a && a.family === "IPv4" && !a.internal).map((a) => `http://${a.address}:${port}/v1`))] : [];
70
+ return {
71
+ ...settings,
72
+ revision: revision(this.settings),
73
+ phase: this.phase,
74
+ error: this.error,
75
+ hasKey: !!key,
76
+ keyHint: key ? `sk-dsh-\u2022\u2022\u2022\u2022${key.slice(-4)}` : null,
77
+ active: this.controllers.size,
78
+ baseUrl: `http://127.0.0.1:${port}/v1`,
79
+ lanUrls: addresses,
80
+ choices: this.choices().map((m) => ({ id: m.id, name: m.name, visible: m.visible !== false, reasoning: m.reasoning })),
81
+ models: this.models().map((m) => ({ id: m.id, name: m.name })),
82
+ today: { calls: new Set(events.map((e) => e.callId)).size, attempts: events.length, tokens: events.reduce((n, e) => n + (e.tokens ?? 0), 0) }
83
+ };
84
+ }
85
+ action(input) {
86
+ const task = this.queue.catch(() => {
87
+ }).then(() => withFileLock(this.file, async () => {
88
+ if (this.closed) throw Error("API \u670D\u52A1\u5DF2\u5173\u95ED\u3002");
89
+ let current = this.settings;
90
+ try {
91
+ current = validate(JSON.parse(await readFile(this.file, "utf8")));
92
+ } catch (e) {
93
+ if (e.code !== "ENOENT" && this.phase !== "error") throw e;
94
+ }
95
+ if (input.apiRevision !== revision(current)) throw Error("API \u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u9762\u677F\u540E\u91CD\u8BD5\u3002");
96
+ const next = structuredClone(current);
97
+ let apiKey;
98
+ if (input.action === "api.key.reveal") return { apiKey: next.key };
99
+ if (input.action === "api.key.create") {
100
+ next.key = `sk-dsh-${randomBytes(32).toString("base64url")}`;
101
+ apiKey = next.key;
102
+ } else if (input.action === "api.key.revoke") {
103
+ next.key = null;
104
+ next.enabled = false;
105
+ } else if (input.action === "api.settings") {
106
+ for (const k of ["enabled", "port", "allowLan", "modelIds"]) if (input[k] !== void 0) next[k] = input[k];
107
+ if (next.modelIds?.some((id) => !this.choices().some((m) => m.id === id) && !current.modelIds?.includes(id))) throw Error("\u6A21\u578B\u76EE\u5F55\u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0\u9762\u677F\u540E\u91CD\u65B0\u9009\u62E9\u3002");
108
+ } else throw Error("\u672A\u77E5 API \u64CD\u4F5C\u3002");
109
+ validate(next);
110
+ await writePrivateJson(this.file, next);
111
+ this.configError = false;
112
+ const restart = next.enabled !== this.settings.enabled || next.port !== this.settings.port || next.allowLan !== this.settings.allowLan;
113
+ this.settings = next;
114
+ if (restart || this.phase === "error" || !this.server && next.enabled) await this.reconcile();
115
+ return { apiKey };
116
+ }, { waitMs: 1e4 }));
117
+ this.queue = task;
118
+ return task;
119
+ }
120
+ async reconcile() {
121
+ await this.stop();
122
+ if (this.configError) {
123
+ this.phase = "error";
124
+ return;
125
+ }
126
+ this.error = void 0;
127
+ if (this.closed || !this.settings.enabled) {
128
+ this.phase = "stopped";
129
+ return;
130
+ }
131
+ this.phase = "starting";
132
+ const server = createServer((req, res) => {
133
+ void this.handle(req, res);
134
+ });
135
+ server.requestTimeout = 3e4;
136
+ server.headersTimeout = 1e4;
137
+ server.keepAliveTimeout = 5e3;
138
+ this.server = server;
139
+ try {
140
+ await new Promise((resolve, reject) => {
141
+ server.once("error", reject);
142
+ server.listen(this.settings.port, this.settings.allowLan ? "0.0.0.0" : "127.0.0.1", resolve);
143
+ });
144
+ this.phase = "running";
145
+ server.on("error", () => {
146
+ this.phase = "error";
147
+ this.error = "API \u76D1\u542C\u5F02\u5E38\uFF0C\u8BF7\u91CD\u65B0\u4FDD\u5B58\u8BBE\u7F6E\u3002";
148
+ });
149
+ } catch (e) {
150
+ this.server = void 0;
151
+ this.phase = "error";
152
+ this.error = e.code === "EADDRINUSE" ? "\u7AEF\u53E3\u5DF2\u88AB\u5360\u7528\uFF0C\u8BF7\u4FEE\u6539\u7AEF\u53E3\u540E\u4FDD\u5B58\u3002" : e.code === "EACCES" ? "\u6CA1\u6709\u76D1\u542C\u6B64\u7AEF\u53E3\u7684\u6743\u9650\uFF0C\u8BF7\u4FEE\u6539\u7AEF\u53E3\u3002" : "API \u670D\u52A1\u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7AEF\u53E3\u8BBE\u7F6E\u3002";
153
+ }
154
+ }
155
+ async stop() {
156
+ const server = this.server;
157
+ this.server = void 0;
158
+ for (const c of this.controllers) c.abort();
159
+ if (server) {
160
+ server.closeAllConnections();
161
+ await new Promise((resolve) => server.close(resolve));
162
+ }
163
+ this.phase = "stopped";
164
+ }
165
+ async close() {
166
+ this.closed = true;
167
+ await this.queue.catch(() => {
168
+ });
169
+ await this.stop();
170
+ }
171
+ async handle(req, res) {
172
+ const controller = new AbortController();
173
+ const signal = AbortSignal.any([controller.signal, AbortSignal.timeout(Math.min(this.manager.config.requestTimeoutMs, 2147483647))]);
174
+ req.on("aborted", () => controller.abort());
175
+ res.on("close", () => {
176
+ if (!res.writableEnded) controller.abort();
177
+ });
178
+ let selected;
179
+ try {
180
+ if (!this.settings.enabled || this.closed) fail(503, "service_disabled");
181
+ if (!this.settings.allowLan && !hostIsLoopback(req.headers.host)) fail(403, "loopback_required");
182
+ if (req.headers.origin || req.headers["sec-fetch-site"] === "cross-site") fail(403, "browser_origin_not_allowed");
183
+ const token = /^Bearer\s+(\S+)$/i.exec(req.headers.authorization ?? "")?.[1] ?? "";
184
+ const actual = Buffer.from(token), expected = Buffer.from(this.settings.key ?? "");
185
+ if (!expected.length || actual.length !== expected.length || !timingSafeEqual(actual, expected)) fail(401, "invalid_api_key");
186
+ if (req.method === "GET" && req.url === "/v1/models") {
187
+ json(res, 200, { object: "list", data: this.models().map((m) => ({ id: m.id, object: "model", created: 0, owned_by: "dsh-multi-router" })) });
188
+ return;
189
+ }
190
+ if (req.method !== "POST" || req.url !== "/v1/chat/completions") fail(404, "not_found");
191
+ if (this.controllers.size >= 8) fail(429, "too_many_requests");
192
+ this.controllers.add(controller);
193
+ if (!/^application\/json(?:\s*;|$)/i.test(req.headers["content-type"] ?? "")) fail(415, "json_required");
194
+ const chunks = [];
195
+ let size = 0;
196
+ for await (const chunk of req) {
197
+ size += chunk.length;
198
+ if (size > 32 * 1024 * 1024) fail(413, "request_too_large");
199
+ signal.throwIfAborted();
200
+ chunks.push(chunk);
201
+ }
202
+ let input;
203
+ try {
204
+ input = JSON.parse(Buffer.concat(chunks).toString("utf8"));
205
+ } catch {
206
+ fail(400, "invalid_json");
207
+ }
208
+ if (!input || typeof input !== "object" || Array.isArray(input) || typeof input.model !== "string" || !Array.isArray(input.messages) || !input.messages.length || input.messages.some((m) => !m || typeof m !== "object" || !["system", "developer", "user", "assistant", "tool", "function"].includes(m.role)) || input.stream !== void 0 && typeof input.stream !== "boolean") fail(400, "invalid_request");
209
+ if (!this.models().some((m) => m.id === input.model)) fail(404, "model_not_exposed");
210
+ if (input.n !== void 0 && input.n !== 1) fail(400, "only_n_1_supported");
211
+ if (input.reasoning_effort != null && !REASONING_EFFORTS.includes(input.reasoning_effort)) fail(400, "invalid_reasoning_effort");
212
+ selected = await abortable(this.manager.router.chat({ ...input, stream: true }, signal, { callId: randomUUID(), source: "api" }), signal);
213
+ signal.throwIfAborted();
214
+ const frames = completionFrames(selected.response, input.model, signal);
215
+ if (input.stream === true) {
216
+ res.writeHead(200, { "Content-Type": "text/event-stream; charset=utf-8", "Cache-Control": "no-cache", "X-Accel-Buffering": "no" });
217
+ await pipeline(Readable.from((async function* () {
218
+ for await (const frame of frames) {
219
+ if (!input.stream_options?.include_usage && !frame.choices?.length && frame.usage) continue;
220
+ if (!input.stream_options?.include_usage) delete frame.usage;
221
+ yield `data: ${JSON.stringify(frame)}
222
+
223
+ `;
224
+ }
225
+ yield "data: [DONE]\n\n";
226
+ })()), res, { signal });
227
+ } else json(res, 200, await collectCompletion(frames, input.model));
228
+ } catch (e) {
229
+ if (res.destroyed) return;
230
+ if (res.headersSent) {
231
+ res.destroy();
232
+ return;
233
+ }
234
+ const status = e instanceof RouteError ? e.status : signal.aborted ? 504 : 500;
235
+ const code = e instanceof RouteError ? e.code : signal.aborted ? "request_timeout" : "internal_error";
236
+ json(res, status, { error: { message: code, type: status === 401 ? "authentication_error" : status < 500 ? "invalid_request_error" : "server_error", code, param: null } });
237
+ } finally {
238
+ this.controllers.delete(controller);
239
+ if (selected?.response.body && !selected.response.body.locked) await selected.response.body.cancel().catch(() => {
240
+ });
241
+ }
242
+ }
243
+ };
244
+ async function* completionFrames(response, model, signal) {
245
+ if (!response.body) fail(502, "empty_upstream_response");
246
+ const reader = response.body.getReader(), decoder = new TextDecoder(), sse = new SseDecoder();
247
+ let finished = false, total = 0, frameBytes = 0;
248
+ const abort = () => {
249
+ void reader.cancel().catch(() => {
250
+ });
251
+ };
252
+ signal.addEventListener("abort", abort, { once: true });
253
+ function parse(event) {
254
+ if (event.data === "[DONE]") return null;
255
+ let value;
256
+ try {
257
+ value = JSON.parse(event.data);
258
+ } catch {
259
+ fail(502, "invalid_upstream_stream");
260
+ }
261
+ if (!value || typeof value !== "object" || Array.isArray(value) || value.error) fail(502, "upstream_stream_error");
262
+ if (value.choices !== void 0 && (!Array.isArray(value.choices) || value.choices.length > 32)) fail(502, "invalid_upstream_stream");
263
+ for (const c of value.choices ?? []) {
264
+ if (!c || !Number.isInteger(c.index) || c.index < 0 || c.index > 31) fail(502, "invalid_upstream_stream");
265
+ if (c.delta?.tool_calls && (!Array.isArray(c.delta.tool_calls) || c.delta.tool_calls.some((t) => !t || !Number.isInteger(t.index) || t.index < 0 || t.index > 127))) fail(502, "invalid_upstream_stream");
266
+ }
267
+ if (value.choices?.some((c) => c.finish_reason)) finished = true;
268
+ return { ...value, model };
269
+ }
270
+ try {
271
+ while (true) {
272
+ signal.throwIfAborted();
273
+ const chunk = await reader.read();
274
+ signal.throwIfAborted();
275
+ if (chunk.done) break;
276
+ total += chunk.value.byteLength;
277
+ frameBytes += chunk.value.byteLength;
278
+ if (total > 32 * 1024 * 1024 || frameBytes > 1024 * 1024) fail(502, "upstream_response_too_large");
279
+ const events = sse.push(decoder.decode(chunk.value, { stream: true }));
280
+ if (events.length) frameBytes = 0;
281
+ for (const event of events) {
282
+ const value = parse(event);
283
+ if (value) yield value;
284
+ }
285
+ }
286
+ for (const event of sse.finish()) {
287
+ const value = parse(event);
288
+ if (value) yield value;
289
+ }
290
+ if (!finished) fail(502, "upstream_stream_incomplete");
291
+ } finally {
292
+ signal.removeEventListener("abort", abort);
293
+ await reader.cancel().catch(() => {
294
+ });
295
+ reader.releaseLock();
296
+ }
297
+ }
298
+ async function collectCompletion(frames, model) {
299
+ const result = { id: `chatcmpl-${randomUUID()}`, object: "chat.completion", created: Math.floor(Date.now() / 1e3), model, choices: [] };
300
+ const choices = /* @__PURE__ */ new Map();
301
+ for await (const frame of frames) {
302
+ if (frame.id) result.id = frame.id;
303
+ if (frame.created != null) result.created = frame.created;
304
+ if (frame.usage) result.usage = frame.usage;
305
+ for (const part of frame.choices ?? []) {
306
+ const index = part.index ?? 0;
307
+ if (!choices.has(index)) choices.set(index, { index, message: { role: "assistant", content: null }, finish_reason: null, logprobs: null });
308
+ const choice = choices.get(index), delta = part.delta ?? {};
309
+ for (const k of ["content", "reasoning_content", "reasoning", "refusal"]) if (typeof delta[k] === "string") choice.message[k] = (choice.message[k] ?? "") + delta[k];
310
+ if (delta.function_call) {
311
+ choice.message.function_call ??= { name: "", arguments: "" };
312
+ for (const k of ["name", "arguments"]) if (typeof delta.function_call[k] === "string") choice.message.function_call[k] += delta.function_call[k];
313
+ }
314
+ if (delta.tool_calls) for (const tool of delta.tool_calls) {
315
+ choice.message.tool_calls ??= [];
316
+ const i = tool.index ?? 0;
317
+ const value = choice.message.tool_calls[i] ??= { id: "", type: "function", function: { name: "", arguments: "" } };
318
+ if (tool.id) value.id += tool.id;
319
+ if (tool.type) value.type = tool.type;
320
+ for (const k of ["name", "arguments"]) if (typeof tool.function?.[k] === "string") value.function[k] += tool.function[k];
321
+ }
322
+ if (part.finish_reason) choice.finish_reason = part.finish_reason;
323
+ }
324
+ }
325
+ result.choices = [...choices.values()].sort((a, b) => a.index - b.index);
326
+ return result;
327
+ }
328
+
329
+ export {
330
+ ApiService
331
+ };
332
+ //# sourceMappingURL=chunk-625KMEYS.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/api-service.mjs"],
4
+ "sourcesContent": ["import { createServer } from 'node:http';\nimport { randomBytes, randomUUID, createHash, timingSafeEqual } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { networkInterfaces } from 'node:os';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { withFileLock } from '@deepseek-ai/dsh-atomic-write';\nimport { writePrivateJson, beijingDay } from './config.mjs';\nimport { RouteError, abortable } from './router.mjs';\nimport { REASONING_EFFORTS } from './reasoning.mjs';\nimport { hostIsLoopback } from '../upstream/workbuddy/src/loopback.ts';\nimport { SseDecoder } from '../upstream/trae/src/sse.ts';\n\nconst defaults = () => ({ version: 1, enabled: false, port: 8787, allowLan: false, modelIds: null, key: null });\nconst revision = value => createHash('sha256').update(JSON.stringify(value)).digest('hex');\nconst fail = (status, code) => { throw new RouteError(status, code); };\nconst json = (res, status, value) => {\n res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff' });\n res.end(JSON.stringify(value));\n};\nfunction validate(value) {\n if (!value || value.version !== 1 || typeof value.enabled !== 'boolean' || typeof value.allowLan !== 'boolean'\n || !Number.isInteger(value.port) || value.port < 1024 || value.port > 65535\n || value.modelIds !== null && (!Array.isArray(value.modelIds) || value.modelIds.length > 1000 || value.modelIds.some(id => typeof id !== 'string' || !/^[\\w.-]{1,128}$/.test(id)))\n || value.key !== null && !/^sk-dsh-[A-Za-z0-9_-]{43}$/.test(value.key)\n || value.enabled && !value.key) throw Error('API \u8BBE\u7F6E\u65E0\u6548\uFF1A\u7AEF\u53E3\u9700\u4E3A 1024\u201365535\uFF0C\u542F\u7528\u524D\u8BF7\u751F\u6210 API Key\u3002');\n return value;\n}\n\n// The service owns only its listener and private access key. Routing, provider\n// credentials, failover and metering remain with the existing Manager/Router.\nexport class ApiService {\n constructor(file, manager) {\n this.file = file; this.manager = manager; this.settings = defaults();\n this.phase = 'stopped'; this.controllers = new Set(); this.queue = Promise.resolve();\n }\n async load() {\n this.configError = false;\n try { this.settings = validate(JSON.parse(await readFile(this.file, 'utf8'))); }\n catch (e) { if (e.code !== 'ENOENT') { this.configError = true; this.phase = 'error'; this.error = 'API \u914D\u7F6E\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u670D\u52A1\u672A\u542F\u52A8\u3002\u8BF7\u91CD\u65B0\u4FDD\u5B58\u8BBE\u7F6E\u3002'; } }\n }\n choices() { return this.manager.adapterModels().filter(m => !m.freeOnly || m.dynamicFree); }\n models() { return this.choices().filter(m => this.settings.modelIds === null ? m.visible !== false : this.settings.modelIds.includes(m.id)); }\n state() {\n const { key, ...settings } = this.settings;\n const port = this.server?.address()?.port ?? settings.port;\n const events = this.manager.telemetry.data.events.filter(e => e.source === 'api' && beijingDay(e.at) === beijingDay(Date.now()));\n const addresses = settings.allowLan ? [...new Set(Object.values(networkInterfaces()).flat().filter(a => a && a.family === 'IPv4' && !a.internal).map(a => `http://${a.address}:${port}/v1`))] : [];\n return { ...settings, revision: revision(this.settings), phase: this.phase, error: this.error,\n hasKey: !!key, keyHint: key ? `sk-dsh-\u2022\u2022\u2022\u2022${key.slice(-4)}` : null, active: this.controllers.size,\n baseUrl: `http://127.0.0.1:${port}/v1`, lanUrls: addresses,\n choices: this.choices().map(m => ({ id: m.id, name: m.name, visible: m.visible !== false, reasoning: m.reasoning })),\n models: this.models().map(m => ({ id: m.id, name: m.name })),\n today: { calls: new Set(events.map(e => e.callId)).size, attempts: events.length, tokens: events.reduce((n, e) => n + (e.tokens ?? 0), 0) } };\n }\n action(input) {\n const task = this.queue.catch(() => {}).then(() => withFileLock(this.file, async () => {\n if (this.closed) throw Error('API \u670D\u52A1\u5DF2\u5173\u95ED\u3002');\n // Compare the on-disk revision too; two DSH instances must not overwrite a key.\n let current = this.settings;\n try { current = validate(JSON.parse(await readFile(this.file, 'utf8'))); } catch (e) { if (e.code !== 'ENOENT' && this.phase !== 'error') throw e; }\n if (input.apiRevision !== revision(current)) throw Error('API \u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u9762\u677F\u540E\u91CD\u8BD5\u3002');\n const next = structuredClone(current);\n let apiKey;\n if (input.action === 'api.key.reveal') return { apiKey: next.key };\n if (input.action === 'api.key.create') { next.key = `sk-dsh-${randomBytes(32).toString('base64url')}`; apiKey = next.key; }\n else if (input.action === 'api.key.revoke') { next.key = null; next.enabled = false; }\n else if (input.action === 'api.settings') {\n for (const k of ['enabled', 'port', 'allowLan', 'modelIds']) if (input[k] !== undefined) next[k] = input[k];\n if (next.modelIds?.some(id => !this.choices().some(m => m.id === id) && !current.modelIds?.includes(id))) throw Error('\u6A21\u578B\u76EE\u5F55\u5DF2\u53D8\u5316\uFF0C\u8BF7\u5237\u65B0\u9762\u677F\u540E\u91CD\u65B0\u9009\u62E9\u3002');\n } else throw Error('\u672A\u77E5 API \u64CD\u4F5C\u3002');\n validate(next);\n await writePrivateJson(this.file, next);\n this.configError = false;\n const restart = next.enabled !== this.settings.enabled || next.port !== this.settings.port || next.allowLan !== this.settings.allowLan;\n this.settings = next;\n if (restart || this.phase === 'error' || !this.server && next.enabled) await this.reconcile();\n return { apiKey };\n }, { waitMs: 10000 }));\n this.queue = task; return task;\n }\n async reconcile() {\n await this.stop();\n if (this.configError) { this.phase = 'error'; return; }\n this.error = undefined;\n if (this.closed || !this.settings.enabled) { this.phase = 'stopped'; return; }\n this.phase = 'starting';\n const server = createServer((req, res) => { void this.handle(req, res); });\n server.requestTimeout = 30000; server.headersTimeout = 10000; server.keepAliveTimeout = 5000;\n this.server = server;\n try {\n await new Promise((resolve, reject) => {\n server.once('error', reject);\n server.listen(this.settings.port, this.settings.allowLan ? '0.0.0.0' : '127.0.0.1', resolve);\n });\n this.phase = 'running';\n server.on('error', () => { this.phase = 'error'; this.error = 'API \u76D1\u542C\u5F02\u5E38\uFF0C\u8BF7\u91CD\u65B0\u4FDD\u5B58\u8BBE\u7F6E\u3002'; });\n } catch (e) {\n this.server = undefined; this.phase = 'error';\n this.error = e.code === 'EADDRINUSE' ? '\u7AEF\u53E3\u5DF2\u88AB\u5360\u7528\uFF0C\u8BF7\u4FEE\u6539\u7AEF\u53E3\u540E\u4FDD\u5B58\u3002' : e.code === 'EACCES' ? '\u6CA1\u6709\u76D1\u542C\u6B64\u7AEF\u53E3\u7684\u6743\u9650\uFF0C\u8BF7\u4FEE\u6539\u7AEF\u53E3\u3002' : 'API \u670D\u52A1\u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7AEF\u53E3\u8BBE\u7F6E\u3002';\n }\n }\n async stop() {\n const server = this.server; this.server = undefined;\n for (const c of this.controllers) c.abort();\n if (server) { server.closeAllConnections(); await new Promise(resolve => server.close(resolve)); }\n this.phase = 'stopped';\n }\n async close() { this.closed = true; await this.queue.catch(() => {}); await this.stop(); }\n async handle(req, res) {\n const controller = new AbortController();\n const signal = AbortSignal.any([controller.signal, AbortSignal.timeout(Math.min(this.manager.config.requestTimeoutMs, 2147483647))]);\n req.on('aborted', () => controller.abort());\n res.on('close', () => { if (!res.writableEnded) controller.abort(); });\n let selected;\n try {\n if (!this.settings.enabled || this.closed) fail(503, 'service_disabled');\n if (!this.settings.allowLan && !hostIsLoopback(req.headers.host)) fail(403, 'loopback_required');\n // No browser CORS access: an unrelated page must never drive the local service.\n if (req.headers.origin || req.headers['sec-fetch-site'] === 'cross-site') fail(403, 'browser_origin_not_allowed');\n const token = /^Bearer\\s+(\\S+)$/i.exec(req.headers.authorization ?? '')?.[1] ?? '';\n const actual = Buffer.from(token), expected = Buffer.from(this.settings.key ?? '');\n if (!expected.length || actual.length !== expected.length || !timingSafeEqual(actual, expected)) fail(401, 'invalid_api_key');\n if (req.method === 'GET' && req.url === '/v1/models') {\n json(res, 200, { object: 'list', data: this.models().map(m => ({ id: m.id, object: 'model', created: 0, owned_by: 'dsh-multi-router' })) }); return;\n }\n if (req.method !== 'POST' || req.url !== '/v1/chat/completions') fail(404, 'not_found');\n if (this.controllers.size >= 8) fail(429, 'too_many_requests');\n this.controllers.add(controller);\n if (!/^application\\/json(?:\\s*;|$)/i.test(req.headers['content-type'] ?? '')) fail(415, 'json_required');\n const chunks = []; let size = 0;\n for await (const chunk of req) { size += chunk.length; if (size > 32 * 1024 * 1024) fail(413, 'request_too_large'); signal.throwIfAborted(); chunks.push(chunk); }\n let input;\n try { input = JSON.parse(Buffer.concat(chunks).toString('utf8')); } catch { fail(400, 'invalid_json'); }\n if (!input || typeof input !== 'object' || Array.isArray(input) || typeof input.model !== 'string'\n || !Array.isArray(input.messages) || !input.messages.length || input.messages.some(m => !m || typeof m !== 'object' || !['system', 'developer', 'user', 'assistant', 'tool', 'function'].includes(m.role))\n || input.stream !== undefined && typeof input.stream !== 'boolean') fail(400, 'invalid_request');\n if (!this.models().some(m => m.id === input.model)) fail(404, 'model_not_exposed');\n if (input.n !== undefined && input.n !== 1) fail(400, 'only_n_1_supported');\n if (input.reasoning_effort != null && !REASONING_EFFORTS.includes(input.reasoning_effort)) fail(400, 'invalid_reasoning_effort');\n // Never accept internal account/session headers or persist caller user IDs.\n selected = await abortable(this.manager.router.chat({ ...input, stream: true }, signal, { callId: randomUUID(), source: 'api' }), signal);\n signal.throwIfAborted();\n const frames = completionFrames(selected.response, input.model, signal);\n if (input.stream === true) {\n res.writeHead(200, { 'Content-Type': 'text/event-stream; charset=utf-8', 'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no' });\n await pipeline(Readable.from((async function* () {\n for await (const frame of frames) {\n if (!input.stream_options?.include_usage && !frame.choices?.length && frame.usage) continue;\n if (!input.stream_options?.include_usage) delete frame.usage;\n yield `data: ${JSON.stringify(frame)}\\n\\n`;\n }\n yield 'data: [DONE]\\n\\n';\n })()), res, { signal });\n } else json(res, 200, await collectCompletion(frames, input.model));\n } catch (e) {\n if (res.destroyed) return;\n if (res.headersSent) { res.destroy(); return; }\n const status = e instanceof RouteError ? e.status : signal.aborted ? 504 : 500;\n const code = e instanceof RouteError ? e.code : signal.aborted ? 'request_timeout' : 'internal_error';\n // RouteError.message includes account IDs; upstream exception text can contain credentials.\n json(res, status, { error: { message: code, type: status === 401 ? 'authentication_error' : status < 500 ? 'invalid_request_error' : 'server_error', code, param: null } });\n } finally {\n this.controllers.delete(controller);\n if (selected?.response.body && !selected.response.body.locked) await selected.response.body.cancel().catch(() => {});\n }\n }\n}\n\nasync function* completionFrames(response, model, signal) {\n if (!response.body) fail(502, 'empty_upstream_response');\n const reader = response.body.getReader(), decoder = new TextDecoder(), sse = new SseDecoder();\n let finished = false, total = 0, frameBytes = 0;\n const abort = () => { void reader.cancel().catch(() => {}); };\n signal.addEventListener('abort', abort, { once: true });\n function parse(event) {\n if (event.data === '[DONE]') return null;\n let value;\n try { value = JSON.parse(event.data); } catch { fail(502, 'invalid_upstream_stream'); }\n if (!value || typeof value !== 'object' || Array.isArray(value) || value.error) fail(502, 'upstream_stream_error');\n if (value.choices !== undefined && (!Array.isArray(value.choices) || value.choices.length > 32)) fail(502, 'invalid_upstream_stream');\n for (const c of value.choices ?? []) {\n if (!c || !Number.isInteger(c.index) || c.index < 0 || c.index > 31) fail(502, 'invalid_upstream_stream');\n if (c.delta?.tool_calls && (!Array.isArray(c.delta.tool_calls) || c.delta.tool_calls.some(t => !t || !Number.isInteger(t.index) || t.index < 0 || t.index > 127))) fail(502, 'invalid_upstream_stream');\n }\n if (value.choices?.some(c => c.finish_reason)) finished = true;\n return { ...value, model };\n }\n try {\n while (true) {\n signal.throwIfAborted(); const chunk = await reader.read(); signal.throwIfAborted();\n if (chunk.done) break;\n total += chunk.value.byteLength; frameBytes += chunk.value.byteLength;\n if (total > 32 * 1024 * 1024 || frameBytes > 1024 * 1024) fail(502, 'upstream_response_too_large');\n const events = sse.push(decoder.decode(chunk.value, { stream: true }));\n if (events.length) frameBytes = 0;\n for (const event of events) { const value = parse(event); if (value) yield value; }\n }\n for (const event of sse.finish()) { const value = parse(event); if (value) yield value; }\n if (!finished) fail(502, 'upstream_stream_incomplete');\n } finally { signal.removeEventListener('abort', abort); await reader.cancel().catch(() => {}); reader.releaseLock(); }\n}\n\nasync function collectCompletion(frames, model) {\n const result = { id: `chatcmpl-${randomUUID()}`, object: 'chat.completion', created: Math.floor(Date.now() / 1000), model, choices: [] };\n const choices = new Map();\n for await (const frame of frames) {\n if (frame.id) result.id = frame.id;\n if (frame.created != null) result.created = frame.created;\n if (frame.usage) result.usage = frame.usage;\n for (const part of frame.choices ?? []) {\n const index = part.index ?? 0;\n if (!choices.has(index)) choices.set(index, { index, message: { role: 'assistant', content: null }, finish_reason: null, logprobs: null });\n const choice = choices.get(index), delta = part.delta ?? {};\n for (const k of ['content', 'reasoning_content', 'reasoning', 'refusal']) if (typeof delta[k] === 'string') choice.message[k] = (choice.message[k] ?? '') + delta[k];\n if (delta.function_call) {\n choice.message.function_call ??= { name: '', arguments: '' };\n for (const k of ['name', 'arguments']) if (typeof delta.function_call[k] === 'string') choice.message.function_call[k] += delta.function_call[k];\n }\n if (delta.tool_calls) for (const tool of delta.tool_calls) {\n choice.message.tool_calls ??= [];\n const i = tool.index ?? 0;\n const value = choice.message.tool_calls[i] ??= { id: '', type: 'function', function: { name: '', arguments: '' } };\n if (tool.id) value.id += tool.id;\n if (tool.type) value.type = tool.type;\n for (const k of ['name', 'arguments']) if (typeof tool.function?.[k] === 'string') value.function[k] += tool.function[k];\n }\n if (part.finish_reason) choice.finish_reason = part.finish_reason;\n }\n }\n result.choices = [...choices.values()].sort((a, b) => a.index - b.index);\n return result;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -4,10 +4,10 @@ import {
4
4
  } from "./chunk-DNQPZMPF.js";
5
5
  import {
6
6
  RouteError
7
- } from "./chunk-J3XO7RTF.js";
7
+ } from "./chunk-DZ4ZUAYH.js";
8
8
  import {
9
9
  REASONING_EFFORTS
10
- } from "./chunk-MCHV2R25.js";
10
+ } from "./chunk-NGVWVIBM.js";
11
11
 
12
12
  // src/shim.mjs
13
13
  import { createServer } from "node:http";
@@ -117,4 +117,4 @@ function createShim(router, { modelPrefix = "" } = {}) {
117
117
  export {
118
118
  createShim
119
119
  };
120
- //# sourceMappingURL=chunk-P43AWJ4Q.js.map
120
+ //# sourceMappingURL=chunk-BSAI3SW5.js.map