import { upsertAuthProfile } from "../agents/auth-profiles/profiles.js" ;
import type { OpenClawConfig } from "../config/types.openclaw.js" ;
import type { SecretInput } from "../config/types.secrets.js" ;
import { createLazyRuntimeSurface } from "../shared/lazy-runtime.js" ;
import { normalizeOptionalString } from "../shared/string-coerce.js" ;
import { normalizeStringEntries } from "../shared/string-normalization.js" ;
import { normalizeOptionalSecretInput } from "../utils/normalize-secret-input.js" ;
import type {
ProviderAuthMethod,
ProviderAuthMethodNonInteractiveContext,
ProviderPluginWizardSetup,
} from "./types.js" ;
type ProviderApiKeyAuthMethodOptions = {
providerId: string;
methodId: string;
label: string;
hint?: string;
wizard?: ProviderPluginWizardSetup;
optionKey: string;
flagName: `--${string}`;
envVar: string;
promptMessage: string;
profileId?: string;
profileIds?: string[];
allowProfile?: boolean ;
defaultModel?: string;
expectedProviders?: string[];
metadata?: Record<string, string>;
noteMessage?: string;
noteTitle?: string;
applyConfig?: (cfg: OpenClawConfig) => OpenClawConfig;
};
const loadProviderApiKeyAuthRuntime = createLazyRuntimeSurface(
() => import ("./provider-api-key-auth.runtime.js" ),
({ providerApiKeyAuthRuntime }) => providerApiKeyAuthRuntime,
);
function resolveStringOption(opts: Record<string, unknown> | undefined, optionKey: string) {
return normalizeOptionalSecretInput(opts?.[optionKey]);
}
function resolveProfileId(params: { providerId: string; profileId?: string }) {
return normalizeOptionalString(params.profileId) || `${params.providerId}:default `;
}
function resolveProfileIds(params: {
providerId: string;
profileId?: string;
profileIds?: string[];
}) {
const explicit = Array.from(new Set(normalizeStringEntries(params.profileIds ?? [])));
if (explicit.length > 0 ) {
return explicit;
}
return [resolveProfileId(params)];
}
async function applyApiKeyConfig(params: {
ctx: ProviderAuthMethodNonInteractiveContext;
providerId: string;
profileIds: string[];
defaultModel?: string;
applyConfig?: (cfg: OpenClawConfig) => OpenClawConfig;
}) {
const { applyAuthProfileConfig, applyPrimaryModel } = await loadProviderApiKeyAuthRuntime();
let next = params.ctx.config;
for (const profileId of params.profileIds) {
next = applyAuthProfileConfig(next, {
profileId,
provider: normalizeOptionalString(profileId.split(":" , 1 )[0 ]) || params.providerId,
mode: "api_key" ,
});
}
if (params.applyConfig) {
next = params.applyConfig(next);
}
return params.defaultModel ? applyPrimaryModel(next, params.defaultModel) : next;
}
export function createProviderApiKeyAuthMethod(
params: ProviderApiKeyAuthMethodOptions,
): ProviderAuthMethod {
return {
id: params.methodId,
label: params.label,
hint: params.hint,
kind: "api_key" ,
wizard: params.wizard,
run: async (ctx) => {
const opts = ctx.opts as Record<string, unknown> | undefined;
const flagValue = resolveStringOption(opts, params.optionKey);
let capturedSecretInput: SecretInput | undefined;
let capturedCredential = false ;
let capturedMode: "plaintext" | "ref" | undefined;
const {
buildApiKeyCredential,
ensureApiKeyFromOptionEnvOrPrompt,
normalizeApiKeyInput,
validateApiKeyInput,
} = await loadProviderApiKeyAuthRuntime();
await ensureApiKeyFromOptionEnvOrPrompt({
token: flagValue ?? normalizeOptionalSecretInput(ctx.opts?.token),
tokenProvider: flagValue
? params.providerId
: normalizeOptionalSecretInput(ctx.opts?.tokenProvider),
secretInputMode:
ctx.allowSecretRefPrompt === false
? (ctx.secretInputMode ?? "plaintext" )
: ctx.secretInputMode,
config: ctx.config,
env: ctx.env,
expectedProviders: params.expectedProviders ?? [params.providerId],
provider: params.providerId,
envLabel: params.envVar,
promptMessage: params.promptMessage,
normalize: normalizeApiKeyInput,
validate: validateApiKeyInput,
prompter: ctx.prompter,
noteMessage: params.noteMessage,
noteTitle: params.noteTitle,
setCredential: async (apiKey, mode) => {
capturedSecretInput = apiKey;
capturedCredential = true ;
capturedMode = mode;
},
});
if (!capturedCredential) {
throw new Error(`Missing API key input for provider "${params.providerId}" .`);
}
const credentialInput = capturedSecretInput ?? "" ;
const profileIds = resolveProfileIds(params);
return {
profiles: profileIds.map((profileId) => ({
profileId,
credential: buildApiKeyCredential(
normalizeOptionalString(profileId.split(":" , 1 )[0 ]) || params.providerId,
credentialInput,
params.metadata,
capturedMode
? {
secretInputMode: capturedMode,
config: ctx.config,
}
: undefined,
),
})),
...(params.applyConfig ? { configPatch: params.applyConfig(ctx.config) } : {}),
...(params.defaultModel ? { defaultModel: params.defaultModel } : {}),
};
},
runNonInteractive: async (ctx) => {
const opts = ctx.opts as Record<string, unknown> | undefined;
const resolved = await ctx.resolveApiKey({
provider: params.providerId,
flagValue: resolveStringOption(opts, params.optionKey),
flagName: params.flagName,
envVar: params.envVar,
...(params.allowProfile === false ? { allowProfile: false } : {}),
});
if (!resolved) {
return null ;
}
const profileIds = resolveProfileIds(params);
if (resolved.source !== "profile" ) {
for (const profileId of profileIds) {
const credential = ctx.toApiKeyCredential({
provider: normalizeOptionalString(profileId.split(":" , 1 )[0 ]) || params.providerId,
resolved,
...(params.metadata ? { metadata: params.metadata } : {}),
});
if (!credential) {
return null ;
}
upsertAuthProfile({
profileId,
credential,
agentDir: ctx.agentDir,
});
}
}
return await applyApiKeyConfig({
ctx,
providerId: params.providerId,
profileIds,
defaultModel: params.defaultModel,
applyConfig: params.applyConfig,
});
},
};
}
Messung V0.5 in Prozent C=100 H=90 G=95
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland