@chrysb/alphaclaw 0.9.19 → 0.9.21
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/bin/alphaclaw.js +15 -1
- package/lib/public/dist/app.bundle.js +1055 -1055
- package/lib/public/js/components/models-tab/index.js +18 -21
- package/lib/public/js/components/models-tab/model-picker.js +24 -1
- package/lib/public/js/lib/model-config.js +22 -2
- package/lib/scripts/migrate-openclaw-codex.js +17 -0
- package/lib/server/auth-profiles.js +15 -4
- package/lib/server/constants.js +5 -5
- package/lib/server/openclaw-codex-migration.js +78 -0
- package/package.json +1 -1
|
@@ -13,13 +13,15 @@ import {
|
|
|
13
13
|
buildSyntheticModelEntry,
|
|
14
14
|
getModelCatalogProvider,
|
|
15
15
|
getModelsTabAuthProvider,
|
|
16
|
+
getModelsTabRequiredAuthProviders,
|
|
17
|
+
getProviderAuthDisplayOrder,
|
|
16
18
|
getProviderSortIndex,
|
|
17
19
|
SearchableModelPicker,
|
|
18
20
|
} from "./model-picker.js";
|
|
19
21
|
import { ProviderAuthCard } from "./provider-auth-card.js";
|
|
20
22
|
import {
|
|
21
23
|
getFeaturedModels,
|
|
22
|
-
|
|
24
|
+
withAlwaysAvailableModels,
|
|
23
25
|
} from "../../lib/model-config.js";
|
|
24
26
|
|
|
25
27
|
const html = htm.bind(h);
|
|
@@ -27,19 +29,13 @@ const html = htm.bind(h);
|
|
|
27
29
|
const deriveRequiredProviders = (configuredModels) => {
|
|
28
30
|
const providers = new Set();
|
|
29
31
|
for (const modelKey of Object.keys(configuredModels)) {
|
|
30
|
-
const provider
|
|
31
|
-
|
|
32
|
+
for (const provider of getModelsTabRequiredAuthProviders(modelKey)) {
|
|
33
|
+
providers.add(provider);
|
|
34
|
+
}
|
|
32
35
|
}
|
|
33
36
|
return [...providers];
|
|
34
37
|
};
|
|
35
38
|
|
|
36
|
-
const kProviderDisplayOrder = [
|
|
37
|
-
"anthropic",
|
|
38
|
-
"openai",
|
|
39
|
-
"openai-codex",
|
|
40
|
-
...kProviderOrder.filter((provider) => !["anthropic", "openai"].includes(provider)),
|
|
41
|
-
];
|
|
42
|
-
|
|
43
39
|
export const Models = ({ onRestartRequired = () => {}, agentId, embedded = false }) => {
|
|
44
40
|
const {
|
|
45
41
|
catalog,
|
|
@@ -70,14 +66,22 @@ export const Models = ({ onRestartRequired = () => {}, agentId, embedded = false
|
|
|
70
66
|
[configuredModels],
|
|
71
67
|
);
|
|
72
68
|
|
|
73
|
-
const
|
|
69
|
+
const selectableCatalog = useMemo(
|
|
70
|
+
() => withAlwaysAvailableModels(catalog),
|
|
71
|
+
[catalog],
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const featuredModels = useMemo(
|
|
75
|
+
() => getFeaturedModels(selectableCatalog),
|
|
76
|
+
[selectableCatalog],
|
|
77
|
+
);
|
|
74
78
|
const popularPickerModels = useMemo(
|
|
75
79
|
() => featuredModels.filter((model) => !configuredKeys.has(model.key)),
|
|
76
80
|
[featuredModels, configuredKeys],
|
|
77
81
|
);
|
|
78
82
|
|
|
79
83
|
const pickerModels = useMemo(() => {
|
|
80
|
-
return [...
|
|
84
|
+
return [...selectableCatalog]
|
|
81
85
|
.filter((model) => !configuredKeys.has(model.key))
|
|
82
86
|
.sort((a, b) => {
|
|
83
87
|
const providerCompare =
|
|
@@ -86,7 +90,7 @@ export const Models = ({ onRestartRequired = () => {}, agentId, embedded = false
|
|
|
86
90
|
if (providerCompare !== 0) return providerCompare;
|
|
87
91
|
return String(a.label || a.key).localeCompare(String(b.label || b.key));
|
|
88
92
|
});
|
|
89
|
-
}, [
|
|
93
|
+
}, [selectableCatalog, configuredKeys]);
|
|
90
94
|
|
|
91
95
|
const requiredProviders = useMemo(
|
|
92
96
|
() => deriveRequiredProviders(configuredModels),
|
|
@@ -94,14 +98,7 @@ export const Models = ({ onRestartRequired = () => {}, agentId, embedded = false
|
|
|
94
98
|
);
|
|
95
99
|
|
|
96
100
|
const sortedProviders = useMemo(() => {
|
|
97
|
-
|
|
98
|
-
for (const p of kProviderDisplayOrder) {
|
|
99
|
-
if (requiredProviders.includes(p)) ordered.push(p);
|
|
100
|
-
}
|
|
101
|
-
for (const p of requiredProviders) {
|
|
102
|
-
if (!ordered.includes(p)) ordered.push(p);
|
|
103
|
-
}
|
|
104
|
-
return ordered;
|
|
101
|
+
return getProviderAuthDisplayOrder(requiredProviders);
|
|
105
102
|
}, [requiredProviders]);
|
|
106
103
|
|
|
107
104
|
const providerHasAuth = useMemo(
|
|
@@ -19,10 +19,30 @@ const kProviderDisplayOrder = [
|
|
|
19
19
|
|
|
20
20
|
export const getModelsTabAuthProvider = (modelKey) => {
|
|
21
21
|
const provider = getModelProvider(modelKey);
|
|
22
|
-
if (provider === "openai
|
|
22
|
+
if (provider === "openai" || provider === "openai-codex") {
|
|
23
|
+
return "openai-codex";
|
|
24
|
+
}
|
|
23
25
|
return getAuthProviderFromModelProvider(provider);
|
|
24
26
|
};
|
|
25
27
|
|
|
28
|
+
export const getModelsTabRequiredAuthProviders = (modelKey) => {
|
|
29
|
+
const provider = getModelProvider(modelKey);
|
|
30
|
+
if (provider === "openai" || provider === "openai-codex") {
|
|
31
|
+
return ["openai", "openai-codex"];
|
|
32
|
+
}
|
|
33
|
+
const authProvider = getAuthProviderFromModelProvider(provider);
|
|
34
|
+
return authProvider ? [authProvider] : [];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const getProviderAuthDisplayOrder = (requiredProviders = []) => {
|
|
38
|
+
const required = new Set(["openai-codex", ...requiredProviders]);
|
|
39
|
+
const ordered = kProviderDisplayOrder.filter((provider) => required.has(provider));
|
|
40
|
+
for (const provider of required) {
|
|
41
|
+
if (!ordered.includes(provider)) ordered.push(provider);
|
|
42
|
+
}
|
|
43
|
+
return ordered;
|
|
44
|
+
};
|
|
45
|
+
|
|
26
46
|
export const getModelCatalogProvider = (model) =>
|
|
27
47
|
String(model?.provider || getModelProvider(model?.key)).trim();
|
|
28
48
|
|
|
@@ -88,6 +108,9 @@ export const buildProviderHasAuth = ({
|
|
|
88
108
|
if (codexStatus?.connected) {
|
|
89
109
|
result["openai-codex"] = true;
|
|
90
110
|
}
|
|
111
|
+
if (result.openai) {
|
|
112
|
+
result["openai-codex"] = true;
|
|
113
|
+
}
|
|
91
114
|
return result;
|
|
92
115
|
};
|
|
93
116
|
|
|
@@ -27,11 +27,14 @@ export const kFeaturedModelDefs = [
|
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
label: "Codex 5.3",
|
|
30
|
-
preferredKeys: [
|
|
30
|
+
preferredKeys: [
|
|
31
|
+
"openai/gpt-5.3-codex",
|
|
32
|
+
"openai-codex/gpt-5.3-codex",
|
|
33
|
+
],
|
|
31
34
|
},
|
|
32
35
|
{
|
|
33
36
|
label: "GPT-5.5",
|
|
34
|
-
preferredKeys: ["openai-codex/gpt-5.5"],
|
|
37
|
+
preferredKeys: ["openai/gpt-5.5", "openai-codex/gpt-5.5"],
|
|
35
38
|
},
|
|
36
39
|
{
|
|
37
40
|
label: "Gemini 3.1 Pro",
|
|
@@ -39,6 +42,23 @@ export const kFeaturedModelDefs = [
|
|
|
39
42
|
},
|
|
40
43
|
];
|
|
41
44
|
|
|
45
|
+
export const kAlwaysAvailableModelDefs = [
|
|
46
|
+
{
|
|
47
|
+
key: "openai/gpt-5.5",
|
|
48
|
+
provider: "openai",
|
|
49
|
+
label: "GPT-5.5",
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
export const withAlwaysAvailableModels = (models = []) => {
|
|
54
|
+
const merged = [...models];
|
|
55
|
+
const keys = new Set(merged.map((model) => model?.key));
|
|
56
|
+
for (const model of kAlwaysAvailableModelDefs) {
|
|
57
|
+
if (!keys.has(model.key)) merged.push(model);
|
|
58
|
+
}
|
|
59
|
+
return merged;
|
|
60
|
+
};
|
|
61
|
+
|
|
42
62
|
export const getFeaturedModels = (allModels) => {
|
|
43
63
|
const picked = [];
|
|
44
64
|
const used = new Set();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { migrateLegacyCodexState } = require("../server/openclaw-codex-migration");
|
|
4
|
+
|
|
5
|
+
migrateLegacyCodexState()
|
|
6
|
+
.then((result) => {
|
|
7
|
+
if (result.changed) {
|
|
8
|
+
console.log("[alphaclaw] Migrated legacy OpenAI Codex model and auth state");
|
|
9
|
+
}
|
|
10
|
+
for (const warning of result.warnings) {
|
|
11
|
+
console.warn(`[alphaclaw] Codex migration warning: ${warning}`);
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
.catch((error) => {
|
|
15
|
+
console.error(`[alphaclaw] Codex migration failed: ${error.message}`);
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
});
|
|
@@ -281,7 +281,12 @@ const createAuthProfiles = () => {
|
|
|
281
281
|
|
|
282
282
|
// ── Legacy Codex-specific wrappers ──
|
|
283
283
|
|
|
284
|
-
const listCodexProfiles = () =>
|
|
284
|
+
const listCodexProfiles = () =>
|
|
285
|
+
listProfiles().filter(
|
|
286
|
+
(profile) =>
|
|
287
|
+
profile.type === "oauth" &&
|
|
288
|
+
(profile.provider === "openai" || profile.provider === "openai-codex"),
|
|
289
|
+
);
|
|
285
290
|
|
|
286
291
|
const getCodexProfile = () => {
|
|
287
292
|
const profiles = listCodexProfiles();
|
|
@@ -299,7 +304,7 @@ const createAuthProfiles = () => {
|
|
|
299
304
|
const upsertCodexProfile = ({ access, refresh, expires, accountId }) => {
|
|
300
305
|
upsertProfile(CODEX_PROFILE_ID, {
|
|
301
306
|
type: "oauth",
|
|
302
|
-
provider: "openai
|
|
307
|
+
provider: "openai",
|
|
303
308
|
access,
|
|
304
309
|
refresh,
|
|
305
310
|
expires,
|
|
@@ -311,7 +316,10 @@ const createAuthProfiles = () => {
|
|
|
311
316
|
const store = loadAuthStore();
|
|
312
317
|
let changed = false;
|
|
313
318
|
for (const [id, cred] of Object.entries(store.profiles || {})) {
|
|
314
|
-
if (
|
|
319
|
+
if (
|
|
320
|
+
cred?.type === "oauth" &&
|
|
321
|
+
(cred.provider === "openai" || cred.provider === "openai-codex")
|
|
322
|
+
) {
|
|
315
323
|
delete store.profiles[id];
|
|
316
324
|
changed = true;
|
|
317
325
|
}
|
|
@@ -321,7 +329,10 @@ const createAuthProfiles = () => {
|
|
|
321
329
|
if (!canSyncOpenclawAuthReferences()) return changed;
|
|
322
330
|
let cfg = loadOpenclawConfig();
|
|
323
331
|
for (const [id, cred] of Object.entries(cfg.auth?.profiles || {})) {
|
|
324
|
-
if (
|
|
332
|
+
if (
|
|
333
|
+
cred?.mode === "oauth" &&
|
|
334
|
+
(cred.provider === "openai" || cred.provider === "openai-codex")
|
|
335
|
+
) {
|
|
325
336
|
cfg = removeConfigAuthReference(cfg, id);
|
|
326
337
|
}
|
|
327
338
|
}
|
package/lib/server/constants.js
CHANGED
|
@@ -28,7 +28,7 @@ const AUTH_PROFILES_PATH = path.join(
|
|
|
28
28
|
"agent",
|
|
29
29
|
"auth-profiles.json",
|
|
30
30
|
);
|
|
31
|
-
const CODEX_PROFILE_ID = "openai
|
|
31
|
+
const CODEX_PROFILE_ID = "openai:codex-cli";
|
|
32
32
|
const CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
33
33
|
const CODEX_OAUTH_AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
|
|
34
34
|
const CODEX_OAUTH_TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
@@ -173,13 +173,13 @@ const kMinimalFallbackOnboardingModels = [
|
|
|
173
173
|
label: "Claude Haiku 4.6",
|
|
174
174
|
},
|
|
175
175
|
{
|
|
176
|
-
key: "openai
|
|
177
|
-
provider: "openai
|
|
176
|
+
key: "openai/gpt-5.5",
|
|
177
|
+
provider: "openai",
|
|
178
178
|
label: "GPT-5.5",
|
|
179
179
|
},
|
|
180
180
|
{
|
|
181
|
-
key: "openai
|
|
182
|
-
provider: "openai
|
|
181
|
+
key: "openai/gpt-5.3-codex",
|
|
182
|
+
provider: "openai",
|
|
183
183
|
label: "Codex GPT-5.3",
|
|
184
184
|
},
|
|
185
185
|
{
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { pathToFileURL } = require("url");
|
|
4
|
+
|
|
5
|
+
const findOpenclawDistModule = (prefix) => {
|
|
6
|
+
const entryPath = require.resolve("openclaw");
|
|
7
|
+
const distDir = path.dirname(entryPath);
|
|
8
|
+
const filename = fs
|
|
9
|
+
.readdirSync(distDir)
|
|
10
|
+
.find((name) => name.startsWith(`${prefix}-`) && name.endsWith(".js"));
|
|
11
|
+
if (!filename) throw new Error(`OpenClaw migration module not found: ${prefix}`);
|
|
12
|
+
return path.join(distDir, filename);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const writeConfig = (configPath, cfg) => {
|
|
16
|
+
fs.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}\n`, "utf8");
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const migrateLegacyCodexState = async ({
|
|
20
|
+
configPath = process.env.OPENCLAW_CONFIG_PATH,
|
|
21
|
+
env = process.env,
|
|
22
|
+
} = {}) => {
|
|
23
|
+
if (!configPath || !fs.existsSync(configPath)) {
|
|
24
|
+
return { changed: false, changes: [], warnings: [] };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const cfg = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
28
|
+
const routeModule = await import(
|
|
29
|
+
pathToFileURL(findOpenclawDistModule("codex-route-warnings")).href
|
|
30
|
+
);
|
|
31
|
+
const authModule = await import(
|
|
32
|
+
pathToFileURL(findOpenclawDistModule("doctor-auth-flat-profiles")).href
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const changes = [];
|
|
36
|
+
const warnings = [];
|
|
37
|
+
const routeRepair = routeModule.r({ cfg, env, shouldRepair: true });
|
|
38
|
+
let nextCfg = routeRepair.cfg;
|
|
39
|
+
changes.push(...routeRepair.changes);
|
|
40
|
+
warnings.push(...routeRepair.warnings);
|
|
41
|
+
|
|
42
|
+
const profileIdMap = authModule.t({ cfg: nextCfg, env });
|
|
43
|
+
const configAuthRepair = authModule.a(nextCfg, { profileIdMap });
|
|
44
|
+
nextCfg = configAuthRepair.config;
|
|
45
|
+
changes.push(...configAuthRepair.changes);
|
|
46
|
+
warnings.push(...configAuthRepair.warnings);
|
|
47
|
+
|
|
48
|
+
if (changes.length > 0) writeConfig(configPath, nextCfg);
|
|
49
|
+
|
|
50
|
+
const storeRepair = await authModule.o({ cfg: nextCfg, env });
|
|
51
|
+
changes.push(...storeRepair.changes);
|
|
52
|
+
warnings.push(...storeRepair.warnings);
|
|
53
|
+
|
|
54
|
+
const sqliteMigration = await authModule.n({
|
|
55
|
+
cfg: nextCfg,
|
|
56
|
+
env,
|
|
57
|
+
prompter: { confirmAutoFix: async () => true },
|
|
58
|
+
});
|
|
59
|
+
changes.push(...sqliteMigration.changes);
|
|
60
|
+
warnings.push(...sqliteMigration.warnings);
|
|
61
|
+
if (sqliteMigration.configChanged) writeConfig(configPath, nextCfg);
|
|
62
|
+
|
|
63
|
+
const sessionRepair = await routeModule.i({
|
|
64
|
+
cfg: nextCfg,
|
|
65
|
+
env,
|
|
66
|
+
shouldRepair: true,
|
|
67
|
+
});
|
|
68
|
+
changes.push(...sessionRepair.changes);
|
|
69
|
+
warnings.push(...sessionRepair.warnings);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
changed: changes.length > 0,
|
|
73
|
+
changes,
|
|
74
|
+
warnings,
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
module.exports = { migrateLegacyCodexState };
|