import * as Schema from "effect/Schema"; import { ForwardCompatibleArray, IsoDateTime, NonNegativeInt, TrimmedNonEmptyString,} from "./baseSchemas.ts";import { ProviderDriverKind, ProviderInstanceId } from "./providerInstance.ts";import { UsageLimitSourceId } from "./usageLimitSourceId.ts"; /** * One rolling quota window a subscription provider reports for the signed-in * account, e.g. Claude's five-hour session or Codex's weekly allowance. * * `id` is stable per provider (`five_hour`, `seven_day_opus`, `primary`) so a * sparse turn-driven update lands on the same row a full probe produced. * `kind` only orders and labels the bar. */export const ServerProviderUsageWindow = Schema.Struct({ id: TrimmedNonEmptyString, kind: Schema.Literals(["session", "weekly", "monthly", "other"]), label: TrimmedNonEmptyString, usedPercent: Schema.Number.check(Schema.isBetween({ minimum: 0, maximum: 100 })), resetsAt: Schema.optional(IsoDateTime), windowDurationMins: Schema.optional(NonNegativeInt),});export type ServerProviderUsageWindow = typeof ServerProviderUsageWindow.Type; /** * Reset credits a provider banks on the account. Codex grants these when it * has rate-limited the user unfairly; redeeming one clears the current * windows. Only present when the provider reports them at all. */export const ServerProviderResetCredits = Schema.Struct({ availableCount: NonNegativeInt, nextExpiresAt: Schema.optional(IsoDateTime), /** Pins hub redemption to the displayed credit, including retries from another client. */ nextCreditId: Schema.optional(TrimmedNonEmptyString),});export type ServerProviderResetCredits = typeof ServerProviderResetCredits.Type; /** * Subscription usage the provider knows about the signed-in account. * * `unavailable` distinguishes an account that can never report windows (API * key, Bedrock) from a probe that failed this time, so clients can keep the * last good bars for the latter and clear them for the former. */export const ServerProviderUsageLimits = Schema.Struct({ checkedAt: IsoDateTime, windows: ForwardCompatibleArray(ServerProviderUsageWindow), resetCredits: Schema.optional(ServerProviderResetCredits), unavailable: Schema.optional( Schema.Struct({ reason: Schema.Literals(["unsupported", "probeFailed"]), message: Schema.optional(TrimmedNonEmptyString), }), ),});export type ServerProviderUsageLimits = typeof ServerProviderUsageLimits.Type; /** * What an adapter reports when its runtime pushes a rate-limit update during * a turn. Sparse by contract: Claude's `rate_limit_event` names one window at * a time and Codex documents its notification as a partial. Windows merge by * `id` onto the instance's published snapshot; omitted windows are unchanged. */export const ProviderUsageLimitsUpdate = Schema.Struct({ windows: Schema.Array(ServerProviderUsageWindow),});export type ProviderUsageLimitsUpdate = typeof ProviderUsageLimitsUpdate.Type; /** * One account a usage-limit source reports on. `driver` is the provider the * account belongs to, for the icon and colour clients already have; the * account itself is not something this environment can run turns on. */export const UsageLimitSourceAccount = Schema.Struct({ id: TrimmedNonEmptyString, driver: ProviderDriverKind, /** The signed-in address, when the source names one; clients blur it like provider auth. */ email: Schema.optional(TrimmedNonEmptyString), /** Plan as the matching provider would label it (`ChatGPT Pro 20x Subscription`). */ plan: Schema.optional(TrimmedNonEmptyString), usageLimits: ServerProviderUsageLimits,});export type UsageLimitSourceAccount = typeof UsageLimitSourceAccount.Type; /** * The published state of one configured `usageLimitSources` entry. A source * that could not be read keeps `error` beside an empty account list rather * than vanishing, so the user can see it is configured but failing. */export const UsageLimitSourceSnapshot = Schema.Struct({ id: UsageLimitSourceId, kind: Schema.Literal("cliproxy"), label: TrimmedNonEmptyString, checkedAt: IsoDateTime, accounts: ForwardCompatibleArray(UsageLimitSourceAccount), error: Schema.optional(TrimmedNonEmptyString),});export type UsageLimitSourceSnapshot = typeof UsageLimitSourceSnapshot.Type; export const UsageLimitSourceSnapshots = ForwardCompatibleArray(UsageLimitSourceSnapshot);export type UsageLimitSourceSnapshots = typeof UsageLimitSourceSnapshots.Type; export const UsageLimitSourceConsumeResetCreditInput = Schema.Struct({ sourceId: UsageLimitSourceId, accountId: TrimmedNonEmptyString, creditId: TrimmedNonEmptyString,});export type UsageLimitSourceConsumeResetCreditInput = typeof UsageLimitSourceConsumeResetCreditInput.Type; export const ProviderConsumeResetCreditInput = Schema.Union([ Schema.Struct({ instanceId: ProviderInstanceId }), UsageLimitSourceConsumeResetCreditInput,]);export type ProviderConsumeResetCreditInput = typeof ProviderConsumeResetCreditInput.Type; export class UsageLimitSourceError extends Schema.TaggedError<UsageLimitSourceError>()( "UsageLimitSourceError", { detail: Schema.String },) { override get message(): string { return this.detail; }} /** Mirrors Codex's own outcome set; other providers map onto it. */export const ProviderConsumeResetCreditOutcome = Schema.Literals([ "reset", "nothingToReset", "noCredit", "alreadyRedeemed",]);export type ProviderConsumeResetCreditOutcome = typeof ProviderConsumeResetCreditOutcome.Type; export const ProviderConsumeResetCreditResult = Schema.Struct({ outcome: ProviderConsumeResetCreditOutcome, /** Redemption succeeded, but a follow-up such as clearing the hub cooldown failed. */ warning: Schema.optional(TrimmedNonEmptyString),});export type ProviderConsumeResetCreditResult = typeof ProviderConsumeResetCreditResult.Type; /** A point-in-time view of one provider's limits, built for the /usage-limits panel. */export const UsageLimitsReport = Schema.Struct({ createdAt: IsoDateTime, accounts: Schema.Array( Schema.Struct({ id: TrimmedNonEmptyString, driver: ProviderDriverKind, label: TrimmedNonEmptyString, plan: Schema.optional(TrimmedNonEmptyString), email: Schema.optional(TrimmedNonEmptyString), sourceLabel: Schema.optional(TrimmedNonEmptyString), instanceId: Schema.optional(ProviderInstanceId), resetCreditInput: Schema.optional(ProviderConsumeResetCreditInput), displayName: Schema.optional(Schema.String), accentColor: Schema.optional(Schema.String), limits: ServerProviderUsageLimits, }), ), notices: Schema.Array(Schema.String),});export type UsageLimitsReport = typeof UsageLimitsReport.Type;
import * as Schema from "effect/Schema";
import {
ForwardCompatibleArray,
IsoDateTime,
NonNegativeInt,
TrimmedNonEmptyString,
} from "./baseSchemas.ts";
import { ProviderDriverKind, ProviderInstanceId } from "./providerInstance.ts";
import { UsageLimitSourceId } from "./usageLimitSourceId.ts";
/**
* One rolling quota window a subscription provider reports for the signed-in
* account, e.g. Claude's five-hour session or Codex's weekly allowance.
*
* `id` is stable per provider (`five_hour`, `seven_day_opus`, `primary`) so a
* sparse turn-driven update lands on the same row a full probe produced.
* `kind` only orders and labels the bar.
*/
export const ServerProviderUsageWindow = Schema.Struct({
id: TrimmedNonEmptyString,
kind: Schema.Literals(["session", "weekly", "monthly", "other"]),
label: TrimmedNonEmptyString,
usedPercent: Schema.Number.check(Schema.isBetween({ minimum: 0, maximum: 100 })),
resetsAt: Schema.optional(IsoDateTime),
windowDurationMins: Schema.optional(NonNegativeInt),
});
export type ServerProviderUsageWindow = typeof ServerProviderUsageWindow.Type;
/**
* Reset credits a provider banks on the account. Codex grants these when it
* has rate-limited the user unfairly; redeeming one clears the current
* windows. Only present when the provider reports them at all.
*/
export const ServerProviderResetCredits = Schema.Struct({
availableCount: NonNegativeInt,
nextExpiresAt: Schema.optional(IsoDateTime),
/** Pins hub redemption to the displayed credit, including retries from another client. */
nextCreditId: Schema.optional(TrimmedNonEmptyString),
});
export type ServerProviderResetCredits = typeof ServerProviderResetCredits.Type;
/**
* Subscription usage the provider knows about the signed-in account.
*
* `unavailable` distinguishes an account that can never report windows (API
* key, Bedrock) from a probe that failed this time, so clients can keep the
* last good bars for the latter and clear them for the former.
*/
export const ServerProviderUsageLimits = Schema.Struct({
checkedAt: IsoDateTime,
windows: ForwardCompatibleArray(ServerProviderUsageWindow),
resetCredits: Schema.optional(ServerProviderResetCredits),
unavailable: Schema.optional(
Schema.Struct({
reason: Schema.Literals(["unsupported", "probeFailed"]),
message: Schema.optional(TrimmedNonEmptyString),
}),
),
});
export type ServerProviderUsageLimits = typeof ServerProviderUsageLimits.Type;
/**
* What an adapter reports when its runtime pushes a rate-limit update during
* a turn. Sparse by contract: Claude's `rate_limit_event` names one window at
* a time and Codex documents its notification as a partial. Windows merge by
* `id` onto the instance's published snapshot; omitted windows are unchanged.
*/
export const ProviderUsageLimitsUpdate = Schema.Struct({
windows: Schema.Array(ServerProviderUsageWindow),
});
export type ProviderUsageLimitsUpdate = typeof ProviderUsageLimitsUpdate.Type;
/**
* One account a usage-limit source reports on. `driver` is the provider the
* account belongs to, for the icon and colour clients already have; the
* account itself is not something this environment can run turns on.
*/
export const UsageLimitSourceAccount = Schema.Struct({
id: TrimmedNonEmptyString,
driver: ProviderDriverKind,
/** The signed-in address, when the source names one; clients blur it like provider auth. */
email: Schema.optional(TrimmedNonEmptyString),
/** Plan as the matching provider would label it (`ChatGPT Pro 20x Subscription`). */
plan: Schema.optional(TrimmedNonEmptyString),
usageLimits: ServerProviderUsageLimits,
});
export type UsageLimitSourceAccount = typeof UsageLimitSourceAccount.Type;
/**
* The published state of one configured `usageLimitSources` entry. A source
* that could not be read keeps `error` beside an empty account list rather
* than vanishing, so the user can see it is configured but failing.
*/
export const UsageLimitSourceSnapshot = Schema.Struct({
id: UsageLimitSourceId,
kind: Schema.Literal("cliproxy"),
label: TrimmedNonEmptyString,
checkedAt: IsoDateTime,
accounts: ForwardCompatibleArray(UsageLimitSourceAccount),
error: Schema.optional(TrimmedNonEmptyString),
});
export type UsageLimitSourceSnapshot = typeof UsageLimitSourceSnapshot.Type;
export const UsageLimitSourceSnapshots = ForwardCompatibleArray(UsageLimitSourceSnapshot);
export type UsageLimitSourceSnapshots = typeof UsageLimitSourceSnapshots.Type;
export const UsageLimitSourceConsumeResetCreditInput = Schema.Struct({
sourceId: UsageLimitSourceId,
accountId: TrimmedNonEmptyString,
creditId: TrimmedNonEmptyString,
});
export type UsageLimitSourceConsumeResetCreditInput =
typeof UsageLimitSourceConsumeResetCreditInput.Type;
export const ProviderConsumeResetCreditInput = Schema.Union([
Schema.Struct({ instanceId: ProviderInstanceId }),
UsageLimitSourceConsumeResetCreditInput,
]);
export type ProviderConsumeResetCreditInput = typeof ProviderConsumeResetCreditInput.Type;
export class UsageLimitSourceError extends Schema.TaggedError<UsageLimitSourceError>()(
"UsageLimitSourceError",
{ detail: Schema.String },
) {
override get message(): string {
return this.detail;
}
}
/** Mirrors Codex's own outcome set; other providers map onto it. */
export const ProviderConsumeResetCreditOutcome = Schema.Literals([
"reset",
"nothingToReset",
"noCredit",
"alreadyRedeemed",
]);
export type ProviderConsumeResetCreditOutcome = typeof ProviderConsumeResetCreditOutcome.Type;
export const ProviderConsumeResetCreditResult = Schema.Struct({
outcome: ProviderConsumeResetCreditOutcome,
/** Redemption succeeded, but a follow-up such as clearing the hub cooldown failed. */
warning: Schema.optional(TrimmedNonEmptyString),
});
export type ProviderConsumeResetCreditResult = typeof ProviderConsumeResetCreditResult.Type;
/** A point-in-time view of one provider's limits, built for the /usage-limits panel. */
export const UsageLimitsReport = Schema.Struct({
createdAt: IsoDateTime,
accounts: Schema.Array(
Schema.Struct({
id: TrimmedNonEmptyString,
driver: ProviderDriverKind,
label: TrimmedNonEmptyString,
plan: Schema.optional(TrimmedNonEmptyString),
email: Schema.optional(TrimmedNonEmptyString),
sourceLabel: Schema.optional(TrimmedNonEmptyString),
instanceId: Schema.optional(ProviderInstanceId),
resetCreditInput: Schema.optional(ProviderConsumeResetCreditInput),
displayName: Schema.optional(Schema.String),
accentColor: Schema.optional(Schema.String),
limits: ServerProviderUsageLimits,
}),
),
notices: Schema.Array(Schema.String),
});
export type UsageLimitsReport = typeof UsageLimitsReport.Type;