@t0ken.ai/memoryx-openclaw-plugin 2.2.62 → 2.2.64
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/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -15
- package/dist/proxy-credentials.d.ts +11 -1
- package/dist/proxy-credentials.d.ts.map +1 -1
- package/dist/proxy-credentials.js +49 -5
- package/dist/sidecar.d.ts +3 -10
- package/dist/sidecar.d.ts.map +1 -1
- package/dist/sidecar.js +43 -117
- package/dist/vendor-normalize.d.ts +5 -5
- package/dist/vendor-normalize.d.ts.map +1 -1
- package/dist/vendor-normalize.js +7 -12
- package/package.json +1 -1
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import * as os from "os";
|
|
6
6
|
// Plugin version - synced from package.json by prebuild script
|
|
7
|
-
export const PLUGIN_VERSION = "2.2.
|
|
7
|
+
export const PLUGIN_VERSION = "2.2.64";
|
|
8
8
|
export const DEFAULT_API_BASE = "https://t0ken.ai/api";
|
|
9
9
|
export const PLUGIN_DIR = path.join(os.homedir(), ".openclaw", "extensions", "memoryx-openclaw-plugin");
|
|
10
10
|
/** 真实上游 baseUrl 缓存文件:重启后若配置已被改成 localhost,从此文件恢复各厂商真实地址。 */
|
package/dist/hooks.d.ts
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
import type { MemoryXPlugin } from "./plugin-core.js";
|
|
5
5
|
export declare function registerHooks(api: any, plugin: MemoryXPlugin, wrapProvidersWithProxy: () => void, applySidecarRedirect: (opts?: {
|
|
6
6
|
quiet?: boolean;
|
|
7
|
-
}) => void, shouldApplyProxy: () => boolean): void;
|
|
7
|
+
}) => void, shouldApplyProxy: () => boolean, syncRealUpstreamBaseUrlCache?: () => Promise<void>): void;
|
|
8
8
|
//# sourceMappingURL=hooks.d.ts.map
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,wBAAgB,aAAa,CACzB,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,aAAa,EACrB,sBAAsB,EAAE,MAAM,IAAI,EAClC,oBAAoB,EAAE,CAAC,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,KAAK,IAAI,EAC1D,gBAAgB,EAAE,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,wBAAgB,aAAa,CACzB,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,aAAa,EACrB,sBAAsB,EAAE,MAAM,IAAI,EAClC,oBAAoB,EAAE,CAAC,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,KAAK,IAAI,EAC1D,gBAAgB,EAAE,MAAM,OAAO,EAC/B,4BAA4B,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACnD,IAAI,CAuCN"}
|
package/dist/hooks.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function registerHooks(api, plugin, wrapProvidersWithProxy, applySidecarRedirect, shouldApplyProxy) {
|
|
1
|
+
export function registerHooks(api, plugin, wrapProvidersWithProxy, applySidecarRedirect, shouldApplyProxy, syncRealUpstreamBaseUrlCache) {
|
|
2
2
|
let useVirtualProviderInLastRun = false;
|
|
3
3
|
api.on("message_received", async (event) => {
|
|
4
4
|
const { content } = event;
|
|
@@ -18,6 +18,7 @@ export function registerHooks(api, plugin, wrapProvidersWithProxy, applySidecarR
|
|
|
18
18
|
});
|
|
19
19
|
api.on("before_agent_start", async (event) => {
|
|
20
20
|
if (shouldApplyProxy()) {
|
|
21
|
+
await syncRealUpstreamBaseUrlCache?.();
|
|
21
22
|
wrapProvidersWithProxy();
|
|
22
23
|
applySidecarRedirect({ quiet: true });
|
|
23
24
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAU,MAAM,kBAAkB,CAAC;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAU,MAAM,kBAAkB,CAAC;;;;;;kBAsBvC,GAAG,iBAAiB,YAAY,GAAG,IAAI;;AARzD,wBA6FE;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { PLUGIN_VERSION, DEFAULT_API_BASE, SIDECAR_PORT } from "./constants.js";
|
|
17
17
|
import { log, LOG_FILE } from "./logger.js";
|
|
18
18
|
import { MemoryXPlugin, getSDK } from "./plugin-core.js";
|
|
19
|
-
import { extractProviderCredentials, getDefaultModelAndProvider,
|
|
19
|
+
import { extractProviderCredentials, getDefaultModelAndProvider, realUpstreamCredentialsForSidecar, syncRealUpstreamBaseUrlCacheFromConfig, } from "./proxy-credentials.js";
|
|
20
20
|
import { createProxyRedirect } from "./proxy-redirect.js";
|
|
21
21
|
import { SidecarServer } from "./sidecar.js";
|
|
22
22
|
import { registerHooks } from "./hooks.js";
|
|
@@ -43,8 +43,7 @@ export default {
|
|
|
43
43
|
log(`[Proxy] Default: ${defaultConfig.provider}/${defaultConfig.model}`);
|
|
44
44
|
const realProviderHeader = "X-MemoryX-Real-Provider";
|
|
45
45
|
const sidecarBaseUrl = `http://localhost:${SIDECAR_PORT}`;
|
|
46
|
-
const
|
|
47
|
-
const realUpstreamCredentials = realUpstreamCredentialsForSidecar(providerCredentials, realUpstreamBaseUrlMap);
|
|
46
|
+
const realUpstreamCredentials = realUpstreamCredentialsForSidecar(providerCredentials, new Map());
|
|
48
47
|
const proxyUrl = (pluginConfig?.apiBaseUrl || DEFAULT_API_BASE) + "/llm/proxy/chat/completions";
|
|
49
48
|
const sidecar = new SidecarServer(realUpstreamCredentials, { model: defaultConfig.model, provider: defaultConfig.provider }, defaultConfig.availableProviders, {
|
|
50
49
|
proxyUrl,
|
|
@@ -56,7 +55,8 @@ export default {
|
|
|
56
55
|
const { applySidecarRedirect, wrapProvidersWithProxy } = createProxyRedirect(api, getSidecarBase, realProviderHeader);
|
|
57
56
|
/** 仅当用户当前默认使用的是 memoryx-gateway 时才做拦截/注入,否则不碰配置,避免装完插件就用不了 OpenClaw。 */
|
|
58
57
|
const shouldApplyProxy = () => getDefaultModelAndProvider(extractProviderCredentials(api.config), api.config).provider === "memoryx-gateway";
|
|
59
|
-
|
|
58
|
+
const syncRealUpstreamBaseUrlCache = () => syncRealUpstreamBaseUrlCacheFromConfig(api.config, getSidecarBase());
|
|
59
|
+
registerHooks(api, plugin, wrapProvidersWithProxy, applySidecarRedirect, shouldApplyProxy, syncRealUpstreamBaseUrlCache);
|
|
60
60
|
api.registerService({
|
|
61
61
|
id: "memoryx-sidecar",
|
|
62
62
|
start: async () => {
|
|
@@ -92,18 +92,8 @@ export default {
|
|
|
92
92
|
catch (e) {
|
|
93
93
|
// ignore
|
|
94
94
|
}
|
|
95
|
-
// 仅用「非 localhost」的 baseUrl 更新缓存,避免配置被改成 localhost 时覆盖掉真实地址
|
|
96
95
|
try {
|
|
97
|
-
|
|
98
|
-
const merged = new Map(cached);
|
|
99
|
-
for (const [id, url] of realUpstreamBaseUrlMap) {
|
|
100
|
-
if (id === "memoryx-gateway")
|
|
101
|
-
continue;
|
|
102
|
-
if (url && !isLocalhostBaseUrl(url, sidecarBaseUrl)) {
|
|
103
|
-
merged.set(id, url);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
await saveRealUpstreamBaseUrlCache(merged);
|
|
96
|
+
await syncRealUpstreamBaseUrlCacheFromConfig(api.config, sidecarBaseUrl);
|
|
107
97
|
}
|
|
108
98
|
catch (e) {
|
|
109
99
|
// ignore
|
|
@@ -24,14 +24,24 @@ export declare function extractProviderCredentials(config: any, providerOverride
|
|
|
24
24
|
export declare function buildRealUpstreamBaseUrlMap(credentials: Map<string, ProviderCredentials>, _sidecarBaseUrl: string): Map<string, string>;
|
|
25
25
|
/**
|
|
26
26
|
* 用 init 时缓存的「真实上游 baseUrl 映射表」生成供 Sidecar 使用的 credentials。
|
|
27
|
-
* 发给 llm_proxy
|
|
27
|
+
* 发给 llm_proxy 的 base_url_map(各厂商 api_base)均来自此映射表(真实 baseUrl),不会被 redirect 后的 localhost 覆盖。
|
|
28
28
|
* 用户改配置后重启即可生效。
|
|
29
29
|
*/
|
|
30
30
|
export declare function realUpstreamCredentialsForSidecar(credentials: Map<string, ProviderCredentials>, realUpstreamBaseUrlMap: Map<string, string>): Map<string, ProviderCredentials>;
|
|
31
31
|
/**
|
|
32
32
|
* 从缓存文件加载「厂商 -> 真实 baseUrl」映射。文件不存在或解析失败返回空 Map。
|
|
33
|
+
* 供插件 sync 时使用(先读已有缓存,没有则当空)。
|
|
33
34
|
*/
|
|
34
35
|
export declare function loadRealUpstreamBaseUrlCache(): Promise<Map<string, string>>;
|
|
36
|
+
/**
|
|
37
|
+
* 从缓存文件加载「厂商 -> 真实 baseUrl」映射;文件不存在、IO 或解析错误时 throw。
|
|
38
|
+
* 供 Sidecar 每次请求读盘使用,不缓存。
|
|
39
|
+
*/
|
|
40
|
+
export declare function loadRealUpstreamBaseUrlCacheStrict(): Promise<Map<string, string>>;
|
|
41
|
+
/**
|
|
42
|
+
* 根据 OpenClaw 配置更新 real-upstream-baseurl.json:非 localhost 的 baseUrl 写入/覆盖,localhost 绝不覆盖。
|
|
43
|
+
*/
|
|
44
|
+
export declare function syncRealUpstreamBaseUrlCacheFromConfig(config: any, sidecarBaseUrl: string): Promise<void>;
|
|
35
45
|
/**
|
|
36
46
|
* 将「厂商 -> 真实 baseUrl」映射写入缓存文件,重启后若配置被改成 localhost 可从此恢复。
|
|
37
47
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy-credentials.d.ts","sourceRoot":"","sources":["../src/proxy-credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAuCtD,wBAAgB,0BAA0B,CACtC,MAAM,EAAE,GAAG,EACX,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9F,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"proxy-credentials.d.ts","sourceRoot":"","sources":["../src/proxy-credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAuCtD,wBAAgB,0BAA0B,CACtC,MAAM,EAAE,GAAG,EACX,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9F,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAiDlC;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACvC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAC7C,eAAe,EAAE,MAAM,GACxB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAQrB;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC7C,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAC7C,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5C,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAWlC;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAcjF;AAED;;;GAGG;AACH,wBAAsB,kCAAkC,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAUvF;AAED;;GAEG;AACH,wBAAsB,sCAAsC,CACxD,MAAM,EAAE,GAAG,EACX,cAAc,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1F;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAI/E;AAOD,wGAAwG;AACxG,wBAAgB,qBAAqB,CACjC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAC9C,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAc5C;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACvC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAC9C,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAU5C;AAoBD,+HAA+H;AAC/H,wBAAgB,0BAA0B,CACtC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAC7C,MAAM,CAAC,EAAE,GAAG,GACb;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CA8BrG"}
|
|
@@ -35,9 +35,6 @@ function loadAuthProfilesKeys(profilesPath) {
|
|
|
35
35
|
export function extractProviderCredentials(config, providerOverrides) {
|
|
36
36
|
const credentials = new Map();
|
|
37
37
|
const authKeys = loadAuthProfilesKeys(DEFAULT_AUTH_PROFILES_PATH);
|
|
38
|
-
if (authKeys.size > 0) {
|
|
39
|
-
log(`[Proxy] Loaded apiKey from auth-profiles for providers: ${[...authKeys.keys()].join(", ")}`);
|
|
40
|
-
}
|
|
41
38
|
if (config?.models?.providers) {
|
|
42
39
|
for (const [id, providerConfig] of Object.entries(config.models.providers)) {
|
|
43
40
|
if (typeof providerConfig !== "object" ||
|
|
@@ -62,10 +59,17 @@ export function extractProviderCredentials(config, providerOverrides) {
|
|
|
62
59
|
apiKey,
|
|
63
60
|
models: pc.models,
|
|
64
61
|
});
|
|
65
|
-
log(`[Proxy] Extracted credentials for ${id}: models=${pc.models?.length || 0}`);
|
|
66
62
|
}
|
|
67
63
|
}
|
|
68
64
|
}
|
|
65
|
+
if (credentials.size > 0) {
|
|
66
|
+
const parts = [...credentials.entries()].map(([id, c]) => `${id}(${c.models?.length ?? 0})`);
|
|
67
|
+
const authFromProfiles = [...credentials.keys()].filter((id) => authKeys.has(id));
|
|
68
|
+
const summary = authFromProfiles.length > 0
|
|
69
|
+
? `[Proxy] Credentials: ${parts.join(", ")}; apiKey from auth-profiles: ${authFromProfiles.join(", ")}`
|
|
70
|
+
: `[Proxy] Credentials: ${parts.join(", ")}`;
|
|
71
|
+
log(summary);
|
|
72
|
+
}
|
|
69
73
|
return credentials;
|
|
70
74
|
}
|
|
71
75
|
/**
|
|
@@ -86,7 +90,7 @@ export function buildRealUpstreamBaseUrlMap(credentials, _sidecarBaseUrl) {
|
|
|
86
90
|
}
|
|
87
91
|
/**
|
|
88
92
|
* 用 init 时缓存的「真实上游 baseUrl 映射表」生成供 Sidecar 使用的 credentials。
|
|
89
|
-
* 发给 llm_proxy
|
|
93
|
+
* 发给 llm_proxy 的 base_url_map(各厂商 api_base)均来自此映射表(真实 baseUrl),不会被 redirect 后的 localhost 覆盖。
|
|
90
94
|
* 用户改配置后重启即可生效。
|
|
91
95
|
*/
|
|
92
96
|
export function realUpstreamCredentialsForSidecar(credentials, realUpstreamBaseUrlMap) {
|
|
@@ -103,6 +107,7 @@ export function realUpstreamCredentialsForSidecar(credentials, realUpstreamBaseU
|
|
|
103
107
|
}
|
|
104
108
|
/**
|
|
105
109
|
* 从缓存文件加载「厂商 -> 真实 baseUrl」映射。文件不存在或解析失败返回空 Map。
|
|
110
|
+
* 供插件 sync 时使用(先读已有缓存,没有则当空)。
|
|
106
111
|
*/
|
|
107
112
|
export async function loadRealUpstreamBaseUrlCache() {
|
|
108
113
|
try {
|
|
@@ -121,6 +126,45 @@ export async function loadRealUpstreamBaseUrlCache() {
|
|
|
121
126
|
return new Map();
|
|
122
127
|
}
|
|
123
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* 从缓存文件加载「厂商 -> 真实 baseUrl」映射;文件不存在、IO 或解析错误时 throw。
|
|
131
|
+
* 供 Sidecar 每次请求读盘使用,不缓存。
|
|
132
|
+
*/
|
|
133
|
+
export async function loadRealUpstreamBaseUrlCacheStrict() {
|
|
134
|
+
const raw = await fs.promises.readFile(REAL_UPSTREAM_BASEURL_CACHE_FILE, "utf8");
|
|
135
|
+
const obj = JSON.parse(raw);
|
|
136
|
+
const map = new Map();
|
|
137
|
+
if (obj && typeof obj === "object") {
|
|
138
|
+
for (const [id, url] of Object.entries(obj)) {
|
|
139
|
+
if (id && typeof url === "string" && url.trim())
|
|
140
|
+
map.set(id, url.trim());
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return map;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 根据 OpenClaw 配置更新 real-upstream-baseurl.json:非 localhost 的 baseUrl 写入/覆盖,localhost 绝不覆盖。
|
|
147
|
+
*/
|
|
148
|
+
export async function syncRealUpstreamBaseUrlCacheFromConfig(config, sidecarBaseUrl) {
|
|
149
|
+
let cached;
|
|
150
|
+
try {
|
|
151
|
+
cached = await loadRealUpstreamBaseUrlCache();
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
cached = new Map();
|
|
155
|
+
}
|
|
156
|
+
const credentials = extractProviderCredentials(config);
|
|
157
|
+
const fromConfig = buildRealUpstreamBaseUrlMap(credentials, sidecarBaseUrl);
|
|
158
|
+
const merged = new Map(cached);
|
|
159
|
+
for (const [id, url] of fromConfig) {
|
|
160
|
+
if (id === "memoryx-gateway")
|
|
161
|
+
continue;
|
|
162
|
+
if (url && !isLocalhostBaseUrl(url, sidecarBaseUrl)) {
|
|
163
|
+
merged.set(id, url);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
await saveRealUpstreamBaseUrlCache(merged);
|
|
167
|
+
}
|
|
124
168
|
/**
|
|
125
169
|
* 将「厂商 -> 真实 baseUrl」映射写入缓存文件,重启后若配置被改成 localhost 可从此恢复。
|
|
126
170
|
*/
|
package/dist/sidecar.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local HTTP Sidecar:
|
|
2
|
+
* Local HTTP Sidecar: 轻量化转发。只读 base_url_map + credentials,打包发给服务端;
|
|
3
|
+
* 服务端解析 provider、用 api_base 调 LiteLLM(不拼 URL),做记忆注入。无本地解析、无 target。
|
|
3
4
|
*/
|
|
4
5
|
import type { ProviderCredentials } from "./types.js";
|
|
5
6
|
import type { PluginConfig } from "./types.js";
|
|
@@ -26,15 +27,7 @@ export declare class SidecarServer {
|
|
|
26
27
|
start(): Promise<void>;
|
|
27
28
|
stop(): Promise<void>;
|
|
28
29
|
getPort(): number;
|
|
29
|
-
/**
|
|
30
|
-
* 用持久化/合并后的真实上游 baseUrl 映射更新 credentials,避免重启后配置已是 localhost 时仍用旧缓存。
|
|
31
|
-
*/
|
|
32
|
-
updateRealUpstreamBaseUrlMap(map: Map<string, string>): void;
|
|
33
|
-
/** For logging: redact headers (Authorization, x-api-key, etc. show as ***) */
|
|
34
|
-
private redactHeaders;
|
|
35
|
-
/** Build forward request headers from apiKey in OpenClaw style; does not overwrite user config */
|
|
36
|
-
private buildForwardHeaders;
|
|
37
|
-
/** 仅转发到服务端 proxy(记忆注入),无本地回落。 */
|
|
30
|
+
/** 轻量化:只读 base_url_map + credentials,打包发给服务端;不做 provider 解析、无 target。 */
|
|
38
31
|
private handleRequest;
|
|
39
32
|
private readBody;
|
|
40
33
|
}
|
package/dist/sidecar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,MAAM,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,eAAe,CAAsC;IAC7D,OAAO,CAAC,kBAAkB,CAA6C;IACvE,OAAO,CAAC,OAAO,CAAiB;gBAG5B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAC7C,eAAe,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EACpD,kBAAkB,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,EAC9D,OAAO,EAAE,cAAc;IAQrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,OAAO,IAAI,MAAM;IAMjB,yEAAyE;YAC3D,aAAa;IAqK3B,OAAO,CAAC,QAAQ;CAQnB"}
|
package/dist/sidecar.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local HTTP Sidecar:
|
|
2
|
+
* Local HTTP Sidecar: 轻量化转发。只读 base_url_map + credentials,打包发给服务端;
|
|
3
|
+
* 服务端解析 provider、用 api_base 调 LiteLLM(不拼 URL),做记忆注入。无本地解析、无 target。
|
|
3
4
|
*/
|
|
4
5
|
import * as http from "http";
|
|
5
6
|
import { SIDECAR_PORT } from "./constants.js";
|
|
6
7
|
import { log, LOG_FILE } from "./logger.js";
|
|
8
|
+
import { loadRealUpstreamBaseUrlCache } from "./proxy-credentials.js";
|
|
7
9
|
export class SidecarServer {
|
|
8
10
|
server = null;
|
|
9
11
|
credentials;
|
|
@@ -58,44 +60,7 @@ export class SidecarServer {
|
|
|
58
60
|
? this.server.address().port
|
|
59
61
|
: SIDECAR_PORT;
|
|
60
62
|
}
|
|
61
|
-
/**
|
|
62
|
-
* 用持久化/合并后的真实上游 baseUrl 映射更新 credentials,避免重启后配置已是 localhost 时仍用旧缓存。
|
|
63
|
-
*/
|
|
64
|
-
updateRealUpstreamBaseUrlMap(map) {
|
|
65
|
-
for (const [id, baseUrl] of map) {
|
|
66
|
-
const creds = this.credentials.get(id);
|
|
67
|
-
if (creds && baseUrl) {
|
|
68
|
-
this.credentials.set(id, { ...creds, baseUrl });
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
log(`[Sidecar] Updated real upstream baseUrl map for ${map.size} provider(s)`);
|
|
72
|
-
}
|
|
73
|
-
/** For logging: redact headers (Authorization, x-api-key, etc. show as ***) */
|
|
74
|
-
redactHeaders(h) {
|
|
75
|
-
const out = {};
|
|
76
|
-
const secretKeys = ["authorization", "x-api-key", "cookie"];
|
|
77
|
-
for (const [k, v] of Object.entries(h)) {
|
|
78
|
-
const lower = k.toLowerCase();
|
|
79
|
-
out[k] = secretKeys.some((s) => lower === s || lower.includes("api-key")) ? "***" : v;
|
|
80
|
-
}
|
|
81
|
-
return out;
|
|
82
|
-
}
|
|
83
|
-
/** Build forward request headers from apiKey in OpenClaw style; does not overwrite user config */
|
|
84
|
-
buildForwardHeaders(provider, apiKey) {
|
|
85
|
-
const h = { "Content-Type": "application/json" };
|
|
86
|
-
const key = (apiKey || "").trim();
|
|
87
|
-
if (!key)
|
|
88
|
-
return h;
|
|
89
|
-
if (provider === "anthropic") {
|
|
90
|
-
h["x-api-key"] = key;
|
|
91
|
-
h["anthropic-version"] = "2023-06-01";
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
h["Authorization"] = `Bearer ${key}`;
|
|
95
|
-
}
|
|
96
|
-
return h;
|
|
97
|
-
}
|
|
98
|
-
/** 仅转发到服务端 proxy(记忆注入),无本地回落。 */
|
|
63
|
+
/** 轻量化:只读 base_url_map + credentials,打包发给服务端;不做 provider 解析、无 target。 */
|
|
99
64
|
async handleRequest(req, res) {
|
|
100
65
|
const url = req.url || "/";
|
|
101
66
|
const method = req.method?.toUpperCase();
|
|
@@ -106,12 +71,12 @@ export class SidecarServer {
|
|
|
106
71
|
return;
|
|
107
72
|
}
|
|
108
73
|
const reqId = `req-${Date.now()}`;
|
|
109
|
-
log(`[Sidecar] ${reqId} Incoming ${method} ${url}`);
|
|
110
74
|
let body;
|
|
111
75
|
try {
|
|
112
76
|
body = await this.readBody(req);
|
|
113
77
|
}
|
|
114
78
|
catch (e) {
|
|
79
|
+
log(`[Sidecar] ${reqId} err read body: ${e?.message ?? "Read body failed"}`, { console: true });
|
|
115
80
|
res.writeHead(502, { "Content-Type": "application/json" });
|
|
116
81
|
res.end(JSON.stringify({ error: e?.message || "Read body failed" }));
|
|
117
82
|
return;
|
|
@@ -123,61 +88,32 @@ export class SidecarServer {
|
|
|
123
88
|
catch {
|
|
124
89
|
openaiRequest = {};
|
|
125
90
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const lastContentLen = lastMsg && lastMsg.content != null
|
|
131
|
-
? typeof lastMsg.content === "string"
|
|
132
|
-
? lastMsg.content.length
|
|
133
|
-
: JSON.stringify(lastMsg.content).length
|
|
134
|
-
: 0;
|
|
135
|
-
const topKeys = Object.keys(openaiRequest).filter((k) => !["messages", "model"].includes(k) && openaiRequest[k] != null);
|
|
136
|
-
log(`[Sidecar] ${reqId} request detail: bodyLen=${(body || "").length} messages=${messages.length} roles=${roleSeq} lastRole=${lastRole} lastContentLen=${lastContentLen} model=${openaiRequest.model ?? "-"} stream=${!!openaiRequest.stream} extraKeys=[${topKeys.join(",")}]`);
|
|
137
|
-
const rawProvider = req.headers["x-memoryx-real-provider"]?.trim() || "";
|
|
138
|
-
const modelStr = openaiRequest.model || "";
|
|
139
|
-
let provider = rawProvider || (modelStr.includes("/") ? modelStr.split("/")[0] : "") || "";
|
|
140
|
-
if (provider === "memoryx-gateway") {
|
|
141
|
-
const real = this.availableProviders.find((p) => p.provider !== "memoryx-gateway");
|
|
142
|
-
provider = real ? real.provider : "";
|
|
143
|
-
}
|
|
144
|
-
if (!provider || !this.credentials.has(provider)) {
|
|
145
|
-
provider = this.defaultProvider?.provider || "";
|
|
146
|
-
}
|
|
147
|
-
if (!provider || !this.credentials.has(provider)) {
|
|
148
|
-
for (const [id] of this.credentials) {
|
|
149
|
-
if (id !== "memoryx-gateway") {
|
|
150
|
-
provider = id;
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
let creds = provider ? this.credentials.get(provider) : undefined;
|
|
156
|
-
if (!creds?.baseUrl?.trim() || !(creds.apiKey ?? "").trim()) {
|
|
157
|
-
for (const [id, c] of this.credentials) {
|
|
158
|
-
if (id !== "memoryx-gateway" && (c.baseUrl || "").trim() && (c.apiKey ?? "").trim()) {
|
|
159
|
-
provider = id;
|
|
160
|
-
creds = c;
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
const baseUrl = (creds?.baseUrl || "").trim();
|
|
166
|
-
const apiKey = (creds?.apiKey ?? "").trim();
|
|
167
|
-
if (!baseUrl || !apiKey) {
|
|
168
|
-
res.writeHead(502, { "Content-Type": "application/json" });
|
|
169
|
-
res.end(JSON.stringify({ error: "No upstream" }));
|
|
170
|
-
return;
|
|
91
|
+
const stream = !!openaiRequest.stream;
|
|
92
|
+
let baseUrlMap;
|
|
93
|
+
try {
|
|
94
|
+
baseUrlMap = await loadRealUpstreamBaseUrlCache();
|
|
171
95
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
96
|
+
catch {
|
|
97
|
+
baseUrlMap = new Map();
|
|
98
|
+
}
|
|
99
|
+
const baseUrlMapObj = {};
|
|
100
|
+
for (const [id, u] of baseUrlMap) {
|
|
101
|
+
if (id && u?.trim())
|
|
102
|
+
baseUrlMapObj[id] = u.trim();
|
|
103
|
+
}
|
|
104
|
+
const credentialsObj = {};
|
|
105
|
+
for (const [id, c] of this.credentials) {
|
|
106
|
+
if (!c)
|
|
107
|
+
continue;
|
|
108
|
+
credentialsObj[id] = {
|
|
109
|
+
apiKey: (c.apiKey ?? "").trim(),
|
|
110
|
+
models: c.models,
|
|
111
|
+
};
|
|
180
112
|
}
|
|
113
|
+
const rawProvider = req.headers["x-memoryx-real-provider"]?.trim() || "";
|
|
114
|
+
const messages = openaiRequest.messages || [];
|
|
115
|
+
const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
|
|
116
|
+
const searchQuery = typeof lastUserMsg?.content === "string" ? lastUserMsg.content : "";
|
|
181
117
|
let memoryxApiKey = "";
|
|
182
118
|
let agentId = "";
|
|
183
119
|
try {
|
|
@@ -187,25 +123,19 @@ export class SidecarServer {
|
|
|
187
123
|
agentId = accountInfo.agentId || "";
|
|
188
124
|
}
|
|
189
125
|
catch (_e) {
|
|
190
|
-
/*
|
|
126
|
+
/* do not block */
|
|
191
127
|
}
|
|
192
|
-
const headers = this.buildForwardHeaders(provider, apiKey);
|
|
193
|
-
const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
|
|
194
|
-
const searchQuery = typeof lastUserMsg?.content === "string" ? lastUserMsg.content : "";
|
|
195
128
|
const proxyRequestBody = {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
headers,
|
|
129
|
+
base_url_map: baseUrlMapObj,
|
|
130
|
+
credentials: credentialsObj,
|
|
199
131
|
body: openaiRequest,
|
|
200
|
-
|
|
132
|
+
request_headers: { "x-memoryx-real-provider": rawProvider },
|
|
133
|
+
search_query: searchQuery,
|
|
201
134
|
agent_id: agentId,
|
|
202
135
|
available_models: this.availableProviders.map((p) => `${p.provider}/${p.model}`),
|
|
203
136
|
};
|
|
204
|
-
const
|
|
205
|
-
log(`[Sidecar] ${reqId}
|
|
206
|
-
log(`[Sidecar] ${reqId} Proxy request headers: ${JSON.stringify(proxyReqHeaders)}`);
|
|
207
|
-
log(`[Sidecar] ${reqId} Proxy body: targetUrl=${targetUrl} model=${openaiRequest.model} stream=${!!openaiRequest.stream} searchQuery.length=${searchQuery.length} agent_id=${agentId || "(empty)"}`);
|
|
208
|
-
log(`[Sidecar] ${reqId} Forward headers (to upstream): ${JSON.stringify(this.redactHeaders(headers))}`);
|
|
137
|
+
const pathLog = (req.url || "/").split("?")[0] || "/";
|
|
138
|
+
log(`[Sidecar] ${reqId} ${method} ${pathLog} model=${openaiRequest.model ?? "-"} stream=${stream} → proxy`);
|
|
209
139
|
let proxyResponse = null;
|
|
210
140
|
try {
|
|
211
141
|
proxyResponse = await fetch(proxyUrl, {
|
|
@@ -216,10 +146,7 @@ export class SidecarServer {
|
|
|
216
146
|
}
|
|
217
147
|
catch (e) {
|
|
218
148
|
proxyResponse = null;
|
|
219
|
-
log(`[Sidecar] ${reqId}
|
|
220
|
-
}
|
|
221
|
-
if (proxyResponse) {
|
|
222
|
-
log(`[Sidecar] ${reqId} Proxy response status=${proxyResponse.status} ${proxyResponse.statusText}`);
|
|
149
|
+
log(`[Sidecar] ${reqId} err proxy fetch: ${e?.message ?? String(e)}`, { console: true });
|
|
223
150
|
}
|
|
224
151
|
const proxyFailed = !proxyResponse || proxyResponse.status >= 500;
|
|
225
152
|
if (proxyFailed) {
|
|
@@ -233,12 +160,12 @@ export class SidecarServer {
|
|
|
233
160
|
}
|
|
234
161
|
}
|
|
235
162
|
catch (_) {
|
|
236
|
-
/* drain
|
|
163
|
+
/* drain */
|
|
237
164
|
}
|
|
238
165
|
}
|
|
239
|
-
log(`[Sidecar] ${reqId} Proxy failed, returning error (no local fallback)`, { console: true });
|
|
240
166
|
const status = proxyResponse?.status ?? 502;
|
|
241
167
|
const detail = proxyResponse?.statusText || "MemoryX proxy unavailable";
|
|
168
|
+
log(`[Sidecar] ${reqId} ← ${status} proxy failed: ${detail}`, { console: true });
|
|
242
169
|
res.writeHead(status, { "Content-Type": "application/json" });
|
|
243
170
|
res.end(JSON.stringify({ error: detail }));
|
|
244
171
|
return;
|
|
@@ -255,9 +182,7 @@ export class SidecarServer {
|
|
|
255
182
|
}
|
|
256
183
|
catch (firstErr) {
|
|
257
184
|
reader.releaseLock();
|
|
258
|
-
log(`[Sidecar] ${reqId}
|
|
259
|
-
console: true,
|
|
260
|
-
});
|
|
185
|
+
log(`[Sidecar] ${reqId} err stream first chunk: ${firstErr?.message ?? "timeout"}`, { console: true });
|
|
261
186
|
res.writeHead(502, { "Content-Type": "application/json" });
|
|
262
187
|
res.end(JSON.stringify({ error: "MemoryX proxy stream failed" }));
|
|
263
188
|
return;
|
|
@@ -279,7 +204,7 @@ export class SidecarServer {
|
|
|
279
204
|
reader.releaseLock();
|
|
280
205
|
}
|
|
281
206
|
res.end();
|
|
282
|
-
log(`[Sidecar] ${reqId}
|
|
207
|
+
log(`[Sidecar] ${reqId} ← ${proxy.status} stream`);
|
|
283
208
|
return;
|
|
284
209
|
}
|
|
285
210
|
if (!proxy.body) {
|
|
@@ -287,10 +212,11 @@ export class SidecarServer {
|
|
|
287
212
|
"Content-Type": proxy.headers.get("content-type") || "application/json",
|
|
288
213
|
});
|
|
289
214
|
res.end();
|
|
215
|
+
log(`[Sidecar] ${reqId} ← ${proxy.status} (no body)`);
|
|
290
216
|
return;
|
|
291
217
|
}
|
|
292
218
|
const text = await proxy.text();
|
|
293
|
-
log(`[Sidecar] ${reqId}
|
|
219
|
+
log(`[Sidecar] ${reqId} ← ${proxy.status} body=${text.length}`);
|
|
294
220
|
res.writeHead(proxy.status, {
|
|
295
221
|
"Content-Type": proxy.headers.get("content-type") || "application/json",
|
|
296
222
|
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 与服务端 llm_proxy 一致的厂商请求体规范化。
|
|
3
|
-
*
|
|
3
|
+
* 当前插件内无调用方,规范化由服务端 llm_proxy 完成;保留本模块供将来如需在插件侧做兼容时复用。
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* 判断是否为 Z.AI GLM-5:按 provider
|
|
6
|
+
* 判断是否为 Z.AI GLM-5:按 provider 与 model 判断(不再依赖 targetUrl)。
|
|
7
7
|
*/
|
|
8
|
-
export declare function isZaiGlm5(provider: string,
|
|
8
|
+
export declare function isZaiGlm5(provider: string, model: string): boolean;
|
|
9
9
|
/**
|
|
10
|
-
* 按厂商与
|
|
10
|
+
* 按厂商与 model 规范化请求体;与服务端逻辑一致。当前插件内无调用,规范化在服务端完成。
|
|
11
11
|
* 返回规范化后的 body(不修改入参)。
|
|
12
12
|
*/
|
|
13
|
-
export declare function normalizeBodyForVendor(provider: string,
|
|
13
|
+
export declare function normalizeBodyForVendor(provider: string, body: Record<string, unknown>): Record<string, unknown>;
|
|
14
14
|
//# sourceMappingURL=vendor-normalize.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vendor-normalize.d.ts","sourceRoot":"","sources":["../src/vendor-normalize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"vendor-normalize.d.ts","sourceRoot":"","sources":["../src/vendor-normalize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAIlE;AA4DD;;;GAGG;AACH,wBAAgB,sBAAsB,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB"}
|
package/dist/vendor-normalize.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 与服务端 llm_proxy 一致的厂商请求体规范化。
|
|
3
|
-
*
|
|
3
|
+
* 当前插件内无调用方,规范化由服务端 llm_proxy 完成;保留本模块供将来如需在插件侧做兼容时复用。
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* 判断是否为 Z.AI GLM-5:按 provider
|
|
6
|
+
* 判断是否为 Z.AI GLM-5:按 provider 与 model 判断(不再依赖 targetUrl)。
|
|
7
7
|
*/
|
|
8
|
-
export function isZaiGlm5(provider,
|
|
8
|
+
export function isZaiGlm5(provider, model) {
|
|
9
9
|
const prov = (provider || "").toLowerCase();
|
|
10
|
-
const url = (targetUrl || "").toLowerCase();
|
|
11
10
|
const m = (model || "").toLowerCase();
|
|
12
|
-
|
|
13
|
-
return true;
|
|
14
|
-
if ((url.includes("open.bigmodel.cn") || url.includes("api.z.ai")) && (m === "glm-5" || m.endsWith("/glm-5")))
|
|
15
|
-
return true;
|
|
16
|
-
return false;
|
|
11
|
+
return prov === "zai" && (m === "glm-5" || m.endsWith("/glm-5"));
|
|
17
12
|
}
|
|
18
13
|
/**
|
|
19
14
|
* Z.AI GLM-5 兼容:与 api/app/routers/llm_proxy.py _normalize_body_for_zai_glm5 保持一致。
|
|
@@ -70,12 +65,12 @@ function normalizeBodyForZaiGlm5(body) {
|
|
|
70
65
|
return out;
|
|
71
66
|
}
|
|
72
67
|
/**
|
|
73
|
-
* 按厂商与
|
|
68
|
+
* 按厂商与 model 规范化请求体;与服务端逻辑一致。当前插件内无调用,规范化在服务端完成。
|
|
74
69
|
* 返回规范化后的 body(不修改入参)。
|
|
75
70
|
*/
|
|
76
|
-
export function normalizeBodyForVendor(provider,
|
|
71
|
+
export function normalizeBodyForVendor(provider, body) {
|
|
77
72
|
const model = String(body?.model || "").trim();
|
|
78
|
-
if (isZaiGlm5(provider,
|
|
73
|
+
if (isZaiGlm5(provider, model)) {
|
|
79
74
|
return normalizeBodyForZaiGlm5(body);
|
|
80
75
|
}
|
|
81
76
|
return body;
|
package/package.json
CHANGED