mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-04 03:25:19 -04:00
110 lines
4.0 KiB
Go
110 lines
4.0 KiB
Go
package pricing
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"sort"
|
|
"strconv"
|
|
)
|
|
|
|
// MarshalDefaultsYAML renders the built-in default pricing table (catalog
|
|
// + supplementals, WITHOUT any operator override) as the YAML schema
|
|
// LoadOverrideFile consumes. It backs the generated
|
|
// defaults_llm_pricing.example.yaml so operators start from a file that
|
|
// matches the compiled-in rates exactly; a golden test keeps the two in
|
|
// sync. Output is deterministic (sorted surfaces and models).
|
|
func MarshalDefaultsYAML() []byte {
|
|
var b bytes.Buffer
|
|
b.WriteString(exampleHeader)
|
|
|
|
table := buildDefaultTable()
|
|
surfaces := make([]string, 0, len(table))
|
|
for s := range table {
|
|
surfaces = append(surfaces, s)
|
|
}
|
|
sort.Strings(surfaces)
|
|
|
|
for _, surface := range surfaces {
|
|
fmt.Fprintf(&b, "\n%s:\n", surface)
|
|
models := table[surface]
|
|
ids := make([]string, 0, len(models))
|
|
for id := range models {
|
|
ids = append(ids, id)
|
|
}
|
|
sort.Strings(ids)
|
|
for _, id := range ids {
|
|
e := models[id]
|
|
fmt.Fprintf(&b, " %s:\n", yamlKey(id))
|
|
fmt.Fprintf(&b, " input_per_1k: %s\n", rate(e.InputPer1k))
|
|
fmt.Fprintf(&b, " output_per_1k: %s\n", rate(e.OutputPer1k))
|
|
if e.CachedInputPer1k > 0 {
|
|
fmt.Fprintf(&b, " cached_input_per_1k: %s\n", rate(e.CachedInputPer1k))
|
|
}
|
|
if e.CacheReadPer1k > 0 {
|
|
fmt.Fprintf(&b, " cache_read_per_1k: %s\n", rate(e.CacheReadPer1k))
|
|
}
|
|
if e.CacheCreationPer1k > 0 {
|
|
fmt.Fprintf(&b, " cache_creation_per_1k: %s\n", rate(e.CacheCreationPer1k))
|
|
}
|
|
}
|
|
}
|
|
return b.Bytes()
|
|
}
|
|
|
|
// rate renders a USD-per-1k rate without float noise ("0.00015", not
|
|
// "0.000150000000...").
|
|
func rate(v float64) string {
|
|
return strconv.FormatFloat(v, 'f', -1, 64)
|
|
}
|
|
|
|
// yamlKey quotes model ids that YAML would otherwise misparse (e.g.
|
|
// "kimi-k3[1m]" starts a flow sequence unquoted).
|
|
func yamlKey(id string) string {
|
|
for _, r := range id {
|
|
switch r {
|
|
case '[', ']', '{', '}', ':', '#', ',', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
|
|
return strconv.Quote(id)
|
|
}
|
|
}
|
|
return id
|
|
}
|
|
|
|
const exampleHeader = `# Default LLM pricing used by NetBird's Agent Network cost metering.
|
|
# GENERATED from the management catalog — do not edit this file in the
|
|
# repository; regenerate with:
|
|
#
|
|
# go generate ./management/internals/modules/agentnetwork/pricing
|
|
#
|
|
# Operators: copy this file to <datadir>/defaults_llm_pricing.yaml (or
|
|
# any path configured via management.json:
|
|
#
|
|
# { "AgentNetwork": { "PricingDefaultsFile": "/path/defaults_llm_pricing.yaml" } }
|
|
#
|
|
# ) and adjust the entries you want to change. Management re-reads the
|
|
# file periodically (mtime poll, every minute): the live table feeds the
|
|
# proxies' cost metering and the dashboard's model-price prefill, so
|
|
# edits apply without a restart. Your file only needs the entries you
|
|
# want to change — but each entry REPLACES the built-in entry for that
|
|
# surface+model whole, so repeat the cache rates you want to keep.
|
|
# Unknown fields and negative or non-finite rates are rejected: at
|
|
# startup that fails boot (for an explicitly configured path); at
|
|
# runtime the previous table is kept and a warning is logged. Deleting
|
|
# the file reverts to the built-in defaults below.
|
|
#
|
|
# Top-level keys are pricing surfaces — the parser shape requests are
|
|
# metered under: "openai" (also Azure, Mistral, and OpenAI-compatible
|
|
# gateways), "anthropic" (also Anthropic-on-Vertex), "bedrock"
|
|
# (normalized ids, e.g. anthropic.claude-sonnet-4-5). Model keys must be
|
|
# the normalized id the proxy meters (version/region suffixes stripped).
|
|
#
|
|
# Values are USD per 1_000 tokens. Optional cache fields:
|
|
# cached_input_per_1k OpenAI shape: rate for cached prompt tokens
|
|
# (a SUBSET of input tokens). Absent -> cached
|
|
# portion bills at input_per_1k.
|
|
# cache_read_per_1k Anthropic shape: rate for cache_read tokens
|
|
# (ADDITIVE to input). Absent -> input rate.
|
|
# cache_creation_per_1k Anthropic shape: rate for cache_creation
|
|
# tokens (ADDITIVE to input). Absent -> input
|
|
# rate.
|
|
`
|