@gguf/claw
Version:
WhatsApp gateway CLI (Baileys web) with Pi RPC agent
1,355 lines (1,333 loc) • 89.5 kB
JavaScript
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 =