package quota import ( "fmt" "math" "strings" ) // Multipliers are the z.ai credit formula coefficients (per 10k tokens, // docs.z.ai/devpack/overview). Family selects by concrete model name; the // flash tier (GLM-5.3-Flash, routed from glm-4.7*) is the cheap one. type Multipliers struct { Input float64 CachedInput float64 Output float64 } // Flagship multipliers: GLM-5.3 (and everything auto-routed to it). func FlagshipMultipliers() Multipliers { return Multipliers{Input: 6.9, CachedInput: 1.7, Output: 24} } // Flash multipliers: GLM-5.3-Flash (and glm-4.7* routing). func FlashMultipliers() Multipliers { return Multipliers{Input: 2.3, CachedInput: 0.56, Output: 8} } // MultipliersFor maps a concrete proxy model name to its credit multiplier // family. Unknown models read as flagship (conservative: overestimate cost // rather than silently burn quota). func MultipliersFor(model string) Multipliers { m := strings.ToLower(model) switch { case strings.Contains(m, "flash"): return FlashMultipliers() default: return FlagshipMultipliers() } } // EstimateCredits computes the z.ai credits one turn consumed from its token // usage: (input*in + cached*cache + output*out) / 10000, halved when the // turn ran off-peak (z.ai charges 50% outside peak hours). func EstimateCredits(model string, promptTokens, cachedTokens, completionTokens int, peak bool) float64 { mult := MultipliersFor(model) credits := (float64(promptTokens)*mult.Input + float64(cachedTokens)*mult.CachedInput + float64(completionTokens)*mult.Output) / 10000 if !peak { credits /= 2 } // Round to 6 decimals: keeps redis INCRBYFLOAT values readable and the // JSONL compact; sub-microcredit noise is meaningless. return math.Round(credits*1e6) / 1e6 } // EstimateTurnInput is the per-turn usage record the loop hands the gate. type EstimateTurnInput struct { Model string PromptTokens int CachedTokens int CompletionTokens int Peak bool // turn ran inside the peak window } // Describe renders a human summary of one turn's credit cost (logs, REPORTs). func (e EstimateTurnInput) Describe() string { return fmt.Sprintf("%s: %d/%d/%d tokens (in/cached/out) %s = %.4f credits", e.Model, e.PromptTokens, e.CachedTokens, e.CompletionTokens, peakTag(e.Peak), EstimateCredits(e.Model, e.PromptTokens, e.CachedTokens, e.CompletionTokens, e.Peak)) } func peakTag(peak bool) string { if peak { return "peak" } return "off-peak" }