feat(cost-guard): global Gemini daily budget + EOC alarm; trial requires verified email
This commit is contained in:
@@ -33,6 +33,10 @@ class RedisBudgetStore implements BudgetStore {
|
||||
private readonly key: string,
|
||||
) {}
|
||||
|
||||
private alarmKey(): string {
|
||||
return this.key.replace(/^gemini:daily:budget:/, "gemini:daily:budget:alarm:");
|
||||
}
|
||||
|
||||
async getDailySpendUsd(): Promise<number> {
|
||||
const val = await this.redis.get(this.key);
|
||||
return val ? Number(val) : 0;
|
||||
@@ -46,6 +50,11 @@ class RedisBudgetStore implements BudgetStore {
|
||||
return Number(newVal);
|
||||
}
|
||||
|
||||
async raiseBudgetAlarm(): Promise<void> {
|
||||
const ttl = this.secondsUntilMidnightUtc();
|
||||
await this.redis.set(this.alarmKey(), "1", "EX", ttl);
|
||||
}
|
||||
|
||||
private secondsUntilMidnightUtc(): number {
|
||||
const now = new Date();
|
||||
const midnight = new Date(
|
||||
|
||||
@@ -102,6 +102,9 @@ function mapPayloadForEoc(parsed: Record<string, unknown>): Record<string, unkno
|
||||
if (tile.label === "Allergen-brott" && allergenBreach) {
|
||||
tone = "crit";
|
||||
}
|
||||
if (tile.label === "AI-budget" && tone === "crit") {
|
||||
// already crit from buildWall
|
||||
}
|
||||
return { ...tile, tone };
|
||||
}),
|
||||
})),
|
||||
|
||||
Reference in New Issue
Block a user