UNPKG

@gguf/claw

Version:

WhatsApp gateway CLI (Baileys web) with Pi RPC agent

1,355 lines (1,333 loc) 89.5 kB
import { l as createSubsystemLogger, w as resolveUserPath } from "./exec-CjyVHUuE.js"; import { T as DEFAULT_AGENT_ID, a as resolveAgentModelPrimary } from "./agent-scope-qNPdmst1.js"; import { o as resolveOAuthPath, s as resolveStateDir } from "./paths-BFxmmTT5.js"; import { t as formatCliCommand } from "./command-format-CFzL448l.js"; import { a as saveJsonFile, i as loadJsonFile, r as resolveCopilotApiToken, t as DEFAULT_COPILOT_API_BASE_URL } from "./github-copilot-token-BoPqI-5_.js"; import path from "node:path"; import fs from "node:fs"; import { execFileSync, execSync } from "node:child_process"; import { createHash, randomBytes } from "node:crypto"; import lockfile from "proper-lockfile"; import { getEnvApiKey, getOAuthApiKey, getOAuthProviders } from "@mariozechner/pi-ai"; import { BedrockClient, ListFoundationModelsCommand } from "@aws-sdk/client-bedrock"; //#region src/utils/boolean.ts const DEFAULT_TRUTHY = [ "true", "1", "yes", "on" ]; const DEFAULT_FALSY = [ "false", "0", "no", "off" ]; const DEFAULT_TRUTHY_SET = new Set(DEFAULT_TRUTHY); const DEFAULT_FALSY_SET = new Set(DEFAULT_FALSY); function parseBooleanValue(value, options = {}) { if (typeof value === "boolean") return value; if (typeof value !== "string") return; const normalized = value.trim().toLowerCase(); if (!normalized) return; const truthy = options.truthy ?? DEFAULT_TRUTHY; const falsy = options.falsy ?? DEFAULT_FALSY; const truthySet = truthy === DEFAULT_TRUTHY ? DEFAULT_TRUTHY_SET : new Set(truthy); const falsySet = falsy === DEFAULT_FALSY ? DEFAULT_FALSY_SET : new Set(falsy); if (truthySet.has(normalized)) return true; if (falsySet.has(normalized)) return false; } //#endregion //#region src/infra/env.ts const log$2 = createSubsystemLogger("env"); function isTruthyEnvValue(value) { return parseBooleanValue(value) === true; } //#endregion //#region src/infra/shell-env.ts const DEFAULT_TIMEOUT_MS = 15e3; const DEFAULT_MAX_BUFFER_BYTES = 2 * 1024 * 1024; let lastAppliedKeys = []; let cachedShellPath; function resolveShell(env) { const shell = env.SHELL?.trim(); return shell && shell.length > 0 ? shell : "/bin/sh"; } function parseShellEnv(stdout) { const shellEnv = /* @__PURE__ */ new Map(); const parts = stdout.toString("utf8").split("\0"); for (const part of parts) { if (!part) continue; const eq = part.indexOf("="); if (eq <= 0) continue; const key = part.slice(0, eq); const value = part.slice(eq + 1); if (!key) continue; shellEnv.set(key, value); } return shellEnv; } function loadShellEnvFallback(opts) { const logger = opts.logger ?? console; const exec = opts.exec ?? execFileSync; if (!opts.enabled) { lastAppliedKeys = []; return { ok: true, applied: [], skippedReason: "disabled" }; } if (opts.expectedKeys.some((key) => Boolean(opts.env[key]?.trim()))) { lastAppliedKeys = []; return { ok: true, applied: [], skippedReason: "already-has-keys" }; } const timeoutMs = typeof opts.timeoutMs === "number" && Number.isFinite(opts.timeoutMs) ? Math.max(0, opts.timeoutMs) : DEFAULT_TIMEOUT_MS; const shell = resolveShell(opts.env); let stdout; try { stdout = exec(shell, [ "-l", "-c", "env -0" ], { encoding: "buffer", timeout: timeoutMs, maxBuffer: DEFAULT_MAX_BUFFER_BYTES, env: opts.env, stdio: [ "ignore", "pipe", "pipe" ] }); } catch (err) { const msg = err instanceof Error ? err.message : String(err); logger.warn(`[openclaw] shell env fallback failed: ${msg}`); lastAppliedKeys = []; return { ok: false, error: msg, applied: [] }; } const shellEnv = parseShellEnv(stdout); const applied = []; for (const key of opts.expectedKeys) { if (opts.env[key]?.trim()) continue; const value = shellEnv.get(key); if (!value?.trim()) continue; opts.env[key] = value; applied.push(key); } lastAppliedKeys = applied; return { ok: true, applied }; } function shouldEnableShellEnvFallback(env) { return isTruthyEnvValue(env.OPENCLAW_LOAD_SHELL_ENV); } function shouldDeferShellEnvFallback(env) { return isTruthyEnvValue(env.OPENCLAW_DEFER_SHELL_ENV_FALLBACK); } function resolveShellEnvFallbackTimeoutMs(env) { const raw = env.OPENCLAW_SHELL_ENV_TIMEOUT_MS?.trim(); if (!raw) return DEFAULT_TIMEOUT_MS; const parsed = Number.parseInt(raw, 10); if (!Number.isFinite(parsed)) return DEFAULT_TIMEOUT_MS; return Math.max(0, parsed); } function getShellPathFromLoginShell(opts) { if (cachedShellPath !== void 0) return cachedShellPath; if (process.platform === "win32") { cachedShellPath = null; return cachedShellPath; } const exec = opts.exec ?? execFileSync; const timeoutMs = typeof opts.timeoutMs === "number" && Number.isFinite(opts.timeoutMs) ? Math.max(0, opts.timeoutMs) : DEFAULT_TIMEOUT_MS; const shell = resolveShell(opts.env); let stdout; try { stdout = exec(shell, [ "-l", "-c", "env -0" ], { encoding: "buffer", timeout: timeoutMs, maxBuffer: DEFAULT_MAX_BUFFER_BYTES, env: opts.env, stdio: [ "ignore", "pipe", "pipe" ] }); } catch { cachedShellPath = null; return cachedShellPath; } const shellPath = parseShellEnv(stdout).get("PATH")?.trim(); cachedShellPath = shellPath && shellPath.length > 0 ? shellPath : null; return cachedShellPath; } function getShellEnvAppliedKeys() { return [...lastAppliedKeys]; } //#endregion //#region src/agents/defaults.ts const DEFAULT_PROVIDER = "anthropic"; const DEFAULT_MODEL = "claude-opus-4-5"; const DEFAULT_CONTEXT_TOKENS = 2e5; //#endregion //#region src/agents/auth-profiles/constants.ts const AUTH_STORE_VERSION = 1; const AUTH_PROFILE_FILENAME = "auth-profiles.json"; const LEGACY_AUTH_FILENAME = "auth.json"; const QWEN_CLI_PROFILE_ID = "qwen-portal:qwen-cli"; const MINIMAX_CLI_PROFILE_ID = "minimax-portal:minimax-cli"; const AUTH_STORE_LOCK_OPTIONS = { retries: { retries: 10, factor: 2, minTimeout: 100, maxTimeout: 1e4, randomize: true }, stale: 3e4 }; const EXTERNAL_CLI_SYNC_TTL_MS = 900 * 1e3; const EXTERNAL_CLI_NEAR_EXPIRY_MS = 600 * 1e3; const log$1 = createSubsystemLogger("agents/auth-profiles"); //#endregion //#region src/agents/auth-profiles/display.ts function resolveAuthProfileDisplayLabel(params) { const { cfg, store, profileId } = params; const profile = store.profiles[profileId]; const email = cfg?.auth?.profiles?.[profileId]?.email?.trim() || (profile && "email" in profile ? profile.email?.trim() : void 0); if (email) return `${profileId} (${email})`; return profileId; } //#endregion //#region src/agents/cli-credentials.ts const log = createSubsystemLogger("agents/auth-profiles"); const QWEN_CLI_CREDENTIALS_RELATIVE_PATH = ".qwen/oauth_creds.json"; const MINIMAX_CLI_CREDENTIALS_RELATIVE_PATH = ".minimax/oauth_creds.json"; let qwenCliCache = null; let minimaxCliCache = null; function resolveQwenCliCredentialsPath(homeDir) { const baseDir = homeDir ?? resolveUserPath("~"); return path.join(baseDir, QWEN_CLI_CREDENTIALS_RELATIVE_PATH); } function resolveMiniMaxCliCredentialsPath(homeDir) { const baseDir = homeDir ?? resolveUserPath("~"); return path.join(baseDir, MINIMAX_CLI_CREDENTIALS_RELATIVE_PATH); } function readQwenCliCredentials(options) { const raw = loadJsonFile(resolveQwenCliCredentialsPath(options?.homeDir)); if (!raw || typeof raw !== "object") return null; const data = raw; const accessToken = data.access_token; const refreshToken = data.refresh_token; const expiresAt = data.expiry_date; if (typeof accessToken !== "string" || !accessToken) return null; if (typeof refreshToken !== "string" || !refreshToken) return null; if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt)) return null; return { type: "oauth", provider: "qwen-portal", access: accessToken, refresh: refreshToken, expires: expiresAt }; } function readMiniMaxCliCredentials(options) { const raw = loadJsonFile(resolveMiniMaxCliCredentialsPath(options?.homeDir)); if (!raw || typeof raw !== "object") return null; const data = raw; const accessToken = data.access_token; const refreshToken = data.refresh_token; const expiresAt = data.expiry_date; if (typeof accessToken !== "string" || !accessToken) return null; if (typeof refreshToken !== "string" || !refreshToken) return null; if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt)) return null; return { type: "oauth", provider: "minimax-portal", access: accessToken, refresh: refreshToken, expires: expiresAt }; } function readQwenCliCredentialsCached(options) { const ttlMs = options?.ttlMs ?? 0; const now = Date.now(); const cacheKey = resolveQwenCliCredentialsPath(options?.homeDir); if (ttlMs > 0 && qwenCliCache && qwenCliCache.cacheKey === cacheKey && now - qwenCliCache.readAt < ttlMs) return qwenCliCache.value; const value = readQwenCliCredentials({ homeDir: options?.homeDir }); if (ttlMs > 0) qwenCliCache = { value, readAt: now, cacheKey }; return value; } function readMiniMaxCliCredentialsCached(options) { const ttlMs = options?.ttlMs ?? 0; const now = Date.now(); const cacheKey = resolveMiniMaxCliCredentialsPath(options?.homeDir); if (ttlMs > 0 && minimaxCliCache && minimaxCliCache.cacheKey === cacheKey && now - minimaxCliCache.readAt < ttlMs) return minimaxCliCache.value; const value = readMiniMaxCliCredentials({ homeDir: options?.homeDir }); if (ttlMs > 0) minimaxCliCache = { value, readAt: now, cacheKey }; return value; } //#endregion //#region src/agents/auth-profiles/external-cli-sync.ts function shallowEqualOAuthCredentials(a, b) { if (!a) return false; if (a.type !== "oauth") return false; return a.provider === b.provider && a.access === b.access && a.refresh === b.refresh && a.expires === b.expires && a.email === b.email && a.enterpriseUrl === b.enterpriseUrl && a.projectId === b.projectId && a.accountId === b.accountId; } function isExternalProfileFresh(cred, now) { if (!cred) return false; if (cred.type !== "oauth" && cred.type !== "token") return false; if (cred.provider !== "qwen-portal" && cred.provider !== "minimax-portal") return false; if (typeof cred.expires !== "number") return true; return cred.expires > now + EXTERNAL_CLI_NEAR_EXPIRY_MS; } /** Sync external CLI credentials into the store for a given provider. */ function syncExternalCliCredentialsForProvider(store, profileId, provider, readCredentials, now) { const existing = store.profiles[profileId]; const creds = !existing || existing.provider !== provider || !isExternalProfileFresh(existing, now) ? readCredentials() : null; if (!creds) return false; const existingOAuth = existing?.type === "oauth" ? existing : void 0; if ((!existingOAuth || existingOAuth.provider !== provider || existingOAuth.expires <= now || creds.expires > existingOAuth.expires) && !shallowEqualOAuthCredentials(existingOAuth, creds)) { store.profiles[profileId] = creds; log$1.info(`synced ${provider} credentials from external cli`, { profileId, expires: new Date(creds.expires).toISOString() }); return true; } return false; } /** * Sync OAuth credentials from external CLI tools (Qwen Code CLI, MiniMax CLI) into the store. * * Returns true if any credentials were updated. */ function syncExternalCliCredentials(store) { let mutated = false; const now = Date.now(); const existingQwen = store.profiles[QWEN_CLI_PROFILE_ID]; const qwenCreds = !existingQwen || existingQwen.provider !== "qwen-portal" || !isExternalProfileFresh(existingQwen, now) ? readQwenCliCredentialsCached({ ttlMs: EXTERNAL_CLI_SYNC_TTL_MS }) : null; if (qwenCreds) { const existing = store.profiles[QWEN_CLI_PROFILE_ID]; const existingOAuth = existing?.type === "oauth" ? existing : void 0; if ((!existingOAuth || existingOAuth.provider !== "qwen-portal" || existingOAuth.expires <= now || qwenCreds.expires > existingOAuth.expires) && !shallowEqualOAuthCredentials(existingOAuth, qwenCreds)) { store.profiles[QWEN_CLI_PROFILE_ID] = qwenCreds; mutated = true; log$1.info("synced qwen credentials from qwen cli", { profileId: QWEN_CLI_PROFILE_ID, expires: new Date(qwenCreds.expires).toISOString() }); } } if (syncExternalCliCredentialsForProvider(store, MINIMAX_CLI_PROFILE_ID, "minimax-portal", () => readMiniMaxCliCredentialsCached({ ttlMs: EXTERNAL_CLI_SYNC_TTL_MS }), now)) mutated = true; return mutated; } //#endregion //#region src/agents/agent-paths.ts function resolveOpenClawAgentDir() { const override = process.env.OPENCLAW_AGENT_DIR?.trim() || process.env.PI_CODING_AGENT_DIR?.trim(); if (override) return resolveUserPath(override); return resolveUserPath(path.join(resolveStateDir(), "agents", DEFAULT_AGENT_ID, "agent")); } //#endregion //#region src/agents/auth-profiles/paths.ts function resolveAuthStorePath(agentDir) { const resolved = resolveUserPath(agentDir ?? resolveOpenClawAgentDir()); return path.join(resolved, AUTH_PROFILE_FILENAME); } function resolveLegacyAuthStorePath(agentDir) { const resolved = resolveUserPath(agentDir ?? resolveOpenClawAgentDir()); return path.join(resolved, LEGACY_AUTH_FILENAME); } function resolveAuthStorePathForDisplay(agentDir) { const pathname = resolveAuthStorePath(agentDir); return pathname.startsWith("~") ? pathname : resolveUserPath(pathname); } function ensureAuthStoreFile(pathname) { if (fs.existsSync(pathname)) return; saveJsonFile(pathname, { version: AUTH_STORE_VERSION, profiles: {} }); } //#endregion //#region src/agents/auth-profiles/store.ts async function updateAuthProfileStoreWithLock(params) { const authPath = resolveAuthStorePath(params.agentDir); ensureAuthStoreFile(authPath); let release; try { release = await lockfile.lock(authPath, AUTH_STORE_LOCK_OPTIONS); const store = ensureAuthProfileStore(params.agentDir); if (params.updater(store)) saveAuthProfileStore(store, params.agentDir); return store; } catch { return null; } finally { if (release) try { await release(); } catch {} } } function coerceLegacyStore(raw) { if (!raw || typeof raw !== "object") return null; const record = raw; if ("profiles" in record) return null; const entries = {}; for (const [key, value] of Object.entries(record)) { if (!value || typeof value !== "object") continue; const typed = value; if (typed.type !== "api_key" && typed.type !== "oauth" && typed.type !== "token") continue; entries[key] = { ...typed, provider: String(typed.provider ?? key) }; } return Object.keys(entries).length > 0 ? entries : null; } function coerceAuthStore(raw) { if (!raw || typeof raw !== "object") return null; const record = raw; if (!record.profiles || typeof record.profiles !== "object") return null; const profiles = record.profiles; const normalized = {}; for (const [key, value] of Object.entries(profiles)) { if (!value || typeof value !== "object") continue; const typed = value; if (typed.type !== "api_key" && typed.type !== "oauth" && typed.type !== "token") continue; if (!typed.provider) continue; normalized[key] = typed; } const order = record.order && typeof record.order === "object" ? Object.entries(record.order).reduce((acc, [provider, value]) => { if (!Array.isArray(value)) return acc; const list = value.map((entry) => typeof entry === "string" ? entry.trim() : "").filter(Boolean); if (list.length === 0) return acc; acc[provider] = list; return acc; }, {}) : void 0; return { version: Number(record.version ?? AUTH_STORE_VERSION), profiles: normalized, order, lastGood: record.lastGood && typeof record.lastGood === "object" ? record.lastGood : void 0, usageStats: record.usageStats && typeof record.usageStats === "object" ? record.usageStats : void 0 }; } function mergeRecord(base, override) { if (!base && !override) return; if (!base) return { ...override }; if (!override) return { ...base }; return { ...base, ...override }; } function mergeAuthProfileStores(base, override) { if (Object.keys(override.profiles).length === 0 && !override.order && !override.lastGood && !override.usageStats) return base; return { version: Math.max(base.version, override.version ?? base.version), profiles: { ...base.profiles, ...override.profiles }, order: mergeRecord(base.order, override.order), lastGood: mergeRecord(base.lastGood, override.lastGood), usageStats: mergeRecord(base.usageStats, override.usageStats) }; } function mergeOAuthFileIntoStore(store) { const oauthRaw = loadJsonFile(resolveOAuthPath()); if (!oauthRaw || typeof oauthRaw !== "object") return false; const oauthEntries = oauthRaw; let mutated = false; for (const [provider, creds] of Object.entries(oauthEntries)) { if (!creds || typeof creds !== "object") continue; const profileId = `${provider}:default`; if (store.profiles[profileId]) continue; store.profiles[profileId] = { type: "oauth", provider, ...creds }; mutated = true; } return mutated; } function loadAuthProfileStoreForAgent(agentDir, _options) { const authPath = resolveAuthStorePath(agentDir); const asStore = coerceAuthStore(loadJsonFile(authPath)); if (asStore) { if (syncExternalCliCredentials(asStore)) saveJsonFile(authPath, asStore); return asStore; } if (agentDir) { const mainStore = coerceAuthStore(loadJsonFile(resolveAuthStorePath())); if (mainStore && Object.keys(mainStore.profiles).length > 0) { saveJsonFile(authPath, mainStore); log$1.info("inherited auth-profiles from main agent", { agentDir }); return mainStore; } } const legacy = coerceLegacyStore(loadJsonFile(resolveLegacyAuthStorePath(agentDir))); const store = { version: AUTH_STORE_VERSION, profiles: {} }; if (legacy) for (const [provider, cred] of Object.entries(legacy)) { const profileId = `${provider}:default`; if (cred.type === "api_key") store.profiles[profileId] = { type: "api_key", provider: String(cred.provider ?? provider), key: cred.key, ...cred.email ? { email: cred.email } : {} }; else if (cred.type === "token") store.profiles[profileId] = { type: "token", provider: String(cred.provider ?? provider), token: cred.token, ...typeof cred.expires === "number" ? { expires: cred.expires } : {}, ...cred.email ? { email: cred.email } : {} }; else store.profiles[profileId] = { type: "oauth", provider: String(cred.provider ?? provider), access: cred.access, refresh: cred.refresh, expires: cred.expires, ...cred.enterpriseUrl ? { enterpriseUrl: cred.enterpriseUrl } : {}, ...cred.projectId ? { projectId: cred.projectId } : {}, ...cred.accountId ? { accountId: cred.accountId } : {}, ...cred.email ? { email: cred.email } : {} }; } const mergedOAuth = mergeOAuthFileIntoStore(store); const syncedCli = syncExternalCliCredentials(store); const shouldWrite = legacy !== null || mergedOAuth || syncedCli; if (shouldWrite) saveJsonFile(authPath, store); if (shouldWrite && legacy !== null) { const legacyPath = resolveLegacyAuthStorePath(agentDir); try { fs.unlinkSync(legacyPath); } catch (err) { if (err?.code !== "ENOENT") log$1.warn("failed to delete legacy auth.json after migration", { err, legacyPath }); } } return store; } function ensureAuthProfileStore(agentDir, options) { const store = loadAuthProfileStoreForAgent(agentDir, options); const authPath = resolveAuthStorePath(agentDir); const mainAuthPath = resolveAuthStorePath(); if (!agentDir || authPath === mainAuthPath) return store; return mergeAuthProfileStores(loadAuthProfileStoreForAgent(void 0, options), store); } function saveAuthProfileStore(store, agentDir) { saveJsonFile(resolveAuthStorePath(agentDir), { version: AUTH_STORE_VERSION, profiles: store.profiles, order: store.order ?? void 0, lastGood: store.lastGood ?? void 0, usageStats: store.usageStats ?? void 0 }); } //#endregion //#region src/agents/auth-profiles/profiles.ts function listProfilesForProvider(store, provider) { const providerKey = normalizeProviderId(provider); return Object.entries(store.profiles).filter(([, cred]) => normalizeProviderId(cred.provider) === providerKey).map(([id]) => id); } async function markAuthProfileGood(params) { const { store, provider, profileId, agentDir } = params; const updated = await updateAuthProfileStoreWithLock({ agentDir, updater: (freshStore) => { const profile = freshStore.profiles[profileId]; if (!profile || profile.provider !== provider) return false; freshStore.lastGood = { ...freshStore.lastGood, [provider]: profileId }; return true; } }); if (updated) { store.lastGood = updated.lastGood; return; } const profile = store.profiles[profileId]; if (!profile || profile.provider !== provider) return; store.lastGood = { ...store.lastGood, [provider]: profileId }; saveAuthProfileStore(store, agentDir); } //#endregion //#region src/agents/auth-profiles/repair.ts function getProfileSuffix(profileId) { const idx = profileId.indexOf(":"); if (idx < 0) return ""; return profileId.slice(idx + 1); } function isEmailLike(value) { const trimmed = value.trim(); if (!trimmed) return false; return trimmed.includes("@") && trimmed.includes("."); } function suggestOAuthProfileIdForLegacyDefault(params) { const providerKey = normalizeProviderId(params.provider); if (getProfileSuffix(params.legacyProfileId) !== "default") return null; const legacyCfg = params.cfg?.auth?.profiles?.[params.legacyProfileId]; if (legacyCfg && normalizeProviderId(legacyCfg.provider) === providerKey && legacyCfg.mode !== "oauth") return null; const oauthProfiles = listProfilesForProvider(params.store, providerKey).filter((id) => params.store.profiles[id]?.type === "oauth"); if (oauthProfiles.length === 0) return null; const configuredEmail = legacyCfg?.email?.trim(); if (configuredEmail) { const byEmail = oauthProfiles.find((id) => { const cred = params.store.profiles[id]; if (!cred || cred.type !== "oauth") return false; return cred.email?.trim() === configuredEmail || id === `${providerKey}:${configuredEmail}`; }); if (byEmail) return byEmail; } const lastGood = params.store.lastGood?.[providerKey] ?? params.store.lastGood?.[params.provider]; if (lastGood && oauthProfiles.includes(lastGood)) return lastGood; const nonLegacy = oauthProfiles.filter((id) => id !== params.legacyProfileId); if (nonLegacy.length === 1) return nonLegacy[0] ?? null; const emailLike = nonLegacy.filter((id) => isEmailLike(getProfileSuffix(id))); if (emailLike.length === 1) return emailLike[0] ?? null; return null; } //#endregion //#region src/agents/auth-profiles/doctor.ts function formatAuthDoctorHint(params) { const providerKey = normalizeProviderId(params.provider); if (providerKey !== "anthropic") return ""; const legacyProfileId = params.profileId ?? "anthropic:default"; const suggested = suggestOAuthProfileIdForLegacyDefault({ cfg: params.cfg, store: params.store, provider: providerKey, legacyProfileId }); if (!suggested || suggested === legacyProfileId) return ""; const storeOauthProfiles = listProfilesForProvider(params.store, providerKey).filter((id) => params.store.profiles[id]?.type === "oauth").join(", "); const cfgMode = params.cfg?.auth?.profiles?.[legacyProfileId]?.mode; const cfgProvider = params.cfg?.auth?.profiles?.[legacyProfileId]?.provider; return [ "Doctor hint (for GitHub issue):", `- provider: ${providerKey}`, `- config: ${legacyProfileId}${cfgProvider || cfgMode ? ` (provider=${cfgProvider ?? "?"}, mode=${cfgMode ?? "?"})` : ""}`, `- auth store oauth profiles: ${storeOauthProfiles || "(none)"}`, `- suggested profile: ${suggested}`, `Fix: run "${formatCliCommand("openclaw doctor --yes")}"` ].join("\n"); } //#endregion //#region src/providers/qwen-portal-oauth.ts const QWEN_OAUTH_TOKEN_ENDPOINT = `https://chat.qwen.ai/api/v1/oauth2/token`; const QWEN_OAUTH_CLIENT_ID = "f0304373b74a44d2b584a3fb70ca9e56"; async function refreshQwenPortalCredentials(credentials) { if (!credentials.refresh?.trim()) throw new Error("Qwen OAuth refresh token missing; re-authenticate."); const response = await fetch(QWEN_OAUTH_TOKEN_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" }, body: new URLSearchParams({ grant_type: "refresh_token", refresh_token: credentials.refresh, client_id: QWEN_OAUTH_CLIENT_ID }) }); if (!response.ok) { const text = await response.text(); if (response.status === 400) throw new Error(`Qwen OAuth refresh token expired or invalid. Re-authenticate with \`${formatCliCommand("openclaw models auth login --provider qwen-portal")}\`.`); throw new Error(`Qwen OAuth refresh failed: ${text || response.statusText}`); } const payload = await response.json(); if (!payload.access_token || !payload.expires_in) throw new Error("Qwen OAuth refresh response missing access token."); return { ...credentials, access: payload.access_token, refresh: payload.refresh_token || credentials.refresh, expires: Date.now() + payload.expires_in * 1e3 }; } //#endregion //#region src/agents/chutes-oauth.ts const CHUTES_OAUTH_ISSUER = "https://api.chutes.ai"; const CHUTES_AUTHORIZE_ENDPOINT = `${CHUTES_OAUTH_ISSUER}/idp/authorize`; const CHUTES_TOKEN_ENDPOINT = `${CHUTES_OAUTH_ISSUER}/idp/token`; const CHUTES_USERINFO_ENDPOINT = `${CHUTES_OAUTH_ISSUER}/idp/userinfo`; const DEFAULT_EXPIRES_BUFFER_MS = 300 * 1e3; function coerceExpiresAt(expiresInSeconds, now) { const value = now + Math.max(0, Math.floor(expiresInSeconds)) * 1e3 - DEFAULT_EXPIRES_BUFFER_MS; return Math.max(value, now + 3e4); } async function refreshChutesTokens(params) { const fetchFn = params.fetchFn ?? fetch; const now = params.now ?? Date.now(); const refreshToken = params.credential.refresh?.trim(); if (!refreshToken) throw new Error("Chutes OAuth credential is missing refresh token"); const clientId = params.credential.clientId?.trim() ?? process.env.CHUTES_CLIENT_ID?.trim(); if (!clientId) throw new Error("Missing CHUTES_CLIENT_ID for Chutes OAuth refresh (set env var or re-auth)."); const clientSecret = process.env.CHUTES_CLIENT_SECRET?.trim() || void 0; const body = new URLSearchParams({ grant_type: "refresh_token", client_id: clientId, refresh_token: refreshToken }); if (clientSecret) body.set("client_secret", clientSecret); const response = await fetchFn(CHUTES_TOKEN_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body }); if (!response.ok) { const text = await response.text(); throw new Error(`Chutes token refresh failed: ${text}`); } const data = await response.json(); const access = data.access_token?.trim(); const newRefresh = data.refresh_token?.trim(); const expiresIn = data.expires_in ?? 0; if (!access) throw new Error("Chutes token refresh returned no access_token"); return { ...params.credential, access, refresh: newRefresh || refreshToken, expires: coerceExpiresAt(expiresIn, now), clientId }; } //#endregion //#region src/agents/auth-profiles/oauth.ts const OAUTH_PROVIDER_IDS = new Set(getOAuthProviders().map((provider) => provider.id)); const isOAuthProvider = (provider) => OAUTH_PROVIDER_IDS.has(provider); const resolveOAuthProvider = (provider) => isOAuthProvider(provider) ? provider : null; function buildOAuthApiKey(provider, credentials) { return provider === "google-gemini-cli" || provider === "google-antigravity" ? JSON.stringify({ token: credentials.access, projectId: credentials.projectId }) : credentials.access; } async function refreshOAuthTokenWithLock(params) { const authPath = resolveAuthStorePath(params.agentDir); ensureAuthStoreFile(authPath); let release; try { release = await lockfile.lock(authPath, { ...AUTH_STORE_LOCK_OPTIONS }); const store = ensureAuthProfileStore(params.agentDir); const cred = store.profiles[params.profileId]; if (!cred || cred.type !== "oauth") return null; if (Date.now() < cred.expires) return { apiKey: buildOAuthApiKey(cred.provider, cred), newCredentials: cred }; const oauthCreds = { [cred.provider]: cred }; const result = String(cred.provider) === "chutes" ? await (async () => { const newCredentials = await refreshChutesTokens({ credential: cred }); return { apiKey: newCredentials.access, newCredentials }; })() : String(cred.provider) === "qwen-portal" ? await (async () => { const newCredentials = await refreshQwenPortalCredentials(cred); return { apiKey: newCredentials.access, newCredentials }; })() : await (async () => { const oauthProvider = resolveOAuthProvider(cred.provider); if (!oauthProvider) return null; return await getOAuthApiKey(oauthProvider, oauthCreds); })(); if (!result) return null; store.profiles[params.profileId] = { ...cred, ...result.newCredentials, type: "oauth" }; saveAuthProfileStore(store, params.agentDir); return result; } finally { if (release) try { await release(); } catch {} } } async function tryResolveOAuthProfile(params) { const { cfg, store, profileId } = params; const cred = store.profiles[profileId]; if (!cred || cred.type !== "oauth") return null; const profileConfig = cfg?.auth?.profiles?.[profileId]; if (profileConfig && profileConfig.provider !== cred.provider) return null; if (profileConfig && profileConfig.mode !== cred.type) return null; if (Date.now() < cred.expires) return { apiKey: buildOAuthApiKey(cred.provider, cred), provider: cred.provider, email: cred.email }; const refreshed = await refreshOAuthTokenWithLock({ profileId, agentDir: params.agentDir }); if (!refreshed) return null; return { apiKey: refreshed.apiKey, provider: cred.provider, email: cred.email }; } async function resolveApiKeyForProfile(params) { const { cfg, store, profileId } = params; const cred = store.profiles[profileId]; if (!cred) return null; const profileConfig = cfg?.auth?.profiles?.[profileId]; if (profileConfig && profileConfig.provider !== cred.provider) return null; if (profileConfig && profileConfig.mode !== cred.type) { if (!(profileConfig.mode === "oauth" && cred.type === "token")) return null; } if (cred.type === "api_key") { const key = cred.key?.trim(); if (!key) return null; return { apiKey: key, provider: cred.provider, email: cred.email }; } if (cred.type === "token") { const token = cred.token?.trim(); if (!token) return null; if (typeof cred.expires === "number" && Number.isFinite(cred.expires) && cred.expires > 0 && Date.now() >= cred.expires) return null; return { apiKey: token, provider: cred.provider, email: cred.email }; } if (Date.now() < cred.expires) return { apiKey: buildOAuthApiKey(cred.provider, cred), provider: cred.provider, email: cred.email }; try { const result = await refreshOAuthTokenWithLock({ profileId, agentDir: params.agentDir }); if (!result) return null; return { apiKey: result.apiKey, provider: cred.provider, email: cred.email }; } catch (error) { const refreshedStore = ensureAuthProfileStore(params.agentDir); const refreshed = refreshedStore.profiles[profileId]; if (refreshed?.type === "oauth" && Date.now() < refreshed.expires) return { apiKey: buildOAuthApiKey(refreshed.provider, refreshed), provider: refreshed.provider, email: refreshed.email ?? cred.email }; const fallbackProfileId = suggestOAuthProfileIdForLegacyDefault({ cfg, store: refreshedStore, provider: cred.provider, legacyProfileId: profileId }); if (fallbackProfileId && fallbackProfileId !== profileId) try { const fallbackResolved = await tryResolveOAuthProfile({ cfg, store: refreshedStore, profileId: fallbackProfileId, agentDir: params.agentDir }); if (fallbackResolved) return fallbackResolved; } catch {} if (params.agentDir) try { const mainCred = ensureAuthProfileStore(void 0).profiles[profileId]; if (mainCred?.type === "oauth" && Date.now() < mainCred.expires) { refreshedStore.profiles[profileId] = { ...mainCred }; saveAuthProfileStore(refreshedStore, params.agentDir); log$1.info("inherited fresh OAuth credentials from main agent", { profileId, agentDir: params.agentDir, expires: new Date(mainCred.expires).toISOString() }); return { apiKey: buildOAuthApiKey(mainCred.provider, mainCred), provider: mainCred.provider, email: mainCred.email }; } } catch {} const message = error instanceof Error ? error.message : String(error); const hint = formatAuthDoctorHint({ cfg, store: refreshedStore, provider: cred.provider, profileId }); throw new Error(`OAuth token refresh failed for ${cred.provider}: ${message}. Please try again or re-authenticate.` + (hint ? `\n\n${hint}` : ""), { cause: error }); } } //#endregion //#region src/agents/auth-profiles/usage.ts function resolveProfileUnusableUntil$1(stats) { const values = [stats.cooldownUntil, stats.disabledUntil].filter((value) => typeof value === "number").filter((value) => Number.isFinite(value) && value > 0); if (values.length === 0) return null; return Math.max(...values); } /** * Check if a profile is currently in cooldown (due to rate limiting or errors). */ function isProfileInCooldown(store, profileId) { const stats = store.usageStats?.[profileId]; if (!stats) return false; const unusableUntil = resolveProfileUnusableUntil$1(stats); return unusableUntil ? Date.now() < unusableUntil : false; } /** * Mark a profile as successfully used. Resets error count and updates lastUsed. * Uses store lock to avoid overwriting concurrent usage updates. */ async function markAuthProfileUsed(params) { const { store, profileId, agentDir } = params; const updated = await updateAuthProfileStoreWithLock({ agentDir, updater: (freshStore) => { if (!freshStore.profiles[profileId]) return false; freshStore.usageStats = freshStore.usageStats ?? {}; freshStore.usageStats[profileId] = { ...freshStore.usageStats[profileId], lastUsed: Date.now(), errorCount: 0, cooldownUntil: void 0, disabledUntil: void 0, disabledReason: void 0, failureCounts: void 0 }; return true; } }); if (updated) { store.usageStats = updated.usageStats; return; } if (!store.profiles[profileId]) return; store.usageStats = store.usageStats ?? {}; store.usageStats[profileId] = { ...store.usageStats[profileId], lastUsed: Date.now(), errorCount: 0, cooldownUntil: void 0, disabledUntil: void 0, disabledReason: void 0, failureCounts: void 0 }; saveAuthProfileStore(store, agentDir); } function calculateAuthProfileCooldownMs(errorCount) { const normalized = Math.max(1, errorCount); return Math.min(3600 * 1e3, 60 * 1e3 * 5 ** Math.min(normalized - 1, 3)); } function resolveAuthCooldownConfig(params) { const defaults = { billingBackoffHours: 5, billingMaxHours: 24, failureWindowHours: 24 }; const resolveHours = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback; const cooldowns = params.cfg?.auth?.cooldowns; const billingBackoffHours = resolveHours((() => { const map = cooldowns?.billingBackoffHoursByProvider; if (!map) return; for (const [key, value] of Object.entries(map)) if (normalizeProviderId(key) === params.providerId) return value; })() ?? cooldowns?.billingBackoffHours, defaults.billingBackoffHours); const billingMaxHours = resolveHours(cooldowns?.billingMaxHours, defaults.billingMaxHours); const failureWindowHours = resolveHours(cooldowns?.failureWindowHours, defaults.failureWindowHours); return { billingBackoffMs: billingBackoffHours * 60 * 60 * 1e3, billingMaxMs: billingMaxHours * 60 * 60 * 1e3, failureWindowMs: failureWindowHours * 60 * 60 * 1e3 }; } function calculateAuthProfileBillingDisableMsWithConfig(params) { const normalized = Math.max(1, params.errorCount); const baseMs = Math.max(6e4, params.baseMs); const maxMs = Math.max(baseMs, params.maxMs); const raw = baseMs * 2 ** Math.min(normalized - 1, 10); return Math.min(maxMs, raw); } function computeNextProfileUsageStats(params) { const windowMs = params.cfgResolved.failureWindowMs; const windowExpired = typeof params.existing.lastFailureAt === "number" && params.existing.lastFailureAt > 0 && params.now - params.existing.lastFailureAt > windowMs; const nextErrorCount = (windowExpired ? 0 : params.existing.errorCount ?? 0) + 1; const failureCounts = windowExpired ? {} : { ...params.existing.failureCounts }; failureCounts[params.reason] = (failureCounts[params.reason] ?? 0) + 1; const updatedStats = { ...params.existing, errorCount: nextErrorCount, failureCounts, lastFailureAt: params.now }; if (params.reason === "billing") { const backoffMs = calculateAuthProfileBillingDisableMsWithConfig({ errorCount: failureCounts.billing ?? 1, baseMs: params.cfgResolved.billingBackoffMs, maxMs: params.cfgResolved.billingMaxMs }); updatedStats.disabledUntil = params.now + backoffMs; updatedStats.disabledReason = "billing"; } else { const backoffMs = calculateAuthProfileCooldownMs(nextErrorCount); updatedStats.cooldownUntil = params.now + backoffMs; } return updatedStats; } /** * Mark a profile as failed for a specific reason. Billing failures are treated * as "disabled" (longer backoff) vs the regular cooldown window. */ async function markAuthProfileFailure(params) { const { store, profileId, reason, agentDir, cfg } = params; const updated = await updateAuthProfileStoreWithLock({ agentDir, updater: (freshStore) => { const profile = freshStore.profiles[profileId]; if (!profile) return false; freshStore.usageStats = freshStore.usageStats ?? {}; const existing = freshStore.usageStats[profileId] ?? {}; const now = Date.now(); const cfgResolved = resolveAuthCooldownConfig({ cfg, providerId: normalizeProviderId(profile.provider) }); freshStore.usageStats[profileId] = computeNextProfileUsageStats({ existing, now, reason, cfgResolved }); return true; } }); if (updated) { store.usageStats = updated.usageStats; return; } if (!store.profiles[profileId]) return; store.usageStats = store.usageStats ?? {}; const existing = store.usageStats[profileId] ?? {}; const now = Date.now(); const cfgResolved = resolveAuthCooldownConfig({ cfg, providerId: normalizeProviderId(store.profiles[profileId]?.provider ?? "") }); store.usageStats[profileId] = computeNextProfileUsageStats({ existing, now, reason, cfgResolved }); saveAuthProfileStore(store, agentDir); } //#endregion //#region src/agents/auth-profiles/order.ts function resolveProfileUnusableUntil(stats) { const values = [stats.cooldownUntil, stats.disabledUntil].filter((value) => typeof value === "number").filter((value) => Number.isFinite(value) && value > 0); if (values.length === 0) return null; return Math.max(...values); } function resolveAuthProfileOrder(params) { const { cfg, store, provider, preferredProfile } = params; const providerKey = normalizeProviderId(provider); const now = Date.now(); const storedOrder = (() => { const order = store.order; if (!order) return; for (const [key, value] of Object.entries(order)) if (normalizeProviderId(key) === providerKey) return value; })(); const configuredOrder = (() => { const order = cfg?.auth?.order; if (!order) return; for (const [key, value] of Object.entries(order)) if (normalizeProviderId(key) === providerKey) return value; })(); const explicitOrder = storedOrder ?? configuredOrder; const explicitProfiles = cfg?.auth?.profiles ? Object.entries(cfg.auth.profiles).filter(([, profile]) => normalizeProviderId(profile.provider) === providerKey).map(([profileId]) => profileId) : []; const baseOrder = explicitOrder ?? (explicitProfiles.length > 0 ? explicitProfiles : listProfilesForProvider(store, providerKey)); if (baseOrder.length === 0) return []; const filtered = baseOrder.filter((profileId) => { const cred = store.profiles[profileId]; if (!cred) return false; if (normalizeProviderId(cred.provider) !== providerKey) return false; const profileConfig = cfg?.auth?.profiles?.[profileId]; if (profileConfig) { if (normalizeProviderId(profileConfig.provider) !== providerKey) return false; if (profileConfig.mode !== cred.type) { if (!(profileConfig.mode === "oauth" && cred.type === "token")) return false; } } if (cred.type === "api_key") return Boolean(cred.key?.trim()); if (cred.type === "token") { if (!cred.token?.trim()) return false; if (typeof cred.expires === "number" && Number.isFinite(cred.expires) && cred.expires > 0 && now >= cred.expires) return false; return true; } if (cred.type === "oauth") return Boolean(cred.access?.trim() || cred.refresh?.trim()); return false; }); const deduped = []; for (const entry of filtered) if (!deduped.includes(entry)) deduped.push(entry); if (explicitOrder && explicitOrder.length > 0) { const available = []; const inCooldown = []; for (const profileId of deduped) { const cooldownUntil = resolveProfileUnusableUntil(store.usageStats?.[profileId] ?? {}) ?? 0; if (typeof cooldownUntil === "number" && Number.isFinite(cooldownUntil) && cooldownUntil > 0 && now < cooldownUntil) inCooldown.push({ profileId, cooldownUntil }); else available.push(profileId); } const cooldownSorted = inCooldown.toSorted((a, b) => a.cooldownUntil - b.cooldownUntil).map((entry) => entry.profileId); const ordered = [...available, ...cooldownSorted]; if (preferredProfile && ordered.includes(preferredProfile)) return [preferredProfile, ...ordered.filter((e) => e !== preferredProfile)]; return ordered; } const sorted = orderProfilesByMode(deduped, store); if (preferredProfile && sorted.includes(preferredProfile)) return [preferredProfile, ...sorted.filter((e) => e !== preferredProfile)]; return sorted; } function orderProfilesByMode(order, store) { const now = Date.now(); const available = []; const inCooldown = []; for (const profileId of order) if (isProfileInCooldown(store, profileId)) inCooldown.push(profileId); else available.push(profileId); const sorted = available.map((profileId) => { const type = store.profiles[profileId]?.type; return { profileId, typeScore: type === "oauth" ? 0 : type === "token" ? 1 : type === "api_key" ? 2 : 3, lastUsed: store.usageStats?.[profileId]?.lastUsed ?? 0 }; }).toSorted((a, b) => { if (a.typeScore !== b.typeScore) return a.typeScore - b.typeScore; return a.lastUsed - b.lastUsed; }).map((entry) => entry.profileId); const cooldownSorted = inCooldown.map((profileId) => ({ profileId, cooldownUntil: resolveProfileUnusableUntil(store.usageStats?.[profileId] ?? {}) ?? now })).toSorted((a, b) => a.cooldownUntil - b.cooldownUntil).map((entry) => entry.profileId); return [...sorted, ...cooldownSorted]; } //#endregion //#region src/agents/bedrock-discovery.ts const DEFAULT_REFRESH_INTERVAL_SECONDS = 3600; const DEFAULT_CONTEXT_WINDOW = 32e3; const DEFAULT_MAX_TOKENS = 4096; const DEFAULT_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }; const discoveryCache = /* @__PURE__ */ new Map(); let hasLoggedBedrockError = false; function normalizeProviderFilter(filter) { if (!filter || filter.length === 0) return []; const normalized = new Set(filter.map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0)); return Array.from(normalized).toSorted(); } function buildCacheKey(params) { return JSON.stringify(params); } function includesTextModalities(modalities) { return (modalities ?? []).some((entry) => entry.toLowerCase() === "text"); } function isActive(summary) { const status = summary.modelLifecycle?.status; return typeof status === "string" ? status.toUpperCase() === "ACTIVE" : false; } function mapInputModalities(summary) { const inputs = summary.inputModalities ?? []; const mapped = /* @__PURE__ */ new Set(); for (const modality of inputs) { const lower = modality.toLowerCase(); if (lower === "text") mapped.add("text"); if (lower === "image") mapped.add("image"); } if (mapped.size === 0) mapped.add("text"); return Array.from(mapped); } function inferReasoningSupport(summary) { const haystack = `${summary.modelId ?? ""} ${summary.modelName ?? ""}`.toLowerCase(); return haystack.includes("reasoning") || haystack.includes("thinking"); } function resolveDefaultContextWindow(config) { const value = Math.floor(config?.defaultContextWindow ?? DEFAULT_CONTEXT_WINDOW); return value > 0 ? value : DEFAULT_CONTEXT_WINDOW; } function resolveDefaultMaxTokens(config) { const value = Math.floor(config?.defaultMaxTokens ?? DEFAULT_MAX_TOKENS); return value > 0 ? value : DEFAULT_MAX_TOKENS; } function matchesProviderFilter(summary, filter) { if (filter.length === 0) return true; const normalized = (summary.providerName ?? (typeof summary.modelId === "string" ? summary.modelId.split(".")[0] : void 0))?.trim().toLowerCase(); if (!normalized) return false; return filter.includes(normalized); } function shouldIncludeSummary(summary, filter) { if (!summary.modelId?.trim()) return false; if (!matchesProviderFilter(summary, filter)) return false; if (summary.responseStreamingSupported !== true) return false; if (!includesTextModalities(summary.outputModalities)) return false; if (!isActive(summary)) return false; return true; } function toModelDefinition(summary, defaults) { const id = summary.modelId?.trim() ?? ""; return { id, name: summary.modelName?.trim() || id, reasoning: inferReasoningSupport(summary), input: mapInputModalities(summary), cost: DEFAULT_COST, contextWindow: defaults.contextWindow, maxTokens: defaults.maxTokens }; } async function discoverBedrockModels(params) { const refreshIntervalSeconds = Math.max(0, Math.floor(params.config?.refreshInterval ?? DEFAULT_REFRESH_INTERVAL_SECONDS)); const providerFilter = normalizeProviderFilter(params.config?.providerFilter); const defaultContextWindow = resolveDefaultContextWindow(params.config); const defaultMaxTokens = resolveDefaultMaxTokens(params.config); const cacheKey = buildCacheKey({ region: params.region, providerFilter, refreshIntervalSeconds, defaultContextWindow, defaultMaxTokens }); const now = params.now?.() ?? Date.now(); if (refreshIntervalSeconds > 0) { const cached = discoveryCache.get(cacheKey); if (cached?.value && cached.expiresAt > now) return cached.value; if (cached?.inFlight) return cached.inFlight; } const client = (params.clientFactory ?? ((region) => new BedrockClient({ region })))(params.region); const discoveryPromise = (async () => { const response = await client.send(new ListFoundationModelsCommand({})); const discovered = []; for (const summary of response.modelSummaries ?? []) { if (!shouldIncludeSummary(summary, providerFilter)) continue; discovered.push(toModelDefinition(summary, { contextWindow: defaultContextWindow, maxTokens: defaultMaxTokens })); } return discovered.toSorted((a, b) => a.name.localeCompare(b.name)); })(); if (refreshIntervalSeconds > 0) discoveryCache.set(cacheKey, { expiresAt: now + refreshIntervalSeconds * 1e3, inFlight: discoveryPromise }); try { const value = await discoveryPromise; if (refreshIntervalSeconds > 0) discoveryCache.set(cacheKey, { expiresAt: now + refreshIntervalSeconds * 1e3, value }); return value; } catch (error) { if (refreshIntervalSeconds > 0) discoveryCache.delete(cacheKey); if (!hasLoggedBedrockError) { hasLoggedBedrockError = true; console.warn(`[bedrock-discovery] Failed to list models: ${String(error)}`); } return []; } } //#endregion //#region src/agents/cloudflare-ai-gateway.ts const CLOUDFLARE_AI_GATEWAY_PROVIDER_ID = "cloudflare-ai-gateway"; const CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID = "claude-sonnet-4-5"; const CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF = `${CLOUDFLARE_AI_GATEWAY_PROVIDER_ID}/${CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID}`; const CLOUDFLARE_AI_GATEWAY_DEFAULT_CONTEXT_WINDOW = 2e5; const CLOUDFLARE_AI_GATEWAY_DEFAULT_MAX_TOKENS = 64e3; const CLOUDFLARE_AI_GATEWAY_DEFAULT_COST = { input: 3, output: 15, cacheRead: .3, cacheWrite: 3.75 }; function buildCloudflareAiGatewayModelDefinition(params) { return { id: params?.id?.trim() || CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID, name: params?.name ?? "Claude Sonnet 4.5", reasoning: params?.reasoning ?? true, input: params?.input ?? ["text", "image"], cost: CLOUDFLARE_AI_GATEWAY_DEFAULT_COST, contextWindow: CLOUDFLARE_AI_GATEWAY_DEFAULT_CONTEXT_WINDOW, maxTokens: CLOUDFLARE_AI_GATEWAY_DEFAULT_MAX_TOKENS }; } function resolveCloudflareAiGatewayBaseUrl(params) { const accountId = params.accountId.trim(); const gatewayId = params.gatewayId.trim(); if (!accountId || !gatewayId) return ""; return `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/anthropic`; } //#endregion //#region src/agents/model-auth.ts const AWS_BEARER_ENV = "AWS_BEARER_TOKEN_BEDROCK"; const AWS_ACCESS_KEY_ENV = "AWS_ACCESS_KEY_ID"; const AWS_SECRET_KEY_ENV = "AWS_SECRET_ACCESS_KEY"; const AWS_PROFILE_ENV = "AWS_PROFILE"; function resolveProviderConfig(cfg, provider) { const providers = cfg?.models?.providers ?? {}; const direct = providers[provider]; if (direct) return direct; const normalized = normalizeProviderId(provider); if (normalized === provider) return Object.entries(providers).find(([key]) => normalizeProviderId(key) === normalized)?.[1]; return providers[normalized] ?? Object.entries(providers).find(([key]) => normalizeProviderId(key) === normalized)?.[1]; } function getCustomProviderApiKey(cfg, provider) { return resolveProviderConfig(cfg, provider)?.apiKey?.trim() || void 0; } function resolveProviderAuthOverride(cfg, provider) { const auth = resolveProviderConfig(cfg, provider)?.auth; if (auth === "api-key" || auth =