fix: normalize openclaw agent.model object form before .startsWith (#1216)
OpenClaw 2026.5.x writes agents[].model as either a plain string
or as an object { primary, fallbacks }. The status enrichment and
POST cleanup both called .startsWith() on the raw value, which threw
TypeError when the object form was present and made the dashboard
report 'not configured'.
Add a resolveAgentModel helper that accepts both shapes and returns
the string id (model.primary for the object form, empty string for
missing/invalid). Use it when enriching agents in GET so consumers
receive a string model field, and when filtering the list in POST.
Refs decolua/9router#1196
This commit is contained in:
@@ -9,6 +9,15 @@ import os from "os";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
// OpenClaw 2026.5.x writes agents[].model as either a plain string
|
||||
// (legacy) or as an object `{ primary, fallbacks }`. Normalize to the
|
||||
// string id so downstream consumers can call `.startsWith()` safely.
|
||||
const resolveAgentModel = (m) => {
|
||||
if (typeof m === "string") return m;
|
||||
if (m && typeof m === "object") return m.primary ?? "";
|
||||
return "";
|
||||
};
|
||||
|
||||
const getOpenClawDir = () => path.join(os.homedir(), ".openclaw");
|
||||
const getOpenClawSettingsPath = () => path.join(getOpenClawDir(), "openclaw.json");
|
||||
|
||||
@@ -79,12 +88,14 @@ export async function GET() {
|
||||
|
||||
const settings = await readSettings();
|
||||
|
||||
// Enrich agents list with current per-agent model from models.json
|
||||
// Enrich agents list with current per-agent model from models.json.
|
||||
// Coerce agent.model to its string id when OpenClaw stores it as
|
||||
// `{ primary, fallbacks }` so downstream `.startsWith()` calls work.
|
||||
const agentList = settings?.agents?.list || [];
|
||||
const enrichedAgents = await Promise.all(
|
||||
agentList.map(async (agent) => {
|
||||
const agentModel = agent.agentDir ? await readAgentModel(agent.agentDir) : null;
|
||||
return { ...agent, currentModel: agentModel };
|
||||
return { ...agent, model: resolveAgentModel(agent.model), currentModel: agentModel };
|
||||
})
|
||||
);
|
||||
|
||||
@@ -169,10 +180,11 @@ export async function POST(request) {
|
||||
settings.agents.defaults.models[`9router/${m}`] = {};
|
||||
});
|
||||
|
||||
// Remove old 9router model from each agent in agents.list
|
||||
// Remove old 9router model from each agent in agents.list. The
|
||||
// model field may be a plain string or `{ primary, fallbacks }`.
|
||||
if (settings.agents.list) {
|
||||
settings.agents.list = settings.agents.list.map((agent) => {
|
||||
if (agent.model?.startsWith("9router/")) {
|
||||
if (resolveAgentModel(agent.model).startsWith("9router/")) {
|
||||
const { model: _, ...rest } = agent;
|
||||
return rest;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user