@chrysb/alphaclaw 0.4.6-beta.3 → 0.4.6-beta.5
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/lib/public/js/app.js +158 -1073
- package/lib/public/js/components/doctor/index.js +1 -2
- package/lib/public/js/components/general/index.js +155 -0
- package/lib/public/js/components/general/use-general-tab.js +233 -0
- package/lib/public/js/components/models-tab/index.js +286 -0
- package/lib/public/js/components/models-tab/provider-auth-card.js +369 -0
- package/lib/public/js/components/models-tab/use-models.js +262 -0
- package/lib/public/js/components/routes/browse-route.js +35 -0
- package/lib/public/js/components/routes/doctor-route.js +21 -0
- package/lib/public/js/components/routes/envars-route.js +11 -0
- package/lib/public/js/components/routes/general-route.js +45 -0
- package/lib/public/js/components/routes/index.js +11 -0
- package/lib/public/js/components/routes/models-route.js +11 -0
- package/lib/public/js/components/routes/providers-route.js +11 -0
- package/lib/public/js/components/routes/route-redirect.js +10 -0
- package/lib/public/js/components/routes/telegram-route.js +11 -0
- package/lib/public/js/components/routes/usage-route.js +15 -0
- package/lib/public/js/components/routes/watchdog-route.js +32 -0
- package/lib/public/js/components/routes/webhooks-route.js +43 -0
- package/lib/public/js/components/sidebar.js +2 -3
- package/lib/public/js/components/usage-tab/constants.js +1 -1
- package/lib/public/js/components/usage-tab/overview-section.js +124 -50
- package/lib/public/js/components/usage-tab/use-usage-tab.js +42 -11
- package/lib/public/js/hooks/use-app-shell-controller.js +230 -0
- package/lib/public/js/hooks/use-app-shell-ui.js +112 -0
- package/lib/public/js/hooks/use-browse-navigation.js +193 -0
- package/lib/public/js/hooks/use-hash-location.js +32 -0
- package/lib/public/js/lib/api.js +35 -0
- package/lib/public/js/lib/app-navigation.js +39 -0
- package/lib/public/js/lib/browse-restart-policy.js +28 -0
- package/lib/public/js/lib/browse-route.js +57 -0
- package/lib/public/js/lib/format.js +12 -0
- package/lib/server/auth-profiles.js +223 -52
- package/lib/server/doctor/prompt.js +4 -1
- package/lib/server/gateway.js +29 -9
- package/lib/server/routes/models.js +170 -2
- package/lib/server/watchdog.js +14 -1
- package/lib/server.js +1 -0
- package/package.json +1 -1
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
const { kFallbackOnboardingModels } = require("../constants");
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const runModelsGitSync = async (shellCmd) => {
|
|
4
|
+
if (typeof shellCmd !== "function") return null;
|
|
5
|
+
try {
|
|
6
|
+
await shellCmd('alphaclaw git-sync -m "models: update config" -f "openclaw.json"', {
|
|
7
|
+
timeout: 30000,
|
|
8
|
+
});
|
|
9
|
+
return null;
|
|
10
|
+
} catch (err) {
|
|
11
|
+
return err?.message || "alphaclaw git-sync failed";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const registerModelRoutes = ({
|
|
16
|
+
app,
|
|
17
|
+
shellCmd,
|
|
18
|
+
gatewayEnv,
|
|
19
|
+
parseJsonFromNoisyOutput,
|
|
20
|
+
normalizeOnboardingModels,
|
|
21
|
+
authProfiles,
|
|
22
|
+
}) => {
|
|
23
|
+
// ── Existing CLI-backed catalog/status routes ──
|
|
24
|
+
|
|
4
25
|
app.get("/api/models", async (req, res) => {
|
|
5
26
|
try {
|
|
6
27
|
const output = await shellCmd("openclaw models list --all --json", {
|
|
@@ -60,7 +81,154 @@ const registerModelRoutes = ({ app, shellCmd, gatewayEnv, parseJsonFromNoisyOutp
|
|
|
60
81
|
});
|
|
61
82
|
res.json({ ok: true });
|
|
62
83
|
} catch (err) {
|
|
63
|
-
res
|
|
84
|
+
res
|
|
85
|
+
.status(400)
|
|
86
|
+
.json({ ok: false, error: err.message || "Failed to set model" });
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// ── Model config (direct JSON) ──
|
|
91
|
+
|
|
92
|
+
app.get("/api/models/config", (req, res) => {
|
|
93
|
+
try {
|
|
94
|
+
const { primary, configuredModels } = authProfiles.getModelConfig();
|
|
95
|
+
const agentId = req.query.agentId || undefined;
|
|
96
|
+
const profiles = authProfiles.listProfiles(agentId);
|
|
97
|
+
const store = authProfiles.loadAuthStore(agentId);
|
|
98
|
+
res.json({
|
|
99
|
+
ok: true,
|
|
100
|
+
primary,
|
|
101
|
+
configuredModels,
|
|
102
|
+
authProfiles: profiles,
|
|
103
|
+
authOrder: store.order || {},
|
|
104
|
+
});
|
|
105
|
+
} catch (err) {
|
|
106
|
+
res
|
|
107
|
+
.status(500)
|
|
108
|
+
.json({ ok: false, error: err.message || "Failed to read config" });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
app.put("/api/models/config", async (req, res) => {
|
|
113
|
+
const { primary, configuredModels, profiles, authOrder } = req.body || {};
|
|
114
|
+
const agentId = req.query.agentId || undefined;
|
|
115
|
+
if (primary !== undefined && (typeof primary !== "string" || !primary.includes("/"))) {
|
|
116
|
+
return res
|
|
117
|
+
.status(400)
|
|
118
|
+
.json({ ok: false, error: "Invalid primary model key" });
|
|
119
|
+
}
|
|
120
|
+
if (
|
|
121
|
+
configuredModels !== undefined &&
|
|
122
|
+
(typeof configuredModels !== "object" || configuredModels === null)
|
|
123
|
+
) {
|
|
124
|
+
return res
|
|
125
|
+
.status(400)
|
|
126
|
+
.json({ ok: false, error: "Invalid configuredModels" });
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
authProfiles.setModelConfig({ primary, configuredModels });
|
|
130
|
+
|
|
131
|
+
if (Array.isArray(profiles)) {
|
|
132
|
+
for (const { id: profileId, ...credential } of profiles) {
|
|
133
|
+
if (profileId && credential.type && credential.provider) {
|
|
134
|
+
authProfiles.upsertProfile(profileId, credential, agentId);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (authOrder && typeof authOrder === "object") {
|
|
140
|
+
for (const [provider, order] of Object.entries(authOrder)) {
|
|
141
|
+
if (Array.isArray(order)) {
|
|
142
|
+
authProfiles.setAuthOrder(provider, order, agentId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// `auth-profiles.json` is the durable source of truth. Re-sync
|
|
148
|
+
// `openclaw.json.auth.profiles` on save so model re-adds restore refs.
|
|
149
|
+
authProfiles.syncConfigAuthReferencesForAgent(agentId);
|
|
150
|
+
|
|
151
|
+
const syncWarning = await runModelsGitSync(shellCmd);
|
|
152
|
+
res.json({
|
|
153
|
+
ok: true,
|
|
154
|
+
...(syncWarning ? { syncWarning } : {}),
|
|
155
|
+
});
|
|
156
|
+
} catch (err) {
|
|
157
|
+
res
|
|
158
|
+
.status(500)
|
|
159
|
+
.json({ ok: false, error: err.message || "Failed to save config" });
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// ── Auth profiles (direct JSON) ──
|
|
164
|
+
|
|
165
|
+
app.get("/api/models/auth", (req, res) => {
|
|
166
|
+
try {
|
|
167
|
+
const agentId = req.query.agentId || undefined;
|
|
168
|
+
const profiles = authProfiles.listProfiles(agentId);
|
|
169
|
+
const store = authProfiles.loadAuthStore(agentId);
|
|
170
|
+
res.json({ ok: true, profiles, order: store.order || {} });
|
|
171
|
+
} catch (err) {
|
|
172
|
+
res
|
|
173
|
+
.status(500)
|
|
174
|
+
.json({
|
|
175
|
+
ok: false,
|
|
176
|
+
error: err.message || "Failed to read auth profiles",
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
app.put("/api/models/auth/:profileId", (req, res) => {
|
|
182
|
+
const { profileId } = req.params;
|
|
183
|
+
const credential = req.body;
|
|
184
|
+
if (
|
|
185
|
+
!profileId ||
|
|
186
|
+
!credential?.type ||
|
|
187
|
+
!credential?.provider
|
|
188
|
+
) {
|
|
189
|
+
return res
|
|
190
|
+
.status(400)
|
|
191
|
+
.json({ ok: false, error: "Missing profileId, type, or provider" });
|
|
192
|
+
}
|
|
193
|
+
const validTypes = new Set(["api_key", "token", "oauth"]);
|
|
194
|
+
if (!validTypes.has(credential.type)) {
|
|
195
|
+
return res.status(400).json({
|
|
196
|
+
ok: false,
|
|
197
|
+
error: `Invalid credential type: ${credential.type}`,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const agentId = req.query.agentId || undefined;
|
|
202
|
+
authProfiles.upsertProfile(profileId, credential, agentId);
|
|
203
|
+
res.json({ ok: true });
|
|
204
|
+
} catch (err) {
|
|
205
|
+
res
|
|
206
|
+
.status(500)
|
|
207
|
+
.json({
|
|
208
|
+
ok: false,
|
|
209
|
+
error: err.message || "Failed to save auth profile",
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
app.delete("/api/models/auth/:profileId", (req, res) => {
|
|
215
|
+
const { profileId } = req.params;
|
|
216
|
+
if (!profileId) {
|
|
217
|
+
return res
|
|
218
|
+
.status(400)
|
|
219
|
+
.json({ ok: false, error: "Missing profileId" });
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const agentId = req.query.agentId || undefined;
|
|
223
|
+
const removed = authProfiles.removeProfile(profileId, agentId);
|
|
224
|
+
res.json({ ok: true, removed });
|
|
225
|
+
} catch (err) {
|
|
226
|
+
res
|
|
227
|
+
.status(500)
|
|
228
|
+
.json({
|
|
229
|
+
ok: false,
|
|
230
|
+
error: err.message || "Failed to remove auth profile",
|
|
231
|
+
});
|
|
64
232
|
}
|
|
65
233
|
});
|
|
66
234
|
};
|
package/lib/server/watchdog.js
CHANGED
|
@@ -364,14 +364,27 @@ const createWatchdog = ({
|
|
|
364
364
|
}
|
|
365
365
|
if (parsed.ok) {
|
|
366
366
|
const wasUnhealthy = state.health !== "healthy";
|
|
367
|
+
const recoveredFromCrashLoop = state.lifecycle === "crash_loop";
|
|
367
368
|
state.startupConsecutiveHealthFailures = 0;
|
|
368
369
|
clearDegradedHealthCheckTimer();
|
|
369
370
|
clearExpectedRestartWindow();
|
|
370
371
|
state.health = "healthy";
|
|
371
|
-
|
|
372
|
+
state.lifecycle = "running";
|
|
372
373
|
if (!state.uptimeStartedAt || wasUnhealthy) state.uptimeStartedAt = Date.now();
|
|
373
374
|
state.repairAttempts = 0;
|
|
374
375
|
state.crashRecoveryActive = false;
|
|
376
|
+
if (recoveredFromCrashLoop) {
|
|
377
|
+
logEvent(
|
|
378
|
+
"recovery",
|
|
379
|
+
source,
|
|
380
|
+
"ok",
|
|
381
|
+
{
|
|
382
|
+
previousLifecycle: "crash_loop",
|
|
383
|
+
health: "healthy",
|
|
384
|
+
},
|
|
385
|
+
correlationId,
|
|
386
|
+
);
|
|
387
|
+
}
|
|
375
388
|
if (state.pendingRecoveryNoticeSource) {
|
|
376
389
|
const recoverySource = state.pendingRecoveryNoticeSource;
|
|
377
390
|
state.pendingRecoveryNoticeSource = "";
|
package/lib/server.js
CHANGED