84 lines
2.1 KiB
TypeScript
84 lines
2.1 KiB
TypeScript
export type BotProfile = {
|
|
type: "claude" | "codex";
|
|
model: string;
|
|
token?: string;
|
|
};
|
|
|
|
function isUsageExhausted(error: unknown): boolean {
|
|
return /(?:usage|rate) limit|hit your limit|insufficient_quota|exceeded your current quota|too many requests|(?:api error|http error|http|status(?: code)?)[ :]+4(?:02|29)\b/i
|
|
.test(String(error));
|
|
}
|
|
|
|
export async function runProfiles<
|
|
T,
|
|
P extends Pick<BotProfile, "type" | "model">,
|
|
>(
|
|
profiles: P[],
|
|
attempt: (profile: P) => Promise<T>,
|
|
): Promise<T> {
|
|
for (const [index, profile] of profiles.entries()) {
|
|
try {
|
|
return await attempt(profile);
|
|
} catch (error) {
|
|
if (!isUsageExhausted(error) || index === profiles.length - 1) {
|
|
throw error;
|
|
}
|
|
console.error(`${profile.type} usage exhausted; trying next profile`);
|
|
}
|
|
}
|
|
throw new Error("profiles must contain at least one profile");
|
|
}
|
|
|
|
export function sanitizedEnvironment(
|
|
environment: Record<string, string>,
|
|
): Record<string, string> {
|
|
const result: Record<string, string> = {};
|
|
for (
|
|
const name of [
|
|
"PATH",
|
|
"HOME",
|
|
"LANG",
|
|
"LANGUAGE",
|
|
"LC_ALL",
|
|
"TERM",
|
|
"COLORTERM",
|
|
"CI",
|
|
"TMPDIR",
|
|
"GITEA_TOKEN",
|
|
"GITEA_API_URL",
|
|
"GITEA_REPOSITORY",
|
|
"GITHUB_WORKSPACE",
|
|
"HTTP_PROXY",
|
|
"HTTPS_PROXY",
|
|
"ALL_PROXY",
|
|
"NO_PROXY",
|
|
"http_proxy",
|
|
"https_proxy",
|
|
"all_proxy",
|
|
"no_proxy",
|
|
"SSL_CERT_FILE",
|
|
"SSL_CERT_DIR",
|
|
"NODE_EXTRA_CA_CERTS",
|
|
]
|
|
) {
|
|
if (environment[name] !== undefined) result[name] = environment[name];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export function agentEnvironment(
|
|
environment: Record<string, string>,
|
|
profile: Pick<BotProfile, "type"> & { home: string },
|
|
token?: string,
|
|
): Record<string, string> {
|
|
const result = sanitizedEnvironment(environment);
|
|
result.HOME = profile.home;
|
|
if (profile.type === "codex") result.CODEX_HOME = `${profile.home}/.codex`;
|
|
if (token) {
|
|
result[
|
|
profile.type === "claude" ? "CLAUDE_CODE_OAUTH_TOKEN" : "OPENAI_API_KEY"
|
|
] = token;
|
|
}
|
|
return result;
|
|
}
|