UNPKG

@gguf/claw

Version:

WhatsApp gateway CLI (Baileys web) with Pi RPC agent

1,330 lines (1,312 loc) 99.6 kB
import { t as __exportAll } from "./rolldown-runtime-Cbj13DAv.js"; import { g as resolveStateDir, h as resolveOAuthPath } from "./paths-scjhy7N2.js"; import { n as DEFAULT_AGENT_ID } from "./session-key-Dm2EOhrH.js"; import { t as createSubsystemLogger } from "./subsystem-CAq3uyo7.js"; import { h as resolveUserPath } from "./utils-CKSrBNwq.js"; import { a as resolveAgentModelPrimary } from "./agent-scope-CMs5Y7l-.js"; import { a as saveJsonFile, i as loadJsonFile, r as resolveCopilotApiToken, t as DEFAULT_COPILOT_API_BASE_URL } from "./github-copilot-token-pGSmVaW-.js"; import { t as formatCliCommand } from "./command-format-ChfKqObn.js"; import { t as isTruthyEnvValue } from "./env-0_mKbEWW.js"; import path from "node:path"; import fs from "node:fs"; import { execFileSync, execSync } from "node:child_process"; import lockfile from "proper-lockfile"; import { createHash, randomBytes } from "node:crypto"; import { getEnvApiKey, getOAuthApiKey, getOAuthProviders } from "@mariozechner/pi-ai"; import { BedrockClient, ListFoundationModelsCommand } from "@aws-sdk/client-bedrock"; //#region src/agents/defaults.ts const DEFAULT_PROVIDER = "anthropic"; const DEFAULT_MODEL = "claude-opus-4-6"; 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 CLAUDE_CLI_PROFILE_ID = "anthropic:claude-cli"; const CODEX_CLI_PROFILE_ID = "openai-codex:codex-cli"; 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 loadAuthProfileStore() { const authPath = resolveAuthStorePath(); const asStore = coerceAuthStore(loadJsonFile(authPath)); if (asStore) { if (syncExternalCliCredentials(asStore)) saveJsonFile(authPath, asStore); return asStore; } const legacy = coerceLegacyStore(loadJsonFile(resolveLegacyAuthStorePath())); if (legacy) { const store = { version: AUTH_STORE_VERSION, profiles: {} }; 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 } : {} }; } syncExternalCliCredentials(store); return store; } const store = { version: AUTH_STORE_VERSION, profiles: {} }; syncExternalCliCredentials(store); return store; } 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 async function setAuthProfileOrder(params) { const providerKey = normalizeProviderId(params.provider); const sanitized = params.order && Array.isArray(params.order) ? params.order.map((entry) => String(entry).trim()).filter(Boolean) : []; const deduped = []; for (const entry of sanitized) if (!deduped.includes(entry)) deduped.push(entry); return await updateAuthProfileStoreWithLock({ agentDir: params.agentDir, updater: (store) => { store.order = store.order ?? {}; if (deduped.length === 0) { if (!store.order[providerKey]) return false; delete store.order[providerKey]; if (Object.keys(store.order).length === 0) store.order = void 0; return true; } store.order[providerKey] = deduped; return true; } }); } function upsertAuthProfile(params) { const store = ensureAuthProfileStore(params.agentDir); store.profiles[params.profileId] = params.credential; saveAuthProfileStore(store, params.agentDir); } 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; } function repairOAuthProfileIdMismatch(params) { const legacyProfileId = params.legacyProfileId ?? `${normalizeProviderId(params.provider)}:default`; const legacyCfg = params.cfg.auth?.profiles?.[legacyProfileId]; if (!legacyCfg) return { config: params.cfg, changes: [], migrated: false }; if (legacyCfg.mode !== "oauth") return { config: params.cfg, changes: [], migrated: false }; if (normalizeProviderId(legacyCfg.provider) !== normalizeProviderId(params.provider)) return { config: params.cfg, changes: [], migrated: false }; const toProfileId = suggestOAuthProfileIdForLegacyDefault({ cfg: params.cfg, store: params.store, provider: params.provider, legacyProfileId }); if (!toProfileId || toProfileId === legacyProfileId) return { config: params.cfg, changes: [], migrated: false }; const toCred = params.store.profiles[toProfileId]; const toEmail = toCred?.type === "oauth" ? toCred.email?.trim() : void 0; const nextProfiles = { ...params.cfg.auth?.profiles }; delete nextProfiles[legacyProfileId]; nextProfiles[toProfileId] = { ...legacyCfg, ...toEmail ? { email: toEmail } : {} }; const providerKey = normalizeProviderId(params.provider); const nextOrder = (() => { const order = params.cfg.auth?.order; if (!order) return; const resolvedKey = Object.keys(order).find((key) => normalizeProviderId(key) === providerKey); if (!resolvedKey) return order; const existing = order[resolvedKey]; if (!Array.isArray(existing)) return order; const replaced = existing.map((id) => id === legacyProfileId ? toProfileId : id).filter((id) => typeof id === "string" && id.trim().length > 0); const deduped = []; for (const entry of replaced) if (!deduped.includes(entry)) deduped.push(entry); return { ...order, [resolvedKey]: deduped }; })(); return { config: { ...params.cfg, auth: { ...params.cfg.auth, profiles: nextProfiles, ...nextOrder ? { order: nextOrder } : {} } }, changes: [`Auth: migrate ${legacyProfileId} → ${toProfileId} (OAuth profile id)`], migrated: true, fromProfileId: legacyProfileId, toProfileId }; } //#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 generateChutesPkce() { const verifier = randomBytes(32).toString("hex"); return { verifier, challenge: createHash("sha256").update(verifier).digest("base64url") }; } function parseOAuthCallbackInput(input, expectedState) { const trimmed = input.trim(); if (!trimmed) return { error: "No input provided" }; try { const url = new URL(trimmed); const code = url.searchParams.get("code"); const state = url.searchParams.get("state"); if (!code) return { error: "Missing 'code' parameter in URL" }; if (!state) return { error: "Missing 'state' parameter. Paste the full URL." }; return { code, state }; } catch { if (!expectedState) return { error: "Paste the full redirect URL, not just the code." }; return { code: trimmed, state: expectedState }; } } 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 fetchChutesUserInfo(params) { const response = await (params.fetchFn ?? fetch)(CHUTES_USERINFO_ENDPOINT, { headers: { Authorization: `Bearer ${params.accessToken}` } }); if (!response.ok) return null; const data = await response.json(); if (!data || typeof data !== "object") return null; return data; } async function exchangeChutesCodeForTokens(params) { const fetchFn = params.fetchFn ?? fetch; const now = params.now ?? Date.now(); const body = new URLSearchParams({ grant_type: "authorization_code", client_id: params.app.clientId, code: params.code, redirect_uri: params.app.redirectUri, code_verifier: params.codeVerifier }); if (params.app.clientSecret) body.set("client_secret", params.app.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 exchange failed: ${text}`); } const data = await response.json(); const access = data.access_token?.trim(); const refresh = data.refresh_token?.trim(); const expiresIn = data.expires_in ?? 0; if (!access) throw new Error("Chutes token exchange returned no access_token"); if (!refresh) throw new Error("Chutes token exchange returned no refresh_token"); const info = await fetchChutesUserInfo({ accessToken: access, fetchFn }); return { access, refresh, expires: coerceExpiresAt(expiresIn, now), email: info?.username, accountId: info?.sub, clientId: params.app.clientId }; } 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 resolveProfileUnusableUntilForDisplay(store, profileId) { const stats = store.usageStats?.[profileId]; if (!stats) return null; return resolveProfileUnusableUntil$1(stats); } 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/auth-profiles.ts var auth_profiles_exports = /* @__PURE__ */ __exportAll({ ensureAuthProfileStore: () => ensureAuthProfileStore }); //#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 discoveryPro