mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:40:44 +00:00
fix(ui): persist default agent via agents list flag
Fix the Control UI Set Default action to persist agents.list[].default instead of the unsupported agents.defaultId config key.\n\nCloses #65565.\n\nThanks @luyao618.
This commit is contained in:
@@ -88,6 +88,7 @@ Docs: https://docs.openclaw.ai
|
||||
- CLI/gateway: reuse cached paired-device auth during `gateway probe` and report post-connect diagnostic failures as degraded reachability, so healthy local gateways are no longer marked unreachable after loopback auth or read timeouts. Fixes #48360. Thanks @RacecarGuy.
|
||||
- Channels/Discord: give Discord Gateway WebSocket handshakes a 30s timeout so stalled TLS/network transitions emit an error and Carbon can continue its reconnect loop instead of leaving the bot silent until restart. Refs #50046. Thanks @codexGW.
|
||||
- Channels/Telegram: suppress standalone failed edit/write warning payloads when a user-facing assistant error reply already covers the turn, while keeping unresolved mutating failures visible behind success-looking or suppressed-error replies. Fixes #39631; refs #73750; carries forward #39636 and #39717; leaves #39406 for configurable delivery policy. Thanks @Bartok9 and @Bortlesboat.
|
||||
- Control UI/agents: persist the Set Default action through `agents.list[].default` instead of writing the unsupported `agents.defaultId` field, so saved default-agent changes survive config validation. Fixes #65565; carries forward #72585. Thanks @luyao618.
|
||||
- NVIDIA/NIM: persist the `NVIDIA_API_KEY` provider marker and mark bundled NVIDIA Chat Completions models as string-content compatible, so NIM models load from `models.json` and OpenAI-compatible subagent calls send plain text content. Fixes #73013 and #50107; refs #73014. Thanks @bautrey, @iot2edge, @ifearghal, and @futhgar.
|
||||
- Channels/Discord: let text-only configs drop the `GuildVoiceStates` gateway intent and expose a bounded `/gateway/bot` metadata timeout with rate-limited fallback logs, reducing idle CPU and warning floods. Fixes #73709 and #73585. Thanks @sanchezm86 and @trac3r00.
|
||||
- Agents/sessions: mark same-turn `sessions_send` and A2A reply prompts with an inter-session `isUser=false` envelope before they reach the model, so foreign session output no longer lands as bare active user text. Fixes #73702; refs #73698, #73609, #73595, and #73622. Thanks @alvelda.
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
resetConfigPendingChanges,
|
||||
runUpdate,
|
||||
saveConfig,
|
||||
stageDefaultAgentConfigEntry,
|
||||
stageConfigPreset,
|
||||
updateConfigFormValue,
|
||||
removeConfigFormValue,
|
||||
@@ -2148,10 +2149,7 @@ export function renderApp(state: AppViewState) {
|
||||
updateConfigFormValue(state, basePath, { primary, fallbacks: normalized });
|
||||
},
|
||||
onSetDefault: (agentId) => {
|
||||
if (!configValue) {
|
||||
return;
|
||||
}
|
||||
updateConfigFormValue(state, ["agents", "defaultId"], agentId);
|
||||
stageDefaultAgentConfigEntry(state, agentId);
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
resetConfigPendingChanges,
|
||||
runUpdate,
|
||||
saveConfig,
|
||||
stageDefaultAgentConfigEntry,
|
||||
stageConfigPreset,
|
||||
updateConfigFormValue,
|
||||
type ConfigState,
|
||||
@@ -477,6 +478,50 @@ describe("agent config helpers", () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("sets default via agents.list[].default instead of agents.defaultId", () => {
|
||||
const state = createState();
|
||||
state.configSnapshot = {
|
||||
config: {
|
||||
agents: {
|
||||
list: [{ id: "alpha", default: true }, { id: "beta" }],
|
||||
},
|
||||
},
|
||||
valid: true,
|
||||
issues: [],
|
||||
raw: "{\n}\n",
|
||||
};
|
||||
|
||||
const updated = stageDefaultAgentConfigEntry(state, "beta");
|
||||
|
||||
expect(updated).toBe(true);
|
||||
expect(state.configFormDirty).toBe(true);
|
||||
expect(state.configForm).toEqual({
|
||||
agents: {
|
||||
list: [{ id: "alpha" }, { id: "beta", default: true }],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("does not stage agents.defaultId when the target agent is absent", () => {
|
||||
const state = createState();
|
||||
state.configSnapshot = {
|
||||
config: {
|
||||
agents: {
|
||||
list: [{ id: "alpha", default: true }],
|
||||
},
|
||||
},
|
||||
valid: true,
|
||||
issues: [],
|
||||
raw: "{\n}\n",
|
||||
};
|
||||
|
||||
const updated = stageDefaultAgentConfigEntry(state, "beta");
|
||||
|
||||
expect(updated).toBe(false);
|
||||
expect(state.configFormDirty).toBe(false);
|
||||
expect(state.configForm).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyConfig", () => {
|
||||
|
||||
@@ -359,6 +359,38 @@ export function ensureAgentConfigEntry(state: ConfigState, agentId: string): num
|
||||
return nextIndex;
|
||||
}
|
||||
|
||||
export function stageDefaultAgentConfigEntry(state: ConfigState, agentId: string): boolean {
|
||||
const normalizedAgentId = agentId.trim();
|
||||
if (!normalizedAgentId) {
|
||||
return false;
|
||||
}
|
||||
const source =
|
||||
state.configForm ?? (state.configSnapshot?.config as Record<string, unknown> | null);
|
||||
const targetIndex = findAgentConfigEntryIndex(source, normalizedAgentId);
|
||||
if (targetIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
mutateConfigForm(state, (draft) => {
|
||||
const list = (draft as { agents?: { list?: unknown[] } } | null)?.agents?.list;
|
||||
if (!Array.isArray(list)) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const entry = list[i];
|
||||
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
||||
continue;
|
||||
}
|
||||
const record = entry as Record<string, unknown>;
|
||||
if (i === targetIndex) {
|
||||
record.default = true;
|
||||
} else {
|
||||
delete record.default;
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function openConfigFile(state: ConfigState): Promise<void> {
|
||||
if (!state.client || !state.connected) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user