refactor: dedupe provider reader helpers
This commit is contained in:
@@ -17,6 +17,7 @@ import { resolveOwningPluginIdsForProvider } from "../plugins/providers.js";
|
||||
import type { ProviderPlugin } from "../plugins/types.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { createLazyRuntimeSurface } from "../shared/lazy-runtime.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import type { WizardPrompter, WizardSelectOption } from "../wizard/prompts.js";
|
||||
|
||||
export { applyPrimaryModel } from "../plugins/provider-model-primary.js";
|
||||
@@ -221,7 +222,9 @@ async function promptManualModel(params: {
|
||||
message: params.allowBlank ? "Default model (blank to keep)" : "Default model",
|
||||
initialValue: params.initialValue,
|
||||
placeholder: "provider/model",
|
||||
validate: params.allowBlank ? undefined : (value) => (value?.trim() ? undefined : "Required"),
|
||||
validate: params.allowBlank
|
||||
? undefined
|
||||
: (value) => (normalizeOptionalString(value) ? undefined : "Required"),
|
||||
});
|
||||
const model = String(modelInput ?? "").trim();
|
||||
if (!model) {
|
||||
@@ -410,7 +413,7 @@ export async function promptDefaultModel(
|
||||
const includeManual = params.includeManual ?? true;
|
||||
const includeProviderPluginSetups = params.includeProviderPluginSetups ?? false;
|
||||
const ignoreAllowlist = params.ignoreAllowlist ?? false;
|
||||
const preferredProvider = params.preferredProvider?.trim()
|
||||
const preferredProvider = normalizeOptionalString(params.preferredProvider)
|
||||
? normalizeProviderId(params.preferredProvider)
|
||||
: undefined;
|
||||
const configuredRaw = resolveConfiguredModelRaw(cfg);
|
||||
@@ -578,7 +581,7 @@ export async function promptModelAllowlist(params: {
|
||||
const existingKeys = resolveConfiguredModelKeys(cfg);
|
||||
const allowedKeys = normalizeModelKeys(params.allowedKeys ?? []);
|
||||
const allowedKeySet = allowedKeys.length > 0 ? new Set(allowedKeys) : null;
|
||||
const preferredProvider = params.preferredProvider?.trim()
|
||||
const preferredProvider = normalizeOptionalString(params.preferredProvider)
|
||||
? normalizeProviderId(params.preferredProvider)
|
||||
: undefined;
|
||||
const resolved = resolveConfiguredModelRef({
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from "../plugins/provider-wizard.js";
|
||||
import { resolvePluginProviders } from "../plugins/providers.runtime.js";
|
||||
import type { ProviderPlugin } from "../plugins/types.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import type { FlowContribution, FlowOption } from "./types.js";
|
||||
import { sortFlowContributionsByLabel } from "./types.js";
|
||||
|
||||
@@ -56,9 +57,9 @@ function resolveProviderDocsById(params?: {
|
||||
mode: "setup",
|
||||
})
|
||||
.filter((provider): provider is ProviderPlugin & { docsPath: string } =>
|
||||
Boolean(provider.docsPath?.trim()),
|
||||
Boolean(normalizeOptionalString(provider.docsPath)),
|
||||
)
|
||||
.map((provider) => [provider.id, provider.docsPath.trim()]),
|
||||
.map((provider) => [provider.id, normalizeOptionalString(provider.docsPath)!]),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { PluginWebSearchProviderEntry } from "../plugins/types.js";
|
||||
import { resolvePluginWebSearchProviders } from "../plugins/web-search-providers.runtime.js";
|
||||
import { sortWebSearchProviders } from "../plugins/web-search-providers.shared.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
import type { FlowContribution, FlowOption } from "./types.js";
|
||||
import { sortFlowContributionsByLabel } from "./types.js";
|
||||
@@ -40,7 +41,7 @@ function resolveSearchProviderCredentialLabel(
|
||||
if (entry.requiresCredential === false) {
|
||||
return `${entry.label} setup`;
|
||||
}
|
||||
return entry.credentialLabel?.trim() || `${entry.label} API key`;
|
||||
return normalizeOptionalString(entry.credentialLabel) || `${entry.label} API key`;
|
||||
}
|
||||
|
||||
export function listSearchProviderOptions(
|
||||
@@ -107,7 +108,7 @@ function resolveSearchProviderEntry(
|
||||
}
|
||||
|
||||
export function hasKeyInEnv(entry: Pick<PluginWebSearchProviderEntry, "envVars">): boolean {
|
||||
return entry.envVars.some((k) => Boolean(process.env[k]?.trim()));
|
||||
return entry.envVars.some((k) => Boolean(normalizeOptionalString(process.env[k])));
|
||||
}
|
||||
|
||||
function providerNeedsCredential(
|
||||
@@ -154,13 +155,15 @@ function buildSearchEnvRef(config: OpenClawConfig, provider: SearchProvider): Se
|
||||
resolveSearchProviderEntry(config, provider) ??
|
||||
listSearchProviderOptions(config).find((candidate) => candidate.id === provider) ??
|
||||
listSearchProviderOptions().find((candidate) => candidate.id === provider);
|
||||
const envVar = entry?.envVars.find((k) => Boolean(process.env[k]?.trim())) ?? entry?.envVars[0];
|
||||
if (!envVar) {
|
||||
const resolvedEnvVar =
|
||||
entry?.envVars.find((k) => Boolean(normalizeOptionalString(process.env[k]))) ??
|
||||
entry?.envVars[0];
|
||||
if (!resolvedEnvVar) {
|
||||
throw new Error(
|
||||
`No env var mapping for search provider "${provider}" at ${entry?.credentialPath ?? "unknown path"} in secret-input-mode=ref.`,
|
||||
);
|
||||
}
|
||||
return { source: "env", provider: DEFAULT_SECRET_PROVIDER_ALIAS, id: envVar };
|
||||
return { source: "env", provider: DEFAULT_SECRET_PROVIDER_ALIAS, id: resolvedEnvVar };
|
||||
}
|
||||
|
||||
function resolveSearchSecretInput(
|
||||
@@ -478,7 +481,7 @@ export async function runSearchSetupFlow(
|
||||
placeholder: keyConfigured ? "Leave blank to keep current" : entry.placeholder,
|
||||
});
|
||||
|
||||
const key = keyInput?.trim() ?? "";
|
||||
const key = normalizeOptionalString(keyInput) ?? "";
|
||||
if (key) {
|
||||
const secretInput = resolveSearchSecretInput(config, choice, key, opts?.secretInputMode);
|
||||
return await finalizeSearchProviderSetup({
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
isValidFileSecretRefId,
|
||||
resolveDefaultSecretProviderAlias,
|
||||
} from "../secrets/ref-contract.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
|
||||
let secretResolvePromise: Promise<typeof import("../secrets/resolve.js")> | undefined;
|
||||
@@ -40,7 +41,7 @@ export function extractEnvVarFromSourceLabel(source: string): string | undefined
|
||||
|
||||
function resolveDefaultProviderEnvVar(provider: string): string | undefined {
|
||||
const envVars = getProviderEnvVars(provider);
|
||||
return envVars?.find((candidate) => candidate.trim().length > 0);
|
||||
return envVars?.find((candidate) => normalizeOptionalString(candidate) !== undefined);
|
||||
}
|
||||
|
||||
function resolveDefaultFilePointerId(provider: string): string {
|
||||
@@ -60,7 +61,7 @@ export function resolveRefFallbackInput(params: {
|
||||
);
|
||||
}
|
||||
const env = params.env ?? process.env;
|
||||
const value = env[fallbackEnvVar]?.trim();
|
||||
const value = normalizeOptionalString(env[fallbackEnvVar]);
|
||||
if (!value) {
|
||||
throw new Error(
|
||||
`Environment variable "${fallbackEnvVar}" is required for --secret-input-mode ref in non-interactive setup.`,
|
||||
@@ -99,7 +100,7 @@ async function promptEnvSecretRefForSetup(params: {
|
||||
'Use an env var name like "OPENAI_API_KEY" (uppercase letters, numbers, underscores).'
|
||||
);
|
||||
}
|
||||
if (!env[candidate]?.trim()) {
|
||||
if (!normalizeOptionalString(env[candidate])) {
|
||||
return (
|
||||
params.copy?.envVarMissingError?.(candidate) ??
|
||||
`Environment variable "${candidate}" is missing or empty in this session.`
|
||||
@@ -116,7 +117,7 @@ async function promptEnvSecretRefForSetup(params: {
|
||||
`No valid environment variable name provided for provider "${params.provider}".`,
|
||||
);
|
||||
}
|
||||
const resolvedValue = env[envVar]?.trim();
|
||||
const resolvedValue = normalizeOptionalString(env[envVar]);
|
||||
if (!resolvedValue) {
|
||||
throw new Error(`Environment variable "${envVar}" is missing or empty in this session.`);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DEFAULT_PROVIDER } from "../agents/defaults.js";
|
||||
import { normalizeProviderId } from "../agents/model-selection.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
import { resolvePluginProviders } from "./providers.runtime.js";
|
||||
import type {
|
||||
@@ -31,18 +32,18 @@ export type ProviderModelPickerEntry = {
|
||||
};
|
||||
|
||||
function normalizeChoiceId(choiceId: string): string {
|
||||
return choiceId.trim();
|
||||
return normalizeOptionalString(choiceId) ?? "";
|
||||
}
|
||||
|
||||
function resolveWizardSetupChoiceId(
|
||||
provider: ProviderPlugin,
|
||||
wizard: ProviderPluginWizardSetup,
|
||||
): string {
|
||||
const explicit = wizard.choiceId?.trim();
|
||||
const explicit = normalizeOptionalString(wizard.choiceId);
|
||||
if (explicit) {
|
||||
return explicit;
|
||||
}
|
||||
const explicitMethodId = wizard.methodId?.trim();
|
||||
const explicitMethodId = normalizeOptionalString(wizard.methodId);
|
||||
if (explicitMethodId) {
|
||||
return buildProviderPluginMethodChoice(provider.id, explicitMethodId);
|
||||
}
|
||||
@@ -56,11 +57,13 @@ function resolveMethodById(
|
||||
provider: ProviderPlugin,
|
||||
methodId?: string,
|
||||
): ProviderAuthMethod | undefined {
|
||||
const normalizedMethodId = methodId?.trim().toLowerCase();
|
||||
const normalizedMethodId = normalizeOptionalString(methodId)?.toLowerCase();
|
||||
if (!normalizedMethodId) {
|
||||
return provider.auth[0];
|
||||
}
|
||||
return provider.auth.find((method) => method.id.trim().toLowerCase() === normalizedMethodId);
|
||||
return provider.auth.find(
|
||||
(method) => normalizeOptionalString(method.id)?.toLowerCase() === normalizedMethodId,
|
||||
);
|
||||
}
|
||||
|
||||
function listMethodWizardSetups(provider: ProviderPlugin): Array<{
|
||||
@@ -80,16 +83,16 @@ function buildSetupOptionForMethod(params: {
|
||||
method: ProviderAuthMethod;
|
||||
value: string;
|
||||
}): ProviderWizardOption {
|
||||
const normalizedGroupId = params.wizard.groupId?.trim() || params.provider.id;
|
||||
const normalizedGroupId = normalizeOptionalString(params.wizard.groupId) || params.provider.id;
|
||||
return {
|
||||
value: normalizeChoiceId(params.value),
|
||||
label:
|
||||
params.wizard.choiceLabel?.trim() ||
|
||||
normalizeOptionalString(params.wizard.choiceLabel) ||
|
||||
(params.provider.auth.length === 1 ? params.provider.label : params.method.label),
|
||||
hint: params.wizard.choiceHint?.trim() || params.method.hint,
|
||||
hint: normalizeOptionalString(params.wizard.choiceHint) || params.method.hint,
|
||||
groupId: normalizedGroupId,
|
||||
groupLabel: params.wizard.groupLabel?.trim() || params.provider.label,
|
||||
groupHint: params.wizard.groupHint?.trim(),
|
||||
groupLabel: normalizeOptionalString(params.wizard.groupLabel) || params.provider.label,
|
||||
groupHint: normalizeOptionalString(params.wizard.groupHint),
|
||||
...(params.wizard.onboardingScopes ? { onboardingScopes: params.wizard.onboardingScopes } : {}),
|
||||
...(typeof params.wizard.assistantPriority === "number" &&
|
||||
Number.isFinite(params.wizard.assistantPriority)
|
||||
@@ -102,7 +105,7 @@ function buildSetupOptionForMethod(params: {
|
||||
}
|
||||
|
||||
export function buildProviderPluginMethodChoice(providerId: string, methodId: string): string {
|
||||
return `${PROVIDER_PLUGIN_CHOICE_PREFIX}${providerId.trim()}:${methodId.trim()}`;
|
||||
return `${PROVIDER_PLUGIN_CHOICE_PREFIX}${normalizeChoiceId(providerId)}:${normalizeChoiceId(methodId)}`;
|
||||
}
|
||||
|
||||
function resolveProviderWizardProviders(params: {
|
||||
@@ -134,7 +137,9 @@ export function resolveProviderWizardOptions(params: {
|
||||
provider,
|
||||
wizard,
|
||||
method,
|
||||
value: wizard.choiceId?.trim() || buildProviderPluginMethodChoice(provider.id, method.id),
|
||||
value:
|
||||
normalizeOptionalString(wizard.choiceId) ||
|
||||
buildProviderPluginMethodChoice(provider.id, method.id),
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -177,7 +182,7 @@ function resolveModelPickerChoiceValue(
|
||||
provider: ProviderPlugin,
|
||||
modelPicker: ProviderPluginWizardModelPicker,
|
||||
): string {
|
||||
const explicitMethodId = modelPicker.methodId?.trim();
|
||||
const explicitMethodId = normalizeOptionalString(modelPicker.methodId);
|
||||
if (explicitMethodId) {
|
||||
return buildProviderPluginMethodChoice(provider.id, explicitMethodId);
|
||||
}
|
||||
@@ -202,8 +207,8 @@ export function resolveProviderModelPickerEntries(params: {
|
||||
}
|
||||
entries.push({
|
||||
value: resolveModelPickerChoiceValue(provider, modelPicker),
|
||||
label: modelPicker.label?.trim() || `${provider.label} (custom)`,
|
||||
hint: modelPicker.hint?.trim(),
|
||||
label: normalizeOptionalString(modelPicker.label) || `${provider.label} (custom)`,
|
||||
hint: normalizeOptionalString(modelPicker.hint),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -218,7 +223,7 @@ export function resolveProviderPluginChoice(params: {
|
||||
method: ProviderAuthMethod;
|
||||
wizard?: ProviderPluginWizardSetup;
|
||||
} | null {
|
||||
const choice = params.choice.trim();
|
||||
const choice = normalizeChoiceId(params.choice);
|
||||
if (!choice) {
|
||||
return null;
|
||||
}
|
||||
@@ -241,7 +246,8 @@ export function resolveProviderPluginChoice(params: {
|
||||
for (const provider of params.providers) {
|
||||
for (const { method, wizard } of listMethodWizardSetups(provider)) {
|
||||
const choiceId =
|
||||
wizard.choiceId?.trim() || buildProviderPluginMethodChoice(provider.id, method.id);
|
||||
normalizeOptionalString(wizard.choiceId) ||
|
||||
buildProviderPluginMethodChoice(provider.id, method.id);
|
||||
if (normalizeChoiceId(choiceId) === choice) {
|
||||
return { provider, method, wizard };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveProviderReasoningOutputModeWithPlugin } from "../plugins/provider-runtime.js";
|
||||
import type { ProviderRuntimeModel } from "../plugins/types.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
const BUILTIN_REASONING_OUTPUT_MODES = {
|
||||
"google-generative-ai": "tagged",
|
||||
@@ -19,7 +20,7 @@ export function resolveReasoningOutputMode(params: {
|
||||
modelApi?: string | null;
|
||||
model?: ProviderRuntimeModel;
|
||||
}): "native" | "tagged" {
|
||||
const provider = params.provider?.trim();
|
||||
const provider = normalizeOptionalString(params.provider);
|
||||
if (!provider) {
|
||||
return "native";
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { NormalizedUsage } from "../agents/usage.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { ModelProviderConfig } from "../config/types.models.js";
|
||||
import { getCachedGatewayModelPricing } from "../gateway/model-pricing-cache.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
|
||||
export type ModelCostConfig = {
|
||||
input: number;
|
||||
@@ -69,8 +70,8 @@ function toResolvedModelKey(params: {
|
||||
model?: string;
|
||||
allowPluginNormalization?: boolean;
|
||||
}): string | null {
|
||||
const provider = params.provider?.trim();
|
||||
const model = params.model?.trim();
|
||||
const provider = normalizeOptionalString(params.provider);
|
||||
const model = normalizeOptionalString(params.model);
|
||||
if (!provider || !model) {
|
||||
return null;
|
||||
}
|
||||
@@ -81,8 +82,8 @@ function toResolvedModelKey(params: {
|
||||
}
|
||||
|
||||
function toDirectModelKey(params: { provider?: string; model?: string }): string | null {
|
||||
const provider = normalizeProviderId(params.provider?.trim() ?? "");
|
||||
const model = params.model?.trim();
|
||||
const provider = normalizeProviderId(normalizeOptionalString(params.provider) ?? "");
|
||||
const model = normalizeOptionalString(params.model);
|
||||
if (!provider || !model) {
|
||||
return null;
|
||||
}
|
||||
@@ -90,8 +91,8 @@ function toDirectModelKey(params: { provider?: string; model?: string }): string
|
||||
}
|
||||
|
||||
function shouldUseNormalizedCostLookup(params: { provider?: string; model?: string }): boolean {
|
||||
const provider = normalizeProviderId(params.provider?.trim() ?? "");
|
||||
const model = params.model?.trim() ?? "";
|
||||
const provider = normalizeProviderId(normalizeOptionalString(params.provider) ?? "");
|
||||
const model = normalizeOptionalString(params.model) ?? "";
|
||||
if (!provider || !model) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user