package shared import ( "net/http" "strconv" "strings" ) // PriorityHeader carries the caller's scheduling priority. Priority is a // property of the caller's intent, not of the model — the same model serves // both an interactive request and a batch job — so it travels as a header // rather than as per-model configuration, and leaves the OpenAI-compatible // request body untouched. const PriorityHeader = "X-LlamaSwap-Priority" // Priority band anchors. The number is the interface: callers may send any // signed integer, and these names are conveniences that resolve to a value. // // Bands are spaced 100 apart so a consumer can add a small per-caller offset // (a subscription tier, say) on top of a band without ever promoting a request // across one: a "max member" batch job at -98 still loses to every normal // request at 0. const ( PriorityInteractive = 100 // a human is waiting PriorityNormal = 0 // the default PriorityBatch = -100 ) // bandHalfWidth is how far a priority may sit from a band anchor and still be // reported as that band. It is half the 100-point band spacing, so every // integer belongs to exactly one band. const bandHalfWidth = 50 // Band names used for metrics labels, ordered most to least urgent. const ( BandInteractive = "interactive" BandNormal = "normal" BandBatch = "batch" ) // PriorityBands is every band name, in descending order of urgency. Metrics // emit a series per band regardless of whether any request currently occupies // it, so the label set stays stable. var PriorityBands = []string{BandInteractive, BandNormal, BandBatch} var priorityAliases = map[string]int{ "interactive": PriorityInteractive, "normal": PriorityNormal, "batch": PriorityBatch, } // ParsePriority resolves a PriorityHeader value to a signed integer. A numeric // value is used as-is; a recognised alias resolves to its anchor. Anything // absent or unparseable is PriorityNormal, so a malformed header degrades to // the default rather than failing the request. // // Values are deliberately not clamped: the caller composes band, tier offset // and anything else it wants into one number, and llama-swap honours it. func ParsePriority(value string) int { value = strings.TrimSpace(value) if value == "" { return PriorityNormal } if n, err := strconv.Atoi(value); err == nil { return n } if n, ok := priorityAliases[strings.ToLower(value)]; ok { return n } return PriorityNormal } // RequestPriority reads PriorityHeader off r and resolves it. See ParsePriority. func RequestPriority(r *http.Request) int { return ParsePriority(r.Header.Get(PriorityHeader)) } // PriorityBand buckets a priority into the band it belongs to, for metrics // labels. Values beyond the anchors saturate: +1000 is still "interactive". func PriorityBand(priority int) string { switch { case priority >= PriorityInteractive-bandHalfWidth: return BandInteractive case priority <= PriorityBatch+bandHalfWidth: return BandBatch default: return BandNormal } }