@honor-claw/yoyo 1.1.2 → 1.1.4-beta.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/index.ts +25 -25
- package/package.json +5 -5
- package/src/apis/claw-cloud.ts +124 -124
- package/src/apis/helpers.ts +10 -10
- package/src/apis/honor-auth.ts +158 -158
- package/src/apis/http-client.ts +239 -239
- package/src/apis/index.ts +8 -8
- package/src/apis/types.ts +77 -73
- package/src/cloud-channel/channel.ts +117 -117
- package/src/cloud-channel/client.ts +3 -3
- package/src/cloud-channel/index.ts +4 -4
- package/src/cloud-channel/message-handler.ts +50 -42
- package/src/cloud-channel/session-manager.ts +14 -9
- package/src/cloud-channel/types.ts +115 -115
- package/src/commands/env/impl.ts +58 -58
- package/src/commands/env/index.ts +1 -1
- package/src/commands/index.ts +30 -30
- package/src/commands/login/impl.ts +30 -30
- package/src/commands/login/index.ts +1 -1
- package/src/commands/logout/index.ts +1 -1
- package/src/commands/status/index.ts +194 -194
- package/src/gateway-client/client.ts +90 -90
- package/src/gateway-client/device/auth.ts +57 -57
- package/src/gateway-client/device/builder.ts +105 -105
- package/src/gateway-client/device/helpers.ts +40 -40
- package/src/gateway-client/device/identity.ts +251 -251
- package/src/gateway-client/device/index.ts +40 -40
- package/src/gateway-client/device/types.ts +57 -57
- package/src/gateway-client/index.ts +5 -5
- package/src/gateway-client/protocol-client.ts +49 -34
- package/src/honor-auth/browser.ts +2 -2
- package/src/honor-auth/callback-server.ts +109 -109
- package/src/honor-auth/cloud.ts +57 -57
- package/src/honor-auth/config.ts +43 -43
- package/src/honor-auth/index.ts +3 -3
- package/src/honor-auth/token-manager.ts +90 -90
- package/src/honor-auth/types.ts +50 -50
- package/src/index.ts +10 -10
- package/src/modules/claw-configs/config-manager.ts +409 -409
- package/src/modules/claw-configs/hosts.ts +48 -48
- package/src/modules/claw-configs/index.ts +8 -8
- package/src/modules/claw-configs/provider.ts +394 -394
- package/src/modules/claw-configs/types.ts +34 -34
- package/src/modules/device/device-info.ts +1 -1
- package/src/modules/device/index.ts +3 -3
- package/src/modules/device/providers/base.ts +32 -32
- package/src/modules/device/providers/pad.ts +107 -107
- package/src/modules/device/providers/windows.ts +130 -130
- package/src/modules/device/registry.ts +48 -43
- package/src/modules/login/impl.ts +31 -26
- package/src/modules/login/index.ts +6 -6
- package/src/schemas.ts +23 -23
- package/src/services/connection/impl.ts +339 -339
- package/src/services/connection/status-tracker/events.ts +127 -127
- package/src/services/connection/status-tracker/index.ts +31 -31
- package/src/services/connection/status-tracker/storage.ts +133 -133
- package/src/services/connection/status-tracker/tracker.ts +370 -370
- package/src/services/connection/status-tracker/types.ts +131 -131
- package/src/services/connection/types.ts +20 -20
- package/src/types.ts +64 -64
- package/src/utils/id.ts +8 -8
- package/src/utils/jwt.ts +37 -37
- package/src/utils/logger.ts +20 -20
- package/src/utils/proxy.ts +58 -58
- package/src/utils/version.ts +29 -29
- package/src/utils/ws.ts +21 -21
|
@@ -1,394 +1,394 @@
|
|
|
1
|
-
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 检测需要改名的provider
|
|
7
|
-
*/
|
|
8
|
-
export function detectProvidersToRename(config: OpenClawConfig): Record<string, string> {
|
|
9
|
-
const renameMap: Record<string, string> = {};
|
|
10
|
-
|
|
11
|
-
if (!config.models?.providers) {
|
|
12
|
-
return renameMap;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const providers = Object.keys(config.models.providers);
|
|
16
|
-
|
|
17
|
-
for (const provider of providers) {
|
|
18
|
-
const lowerProvider = provider.trim().toLowerCase();
|
|
19
|
-
if (lowerProvider.includes("minimax")) {
|
|
20
|
-
// 使用下划线分隔:minimax -> mini_max, minimax-pro -> mini_max-pro
|
|
21
|
-
const newName = lowerProvider.replace("minimax", "mini_max");
|
|
22
|
-
renameMap[provider] = newName;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return renameMap;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* 更新所有provider引用
|
|
31
|
-
*/
|
|
32
|
-
export function updateProviderReferences(
|
|
33
|
-
config: OpenClawConfig,
|
|
34
|
-
renameMap: Record<string, string>
|
|
35
|
-
): OpenClawConfig {
|
|
36
|
-
const updatedConfig = { ...config };
|
|
37
|
-
|
|
38
|
-
// 1. 更新 models.providers 本身
|
|
39
|
-
if (updatedConfig.models?.providers) {
|
|
40
|
-
const newProviders: Record<string, any> = {};
|
|
41
|
-
for (const [provider, providerConfig] of Object.entries(updatedConfig.models.providers)) {
|
|
42
|
-
const newName = renameMap[provider];
|
|
43
|
-
if (newName) {
|
|
44
|
-
newProviders[newName] = providerConfig;
|
|
45
|
-
} else {
|
|
46
|
-
newProviders[provider] = providerConfig;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
updatedConfig.models = {
|
|
50
|
-
...updatedConfig.models,
|
|
51
|
-
providers: newProviders,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// 2. 更新 agents 配置
|
|
56
|
-
if (updatedConfig.agents) {
|
|
57
|
-
updatedConfig.agents = updateAgentsProviderReferences(
|
|
58
|
-
updatedConfig.agents,
|
|
59
|
-
renameMap
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 3. 更新 auth.profiles 配置
|
|
64
|
-
if (updatedConfig.auth?.profiles) {
|
|
65
|
-
updatedConfig.auth = {
|
|
66
|
-
...updatedConfig.auth,
|
|
67
|
-
profiles: updateAuthProfilesProviderReferences(
|
|
68
|
-
updatedConfig.auth.profiles,
|
|
69
|
-
renameMap
|
|
70
|
-
),
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// 更新 auth.profiles 文件
|
|
74
|
-
updateAuthProfilesFiles(renameMap);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return updatedConfig;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* 更新 agents 配置中的 provider 引用
|
|
82
|
-
*/
|
|
83
|
-
function updateAgentsProviderReferences(
|
|
84
|
-
agents: any,
|
|
85
|
-
renameMap: Record<string, string>
|
|
86
|
-
): any {
|
|
87
|
-
const updatedAgents = { ...agents };
|
|
88
|
-
|
|
89
|
-
// 更新 defaults 配置
|
|
90
|
-
if (updatedAgents.defaults) {
|
|
91
|
-
updatedAgents.defaults = updateAgentDefaultsProviderReferences(
|
|
92
|
-
updatedAgents.defaults,
|
|
93
|
-
renameMap
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// 更新 list 配置
|
|
98
|
-
if (updatedAgents.list) {
|
|
99
|
-
updatedAgents.list = updatedAgents.list.map((agent: any) =>
|
|
100
|
-
updateAgentConfigProviderReferences(agent, renameMap)
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return updatedAgents;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* 更新 agent defaults 配置中的 provider 引用
|
|
109
|
-
*/
|
|
110
|
-
function updateAgentDefaultsProviderReferences(
|
|
111
|
-
defaults: any,
|
|
112
|
-
renameMap: Record<string, string>
|
|
113
|
-
): any {
|
|
114
|
-
const updatedDefaults = { ...defaults };
|
|
115
|
-
|
|
116
|
-
// 更新 model 配置
|
|
117
|
-
if (updatedDefaults.model) {
|
|
118
|
-
updatedDefaults.model = updateAgentModelConfig(
|
|
119
|
-
updatedDefaults.model,
|
|
120
|
-
renameMap
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// 更新 imageModel 配置
|
|
125
|
-
if (updatedDefaults.imageModel) {
|
|
126
|
-
updatedDefaults.imageModel = updateAgentModelConfig(
|
|
127
|
-
updatedDefaults.imageModel,
|
|
128
|
-
renameMap
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// 更新 pdfModel 配置
|
|
133
|
-
if (updatedDefaults.pdfModel) {
|
|
134
|
-
updatedDefaults.pdfModel = updateAgentModelConfig(
|
|
135
|
-
updatedDefaults.pdfModel,
|
|
136
|
-
renameMap
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// 更新 models 目录(key可能是"provider/model"格式)
|
|
141
|
-
if (updatedDefaults.models) {
|
|
142
|
-
const newModels: Record<string, any> = {};
|
|
143
|
-
for (const [key, value] of Object.entries(updatedDefaults.models)) {
|
|
144
|
-
const newKey = updateStringModelReference(key, renameMap);
|
|
145
|
-
newModels[newKey] = value;
|
|
146
|
-
}
|
|
147
|
-
updatedDefaults.models = newModels;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// 更新 subagents.model 配置
|
|
151
|
-
if (updatedDefaults.subagents?.model) {
|
|
152
|
-
updatedDefaults.subagents = {
|
|
153
|
-
...updatedDefaults.subagents,
|
|
154
|
-
model: updateAgentModelConfig(
|
|
155
|
-
updatedDefaults.subagents.model,
|
|
156
|
-
renameMap
|
|
157
|
-
),
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return updatedDefaults;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* 更新单个 agent 配置中的 provider 引用
|
|
166
|
-
*/
|
|
167
|
-
function updateAgentConfigProviderReferences(
|
|
168
|
-
agent: any,
|
|
169
|
-
renameMap: Record<string, string>
|
|
170
|
-
): any {
|
|
171
|
-
const updatedAgent = { ...agent };
|
|
172
|
-
|
|
173
|
-
// 更新 model 配置
|
|
174
|
-
if (updatedAgent.model) {
|
|
175
|
-
updatedAgent.model = updateAgentModelConfig(
|
|
176
|
-
updatedAgent.model,
|
|
177
|
-
renameMap
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// 更新 subagents.model 配置
|
|
182
|
-
if (updatedAgent.subagents?.model) {
|
|
183
|
-
updatedAgent.subagents = {
|
|
184
|
-
...updatedAgent.subagents,
|
|
185
|
-
model: updateAgentModelConfig(
|
|
186
|
-
updatedAgent.subagents.model,
|
|
187
|
-
renameMap
|
|
188
|
-
),
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return updatedAgent;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* 更新 AgentModelConfig 类型(可能是 string 或 {primary, fallbacks})
|
|
197
|
-
*/
|
|
198
|
-
function updateAgentModelConfig(
|
|
199
|
-
modelConfig: any,
|
|
200
|
-
renameMap: Record<string, string>
|
|
201
|
-
): any {
|
|
202
|
-
if (typeof modelConfig === "string") {
|
|
203
|
-
return updateStringModelReference(modelConfig, renameMap);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (typeof modelConfig === "object" && modelConfig !== null) {
|
|
207
|
-
const updatedModelConfig = { ...modelConfig };
|
|
208
|
-
|
|
209
|
-
if (updatedModelConfig.primary) {
|
|
210
|
-
updatedModelConfig.primary = updateStringModelReference(
|
|
211
|
-
updatedModelConfig.primary,
|
|
212
|
-
renameMap
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (updatedModelConfig.fallbacks && Array.isArray(updatedModelConfig.fallbacks)) {
|
|
217
|
-
updatedModelConfig.fallbacks = updatedModelConfig.fallbacks.map((fallback: string) =>
|
|
218
|
-
updateStringModelReference(fallback, renameMap)
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return updatedModelConfig;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return modelConfig;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* 更新 "provider/model" 格式的字符串
|
|
230
|
-
*/
|
|
231
|
-
function updateStringModelReference(
|
|
232
|
-
modelString: string,
|
|
233
|
-
renameMap: Record<string, string>
|
|
234
|
-
): string {
|
|
235
|
-
const parts = modelString.split("/");
|
|
236
|
-
if (parts.length > 0) {
|
|
237
|
-
const provider = parts[0];
|
|
238
|
-
const newProvider = renameMap[provider];
|
|
239
|
-
if (newProvider) {
|
|
240
|
-
parts[0] = newProvider;
|
|
241
|
-
return parts.join("/");
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return modelString;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* 更新 auth.profiles 配置中的 provider 引用
|
|
249
|
-
*/
|
|
250
|
-
function updateAuthProfilesProviderReferences(
|
|
251
|
-
profiles: Record<string, any>,
|
|
252
|
-
renameMap: Record<string, string>
|
|
253
|
-
): Record<string, any> {
|
|
254
|
-
const updatedProfiles: Record<string, any> = {};
|
|
255
|
-
|
|
256
|
-
for (const [profileId, profileConfig] of Object.entries(profiles)) {
|
|
257
|
-
const updatedProfile = { ...profileConfig };
|
|
258
|
-
const provider = updatedProfile.provider;
|
|
259
|
-
const newProvider = renameMap[provider];
|
|
260
|
-
if (newProvider) {
|
|
261
|
-
updatedProfile.provider = newProvider;
|
|
262
|
-
}
|
|
263
|
-
updatedProfiles[profileId] = updatedProfile;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return updatedProfiles;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* 解析用户主目录路径
|
|
271
|
-
*/
|
|
272
|
-
function resolveHomePath(): string {
|
|
273
|
-
if (process.platform === "win32") {
|
|
274
|
-
return process.env.USERPROFILE || "";
|
|
275
|
-
}
|
|
276
|
-
return process.env.HOME || "";
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* 获取所有 auth-profiles.json 文件路径
|
|
281
|
-
*/
|
|
282
|
-
function getAuthProfilesFilePaths(stateDir?: string): string[] {
|
|
283
|
-
const paths: string[] = [];
|
|
284
|
-
const homePath = resolveHomePath();
|
|
285
|
-
const baseDir = stateDir || path.join(homePath, ".openclaw");
|
|
286
|
-
|
|
287
|
-
// 默认路径: ~/.openclaw/agents/main/agent/auth-profiles.json
|
|
288
|
-
const defaultPath = path.join(baseDir, "agents", "main", "agent", "auth-profiles.json");
|
|
289
|
-
if (fs.existsSync(defaultPath)) {
|
|
290
|
-
paths.push(defaultPath);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// 扫描所有 agent 目录
|
|
294
|
-
const agentsDir = path.join(baseDir, "agents");
|
|
295
|
-
if (fs.existsSync(agentsDir)) {
|
|
296
|
-
const agentDirs = fs.readdirSync(agentsDir, { withFileTypes: true });
|
|
297
|
-
for (const agentDir of agentDirs) {
|
|
298
|
-
if (agentDir.isDirectory()) {
|
|
299
|
-
const agentAuthPath = path.join(agentsDir, agentDir.name, "agent", "auth-profiles.json");
|
|
300
|
-
if (fs.existsSync(agentAuthPath) && !paths.includes(agentAuthPath)) {
|
|
301
|
-
paths.push(agentAuthPath);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return paths;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* 更新 auth-profiles.json 文件中的 provider 引用
|
|
312
|
-
*/
|
|
313
|
-
export function updateAuthProfilesFiles(
|
|
314
|
-
renameMap: Record<string, string>,
|
|
315
|
-
stateDir?: string
|
|
316
|
-
): { updated: boolean; files: string[]; errors: string[] } {
|
|
317
|
-
const filePaths = getAuthProfilesFilePaths(stateDir);
|
|
318
|
-
const updatedFiles: string[] = [];
|
|
319
|
-
const errors: string[] = [];
|
|
320
|
-
let hasUpdates = false;
|
|
321
|
-
|
|
322
|
-
for (const filePath of filePaths) {
|
|
323
|
-
try {
|
|
324
|
-
// 读取文件
|
|
325
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
326
|
-
const store = JSON.parse(content);
|
|
327
|
-
|
|
328
|
-
if (!store.profiles || typeof store.profiles !== "object") {
|
|
329
|
-
continue;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
let fileHasUpdates = false;
|
|
333
|
-
|
|
334
|
-
// 更新 profiles 中的 provider
|
|
335
|
-
for (const [profileId, credential] of Object.entries(store.profiles)) {
|
|
336
|
-
const cred = credential as any;
|
|
337
|
-
const provider = cred.provider;
|
|
338
|
-
const newProvider = renameMap[provider];
|
|
339
|
-
if (newProvider && provider !== newProvider) {
|
|
340
|
-
cred.provider = newProvider;
|
|
341
|
-
fileHasUpdates = true;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// 更新 order 中的 provider key
|
|
346
|
-
if (store.order && typeof store.order === "object") {
|
|
347
|
-
const newOrder: Record<string, string[]> = {};
|
|
348
|
-
for (const [provider, profileList] of Object.entries<string[]>(store.order)) {
|
|
349
|
-
const newProvider = renameMap[provider];
|
|
350
|
-
const targetProvider = newProvider || provider;
|
|
351
|
-
newOrder[targetProvider] = profileList;
|
|
352
|
-
if (newProvider && provider !== newProvider) {
|
|
353
|
-
fileHasUpdates = true;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
if (fileHasUpdates) {
|
|
357
|
-
store.order = newOrder;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// 更新 lastGood 中的 provider key
|
|
362
|
-
if (store.lastGood && typeof store.lastGood === "object") {
|
|
363
|
-
const newLastGood: Record<string, string> = {};
|
|
364
|
-
for (const [provider, profileId] of Object.entries<string>(store.lastGood)) {
|
|
365
|
-
const newProvider = renameMap[provider];
|
|
366
|
-
const targetProvider = newProvider || provider;
|
|
367
|
-
newLastGood[targetProvider] = profileId;
|
|
368
|
-
if (newProvider && provider !== newProvider) {
|
|
369
|
-
fileHasUpdates = true;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if (fileHasUpdates) {
|
|
373
|
-
store.lastGood = newLastGood;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// 如果有更新,保存文件
|
|
378
|
-
if (fileHasUpdates) {
|
|
379
|
-
fs.writeFileSync(filePath, JSON.stringify(store, null, 2) + "\n", "utf-8");
|
|
380
|
-
updatedFiles.push(filePath);
|
|
381
|
-
hasUpdates = true;
|
|
382
|
-
}
|
|
383
|
-
} catch (error) {
|
|
384
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
385
|
-
errors.push(`${filePath}: ${errorMsg}`);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
return {
|
|
390
|
-
updated: hasUpdates,
|
|
391
|
-
files: updatedFiles,
|
|
392
|
-
errors,
|
|
393
|
-
};
|
|
394
|
-
}
|
|
1
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 检测需要改名的provider
|
|
7
|
+
*/
|
|
8
|
+
export function detectProvidersToRename(config: OpenClawConfig): Record<string, string> {
|
|
9
|
+
const renameMap: Record<string, string> = {};
|
|
10
|
+
|
|
11
|
+
if (!config.models?.providers) {
|
|
12
|
+
return renameMap;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const providers = Object.keys(config.models.providers);
|
|
16
|
+
|
|
17
|
+
for (const provider of providers) {
|
|
18
|
+
const lowerProvider = provider.trim().toLowerCase();
|
|
19
|
+
if (lowerProvider.includes("minimax")) {
|
|
20
|
+
// 使用下划线分隔:minimax -> mini_max, minimax-pro -> mini_max-pro
|
|
21
|
+
const newName = lowerProvider.replace("minimax", "mini_max");
|
|
22
|
+
renameMap[provider] = newName;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return renameMap;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 更新所有provider引用
|
|
31
|
+
*/
|
|
32
|
+
export function updateProviderReferences(
|
|
33
|
+
config: OpenClawConfig,
|
|
34
|
+
renameMap: Record<string, string>
|
|
35
|
+
): OpenClawConfig {
|
|
36
|
+
const updatedConfig = { ...config };
|
|
37
|
+
|
|
38
|
+
// 1. 更新 models.providers 本身
|
|
39
|
+
if (updatedConfig.models?.providers) {
|
|
40
|
+
const newProviders: Record<string, any> = {};
|
|
41
|
+
for (const [provider, providerConfig] of Object.entries(updatedConfig.models.providers)) {
|
|
42
|
+
const newName = renameMap[provider];
|
|
43
|
+
if (newName) {
|
|
44
|
+
newProviders[newName] = providerConfig;
|
|
45
|
+
} else {
|
|
46
|
+
newProviders[provider] = providerConfig;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
updatedConfig.models = {
|
|
50
|
+
...updatedConfig.models,
|
|
51
|
+
providers: newProviders,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 2. 更新 agents 配置
|
|
56
|
+
if (updatedConfig.agents) {
|
|
57
|
+
updatedConfig.agents = updateAgentsProviderReferences(
|
|
58
|
+
updatedConfig.agents,
|
|
59
|
+
renameMap
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 3. 更新 auth.profiles 配置
|
|
64
|
+
if (updatedConfig.auth?.profiles) {
|
|
65
|
+
updatedConfig.auth = {
|
|
66
|
+
...updatedConfig.auth,
|
|
67
|
+
profiles: updateAuthProfilesProviderReferences(
|
|
68
|
+
updatedConfig.auth.profiles,
|
|
69
|
+
renameMap
|
|
70
|
+
),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// 更新 auth.profiles 文件
|
|
74
|
+
updateAuthProfilesFiles(renameMap);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return updatedConfig;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 更新 agents 配置中的 provider 引用
|
|
82
|
+
*/
|
|
83
|
+
function updateAgentsProviderReferences(
|
|
84
|
+
agents: any,
|
|
85
|
+
renameMap: Record<string, string>
|
|
86
|
+
): any {
|
|
87
|
+
const updatedAgents = { ...agents };
|
|
88
|
+
|
|
89
|
+
// 更新 defaults 配置
|
|
90
|
+
if (updatedAgents.defaults) {
|
|
91
|
+
updatedAgents.defaults = updateAgentDefaultsProviderReferences(
|
|
92
|
+
updatedAgents.defaults,
|
|
93
|
+
renameMap
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 更新 list 配置
|
|
98
|
+
if (updatedAgents.list) {
|
|
99
|
+
updatedAgents.list = updatedAgents.list.map((agent: any) =>
|
|
100
|
+
updateAgentConfigProviderReferences(agent, renameMap)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return updatedAgents;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 更新 agent defaults 配置中的 provider 引用
|
|
109
|
+
*/
|
|
110
|
+
function updateAgentDefaultsProviderReferences(
|
|
111
|
+
defaults: any,
|
|
112
|
+
renameMap: Record<string, string>
|
|
113
|
+
): any {
|
|
114
|
+
const updatedDefaults = { ...defaults };
|
|
115
|
+
|
|
116
|
+
// 更新 model 配置
|
|
117
|
+
if (updatedDefaults.model) {
|
|
118
|
+
updatedDefaults.model = updateAgentModelConfig(
|
|
119
|
+
updatedDefaults.model,
|
|
120
|
+
renameMap
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 更新 imageModel 配置
|
|
125
|
+
if (updatedDefaults.imageModel) {
|
|
126
|
+
updatedDefaults.imageModel = updateAgentModelConfig(
|
|
127
|
+
updatedDefaults.imageModel,
|
|
128
|
+
renameMap
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 更新 pdfModel 配置
|
|
133
|
+
if (updatedDefaults.pdfModel) {
|
|
134
|
+
updatedDefaults.pdfModel = updateAgentModelConfig(
|
|
135
|
+
updatedDefaults.pdfModel,
|
|
136
|
+
renameMap
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 更新 models 目录(key可能是"provider/model"格式)
|
|
141
|
+
if (updatedDefaults.models) {
|
|
142
|
+
const newModels: Record<string, any> = {};
|
|
143
|
+
for (const [key, value] of Object.entries(updatedDefaults.models)) {
|
|
144
|
+
const newKey = updateStringModelReference(key, renameMap);
|
|
145
|
+
newModels[newKey] = value;
|
|
146
|
+
}
|
|
147
|
+
updatedDefaults.models = newModels;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 更新 subagents.model 配置
|
|
151
|
+
if (updatedDefaults.subagents?.model) {
|
|
152
|
+
updatedDefaults.subagents = {
|
|
153
|
+
...updatedDefaults.subagents,
|
|
154
|
+
model: updateAgentModelConfig(
|
|
155
|
+
updatedDefaults.subagents.model,
|
|
156
|
+
renameMap
|
|
157
|
+
),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return updatedDefaults;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 更新单个 agent 配置中的 provider 引用
|
|
166
|
+
*/
|
|
167
|
+
function updateAgentConfigProviderReferences(
|
|
168
|
+
agent: any,
|
|
169
|
+
renameMap: Record<string, string>
|
|
170
|
+
): any {
|
|
171
|
+
const updatedAgent = { ...agent };
|
|
172
|
+
|
|
173
|
+
// 更新 model 配置
|
|
174
|
+
if (updatedAgent.model) {
|
|
175
|
+
updatedAgent.model = updateAgentModelConfig(
|
|
176
|
+
updatedAgent.model,
|
|
177
|
+
renameMap
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 更新 subagents.model 配置
|
|
182
|
+
if (updatedAgent.subagents?.model) {
|
|
183
|
+
updatedAgent.subagents = {
|
|
184
|
+
...updatedAgent.subagents,
|
|
185
|
+
model: updateAgentModelConfig(
|
|
186
|
+
updatedAgent.subagents.model,
|
|
187
|
+
renameMap
|
|
188
|
+
),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return updatedAgent;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 更新 AgentModelConfig 类型(可能是 string 或 {primary, fallbacks})
|
|
197
|
+
*/
|
|
198
|
+
function updateAgentModelConfig(
|
|
199
|
+
modelConfig: any,
|
|
200
|
+
renameMap: Record<string, string>
|
|
201
|
+
): any {
|
|
202
|
+
if (typeof modelConfig === "string") {
|
|
203
|
+
return updateStringModelReference(modelConfig, renameMap);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (typeof modelConfig === "object" && modelConfig !== null) {
|
|
207
|
+
const updatedModelConfig = { ...modelConfig };
|
|
208
|
+
|
|
209
|
+
if (updatedModelConfig.primary) {
|
|
210
|
+
updatedModelConfig.primary = updateStringModelReference(
|
|
211
|
+
updatedModelConfig.primary,
|
|
212
|
+
renameMap
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (updatedModelConfig.fallbacks && Array.isArray(updatedModelConfig.fallbacks)) {
|
|
217
|
+
updatedModelConfig.fallbacks = updatedModelConfig.fallbacks.map((fallback: string) =>
|
|
218
|
+
updateStringModelReference(fallback, renameMap)
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return updatedModelConfig;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return modelConfig;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* 更新 "provider/model" 格式的字符串
|
|
230
|
+
*/
|
|
231
|
+
function updateStringModelReference(
|
|
232
|
+
modelString: string,
|
|
233
|
+
renameMap: Record<string, string>
|
|
234
|
+
): string {
|
|
235
|
+
const parts = modelString.split("/");
|
|
236
|
+
if (parts.length > 0) {
|
|
237
|
+
const provider = parts[0];
|
|
238
|
+
const newProvider = renameMap[provider];
|
|
239
|
+
if (newProvider) {
|
|
240
|
+
parts[0] = newProvider;
|
|
241
|
+
return parts.join("/");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return modelString;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* 更新 auth.profiles 配置中的 provider 引用
|
|
249
|
+
*/
|
|
250
|
+
function updateAuthProfilesProviderReferences(
|
|
251
|
+
profiles: Record<string, any>,
|
|
252
|
+
renameMap: Record<string, string>
|
|
253
|
+
): Record<string, any> {
|
|
254
|
+
const updatedProfiles: Record<string, any> = {};
|
|
255
|
+
|
|
256
|
+
for (const [profileId, profileConfig] of Object.entries(profiles)) {
|
|
257
|
+
const updatedProfile = { ...profileConfig };
|
|
258
|
+
const provider = updatedProfile.provider;
|
|
259
|
+
const newProvider = renameMap[provider];
|
|
260
|
+
if (newProvider) {
|
|
261
|
+
updatedProfile.provider = newProvider;
|
|
262
|
+
}
|
|
263
|
+
updatedProfiles[profileId] = updatedProfile;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return updatedProfiles;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* 解析用户主目录路径
|
|
271
|
+
*/
|
|
272
|
+
function resolveHomePath(): string {
|
|
273
|
+
if (process.platform === "win32") {
|
|
274
|
+
return process.env.USERPROFILE || "";
|
|
275
|
+
}
|
|
276
|
+
return process.env.HOME || "";
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* 获取所有 auth-profiles.json 文件路径
|
|
281
|
+
*/
|
|
282
|
+
function getAuthProfilesFilePaths(stateDir?: string): string[] {
|
|
283
|
+
const paths: string[] = [];
|
|
284
|
+
const homePath = resolveHomePath();
|
|
285
|
+
const baseDir = stateDir || path.join(homePath, ".openclaw");
|
|
286
|
+
|
|
287
|
+
// 默认路径: ~/.openclaw/agents/main/agent/auth-profiles.json
|
|
288
|
+
const defaultPath = path.join(baseDir, "agents", "main", "agent", "auth-profiles.json");
|
|
289
|
+
if (fs.existsSync(defaultPath)) {
|
|
290
|
+
paths.push(defaultPath);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// 扫描所有 agent 目录
|
|
294
|
+
const agentsDir = path.join(baseDir, "agents");
|
|
295
|
+
if (fs.existsSync(agentsDir)) {
|
|
296
|
+
const agentDirs = fs.readdirSync(agentsDir, { withFileTypes: true });
|
|
297
|
+
for (const agentDir of agentDirs) {
|
|
298
|
+
if (agentDir.isDirectory()) {
|
|
299
|
+
const agentAuthPath = path.join(agentsDir, agentDir.name, "agent", "auth-profiles.json");
|
|
300
|
+
if (fs.existsSync(agentAuthPath) && !paths.includes(agentAuthPath)) {
|
|
301
|
+
paths.push(agentAuthPath);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return paths;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* 更新 auth-profiles.json 文件中的 provider 引用
|
|
312
|
+
*/
|
|
313
|
+
export function updateAuthProfilesFiles(
|
|
314
|
+
renameMap: Record<string, string>,
|
|
315
|
+
stateDir?: string
|
|
316
|
+
): { updated: boolean; files: string[]; errors: string[] } {
|
|
317
|
+
const filePaths = getAuthProfilesFilePaths(stateDir);
|
|
318
|
+
const updatedFiles: string[] = [];
|
|
319
|
+
const errors: string[] = [];
|
|
320
|
+
let hasUpdates = false;
|
|
321
|
+
|
|
322
|
+
for (const filePath of filePaths) {
|
|
323
|
+
try {
|
|
324
|
+
// 读取文件
|
|
325
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
326
|
+
const store = JSON.parse(content);
|
|
327
|
+
|
|
328
|
+
if (!store.profiles || typeof store.profiles !== "object") {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
let fileHasUpdates = false;
|
|
333
|
+
|
|
334
|
+
// 更新 profiles 中的 provider
|
|
335
|
+
for (const [profileId, credential] of Object.entries(store.profiles)) {
|
|
336
|
+
const cred = credential as any;
|
|
337
|
+
const provider = cred.provider;
|
|
338
|
+
const newProvider = renameMap[provider];
|
|
339
|
+
if (newProvider && provider !== newProvider) {
|
|
340
|
+
cred.provider = newProvider;
|
|
341
|
+
fileHasUpdates = true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// 更新 order 中的 provider key
|
|
346
|
+
if (store.order && typeof store.order === "object") {
|
|
347
|
+
const newOrder: Record<string, string[]> = {};
|
|
348
|
+
for (const [provider, profileList] of Object.entries<string[]>(store.order)) {
|
|
349
|
+
const newProvider = renameMap[provider];
|
|
350
|
+
const targetProvider = newProvider || provider;
|
|
351
|
+
newOrder[targetProvider] = profileList;
|
|
352
|
+
if (newProvider && provider !== newProvider) {
|
|
353
|
+
fileHasUpdates = true;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (fileHasUpdates) {
|
|
357
|
+
store.order = newOrder;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 更新 lastGood 中的 provider key
|
|
362
|
+
if (store.lastGood && typeof store.lastGood === "object") {
|
|
363
|
+
const newLastGood: Record<string, string> = {};
|
|
364
|
+
for (const [provider, profileId] of Object.entries<string>(store.lastGood)) {
|
|
365
|
+
const newProvider = renameMap[provider];
|
|
366
|
+
const targetProvider = newProvider || provider;
|
|
367
|
+
newLastGood[targetProvider] = profileId;
|
|
368
|
+
if (newProvider && provider !== newProvider) {
|
|
369
|
+
fileHasUpdates = true;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (fileHasUpdates) {
|
|
373
|
+
store.lastGood = newLastGood;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// 如果有更新,保存文件
|
|
378
|
+
if (fileHasUpdates) {
|
|
379
|
+
fs.writeFileSync(filePath, JSON.stringify(store, null, 2) + "\n", "utf-8");
|
|
380
|
+
updatedFiles.push(filePath);
|
|
381
|
+
hasUpdates = true;
|
|
382
|
+
}
|
|
383
|
+
} catch (error) {
|
|
384
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
385
|
+
errors.push(`${filePath}: ${errorMsg}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
updated: hasUpdates,
|
|
391
|
+
files: updatedFiles,
|
|
392
|
+
errors,
|
|
393
|
+
};
|
|
394
|
+
}
|