mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-23 23:52:18 +03:00
Merged — locally validated (30/30 focused tests: chatcore-codex-account-pool, codex-account-cooldown-write, codex-account-pool, providers-route-codex-account-pool, resilience-explain-codex-account, sse-auth-codex-account-pool; typecheck:core clean; file-size/complexity/cognitive-complexity/changelog gates all green). Merges clean against the current release tip with zero conflicts. Great refactor — extracting persistCodexQuotaState out of chatCore.ts into a proper codexAccount/ module with virtual quota pool isolation is a solid improvement. Thanks!
190 lines
6.2 KiB
TypeScript
190 lines
6.2 KiB
TypeScript
import { getCodexModelScope } from "../../config/codexQuotaScopes.ts";
|
|
import {
|
|
getCodexChildQuotaHydration,
|
|
getEarliestCodexChildCooldown,
|
|
inspectCodexAccount,
|
|
} from "./state.ts";
|
|
import type {
|
|
CodexAccount,
|
|
CodexAccountConnection,
|
|
CodexAccountPool,
|
|
CodexChildAccount,
|
|
CodexParentAccount,
|
|
CodexAccountPoolProjection,
|
|
CodexQuotaWindowSnapshot,
|
|
} from "./types.ts";
|
|
|
|
function createParentAccount(connection: CodexAccountConnection): CodexParentAccount {
|
|
return {
|
|
kind: "parent",
|
|
key: { parentConnectionId: connection.id, scope: null },
|
|
connectionId: connection.id,
|
|
scope: null,
|
|
connection,
|
|
};
|
|
}
|
|
|
|
function createChildAccount(
|
|
connection: CodexAccountConnection,
|
|
scope: CodexChildAccount["scope"]
|
|
): CodexChildAccount {
|
|
return {
|
|
kind: "child",
|
|
key: { parentConnectionId: connection.id, scope },
|
|
connectionId: connection.id,
|
|
scope,
|
|
connection,
|
|
};
|
|
}
|
|
|
|
/** Build one parent and two virtual children around a single DB connection. */
|
|
export function createCodexAccountPool(connection: CodexAccountConnection): CodexAccountPool {
|
|
const parent = createParentAccount(connection);
|
|
const codex = createChildAccount(connection, "codex");
|
|
const spark = createChildAccount(connection, "spark");
|
|
return {
|
|
parent,
|
|
children: [codex, spark],
|
|
accounts: [parent, codex, spark],
|
|
};
|
|
}
|
|
|
|
/** Project one persisted connection into the safe parent/child account read model. */
|
|
export function projectCodexAccountPool(
|
|
connection: CodexAccountConnection,
|
|
now = Date.now()
|
|
): CodexAccountPoolProjection {
|
|
const pool = createCodexAccountPool(connection);
|
|
const children = pool.children.map((child) => {
|
|
const state = inspectCodexAccount(pool, child, now);
|
|
const hydration = getCodexChildQuotaHydration(child);
|
|
const quotaWindow = (window: "5h" | "7d"): CodexQuotaWindowSnapshot | null => {
|
|
const quota = hydration.quotaState;
|
|
if (!quota) return null;
|
|
const usage = quota[window === "5h" ? "usage5h" : "usage7d"];
|
|
const limit = quota[window === "5h" ? "limit5h" : "limit7d"];
|
|
const resetAt = quota[window === "5h" ? "resetAt5h" : "resetAt7d"] ?? null;
|
|
if (typeof usage !== "number" && typeof limit !== "number" && !resetAt) return null;
|
|
return {
|
|
usage: typeof usage === "number" ? usage : null,
|
|
limit: typeof limit === "number" ? limit : null,
|
|
resetAt,
|
|
usedPercentage:
|
|
typeof usage === "number" && typeof limit === "number" && limit > 0
|
|
? (usage / limit) * 100
|
|
: null,
|
|
};
|
|
};
|
|
const cooldownActive = Boolean(
|
|
state.rateLimitedUntil && new Date(state.rateLimitedUntil).getTime() > now
|
|
);
|
|
const exhaustedWindow = hydration.exhaustedWindow;
|
|
const exhaustedResetAt =
|
|
exhaustedWindow === "5h"
|
|
? hydration.quotaState?.resetAt5h
|
|
: exhaustedWindow === "7d"
|
|
? hydration.quotaState?.resetAt7d
|
|
: null;
|
|
const exhaustionActive = Boolean(
|
|
exhaustedWindow && exhaustedResetAt && new Date(exhaustedResetAt).getTime() > now
|
|
);
|
|
const unavailable = cooldownActive || exhaustionActive;
|
|
return {
|
|
key: child.key,
|
|
unavailable,
|
|
cooldown: {
|
|
active: cooldownActive,
|
|
rateLimitedUntil: cooldownActive ? state.rateLimitedUntil : null,
|
|
},
|
|
quota: {
|
|
exhaustedWindow: exhaustionActive ? exhaustedWindow : null,
|
|
observedAt: hydration.quotaState?.observedAt ?? null,
|
|
windows: { "5h": quotaWindow("5h"), "7d": quotaWindow("7d") },
|
|
},
|
|
};
|
|
}) as [CodexAccountPoolProjection["children"][0], CodexAccountPoolProjection["children"][1]];
|
|
const limitedChildCount = children.filter((child) => child.unavailable).length;
|
|
return {
|
|
parentConnectionId: connection.id,
|
|
aggregate: {
|
|
status:
|
|
limitedChildCount === 0
|
|
? "available"
|
|
: limitedChildCount === children.length
|
|
? "fully_limited"
|
|
: "partially_limited",
|
|
limitedChildCount,
|
|
},
|
|
children,
|
|
};
|
|
}
|
|
|
|
/** Resolve the scoped child whose quota owns a nonblank model, or the parent otherwise. */
|
|
export function resolveCodexAccount(
|
|
pool: CodexAccountPool,
|
|
model: string | null | undefined
|
|
): CodexAccount {
|
|
if (typeof model !== "string" || model.trim().length === 0) return pool.parent;
|
|
const scope = getCodexModelScope(model);
|
|
return pool.children.find((account) => account.scope === scope) || pool.parent;
|
|
}
|
|
|
|
function inspectResolvedCodexChild(
|
|
connection: CodexAccountConnection,
|
|
model: string | null | undefined,
|
|
now = Date.now()
|
|
) {
|
|
const pool = createCodexAccountPool(connection);
|
|
const state = inspectCodexAccount(pool, resolveCodexAccount(pool, model), now);
|
|
return state.kind === "child" ? state : null;
|
|
}
|
|
|
|
/** Return whether the requested model's virtual child is currently unavailable. */
|
|
export function isCodexChildUnavailable(
|
|
connection: CodexAccountConnection,
|
|
model: string | null | undefined,
|
|
now = Date.now()
|
|
): boolean {
|
|
return inspectResolvedCodexChild(connection, model, now)?.unavailable ?? false;
|
|
}
|
|
|
|
/** Return the active cooldown for the requested model's virtual child. */
|
|
export function getCodexChildCooldown(
|
|
connection: CodexAccountConnection,
|
|
model: string | null | undefined,
|
|
now = Date.now()
|
|
): string | null {
|
|
return inspectResolvedCodexChild(connection, model, now)?.rateLimitedUntil ?? null;
|
|
}
|
|
|
|
export {
|
|
getCodexAccountPoolState,
|
|
getCodexChildQuotaHydration,
|
|
getCodexParentAccountDiagnostic,
|
|
getEarliestCodexChildCooldown,
|
|
inspectCodexAccount,
|
|
} from "./state.ts";
|
|
export { persistCodexChildCooldown } from "./write.ts";
|
|
export type { PersistCodexChildCooldownResult } from "./write.ts";
|
|
export { persistCodexChildQuotaResponse } from "./quota.ts";
|
|
export type { PersistCodexChildQuotaResult } from "./quota.ts";
|
|
export type {
|
|
CodexAccount,
|
|
CodexAccountConnection,
|
|
CodexAccountKey,
|
|
CodexAccountPool,
|
|
CodexChildAccount,
|
|
CodexAccountPoolState,
|
|
CodexAccountPoolStatus,
|
|
CodexAccountState,
|
|
CodexChildAccountState,
|
|
CodexChildCooldown,
|
|
CodexChildQuotaHydration,
|
|
CodexAccountPoolProjection,
|
|
CodexChildAccountProjection,
|
|
CodexQuotaWindowSnapshot,
|
|
CodexParentAccount,
|
|
CodexParentAccountDiagnostic,
|
|
CodexPersistedQuotaState,
|
|
} from "./types.ts";
|