llm-simple-router 0.9.32 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/providers.js +1 -1
- package/dist/admin/routes.js +5 -0
- package/dist/admin/schedules.js +1 -1
- package/dist/admin/upgrade.js +3 -3
- package/dist/config/model-context.js +21 -9
- package/dist/config/recommended.js +2 -2
- package/dist/core/constants.d.ts +1 -0
- package/dist/core/constants.js +1 -0
- package/dist/core/container.d.ts +1 -0
- package/dist/core/container.js +1 -0
- package/dist/db/db-size-monitor.js +1 -1
- package/dist/db/index.js +1 -0
- package/dist/db/log-cleaner.js +1 -1
- package/dist/db/mappings.js +6 -15
- package/dist/db/providers.d.ts +1 -0
- package/dist/db/providers.js +11 -26
- package/dist/db/router-keys.js +4 -5
- package/dist/db/settings.js +3 -3
- package/dist/index.js +44 -8
- package/dist/proxy/format/adapters/anthropic.d.ts +2 -0
- package/dist/proxy/format/adapters/anthropic.js +18 -0
- package/dist/proxy/format/adapters/openai.d.ts +2 -0
- package/dist/proxy/format/adapters/openai.js +14 -0
- package/dist/proxy/format/adapters/responses.d.ts +2 -0
- package/dist/proxy/format/adapters/responses.js +9 -0
- package/dist/proxy/format/adapters/shared-error-meta.d.ts +9 -0
- package/dist/proxy/format/adapters/shared-error-meta.js +14 -0
- package/dist/proxy/format/converters/anthropic-openai.d.ts +1 -0
- package/dist/proxy/format/converters/anthropic-openai.js +11 -0
- package/dist/proxy/format/converters/anthropic-responses.d.ts +1 -0
- package/dist/proxy/format/converters/anthropic-responses.js +11 -0
- package/dist/proxy/format/converters/openai-anthropic.d.ts +1 -0
- package/dist/proxy/format/converters/openai-anthropic.js +11 -0
- package/dist/proxy/format/converters/openai-responses.d.ts +1 -0
- package/dist/proxy/format/converters/openai-responses.js +11 -0
- package/dist/proxy/format/converters/responses-anthropic.d.ts +1 -0
- package/dist/proxy/format/converters/responses-anthropic.js +11 -0
- package/dist/proxy/format/converters/responses-openai.d.ts +1 -0
- package/dist/proxy/format/converters/responses-openai.js +11 -0
- package/dist/proxy/format/registry.d.ts +17 -0
- package/dist/proxy/format/registry.js +50 -0
- package/dist/proxy/format/types.d.ts +27 -0
- package/dist/proxy/format/types.js +16 -0
- package/dist/proxy/handler/create-proxy-handler.d.ts +14 -0
- package/dist/proxy/handler/create-proxy-handler.js +235 -0
- package/dist/proxy/handler/failover-loop.d.ts +19 -0
- package/dist/proxy/handler/failover-loop.js +407 -0
- package/dist/proxy/handler/proxy-handler-utils.js +1 -1
- package/dist/proxy/hooks/builtin/allowed-models.d.ts +12 -0
- package/dist/proxy/hooks/builtin/allowed-models.js +37 -0
- package/dist/proxy/hooks/builtin/enhancement-preprocess.d.ts +2 -0
- package/dist/proxy/hooks/builtin/enhancement-preprocess.js +84 -0
- package/dist/proxy/hooks/builtin/error-logging.d.ts +2 -0
- package/dist/proxy/hooks/builtin/error-logging.js +86 -0
- package/dist/proxy/hooks/builtin/overflow-redirect.d.ts +2 -0
- package/dist/proxy/hooks/builtin/overflow-redirect.js +39 -0
- package/dist/proxy/hooks/builtin/plugin-request.d.ts +2 -0
- package/dist/proxy/hooks/builtin/plugin-request.js +49 -0
- package/dist/proxy/hooks/builtin/provider-patches.d.ts +2 -0
- package/dist/proxy/hooks/builtin/provider-patches.js +36 -0
- package/dist/proxy/hooks/builtin/request-logging.d.ts +2 -0
- package/dist/proxy/hooks/builtin/request-logging.js +72 -0
- package/dist/proxy/hooks/plugin-bridge.d.ts +7 -0
- package/dist/proxy/hooks/plugin-bridge.js +106 -0
- package/dist/proxy/hooks/sse-event-transform.d.ts +13 -0
- package/dist/proxy/hooks/sse-event-transform.js +59 -0
- package/dist/proxy/orchestration/resilience.js +2 -3
- package/dist/proxy/patch/deepseek/patch-orphan-tool-results.js +1 -1
- package/dist/proxy/patch/deepseek/utils.js +1 -1
- package/dist/proxy/pipeline/context.d.ts +3 -0
- package/dist/proxy/pipeline/context.js +31 -0
- package/dist/proxy/pipeline/hook-registry.d.ts +20 -0
- package/dist/proxy/pipeline/hook-registry.js +24 -0
- package/dist/proxy/pipeline/pipeline.d.ts +13 -0
- package/dist/proxy/pipeline/pipeline.js +26 -0
- package/dist/proxy/pipeline/register-hooks.d.ts +1 -0
- package/dist/proxy/pipeline/register-hooks.js +23 -0
- package/dist/proxy/pipeline/types.d.ts +63 -0
- package/dist/proxy/pipeline/types.js +10 -0
- package/dist/proxy/proxy-core.js +1 -1
- package/dist/proxy/routing/mapping-resolver.js +7 -16
- package/dist/proxy/transform/message-mapper.js +8 -8
- package/dist/proxy/transform/plugin-types.d.ts +47 -17
- package/dist/proxy/transform/request-bridge-responses.js +21 -21
- package/dist/proxy/transform/request-transform-responses.js +24 -24
- package/dist/proxy/transform/request-transform.js +1 -3
- package/dist/proxy/transform/response-bridge-responses.js +13 -13
- package/dist/proxy/transform/response-transform-responses.js +10 -10
- package/dist/proxy/transform/sanitize.js +5 -1
- package/dist/proxy/transform/stream-transform-base.js +2 -2
- package/dist/proxy/transport/transport-fn.js +0 -1
- package/frontend-dist/assets/{CardContent-D3x1v1V9.js → CardContent-eu5DgvQn.js} +1 -1
- package/frontend-dist/assets/{CardTitle-DIgY93n2.js → CardTitle-B8YCOfF5.js} +1 -1
- package/frontend-dist/assets/{Checkbox-BBj7YMSz.js → Checkbox-BMzIHy1r.js} +1 -1
- package/frontend-dist/assets/{CollapsibleContent-Cy8Zj7F7.js → CollapsibleContent-C_nFgqIi.js} +1 -1
- package/frontend-dist/assets/{CollapsibleTrigger-Vdxg8CPQ.js → CollapsibleTrigger-CPqhHT7X.js} +1 -1
- package/frontend-dist/assets/{Dashboard-BvUBgYaB.js → Dashboard-BLxKSSXs.js} +1 -1
- package/frontend-dist/assets/{Input-yOkodP1n.js → Input-DkWAdwBI.js} +1 -1
- package/frontend-dist/assets/{Label-XqpkYcVi.js → Label-CJ2IIzlx.js} +1 -1
- package/frontend-dist/assets/Login-Dw4f6v19.js +1 -0
- package/frontend-dist/assets/{Logs-bfeOLJad.js → Logs-Df503HB_.js} +1 -1
- package/frontend-dist/assets/{MappingEntryEditor-CMTbBK_d.js → MappingEntryEditor-Dg6zjLjk.js} +1 -1
- package/frontend-dist/assets/{ModelCard-C81l2a_5.js → ModelCard-Ct1-_CKo.js} +1 -1
- package/frontend-dist/assets/ModelMappings-QsbYO-BL.js +1 -0
- package/frontend-dist/assets/{Monitor-BGH6sjdr.js → Monitor-DIiuMy53.js} +1 -1
- package/frontend-dist/assets/{Providers-UK6LN6DF.js → Providers-NyDmz-Aa.js} +1 -1
- package/frontend-dist/assets/{ProxyEnhancement-MX0PRADd.js → ProxyEnhancement-DNtlZsDS.js} +1 -1
- package/frontend-dist/assets/QuickSetup-Ce3GmdB-.js +1 -0
- package/frontend-dist/assets/{RetryRules-gpvpTTSc.js → RetryRules-EqbyA2z0.js} +1 -1
- package/frontend-dist/assets/{RouterKeys-Dc8D6cEV.js → RouterKeys-DMKJn6FW.js} +1 -1
- package/frontend-dist/assets/{RovingFocusItem-B3BLvyzD.js → RovingFocusItem-CebAv0Zc.js} +1 -1
- package/frontend-dist/assets/Schedules-DxHuzar_.js +1 -0
- package/frontend-dist/assets/{Settings-BiYdwrHf.js → Settings-DwULwXPR.js} +2 -2
- package/frontend-dist/assets/{Setup-BVqlQCjs.js → Setup-DNhGIF-c.js} +1 -1
- package/frontend-dist/assets/{Switch-B7QaMMlY.js → Switch-ChIi3Y2O.js} +1 -1
- package/frontend-dist/assets/{TooltipTrigger-Bz3pu02g.js → TooltipTrigger-BcK9IvPW.js} +1 -1
- package/frontend-dist/assets/{TransformRulesForm-DXB1ChZ2.js → TransformRulesForm-CXJhbKc5.js} +1 -1
- package/frontend-dist/assets/{UnifiedRequestDialog-BbGcsFXP.js → UnifiedRequestDialog-I_J8h6X5.js} +1 -1
- package/frontend-dist/assets/{VisuallyHiddenInput-MTmHNjqA.js → VisuallyHiddenInput-awNWLd76.js} +1 -1
- package/frontend-dist/assets/{button-lv9v_6nd.js → button-C50lT23d.js} +2 -2
- package/frontend-dist/assets/{copy-Dwbg7SpV.js → copy-BHunr2eT.js} +1 -1
- package/frontend-dist/assets/{dialog-ZNKLyaHg.js → dialog-Bts2bGWX.js} +1 -1
- package/frontend-dist/assets/{index-CDEwS862.js → index-CGNAzHFe.js} +2 -2
- package/frontend-dist/assets/{trash-2-UQ53WECI.js → trash-2-CkUDjZuE.js} +1 -1
- package/frontend-dist/assets/{useClipboard-CmrKRWL_.js → useClipboard-C3rvTuuE.js} +1 -1
- package/frontend-dist/assets/useLogRetention-DL5cOZfI.js +1 -0
- package/frontend-dist/index.html +2 -2
- package/package.json +1 -1
- package/dist/proxy/handler/anthropic.d.ts +0 -7
- package/dist/proxy/handler/anthropic.js +0 -43
- package/dist/proxy/handler/openai.d.ts +0 -7
- package/dist/proxy/handler/openai.js +0 -131
- package/dist/proxy/handler/proxy-handler.d.ts +0 -15
- package/dist/proxy/handler/proxy-handler.js +0 -430
- package/dist/proxy/handler/responses.d.ts +0 -7
- package/dist/proxy/handler/responses.js +0 -48
- package/dist/proxy/transform/transform-coordinator.d.ts +0 -12
- package/dist/proxy/transform/transform-coordinator.js +0 -151
- package/frontend-dist/assets/Login-BGagonui.js +0 -1
- package/frontend-dist/assets/ModelMappings-CvDWSsDP.js +0 -1
- package/frontend-dist/assets/QuickSetup-CajStS5C.js +0 -1
- package/frontend-dist/assets/Schedules-Criu9-NO.js +0 -1
- package/frontend-dist/assets/useLogRetention-C59RXKSz.js +0 -1
package/dist/admin/providers.js
CHANGED
|
@@ -418,7 +418,7 @@ export const adminProviderRoutes = (app, options, done) => {
|
|
|
418
418
|
return reply.send(modelIds);
|
|
419
419
|
}
|
|
420
420
|
catch (err) {
|
|
421
|
-
const message = err instanceof Error ? err.message :
|
|
421
|
+
const message = err instanceof Error ? err.message : err instanceof Error ? err.message : JSON.stringify(err);
|
|
422
422
|
return reply.code(HTTP_BAD_REQUEST).send(apiError(API_CODE.BAD_REQUEST, `连接上游失败: ${message}`));
|
|
423
423
|
}
|
|
424
424
|
});
|
package/dist/admin/routes.js
CHANGED
|
@@ -18,6 +18,7 @@ import { adminQuickSetupRoutes } from "./quick-setup.js";
|
|
|
18
18
|
import { adminImportExportRoutes } from "./settings-import-export.js";
|
|
19
19
|
import { adminTransformRuleRoutes } from "./transform-rules.js";
|
|
20
20
|
import { adminScheduleRoutes } from "./schedules.js";
|
|
21
|
+
import { hookRegistry } from "../proxy/pipeline/hook-registry.js";
|
|
21
22
|
export const adminRoutes = (app, options, done) => {
|
|
22
23
|
// Setup 路由不需要 auth
|
|
23
24
|
app.register(adminSetupRoutes, { db: options.db });
|
|
@@ -41,5 +42,9 @@ export const adminRoutes = (app, options, done) => {
|
|
|
41
42
|
app.register(adminQuickSetupRoutes, { db: options.db, stateRegistry: options.stateRegistry, tracker: options.tracker, adaptiveController: options.adaptiveController });
|
|
42
43
|
app.register(adminUpgradeRoutes, { db: options.db, closeFn: options.closeFn ?? (async () => { }) });
|
|
43
44
|
app.register(adminTransformRuleRoutes, { db: options.db, pluginRegistry: options.pluginRegistry });
|
|
45
|
+
// Pipeline hooks 查询
|
|
46
|
+
app.get("/admin/api/pipeline/hooks", async () => {
|
|
47
|
+
return { hooks: hookRegistry.getAll() };
|
|
48
|
+
});
|
|
44
49
|
done();
|
|
45
50
|
};
|
package/dist/admin/schedules.js
CHANGED
|
@@ -95,7 +95,7 @@ function checkOverlap(db, groupId, excludeId, weekDays, startHour, endHour) {
|
|
|
95
95
|
}
|
|
96
96
|
const HOUR_PAD_WIDTH = 2;
|
|
97
97
|
function formatHour(h) {
|
|
98
|
-
return
|
|
98
|
+
return h.toString().padStart(HOUR_PAD_WIDTH, "0") + ":00";
|
|
99
99
|
}
|
|
100
100
|
export const adminScheduleRoutes = (app, options, done) => {
|
|
101
101
|
const { db } = options;
|
package/dist/admin/upgrade.js
CHANGED
|
@@ -93,7 +93,7 @@ export const adminUpgradeRoutes = (app, options, done) => {
|
|
|
93
93
|
return reply.send({ ok: true, version });
|
|
94
94
|
}
|
|
95
95
|
catch (err) {
|
|
96
|
-
const msg = err instanceof Error ? err.message :
|
|
96
|
+
const msg = err instanceof Error ? err.message : err instanceof Error ? err.message : JSON.stringify(err);
|
|
97
97
|
return reply.code(HTTP_INTERNAL_ERROR).send(apiError(API_CODE.INTERNAL_ERROR, `升级失败: ${msg}`));
|
|
98
98
|
}
|
|
99
99
|
});
|
|
@@ -125,7 +125,7 @@ export const adminUpgradeRoutes = (app, options, done) => {
|
|
|
125
125
|
process.exit(0);
|
|
126
126
|
}
|
|
127
127
|
catch (err) {
|
|
128
|
-
const msg = err instanceof Error ? err.message :
|
|
128
|
+
const msg = err instanceof Error ? err.message : err instanceof Error ? err.message : JSON.stringify(err);
|
|
129
129
|
req.log.error({ err }, `Restart failed: ${msg}`);
|
|
130
130
|
process.exit(1);
|
|
131
131
|
}
|
|
@@ -162,7 +162,7 @@ export const adminUpgradeRoutes = (app, options, done) => {
|
|
|
162
162
|
return reply.send({ ok: true });
|
|
163
163
|
}
|
|
164
164
|
catch (err) {
|
|
165
|
-
const msg = err instanceof Error ? err.message :
|
|
165
|
+
const msg = err instanceof Error ? err.message : err instanceof Error ? err.message : JSON.stringify(err);
|
|
166
166
|
return reply.code(HTTP_INTERNAL_ERROR).send(apiError(API_CODE.INTERNAL_ERROR, `同步失败: ${msg}`));
|
|
167
167
|
}
|
|
168
168
|
});
|
|
@@ -88,6 +88,22 @@ export function lookupContextWindow(modelName) {
|
|
|
88
88
|
export function normalizePatchName(name) {
|
|
89
89
|
return name.replace(/-/g, "_");
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* 解析 providers.models 的 JSON 文本。
|
|
93
|
+
*
|
|
94
|
+
* 这是解析 providers.models 字段的唯一合法入口。
|
|
95
|
+
* 禁止直接 JSON.parse(provider.models) —— 数据格式已从 string[] 演进为 ModelEntry[],
|
|
96
|
+
* 直接 JSON.parse 会得到对象数组而非字符串数组,导致运行时错误。
|
|
97
|
+
*
|
|
98
|
+
* ESLint 规则 taste/no-raw-json-parse-models 会强制执行此约束。
|
|
99
|
+
*/
|
|
100
|
+
/** 旧 patch ID 到新 patch ID 的迁移映射 */
|
|
101
|
+
const PATCH_ID_MIGRATION = {
|
|
102
|
+
thinking_param: "thinking_consistency",
|
|
103
|
+
thinking_blocks: "thinking_consistency",
|
|
104
|
+
non_ds_tools: "thinking_consistency",
|
|
105
|
+
cache_control: "thinking_consistency",
|
|
106
|
+
};
|
|
91
107
|
export function parseModels(raw) {
|
|
92
108
|
if (!raw)
|
|
93
109
|
return [];
|
|
@@ -100,20 +116,16 @@ export function parseModels(raw) {
|
|
|
100
116
|
return item ? { name: item, patches: [] } : null;
|
|
101
117
|
}
|
|
102
118
|
const obj = item;
|
|
103
|
-
if (!obj
|
|
119
|
+
if (!obj)
|
|
120
|
+
return null;
|
|
121
|
+
const modelName = obj.name ?? obj.id;
|
|
122
|
+
if (!modelName)
|
|
104
123
|
return null;
|
|
105
|
-
/** 旧 patch ID 到新 patch ID 的运行时迁移映射 */
|
|
106
|
-
const PATCH_ID_MIGRATION = {
|
|
107
|
-
thinking_param: "thinking_consistency",
|
|
108
|
-
thinking_blocks: "thinking_consistency",
|
|
109
|
-
non_ds_tools: "thinking_consistency",
|
|
110
|
-
cache_control: "thinking_consistency",
|
|
111
|
-
};
|
|
112
124
|
const rawPatches = (obj.patches ?? []).map(normalizePatchName);
|
|
113
125
|
const migrated = rawPatches.map(p => PATCH_ID_MIGRATION[p] ?? p);
|
|
114
126
|
const patches = [...new Set(migrated)];
|
|
115
127
|
const result = {
|
|
116
|
-
name:
|
|
128
|
+
name: modelName,
|
|
117
129
|
patches,
|
|
118
130
|
};
|
|
119
131
|
if (obj.stream_timeout_ms != null)
|
|
@@ -12,7 +12,7 @@ function loadJson(filename) {
|
|
|
12
12
|
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
13
13
|
}
|
|
14
14
|
catch (err) {
|
|
15
|
-
process.stderr.write(`[recommended] 加载 ${filename} 失败: ${err instanceof Error ? err.message :
|
|
15
|
+
process.stderr.write(`[recommended] 加载 ${filename} 失败: ${err instanceof Error ? err.message : err instanceof Error ? err.message : JSON.stringify(err)}\n`);
|
|
16
16
|
return [];
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -31,7 +31,7 @@ export function getConfigVersions() {
|
|
|
31
31
|
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
32
32
|
}
|
|
33
33
|
catch (err) {
|
|
34
|
-
process.stderr.write(`[recommended] 加载 version.json 失败: ${err instanceof Error ? err.message :
|
|
34
|
+
process.stderr.write(`[recommended] 加载 version.json 失败: ${err instanceof Error ? err.message : err instanceof Error ? err.message : JSON.stringify(err)}\n`);
|
|
35
35
|
return { providers: 0, retryRules: 0 };
|
|
36
36
|
}
|
|
37
37
|
}
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare const HTTP_CONFLICT = 409;
|
|
|
7
7
|
export declare const HTTP_UNPROCESSABLE_ENTITY = 422;
|
|
8
8
|
export declare const HTTP_INTERNAL_ERROR = 500;
|
|
9
9
|
export declare const HTTP_BAD_GATEWAY = 502;
|
|
10
|
+
export declare const HTTP_CLIENT_CLOSED = 499;
|
|
10
11
|
export declare const HTTP_SERVICE_UNAVAILABLE = 503;
|
|
11
12
|
export declare const PROXY_API_TYPES: Record<string, string>;
|
|
12
13
|
export declare function getProxyApiType(url: string): string | null;
|
package/dist/core/constants.js
CHANGED
|
@@ -9,6 +9,7 @@ export const HTTP_CONFLICT = 409;
|
|
|
9
9
|
export const HTTP_UNPROCESSABLE_ENTITY = 422;
|
|
10
10
|
export const HTTP_INTERNAL_ERROR = 500;
|
|
11
11
|
export const HTTP_BAD_GATEWAY = 502;
|
|
12
|
+
export const HTTP_CLIENT_CLOSED = 499; // nginx convention: client disconnected
|
|
12
13
|
export const HTTP_SERVICE_UNAVAILABLE = 503;
|
|
13
14
|
// api_type 路由映射:proxy path → api type,用于全局 hook/errorHandler 中识别代理请求
|
|
14
15
|
export const PROXY_API_TYPES = {
|
package/dist/core/container.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare const SERVICE_KEYS: {
|
|
|
8
8
|
readonly sessionTracker: "sessionTracker";
|
|
9
9
|
readonly adaptiveController: "adaptiveController";
|
|
10
10
|
readonly pluginRegistry: "pluginRegistry";
|
|
11
|
+
readonly formatRegistry: "formatRegistry";
|
|
11
12
|
readonly logFileWriter: "logFileWriter";
|
|
12
13
|
readonly proxyAgentFactory: "proxyAgentFactory";
|
|
13
14
|
};
|
package/dist/core/container.js
CHANGED
|
@@ -8,6 +8,7 @@ export const SERVICE_KEYS = {
|
|
|
8
8
|
sessionTracker: "sessionTracker",
|
|
9
9
|
adaptiveController: "adaptiveController",
|
|
10
10
|
pluginRegistry: "pluginRegistry",
|
|
11
|
+
formatRegistry: "formatRegistry",
|
|
11
12
|
logFileWriter: "logFileWriter",
|
|
12
13
|
proxyAgentFactory: "proxyAgentFactory",
|
|
13
14
|
};
|
|
@@ -57,7 +57,7 @@ export function scheduleDbSizeMonitor(db, dbPath, options) {
|
|
|
57
57
|
}
|
|
58
58
|
catch (e) {
|
|
59
59
|
// DB 可能已关闭(测试清理、进程关闭等)
|
|
60
|
-
options.log.info(`Size monitor check skipped: ${e instanceof Error ? e.message :
|
|
60
|
+
options.log.info(`Size monitor check skipped: ${e instanceof Error ? e.message : e instanceof Error ? e.message : JSON.stringify(e)}`);
|
|
61
61
|
}
|
|
62
62
|
finally {
|
|
63
63
|
running = false;
|
package/dist/db/index.js
CHANGED
|
@@ -105,6 +105,7 @@ function runApplicationMigrations(db) {
|
|
|
105
105
|
db.transaction(() => {
|
|
106
106
|
for (const p of providers) {
|
|
107
107
|
try {
|
|
108
|
+
// eslint-disable-next-line taste/no-raw-json-parse-models -- 迁移代码需要操作原始 JSON 结构,parseModels() 会过滤非标准字段
|
|
108
109
|
const raw = JSON.parse(p.models);
|
|
109
110
|
if (!Array.isArray(raw) || raw.length === 0)
|
|
110
111
|
continue;
|
package/dist/db/log-cleaner.js
CHANGED
|
@@ -29,7 +29,7 @@ export function scheduleLogCleanup(db, log) {
|
|
|
29
29
|
}
|
|
30
30
|
catch (e) {
|
|
31
31
|
// DB 可能已关闭(测试清理、进程关闭等)
|
|
32
|
-
log.info(`Log cleanup skipped: ${e instanceof Error ? e.message :
|
|
32
|
+
log.info(`Log cleanup skipped: ${e instanceof Error ? e.message : e instanceof Error ? e.message : JSON.stringify(e)}`);
|
|
33
33
|
}
|
|
34
34
|
finally {
|
|
35
35
|
cleaning = false;
|
package/dist/db/mappings.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import { buildUpdateQuery, deleteById } from "./helpers.js";
|
|
3
|
+
import { parseModels } from "../config/model-context.js";
|
|
3
4
|
const GROUP_FIELDS = new Set(["client_model", "strategy", "rule", "is_active"]);
|
|
4
5
|
// --- MappingGroups CRUD ---
|
|
5
6
|
export function getMappingGroup(db, clientModel) {
|
|
@@ -35,14 +36,9 @@ export function getActiveProviderModels(db) {
|
|
|
35
36
|
const providers = db.prepare("SELECT name, models, is_active FROM providers WHERE is_active = 1").all();
|
|
36
37
|
const results = [];
|
|
37
38
|
for (const p of providers) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
results.push({ provider_name: p.name, backend_model: m });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
continue;
|
|
39
|
+
const modelEntries = parseModels(p.models);
|
|
40
|
+
for (const m of modelEntries) {
|
|
41
|
+
results.push({ provider_name: p.name, backend_model: m.name });
|
|
46
42
|
}
|
|
47
43
|
}
|
|
48
44
|
return results;
|
|
@@ -83,14 +79,9 @@ export function resolveByProviderModel(db, providerName, backendModel) {
|
|
|
83
79
|
const providerRow = db.prepare("SELECT id, models FROM providers WHERE name = ? AND is_active = 1").get(providerName);
|
|
84
80
|
if (!providerRow)
|
|
85
81
|
return null;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (!models.includes(backendModel))
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
82
|
+
const modelEntries = parseModels(providerRow.models);
|
|
83
|
+
if (!modelEntries.some(m => m.name === backendModel))
|
|
92
84
|
return null;
|
|
93
|
-
}
|
|
94
85
|
// 尝试从 mapping_groups 找到包含此 provider+backend_model 的 client_model
|
|
95
86
|
const groups = db.prepare("SELECT client_model, rule FROM mapping_groups").all();
|
|
96
87
|
for (const g of groups) {
|
package/dist/db/providers.d.ts
CHANGED
package/dist/db/providers.js
CHANGED
|
@@ -1,35 +1,20 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import { buildUpdateQuery, deleteById } from "./helpers.js";
|
|
3
|
+
import { parseModels } from "../config/model-context.js";
|
|
3
4
|
/** 默认流式超时 10 分钟 */
|
|
4
5
|
export const DEFAULT_STREAM_TIMEOUT_MS = 600_000;
|
|
5
6
|
/** 从 provider 的 models JSON 中查找指定模型的超时值 */
|
|
6
7
|
export function getModelStreamTimeout(provider, backendModel) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const obj = m;
|
|
18
|
-
if (!obj || typeof obj !== "object")
|
|
19
|
-
continue;
|
|
20
|
-
const modelId = (obj.name ?? obj.id);
|
|
21
|
-
if (modelId === backendModel) {
|
|
22
|
-
const timeout = obj.stream_timeout_ms;
|
|
23
|
-
// stream_timeout_ms: 0 表示禁用超时,返回 Infinity;
|
|
24
|
-
// undefined/null/未设置 表示使用默认值
|
|
25
|
-
if (timeout === 0)
|
|
26
|
-
return Number.POSITIVE_INFINITY;
|
|
27
|
-
return timeout ?? DEFAULT_STREAM_TIMEOUT_MS;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
catch { /* ignore parse errors — models field may be empty or invalid */ } // eslint-disable-line taste/no-silent-catch
|
|
32
|
-
return DEFAULT_STREAM_TIMEOUT_MS;
|
|
8
|
+
const entries = parseModels(provider.models);
|
|
9
|
+
const entry = entries.find(m => m.name === backendModel);
|
|
10
|
+
if (!entry)
|
|
11
|
+
return DEFAULT_STREAM_TIMEOUT_MS;
|
|
12
|
+
const timeout = entry.stream_timeout_ms;
|
|
13
|
+
// stream_timeout_ms: 0 表示禁用超时,返回 Infinity;
|
|
14
|
+
// undefined/null/未设置 表示使用默认值
|
|
15
|
+
if (timeout === 0)
|
|
16
|
+
return Number.POSITIVE_INFINITY;
|
|
17
|
+
return timeout ?? DEFAULT_STREAM_TIMEOUT_MS;
|
|
33
18
|
}
|
|
34
19
|
export const PROVIDER_CONCURRENCY_DEFAULTS = {
|
|
35
20
|
max_concurrency: 0,
|
package/dist/db/router-keys.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import { buildUpdateQuery, deleteById } from "./helpers.js";
|
|
3
|
+
import { parseModels } from "../config/model-context.js";
|
|
3
4
|
export function getRouterKeyByHash(db, hash) {
|
|
4
5
|
return db.prepare("SELECT id, name, allowed_models FROM router_keys WHERE key_hash = ? AND is_active = 1").get(hash);
|
|
5
6
|
}
|
|
@@ -27,11 +28,9 @@ export function getAvailableModels(db) {
|
|
|
27
28
|
const rows = db.prepare("SELECT models FROM providers WHERE is_active = 1").all();
|
|
28
29
|
const set = new Set();
|
|
29
30
|
for (const r of rows) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
catch {
|
|
34
|
-
continue;
|
|
31
|
+
const entries = parseModels(r.models);
|
|
32
|
+
for (const m of entries) {
|
|
33
|
+
set.add(m.name);
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
return [...set].sort();
|
package/dist/db/settings.js
CHANGED
|
@@ -14,7 +14,7 @@ export function getLogRetentionDays(db) {
|
|
|
14
14
|
return val ? parseInt(val, 10) : DEFAULT_LOG_RETENTION_DAYS;
|
|
15
15
|
}
|
|
16
16
|
export function setLogRetentionDays(db, days) {
|
|
17
|
-
setSetting(db, "log_retention_days",
|
|
17
|
+
setSetting(db, "log_retention_days", days.toString());
|
|
18
18
|
}
|
|
19
19
|
const DEFAULT_DB_MAX_SIZE_MB = 1024;
|
|
20
20
|
const DEFAULT_LOG_TABLE_MAX_SIZE_MB = 800;
|
|
@@ -23,14 +23,14 @@ export function getDbMaxSizeMb(db) {
|
|
|
23
23
|
return val ? parseInt(val, 10) : DEFAULT_DB_MAX_SIZE_MB;
|
|
24
24
|
}
|
|
25
25
|
export function setDbMaxSizeMb(db, mb) {
|
|
26
|
-
setSetting(db, "db_max_size_mb",
|
|
26
|
+
setSetting(db, "db_max_size_mb", mb.toString());
|
|
27
27
|
}
|
|
28
28
|
export function getLogTableMaxSizeMb(db) {
|
|
29
29
|
const val = getSetting(db, "log_table_max_size_mb");
|
|
30
30
|
return val ? parseInt(val, 10) : DEFAULT_LOG_TABLE_MAX_SIZE_MB;
|
|
31
31
|
}
|
|
32
32
|
export function setLogTableMaxSizeMb(db, mb) {
|
|
33
|
-
setSetting(db, "log_table_max_size_mb",
|
|
33
|
+
setSetting(db, "log_table_max_size_mb", mb.toString());
|
|
34
34
|
}
|
|
35
35
|
export function getConfigSyncSource(db) {
|
|
36
36
|
const val = getSetting(db, "config_sync_source");
|
package/dist/index.js
CHANGED
|
@@ -15,12 +15,20 @@ import { getConfig, getBaseConfig } from "./config/index.js";
|
|
|
15
15
|
import { initDatabase, getAllProviders } from "./db/index.js";
|
|
16
16
|
import { loadRecommendedConfig } from "./config/recommended.js";
|
|
17
17
|
import { authMiddleware } from "./middleware/auth.js";
|
|
18
|
-
import {
|
|
19
|
-
import { anthropicProxy } from "./proxy/handler/anthropic.js";
|
|
20
|
-
import { responsesProxy } from "./proxy/handler/responses.js";
|
|
18
|
+
import { createProxyHandler } from "./proxy/handler/create-proxy-handler.js";
|
|
21
19
|
import { adminRoutes } from "./admin/routes.js";
|
|
22
20
|
import { RetryRuleMatcher } from "./proxy/orchestration/retry-rules.js";
|
|
23
21
|
import { PluginRegistry } from "./proxy/transform/plugin-registry.js";
|
|
22
|
+
import { FormatRegistry } from "./proxy/format/registry.js";
|
|
23
|
+
import { openaiAdapter } from "./proxy/format/adapters/openai.js";
|
|
24
|
+
import { anthropicAdapter } from "./proxy/format/adapters/anthropic.js";
|
|
25
|
+
import { responsesAdapter } from "./proxy/format/adapters/responses.js";
|
|
26
|
+
import { openaiToAnthropicConverter } from "./proxy/format/converters/openai-anthropic.js";
|
|
27
|
+
import { anthropicToOpenAIConverter } from "./proxy/format/converters/anthropic-openai.js";
|
|
28
|
+
import { openaiToResponsesConverter } from "./proxy/format/converters/openai-responses.js";
|
|
29
|
+
import { responsesToOpenAIConverter } from "./proxy/format/converters/responses-openai.js";
|
|
30
|
+
import { responsesToAnthropicConverter } from "./proxy/format/converters/responses-anthropic.js";
|
|
31
|
+
import { anthropicToResponsesConverter } from "./proxy/format/converters/anthropic-responses.js";
|
|
24
32
|
import { SemaphoreManager, AdaptiveController } from "@llm-router/core/concurrency";
|
|
25
33
|
import { RequestTracker } from "@llm-router/core/monitor";
|
|
26
34
|
import { UsageWindowTracker } from "./proxy/routing/usage-window-tracker.js";
|
|
@@ -32,6 +40,7 @@ import fastifyStatic from "@fastify/static";
|
|
|
32
40
|
import { ServiceContainer, SERVICE_KEYS } from "./core/container.js";
|
|
33
41
|
import { LogFileWriter } from "./storage/log-file-writer.js";
|
|
34
42
|
import { ProxyAgentFactory } from "./proxy/transport/proxy-agent.js";
|
|
43
|
+
import { registerBuiltinHooks } from "./proxy/pipeline/register-hooks.js";
|
|
35
44
|
import { scheduleLogFileMaintenance } from "./storage/log-file-compressor.js";
|
|
36
45
|
import { getDetailLogEnabled, getLogFileRetentionDays } from "./db/settings.js";
|
|
37
46
|
import { dirname, join } from "node:path";
|
|
@@ -216,6 +225,18 @@ export async function buildApp(options) {
|
|
|
216
225
|
const pluginsDir = path.resolve(__dirname, "../plugins/transform");
|
|
217
226
|
pluginRegistry.scanPluginsDir(pluginsDir);
|
|
218
227
|
container.register(SERVICE_KEYS.pluginRegistry, () => pluginRegistry);
|
|
228
|
+
// 注册 FormatRegistry(3 adapters + 6 converters 覆盖所有格式转换)
|
|
229
|
+
const formatRegistry = new FormatRegistry();
|
|
230
|
+
formatRegistry.registerAdapter(openaiAdapter);
|
|
231
|
+
formatRegistry.registerAdapter(anthropicAdapter);
|
|
232
|
+
formatRegistry.registerAdapter(responsesAdapter);
|
|
233
|
+
formatRegistry.registerConverter(openaiToAnthropicConverter);
|
|
234
|
+
formatRegistry.registerConverter(anthropicToOpenAIConverter);
|
|
235
|
+
formatRegistry.registerConverter(openaiToResponsesConverter);
|
|
236
|
+
formatRegistry.registerConverter(responsesToOpenAIConverter);
|
|
237
|
+
formatRegistry.registerConverter(responsesToAnthropicConverter);
|
|
238
|
+
formatRegistry.registerConverter(anthropicToResponsesConverter);
|
|
239
|
+
container.register(SERVICE_KEYS.formatRegistry, () => formatRegistry);
|
|
219
240
|
// 注册 ProxyAgentFactory
|
|
220
241
|
container.register(SERVICE_KEYS.proxyAgentFactory, () => new ProxyAgentFactory());
|
|
221
242
|
// 从容器解析所有服务
|
|
@@ -230,9 +251,24 @@ export async function buildApp(options) {
|
|
|
230
251
|
// 从 DB 读取已有 provider 的并发配置,初始化信号量/adaptive/tracker(共享逻辑)
|
|
231
252
|
initializeProviderState(db, semaphoreManager, adaptiveController, tracker);
|
|
232
253
|
app.register(authMiddleware, { db });
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
254
|
+
// 注册内置 hooks 到 hookRegistry(供 Admin API 查询)
|
|
255
|
+
registerBuiltinHooks();
|
|
256
|
+
// --- New pipeline-based proxy handlers (Phase 3) ---
|
|
257
|
+
const openaiHandler = createProxyHandler({
|
|
258
|
+
apiType: "openai",
|
|
259
|
+
paths: ["/v1/chat/completions", "/chat/completions"],
|
|
260
|
+
});
|
|
261
|
+
const anthropicHandler = createProxyHandler({
|
|
262
|
+
apiType: "anthropic",
|
|
263
|
+
paths: ["/v1/messages"],
|
|
264
|
+
});
|
|
265
|
+
const responsesHandler = createProxyHandler({
|
|
266
|
+
apiType: "openai-responses",
|
|
267
|
+
paths: ["/v1/responses", "/responses"],
|
|
268
|
+
});
|
|
269
|
+
app.register(openaiHandler, { db, container });
|
|
270
|
+
app.register(anthropicHandler, { db, container });
|
|
271
|
+
app.register(responsesHandler, { db, container });
|
|
236
272
|
// StateRegistry — Admin 层通过此接口触发 proxy 层状态刷新,消除 admin→proxy 依赖
|
|
237
273
|
const stateRegistry = {
|
|
238
274
|
refreshRetryRules: () => matcher.load(db),
|
|
@@ -262,7 +298,7 @@ export async function buildApp(options) {
|
|
|
262
298
|
});
|
|
263
299
|
// SPA fallback: /admin/ 下非 API 路径返回 index.html
|
|
264
300
|
app.setNotFoundHandler((request, reply) => {
|
|
265
|
-
if (request.url.startsWith("/admin") &&
|
|
301
|
+
if ((request.url.startsWith("/admin/") || request.url === "/admin") &&
|
|
266
302
|
!request.url.startsWith("/admin/api")) {
|
|
267
303
|
return reply.sendFile("index.html");
|
|
268
304
|
}
|
|
@@ -347,7 +383,7 @@ export async function main() {
|
|
|
347
383
|
});
|
|
348
384
|
process.on("unhandledRejection", (reason) => {
|
|
349
385
|
try {
|
|
350
|
-
app.log.error({ err: reason instanceof Error ? reason : new Error(
|
|
386
|
+
app.log.error({ err: reason instanceof Error ? reason : new Error(typeof reason === 'string' ? reason : JSON.stringify(reason)) }, "Unhandled rejection");
|
|
351
387
|
/* eslint-disable taste/no-silent-catch -- app.log 可能已崩溃,console 是最后手段 */
|
|
352
388
|
}
|
|
353
389
|
catch {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const ANTHROPIC_ERROR_META = {
|
|
2
|
+
modelNotFound: { type: "not_found_error", code: "model_not_found" },
|
|
3
|
+
modelNotAllowed: { type: "forbidden_error", code: "model_not_allowed" },
|
|
4
|
+
providerUnavailable: { type: "api_error", code: "provider_unavailable" },
|
|
5
|
+
providerTypeMismatch: { type: "api_error", code: "provider_type_mismatch" },
|
|
6
|
+
upstreamConnectionFailed: { type: "upstream_error", code: "upstream_connection_failed" },
|
|
7
|
+
concurrencyQueueFull: { type: "api_error", code: "concurrency_queue_full" },
|
|
8
|
+
concurrencyTimeout: { type: "api_error", code: "concurrency_timeout" },
|
|
9
|
+
promptTooLong: { type: "invalid_request_error", code: "context_window_exceeded" },
|
|
10
|
+
};
|
|
11
|
+
export const anthropicAdapter = {
|
|
12
|
+
apiType: "anthropic",
|
|
13
|
+
defaultPath: "/v1/messages",
|
|
14
|
+
errorMeta: ANTHROPIC_ERROR_META,
|
|
15
|
+
formatError(message) {
|
|
16
|
+
return { type: "error", error: { type: "api_error", message } };
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OPENAI_FAMILY_ERROR_META } from "./shared-error-meta.js";
|
|
2
|
+
export const openaiAdapter = {
|
|
3
|
+
apiType: "openai",
|
|
4
|
+
defaultPath: "/v1/chat/completions",
|
|
5
|
+
errorMeta: OPENAI_FAMILY_ERROR_META,
|
|
6
|
+
beforeSendProxy(body, isStream) {
|
|
7
|
+
if (isStream && !body.stream_options) {
|
|
8
|
+
body.stream_options = { include_usage: true };
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
formatError(message, code) {
|
|
12
|
+
return { error: { message, type: "upstream_error", code: code ?? "upstream_error" } };
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { OPENAI_FAMILY_ERROR_META } from "./shared-error-meta.js";
|
|
2
|
+
export const responsesAdapter = {
|
|
3
|
+
apiType: "openai-responses",
|
|
4
|
+
defaultPath: "/v1/responses",
|
|
5
|
+
errorMeta: OPENAI_FAMILY_ERROR_META,
|
|
6
|
+
formatError(message, code) {
|
|
7
|
+
return { error: { message, type: "invalid_request_error", code: code ?? "upstream_error" } };
|
|
8
|
+
},
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ErrorKind } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI 和 Responses API 共用的错误元数据。
|
|
4
|
+
* 两者 error code/type 完全相同,仅 apiType/defaultPath/formatError 不同。
|
|
5
|
+
*/
|
|
6
|
+
export declare const OPENAI_FAMILY_ERROR_META: Record<ErrorKind, {
|
|
7
|
+
type: string;
|
|
8
|
+
code: string;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI 和 Responses API 共用的错误元数据。
|
|
3
|
+
* 两者 error code/type 完全相同,仅 apiType/defaultPath/formatError 不同。
|
|
4
|
+
*/
|
|
5
|
+
export const OPENAI_FAMILY_ERROR_META = {
|
|
6
|
+
modelNotFound: { type: "invalid_request_error", code: "model_not_found" },
|
|
7
|
+
modelNotAllowed: { type: "invalid_request_error", code: "model_not_allowed" },
|
|
8
|
+
providerUnavailable: { type: "server_error", code: "provider_unavailable" },
|
|
9
|
+
providerTypeMismatch: { type: "server_error", code: "provider_type_mismatch" },
|
|
10
|
+
upstreamConnectionFailed: { type: "upstream_error", code: "upstream_connection_failed" },
|
|
11
|
+
concurrencyQueueFull: { type: "server_error", code: "concurrency_queue_full" },
|
|
12
|
+
concurrencyTimeout: { type: "server_error", code: "concurrency_timeout" },
|
|
13
|
+
promptTooLong: { type: "invalid_request_error", code: "context_window_exceeded" },
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const anthropicToOpenAIConverter: import("../types.js").FormatConverter;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createConverter } from "../types.js";
|
|
2
|
+
import { anthropicToOpenAIRequest } from "../../transform/request-transform.js";
|
|
3
|
+
import { anthropicResponseToOpenAI } from "../../transform/response-transform.js";
|
|
4
|
+
import { AnthropicToOpenAITransform } from "../../transform/stream-ant2oa.js";
|
|
5
|
+
export const anthropicToOpenAIConverter = createConverter({
|
|
6
|
+
sourceType: "anthropic",
|
|
7
|
+
targetType: "openai",
|
|
8
|
+
requestTransform: anthropicToOpenAIRequest,
|
|
9
|
+
responseTransform: anthropicResponseToOpenAI,
|
|
10
|
+
streamTransformClass: AnthropicToOpenAITransform,
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const anthropicToResponsesConverter: import("../types.js").FormatConverter;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createConverter } from "../types.js";
|
|
2
|
+
import { anthropicToResponsesRequest } from "../../transform/request-transform-responses.js";
|
|
3
|
+
import { anthropicToResponsesResponse } from "../../transform/response-transform-responses.js";
|
|
4
|
+
import { AnthropicToResponsesTransform } from "../../transform/stream-ant2resp.js";
|
|
5
|
+
export const anthropicToResponsesConverter = createConverter({
|
|
6
|
+
sourceType: "anthropic",
|
|
7
|
+
targetType: "openai-responses",
|
|
8
|
+
requestTransform: anthropicToResponsesRequest,
|
|
9
|
+
responseTransform: anthropicToResponsesResponse,
|
|
10
|
+
streamTransformClass: AnthropicToResponsesTransform,
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const openaiToAnthropicConverter: import("../types.js").FormatConverter;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createConverter } from "../types.js";
|
|
2
|
+
import { openaiToAnthropicRequest } from "../../transform/request-transform.js";
|
|
3
|
+
import { openaiResponseToAnthropic } from "../../transform/response-transform.js";
|
|
4
|
+
import { OpenAIToAnthropicTransform } from "../../transform/stream-oa2ant.js";
|
|
5
|
+
export const openaiToAnthropicConverter = createConverter({
|
|
6
|
+
sourceType: "openai",
|
|
7
|
+
targetType: "anthropic",
|
|
8
|
+
requestTransform: openaiToAnthropicRequest,
|
|
9
|
+
responseTransform: openaiResponseToAnthropic,
|
|
10
|
+
streamTransformClass: OpenAIToAnthropicTransform,
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const openaiToResponsesConverter: import("../types.js").FormatConverter;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createConverter } from "../types.js";
|
|
2
|
+
import { chatToResponsesRequest } from "../../transform/request-bridge-responses.js";
|
|
3
|
+
import { chatToResponsesResponse } from "../../transform/response-bridge-responses.js";
|
|
4
|
+
import { ChatToResponsesBridgeTransform } from "../../transform/stream-bridge-chat2resp.js";
|
|
5
|
+
export const openaiToResponsesConverter = createConverter({
|
|
6
|
+
sourceType: "openai",
|
|
7
|
+
targetType: "openai-responses",
|
|
8
|
+
requestTransform: chatToResponsesRequest,
|
|
9
|
+
responseTransform: chatToResponsesResponse,
|
|
10
|
+
streamTransformClass: ChatToResponsesBridgeTransform,
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const responsesToAnthropicConverter: import("../types.js").FormatConverter;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createConverter } from "../types.js";
|
|
2
|
+
import { responsesToAnthropicRequest } from "../../transform/request-transform-responses.js";
|
|
3
|
+
import { responsesToAnthropicResponse } from "../../transform/response-transform-responses.js";
|
|
4
|
+
import { ResponsesToAnthropicTransform } from "../../transform/stream-resp2ant.js";
|
|
5
|
+
export const responsesToAnthropicConverter = createConverter({
|
|
6
|
+
sourceType: "openai-responses",
|
|
7
|
+
targetType: "anthropic",
|
|
8
|
+
requestTransform: responsesToAnthropicRequest,
|
|
9
|
+
responseTransform: responsesToAnthropicResponse,
|
|
10
|
+
streamTransformClass: ResponsesToAnthropicTransform,
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const responsesToOpenAIConverter: import("../types.js").FormatConverter;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createConverter } from "../types.js";
|
|
2
|
+
import { responsesToChatRequest } from "../../transform/request-bridge-responses.js";
|
|
3
|
+
import { responsesToChatResponse } from "../../transform/response-bridge-responses.js";
|
|
4
|
+
import { ResponsesToChatBridgeTransform } from "../../transform/stream-bridge-resp2chat.js";
|
|
5
|
+
export const responsesToOpenAIConverter = createConverter({
|
|
6
|
+
sourceType: "openai-responses",
|
|
7
|
+
targetType: "openai",
|
|
8
|
+
requestTransform: responsesToChatRequest,
|
|
9
|
+
responseTransform: responsesToChatResponse,
|
|
10
|
+
streamTransformClass: ResponsesToChatBridgeTransform,
|
|
11
|
+
});
|