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.
- package/CHANGELOG.md +20 -0
- package/README.md +46 -6
- package/THIRD_PARTY_NOTICES.md +4 -0
- package/cordis.patch.yml +2 -2
- package/lib/accounts.js +4 -4
- package/lib/api-service.js +11 -0
- package/lib/api-service.js.map +7 -0
- package/lib/{chunk-U2MU2M5C.js → chunk-2LH6TD2U.js} +25 -115
- package/lib/chunk-2LH6TD2U.js.map +7 -0
- package/lib/chunk-4V52V5GO.js +105 -0
- package/lib/chunk-4V52V5GO.js.map +7 -0
- package/lib/chunk-625KMEYS.js +332 -0
- package/lib/chunk-625KMEYS.js.map +7 -0
- package/lib/{chunk-P43AWJ4Q.js → chunk-BSAI3SW5.js} +3 -3
- package/lib/{chunk-J3XO7RTF.js → chunk-DZ4ZUAYH.js} +50 -6
- package/lib/chunk-DZ4ZUAYH.js.map +7 -0
- package/lib/{chunk-MCHV2R25.js → chunk-NGVWVIBM.js} +22 -6
- package/lib/chunk-NGVWVIBM.js.map +7 -0
- package/lib/{chunk-FTM7RHQV.js → chunk-OK2T2UAZ.js} +4 -4
- package/lib/{chunk-S6ZQ45SS.js → chunk-VZPXRK7Q.js} +3 -3
- package/lib/{chunk-I4EW5TI7.js → chunk-ZQZSXCVR.js} +164 -48
- package/lib/chunk-ZQZSXCVR.js.map +7 -0
- package/lib/cli.js +7 -6
- package/lib/cli.js.map +1 -1
- package/lib/client.js +462 -44
- package/lib/client.js.map +2 -2
- package/lib/clients.js +9 -5
- package/lib/{host-v0.5.9.js → host-v0.6.1.js} +19 -13
- package/lib/host.js +19 -13
- package/lib/index.js +19 -13
- package/lib/index.js.map +2 -2
- package/lib/manager.js +11 -7
- package/lib/router.js +2 -2
- package/lib/shim.js +3 -3
- package/package.json +1 -1
- package/lib/chunk-I4EW5TI7.js.map +0 -7
- package/lib/chunk-J3XO7RTF.js.map +0 -7
- package/lib/chunk-MCHV2R25.js.map +0 -7
- package/lib/chunk-U2MU2M5C.js.map +0 -7
- /package/lib/{chunk-P43AWJ4Q.js.map → chunk-BSAI3SW5.js.map} +0 -0
- /package/lib/{chunk-FTM7RHQV.js.map → chunk-OK2T2UAZ.js.map} +0 -0
- /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-
|
|
7
|
+
} from "./chunk-DZ4ZUAYH.js";
|
|
8
8
|
import {
|
|
9
9
|
REASONING_EFFORTS
|
|
10
|
-
} from "./chunk-
|
|
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-
|
|
120
|
+
//# sourceMappingURL=chunk-BSAI3SW5.js.map
|