mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:50:43 +00:00
fix: avoid setup crash on missing provider ids (#66649) (thanks @Tianworld)
* fix(wizard): avoid trim crash on missing provider ids Guard provider id comparisons in setup-mode model selection policy so setup does not crash when plugin provider metadata is missing an id. Fixes #66641 Fixes #66619 Made-with: Cursor * test: fix wizard provider-id regression coverage * fix: avoid setup crash on missing provider ids (#66649) (thanks @Tianworld) --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
@@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Video generation/live tests: bound provider polling for live video smoke, default to the fast non-FAL text-to-video path, and use a one-second lobster prompt so release validation no longer waits indefinitely on slow provider queues.
|
||||
- Memory-core/QMD `memory_get`: reject reads of arbitrary workspace markdown paths and only allow canonical memory files (`MEMORY.md`, `memory.md`, `DREAMS.md`, `dreams.md`, `memory/**`) plus exact paths of active indexed QMD workspace documents, so the QMD memory backend can no longer be used as a generic workspace-file read shim that bypasses `read` tool-policy denials. (#66026) Thanks @eleqtrizit.
|
||||
- Cron/agents: forward embedded-run tool policy and internal event params into the attempt layer so `--tools` allowlists, cron-owned message-tool suppression, explicit message targeting, and command-path internal events all take effect at runtime again. (#62675) Thanks @hexsprite.
|
||||
- Setup/providers: guard preferred-provider lookup during setup so malformed plugin metadata with a missing provider id no longer crashes the wizard with `Cannot read properties of undefined (reading 'trim')`. (#66649) Thanks @Tianworld.
|
||||
|
||||
## 2026.4.14
|
||||
|
||||
|
||||
@@ -278,6 +278,62 @@ describe("runSetupWizard", () => {
|
||||
return dir;
|
||||
}
|
||||
|
||||
it("does not crash when preferred-provider lookup sees a provider without an id", async () => {
|
||||
setupChannels.mockClear();
|
||||
readConfigFileSnapshot.mockResolvedValueOnce({
|
||||
path: "/tmp/.openclaw/openclaw.json",
|
||||
exists: true,
|
||||
raw: "{}",
|
||||
parsed: {},
|
||||
resolved: {},
|
||||
valid: true,
|
||||
config: {},
|
||||
issues: [],
|
||||
warnings: [],
|
||||
legacyIssues: [],
|
||||
});
|
||||
resolvePreferredProviderForAuthChoice.mockResolvedValueOnce("demo-provider");
|
||||
resolvePluginProvidersRuntime.mockReturnValueOnce([
|
||||
{ id: undefined } as unknown as { id: string },
|
||||
{ id: "demo-provider", wizard: { setup: {} } } as unknown as { id: string },
|
||||
]);
|
||||
|
||||
const caseDir = await makeCaseDir("provider-missing-id-");
|
||||
const select = vi.fn(async ({ message }: WizardSelectParams<unknown>) => {
|
||||
if (message === "Select setup mode") return "quickstart";
|
||||
if (message === "Select channel (QuickStart)") return "__skip__";
|
||||
if (message === "How do you want to hatch your bot?") return "skip";
|
||||
return "skip";
|
||||
}) as unknown as WizardPrompter["select"];
|
||||
const confirm = vi.fn(async () => true) as unknown as WizardPrompter["confirm"];
|
||||
const prompter = buildWizardPrompter({ select, confirm });
|
||||
const runtime = createRuntime({ throwsOnExit: true });
|
||||
|
||||
await expect(
|
||||
runSetupWizard(
|
||||
{
|
||||
acceptRisk: true,
|
||||
flow: "quickstart",
|
||||
authChoice: "ollama",
|
||||
installDaemon: false,
|
||||
skipProviders: false,
|
||||
skipSkills: true,
|
||||
skipSearch: true,
|
||||
skipChannels: false,
|
||||
skipUi: true,
|
||||
workspace: caseDir,
|
||||
},
|
||||
runtime,
|
||||
prompter,
|
||||
),
|
||||
).resolves.toBeUndefined();
|
||||
expect(resolvePreferredProviderForAuthChoice).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ choice: "ollama" }),
|
||||
);
|
||||
expect(resolvePluginProvidersRuntime).toHaveBeenCalled();
|
||||
setupChannels.mockClear();
|
||||
});
|
||||
|
||||
it("exits when config is invalid", async () => {
|
||||
readConfigFileSnapshot.mockResolvedValueOnce({
|
||||
path: "/tmp/.openclaw/openclaw.json",
|
||||
|
||||
@@ -58,9 +58,15 @@ async function resolveAuthChoiceModelSelectionPolicy(params: {
|
||||
});
|
||||
const matchedProvider =
|
||||
resolvedChoice?.provider ??
|
||||
(preferredProvider
|
||||
? providers.find((provider) => provider.id.trim() === preferredProvider.trim())
|
||||
: undefined);
|
||||
(() => {
|
||||
const preferredId = preferredProvider?.trim();
|
||||
if (!preferredId) {
|
||||
return undefined;
|
||||
}
|
||||
return providers.find(
|
||||
(provider) => typeof provider.id === "string" && provider.id.trim() === preferredId,
|
||||
);
|
||||
})();
|
||||
const setupPolicy =
|
||||
resolvedChoice?.wizard?.modelSelection ?? matchedProvider?.wizard?.setup?.modelSelection;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user