Skip to content

Commit 438991b

Browse files
authored
Commands: lazy-load model picker provider runtime (openclaw#47536)
* Commands: lazy-load model picker provider runtime * Tests: cover model picker runtime boundary
1 parent 6309587 commit 438991b

File tree

3 files changed

+54
-31
lines changed

3 files changed

+54
-31
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export {
2+
resolveProviderModelPickerEntries,
3+
resolveProviderPluginChoice,
4+
runProviderModelSelectedHook,
5+
} from "../plugins/provider-wizard.js";
6+
export { resolvePluginProviders } from "../plugins/providers.js";
7+
export { runProviderPluginAuthMethod } from "./auth-choice.apply.plugin-provider.js";

src/commands/model-picker.test.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, expect, it, vi } from "vitest";
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
22
import type { OpenClawConfig } from "../config/config.js";
33
import {
44
applyModelAllowlist,
@@ -37,19 +37,13 @@ vi.mock("../agents/model-auth.js", () => ({
3737
const resolveProviderModelPickerEntries = vi.hoisted(() => vi.fn(() => []));
3838
const resolveProviderPluginChoice = vi.hoisted(() => vi.fn());
3939
const runProviderModelSelectedHook = vi.hoisted(() => vi.fn(async () => {}));
40-
vi.mock("../plugins/provider-wizard.js", () => ({
40+
const resolvePluginProviders = vi.hoisted(() => vi.fn(() => []));
41+
const runProviderPluginAuthMethod = vi.hoisted(() => vi.fn());
42+
vi.mock("./model-picker.runtime.js", () => ({
4143
resolveProviderModelPickerEntries,
4244
resolveProviderPluginChoice,
4345
runProviderModelSelectedHook,
44-
}));
45-
46-
const resolvePluginProviders = vi.hoisted(() => vi.fn(() => []));
47-
vi.mock("../plugins/providers.js", () => ({
4846
resolvePluginProviders,
49-
}));
50-
51-
const runProviderPluginAuthMethod = vi.hoisted(() => vi.fn());
52-
vi.mock("./auth-choice.apply.plugin-provider.js", () => ({
5347
runProviderPluginAuthMethod,
5448
}));
5549

@@ -77,6 +71,10 @@ function createSelectAllMultiselect() {
7771
return vi.fn(async (params) => params.options.map((option: { value: string }) => option.value));
7872
}
7973

74+
beforeEach(() => {
75+
vi.clearAllMocks();
76+
});
77+
8078
describe("promptDefaultModel", () => {
8179
it("supports configuring vLLM during onboarding", async () => {
8280
loadModelCatalog.mockResolvedValue([
@@ -211,6 +209,7 @@ describe("router model filtering", () => {
211209
const allowlistCall = multiselect.mock.calls[0]?.[0];
212210
expectRouterModelFiltering(allowlistCall?.options as Array<{ value: string }>);
213211
expect(allowlistCall?.searchable).toBe(true);
212+
expect(runProviderPluginAuthMethod).not.toHaveBeenCalled();
214213
});
215214
});
216215

src/commands/model-picker.ts

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,8 @@ import {
1111
} from "../agents/model-selection.js";
1212
import type { OpenClawConfig } from "../config/config.js";
1313
import { resolveAgentModelPrimaryValue } from "../config/model-input.js";
14-
import {
15-
resolveProviderPluginChoice,
16-
resolveProviderModelPickerEntries,
17-
runProviderModelSelectedHook,
18-
} from "../plugins/provider-wizard.js";
19-
import { resolvePluginProviders } from "../plugins/providers.js";
14+
import type { ProviderPlugin } from "../plugins/types.js";
2015
import type { WizardPrompter, WizardSelectOption } from "../wizard/prompts.js";
21-
import { runProviderPluginAuthMethod } from "./auth-choice.apply.plugin-provider.js";
2216
import { formatTokenK } from "./models/shared.js";
2317
import { OPENAI_CODEX_DEFAULT_MODEL } from "./openai-codex-model-default.js";
2418

@@ -49,6 +43,10 @@ type PromptDefaultModelParams = {
4943
type PromptDefaultModelResult = { model?: string; config?: OpenClawConfig };
5044
type PromptModelAllowlistResult = { models?: string[] };
5145

46+
async function loadModelPickerRuntime() {
47+
return import("./model-picker.runtime.js");
48+
}
49+
5250
function hasAuthForProvider(
5351
provider: string,
5452
cfg: OpenClawConfig,
@@ -295,6 +293,7 @@ export async function promptDefaultModel(
295293
options.push({ value: MANUAL_VALUE, label: "Enter model manually" });
296294
}
297295
if (includeProviderPluginSetups && agentDir) {
296+
const { resolveProviderModelPickerEntries } = await loadModelPickerRuntime();
298297
options.push(
299298
...resolveProviderModelPickerEntries({
300299
config: cfg,
@@ -347,20 +346,24 @@ export async function promptDefaultModel(
347346
initialValue: configuredRaw || resolvedKey || undefined,
348347
});
349348
}
350-
const pluginProviders = resolvePluginProviders({
351-
config: cfg,
352-
workspaceDir: params.workspaceDir,
353-
env: params.env,
354-
});
355-
const pluginResolution = selection.startsWith("provider-plugin:")
356-
? selection
357-
: selection.includes("/")
358-
? null
359-
: pluginProviders.some(
360-
(provider) => normalizeProviderId(provider.id) === normalizeProviderId(selection),
361-
)
362-
? selection
363-
: null;
349+
350+
let pluginResolution: string | null = null;
351+
let pluginProviders: ProviderPlugin[] = [];
352+
if (selection.startsWith("provider-plugin:")) {
353+
pluginResolution = selection;
354+
} else if (!selection.includes("/")) {
355+
const { resolvePluginProviders } = await loadModelPickerRuntime();
356+
pluginProviders = resolvePluginProviders({
357+
config: cfg,
358+
workspaceDir: params.workspaceDir,
359+
env: params.env,
360+
});
361+
pluginResolution = pluginProviders.some(
362+
(provider) => normalizeProviderId(provider.id) === normalizeProviderId(selection),
363+
)
364+
? selection
365+
: null;
366+
}
364367
if (pluginResolution) {
365368
if (!agentDir || !params.runtime) {
366369
await params.prompter.note(
@@ -369,6 +372,19 @@ export async function promptDefaultModel(
369372
);
370373
return {};
371374
}
375+
const {
376+
resolvePluginProviders,
377+
resolveProviderPluginChoice,
378+
runProviderModelSelectedHook,
379+
runProviderPluginAuthMethod,
380+
} = await loadModelPickerRuntime();
381+
if (pluginProviders.length === 0) {
382+
pluginProviders = resolvePluginProviders({
383+
config: cfg,
384+
workspaceDir: params.workspaceDir,
385+
env: params.env,
386+
});
387+
}
372388
const resolved = resolveProviderPluginChoice({
373389
providers: pluginProviders,
374390
choice: pluginResolution,
@@ -397,6 +413,7 @@ export async function promptDefaultModel(
397413
return { model: applied.defaultModel, config: applied.config };
398414
}
399415
const model = String(selection);
416+
const { runProviderModelSelectedHook } = await loadModelPickerRuntime();
400417
await runProviderModelSelectedHook({
401418
config: cfg,
402419
model,

0 commit comments

Comments
 (0)