refactor(commands): share vllm setup

This commit is contained in:
Peter Steinberger
2026-02-14 15:22:41 +00:00
parent 64df787448
commit 8d1a1d9e86
3 changed files with 88 additions and 133 deletions

View File

@@ -1,16 +1,6 @@
import type { OpenClawConfig } from "../config/config.js";
import type { ApplyAuthChoiceParams, ApplyAuthChoiceResult } from "./auth-choice.apply.js";
import { upsertAuthProfileWithLock } from "../agents/auth-profiles.js";
const VLLM_DEFAULT_BASE_URL = "http://127.0.0.1:8000/v1";
const VLLM_DEFAULT_CONTEXT_WINDOW = 128000;
const VLLM_DEFAULT_MAX_TOKENS = 8192;
const VLLM_DEFAULT_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
};
import { promptAndConfigureVllm } from "./vllm-setup.js";
function applyVllmDefaultModel(cfg: OpenClawConfig, modelRef: string): OpenClawConfig {
const existingModel = cfg.agents?.defaults?.model;
@@ -41,63 +31,12 @@ export async function applyAuthChoiceVllm(
return null;
}
const baseUrlRaw = await params.prompter.text({
message: "vLLM base URL",
initialValue: VLLM_DEFAULT_BASE_URL,
placeholder: VLLM_DEFAULT_BASE_URL,
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const apiKeyRaw = await params.prompter.text({
message: "vLLM API key",
placeholder: "sk-... (or any non-empty string)",
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const modelIdRaw = await params.prompter.text({
message: "vLLM model",
placeholder: "meta-llama/Meta-Llama-3-8B-Instruct",
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const baseUrl = String(baseUrlRaw ?? "")
.trim()
.replace(/\/+$/, "");
const apiKey = String(apiKeyRaw ?? "").trim();
const modelId = String(modelIdRaw ?? "").trim();
const modelRef = `vllm/${modelId}`;
await upsertAuthProfileWithLock({
profileId: "vllm:default",
credential: { type: "api_key", provider: "vllm", key: apiKey },
const { config: nextConfig, modelRef } = await promptAndConfigureVllm({
cfg: params.config,
prompter: params.prompter,
agentDir: params.agentDir,
});
const nextConfig: OpenClawConfig = {
...params.config,
models: {
...params.config.models,
mode: params.config.models?.mode ?? "merge",
providers: {
...params.config.models?.providers,
vllm: {
baseUrl,
api: "openai-completions",
apiKey: "VLLM_API_KEY",
models: [
{
id: modelId,
name: modelId,
reasoning: false,
input: ["text"],
cost: VLLM_DEFAULT_COST,
contextWindow: VLLM_DEFAULT_CONTEXT_WINDOW,
maxTokens: VLLM_DEFAULT_MAX_TOKENS,
},
],
},
},
},
};
if (!params.setDefaultModel) {
return { config: nextConfig, agentModelOverride: modelRef };
}

View File

@@ -1,10 +1,6 @@
import type { OpenClawConfig } from "../config/config.js";
import type { WizardPrompter, WizardSelectOption } from "../wizard/prompts.js";
import {
ensureAuthProfileStore,
listProfilesForProvider,
upsertAuthProfileWithLock,
} from "../agents/auth-profiles.js";
import { ensureAuthProfileStore, listProfilesForProvider } from "../agents/auth-profiles.js";
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
import { getCustomProviderApiKey, resolveEnvApiKey } from "../agents/model-auth.js";
import { loadModelCatalog } from "../agents/model-catalog.js";
@@ -17,20 +13,12 @@ import {
} from "../agents/model-selection.js";
import { formatTokenK } from "./models/shared.js";
import { OPENAI_CODEX_DEFAULT_MODEL } from "./openai-codex-model-default.js";
import { promptAndConfigureVllm } from "./vllm-setup.js";
const KEEP_VALUE = "__keep__";
const MANUAL_VALUE = "__manual__";
const VLLM_VALUE = "__vllm__";
const PROVIDER_FILTER_THRESHOLD = 30;
const VLLM_DEFAULT_BASE_URL = "http://127.0.0.1:8000/v1";
const VLLM_DEFAULT_CONTEXT_WINDOW = 128000;
const VLLM_DEFAULT_MAX_TOKENS = 8192;
const VLLM_DEFAULT_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
};
// Models that are internal routing features and should not be shown in selection lists.
// These may be valid as defaults (e.g., set automatically during auth flow) but are not
@@ -327,63 +315,13 @@ export async function promptDefaultModel(
);
return {};
}
const baseUrlRaw = await params.prompter.text({
message: "vLLM base URL",
initialValue: VLLM_DEFAULT_BASE_URL,
placeholder: VLLM_DEFAULT_BASE_URL,
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const apiKeyRaw = await params.prompter.text({
message: "vLLM API key",
placeholder: "sk-... (or any non-empty string)",
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const modelIdRaw = await params.prompter.text({
message: "vLLM model",
placeholder: "meta-llama/Meta-Llama-3-8B-Instruct",
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const baseUrl = String(baseUrlRaw ?? "")
.trim()
.replace(/\/+$/, "");
const apiKey = String(apiKeyRaw ?? "").trim();
const modelId = String(modelIdRaw ?? "").trim();
await upsertAuthProfileWithLock({
profileId: "vllm:default",
credential: { type: "api_key", provider: "vllm", key: apiKey },
const { config: nextConfig, modelRef } = await promptAndConfigureVllm({
cfg,
prompter: params.prompter,
agentDir,
});
const nextConfig: OpenClawConfig = {
...cfg,
models: {
...cfg.models,
mode: cfg.models?.mode ?? "merge",
providers: {
...cfg.models?.providers,
vllm: {
baseUrl,
api: "openai-completions",
apiKey: "VLLM_API_KEY",
models: [
{
id: modelId,
name: modelId,
reasoning: false,
input: ["text"],
cost: VLLM_DEFAULT_COST,
contextWindow: VLLM_DEFAULT_CONTEXT_WINDOW,
maxTokens: VLLM_DEFAULT_MAX_TOKENS,
},
],
},
},
},
};
return { model: `vllm/${modelId}`, config: nextConfig };
return { model: modelRef, config: nextConfig };
}
return { model: String(selection) };
}

View File

@@ -0,0 +1,78 @@
import type { OpenClawConfig } from "../config/config.js";
import type { WizardPrompter } from "../wizard/prompts.js";
import { upsertAuthProfileWithLock } from "../agents/auth-profiles.js";
export const VLLM_DEFAULT_BASE_URL = "http://127.0.0.1:8000/v1";
export const VLLM_DEFAULT_CONTEXT_WINDOW = 128000;
export const VLLM_DEFAULT_MAX_TOKENS = 8192;
export const VLLM_DEFAULT_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
};
export async function promptAndConfigureVllm(params: {
cfg: OpenClawConfig;
prompter: WizardPrompter;
agentDir?: string;
}): Promise<{ config: OpenClawConfig; modelId: string; modelRef: string }> {
const baseUrlRaw = await params.prompter.text({
message: "vLLM base URL",
initialValue: VLLM_DEFAULT_BASE_URL,
placeholder: VLLM_DEFAULT_BASE_URL,
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const apiKeyRaw = await params.prompter.text({
message: "vLLM API key",
placeholder: "sk-... (or any non-empty string)",
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const modelIdRaw = await params.prompter.text({
message: "vLLM model",
placeholder: "meta-llama/Meta-Llama-3-8B-Instruct",
validate: (value) => (value?.trim() ? undefined : "Required"),
});
const baseUrl = String(baseUrlRaw ?? "")
.trim()
.replace(/\/+$/, "");
const apiKey = String(apiKeyRaw ?? "").trim();
const modelId = String(modelIdRaw ?? "").trim();
const modelRef = `vllm/${modelId}`;
await upsertAuthProfileWithLock({
profileId: "vllm:default",
credential: { type: "api_key", provider: "vllm", key: apiKey },
agentDir: params.agentDir,
});
const nextConfig: OpenClawConfig = {
...params.cfg,
models: {
...params.cfg.models,
mode: params.cfg.models?.mode ?? "merge",
providers: {
...params.cfg.models?.providers,
vllm: {
baseUrl,
api: "openai-completions",
apiKey: "VLLM_API_KEY",
models: [
{
id: modelId,
name: modelId,
reasoning: false,
input: ["text"],
cost: VLLM_DEFAULT_COST,
contextWindow: VLLM_DEFAULT_CONTEXT_WINDOW,
maxTokens: VLLM_DEFAULT_MAX_TOKENS,
},
],
},
},
},
};
return { config: nextConfig, modelId, modelRef };
}