import { ensureAuthProfileStore, resolveApiKeyForProfile, resolveAuthProfileOrder, } from "../../agents/auth-profiles.js"; import { resolveEnvApiKey } from "../../agents/model-auth.js"; import type { OpenClawConfig } from "../../config/config.js"; import type { RuntimeEnv } from "../../runtime.js"; import { normalizeOptionalSecretInput } from "../../utils/normalize-secret-input.js"; import type { SecretInputMode } from "../onboard-types.js"; export type NonInteractiveApiKeySource = "flag" | "env" | "profile"; async function resolveApiKeyFromProfiles(params: { provider: string; cfg: OpenClawConfig; agentDir?: string; }): Promise { const store = ensureAuthProfileStore(params.agentDir); const order = resolveAuthProfileOrder({ cfg: params.cfg, store, provider: params.provider, }); for (const profileId of order) { const cred = store.profiles[profileId]; if (cred?.type !== "api_key") { continue; } const resolved = await resolveApiKeyForProfile({ cfg: params.cfg, store, profileId, agentDir: params.agentDir, }); if (resolved?.apiKey) { return resolved.apiKey; } } return null; } export async function resolveNonInteractiveApiKey(params: { provider: string; cfg: OpenClawConfig; flagValue?: string; flagName: string; envVar: string; envVarName?: string; runtime: RuntimeEnv; agentDir?: string; allowProfile?: boolean; required?: boolean; secretInputMode?: SecretInputMode; }): Promise<{ key: string; source: NonInteractiveApiKeySource } | null> { const flagKey = normalizeOptionalSecretInput(params.flagValue); const envResolved = resolveEnvApiKey(params.provider); const explicitEnvVar = params.envVarName?.trim(); const explicitEnvKey = explicitEnvVar ? normalizeOptionalSecretInput(process.env[explicitEnvVar]) : undefined; const resolvedEnvKey = envResolved?.apiKey ?? explicitEnvKey; if (params.secretInputMode === "ref") { if (!resolvedEnvKey && flagKey) { params.runtime.error( [ `${params.flagName} cannot be used with --secret-input-mode ref unless ${params.envVar} is set in env.`, `Set ${params.envVar} in env and omit ${params.flagName}, or use --secret-input-mode plaintext.`, ].join("\n"), ); params.runtime.exit(1); return null; } if (resolvedEnvKey) { return { key: resolvedEnvKey, source: "env" }; } } if (flagKey) { return { key: flagKey, source: "flag" }; } if (resolvedEnvKey) { return { key: resolvedEnvKey, source: "env" }; } if (params.allowProfile ?? true) { const profileKey = await resolveApiKeyFromProfiles({ provider: params.provider, cfg: params.cfg, agentDir: params.agentDir, }); if (profileKey) { return { key: profileKey, source: "profile" }; } } if (params.required === false) { return null; } const profileHint = params.allowProfile === false ? "" : `, or existing ${params.provider} API-key profile`; params.runtime.error(`Missing ${params.flagName} (or ${params.envVar} in env${profileHint}).`); params.runtime.exit(1); return null; }