import type { CodexAccount, CodexAccountsResponse, CodexRotationSettings, CodexUsageMap, SessionCodexAccountsResponse, SessionEvent } from "@opengeni/sdk"; import { type ClientOverride } from "../provider.js"; import { type SessionEventFeedOptions } from "./internal.js"; import { type SharedQueryKey, type SharedQueryWriter } from "./shared-query.js"; /** * Shared-cache keys for Codex reads. Every surface that reads the same thing * through the same client (the session switcher, Settings > Models) shares one * entry, so a revisit renders the last rows at once and re-reads quietly. * Internal: not exported from the package root. */ export declare const codexAccountsQueryKey: (workspaceId: string, sessionId?: string | null) => SharedQueryKey; /** The last LIVE provider usage per account, written by every live usage read. */ export declare const codexLiveUsageQueryKey: (workspaceId: string) => SharedQueryKey; /** * The last LIVE provider reading per account and when each one was taken. Only * live provider reads write it, never the server's cached limit columns. */ export type CodexLiveUsageSnapshot = { usage: CodexUsageMap; /** Epoch milliseconds of each account's reading. */ readAt: Record; }; /** * Record live readings through a writer created before the read started. * `replace` is a read of every account (the batch); `merge` updates only the * accounts in `readings` and leaves the others' readings and times alone. */ export declare function recordCodexLiveUsage(write: SharedQueryWriter, scope: object, workspaceId: string, readings: CodexUsageMap, mode: "replace" | "merge"): boolean; /** Events that change which Codex account a session runs on (or just ran). */ export declare function isCodexAccountEvent(event: Pick): boolean; /** * The structural slice of the SDK client the Codex-accounts surface needs. Method * NAMES + SIGNATURES match `OpenGeniClient` so the real client satisfies it * directly; declared structurally (not a hard Pick) so a test/Geni client can * stand in. `listSessionCodexAccounts` reads the accepted selection and choices * atomically; `pinSessionCodexAccount` * is the optional mutation (absent ⇒ the indicator hides the switch affordance). */ export type CodexAccountsClientLike = { listCodexAccounts: (workspaceId: string) => Promise; /** Required for session-scoped use; never fall back to another pool. */ listSessionCodexAccounts?: (workspaceId: string, sessionId: string) => Promise; getSession?: (workspaceId: string, sessionId: string) => Promise<{ codexPinnedCredentialId?: string | null; codexLastCredentialId?: string | null; codexCurrentSelection?: { credentialId: string | null; waiting: boolean; } | null; }>; pinSessionCodexAccount?: (workspaceId: string, sessionId: string, target: string) => Promise<{ pinned: string; appliedTo?: "waiting_turn" | "next_turn"; }>; /** Optional (absent ⇒ the card hides live refresh): batched live /wham/usage refresh. */ refreshCodexUsage?: (workspaceId: string) => Promise<{ usage: CodexUsageMap; }>; }; export type UseCodexAccountsOptions = ClientOverride & SessionEventFeedOptions & { pollIntervalMs?: number | undefined; /** Scope to a session so the hook resolves the pin + the effective account. */ sessionId?: string | undefined; /** Override the client with one implementing `CodexAccountsClientLike`. */ codexClient?: CodexAccountsClientLike | undefined; }; export type UseCodexAccountsResult = { accounts: CodexAccount[]; /** The ACTIVE account for the retry pool, or current workspace pool for new work. */ activeAccountId: string | null; /** The session's PINNED account (null ⇒ following workspace active). */ pinnedAccountId: string | null; /** Current preference only; automatic allocation can choose another account. */ effectiveAccountId: string | null; currentSelection: { credentialId: string | null; waiting: boolean; } | null; /** The accepted account can differ from the choices for the next turn. */ currentAccount: CodexAccount | null; switchAppliedTo: "waiting_turn" | "next_turn" | null; /** The account the session's last turn ACTUALLY ran on (the "Running on:" source). */ lastAccountId: string | null; settings: CodexRotationSettings; loading: boolean; error: Error | null; refresh: () => Promise; /** * Trigger a LIVE batched /wham/usage refresh across all accounts, then re-read * the cached metadata so the new windows land on `accounts`. Modeled on `pin`. * No-op (resolves false) when the client can't refresh usage. * With `maxAgeMs`, live readings younger than that are reused instead. */ refreshUsage: (options?: { maxAgeMs?: number | undefined; }) => Promise; /** Live provider readings override stale cached labels after refreshUsage. */ liveUsage: CodexUsageMap; /** When the live readings in `liveUsage` were taken (epoch ms), or null. */ liveUsageUpdatedAt: number | null; /** True while a live usage refresh is in flight (drives the bar skeleton). */ refreshingUsage: boolean; /** Pin (or unpin via "auto") the session's account; returns true on success. */ pin: (target: string) => Promise; pinning: boolean; /** The target of the in-flight pin (for per-row spinner gating). */ pinningTarget: string | null; mutationError: Error | null; }; /** * The workspace's Codex accounts, or session-authorized retry/next-turn choices * and accepted current account. Reads go through the client-scoped shared cache * (`useSharedQuery`): a remount renders the retained rows at once and re-reads * in the background; slow polling plus the `codex.account.switched` event * trigger keep them current, and `pin` invalidates the workspace's entries. * Dual-consumer safe via the structural `CodexAccountsClientLike` surface. */ export declare function useCodexAccounts(options?: UseCodexAccountsOptions): UseCodexAccountsResult;