Recognize sign-in failures for every agent and fall through (#19)
Co-authored-by: Danny Kim <temeddix@gmail.com> Co-committed-by: Danny Kim <temeddix@gmail.com>
This commit was merged in pull request #19.
This commit is contained in:
+30
-4
@@ -17,26 +17,52 @@ export function withProfile(
|
||||
return `${body}\n\n${profileFooter(profile)}`;
|
||||
}
|
||||
|
||||
export type FailureReason = "sign-in failed" | "usage exhausted" | "failed";
|
||||
|
||||
export type ProfileFailure = Pick<BotProfile, "type" | "model"> & {
|
||||
reason: FailureReason;
|
||||
};
|
||||
|
||||
// Raised once an agent's credentials are rejected and any re-login is spent.
|
||||
export class AgentAuthError extends Error {}
|
||||
|
||||
function isUsageExhausted(error: unknown): boolean {
|
||||
return /(?:usage|rate) limit|hit your (?:weekly )?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));
|
||||
}
|
||||
|
||||
function failureReason(error: unknown): FailureReason {
|
||||
if (error instanceof AgentAuthError) return "sign-in failed";
|
||||
return isUsageExhausted(error) ? "usage exhausted" : "failed";
|
||||
}
|
||||
|
||||
export function failureFooter(failures: ProfileFailure[]): string {
|
||||
if (failures.length === 0) return "> Profile: none";
|
||||
return `> Tried: ${
|
||||
failures
|
||||
.map(({ type, model, reason }) =>
|
||||
`\`${type}\` · \`${model}\` (${reason})`
|
||||
)
|
||||
.join(", ")
|
||||
}`;
|
||||
}
|
||||
|
||||
export async function runProfiles<
|
||||
T,
|
||||
P extends Pick<BotProfile, "type" | "model">,
|
||||
>(
|
||||
profiles: P[],
|
||||
attempt: (profile: P) => Promise<T>,
|
||||
failures: ProfileFailure[] = [],
|
||||
): 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`);
|
||||
const reason = failureReason(error);
|
||||
failures.push({ type: profile.type, model: profile.model, reason });
|
||||
if (reason === "failed" || index === profiles.length - 1) throw error;
|
||||
console.error(`${profile.type} ${reason}; trying next profile`);
|
||||
}
|
||||
}
|
||||
throw new Error("profiles must contain at least one profile");
|
||||
|
||||
Reference in New Issue
Block a user