diff --git a/management/internals/modules/agentnetwork/catalog/catalog.go b/management/internals/modules/agentnetwork/catalog/catalog.go index 2c4efd0b4..c534f9a85 100644 --- a/management/internals/modules/agentnetwork/catalog/catalog.go +++ b/management/internals/modules/agentnetwork/catalog/catalog.go @@ -296,6 +296,8 @@ var providers = []Provider{ // account to be on >= 30-day data retention or all requests // 400. Models: []Model{ + {ID: "claude-opus-5", Label: "Claude Opus 5", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, + {ID: "claude-sonnet-5", Label: "Claude Sonnet 5", InputPer1k: 0.003, OutputPer1k: 0.015, CacheReadPer1k: 0.0003, CacheCreationPer1k: 0.00375, ContextWindow: 1000000}, {ID: "claude-fable-5", Label: "Claude Fable 5", InputPer1k: 0.010, OutputPer1k: 0.050, CacheReadPer1k: 0.001, CacheCreationPer1k: 0.0125, ContextWindow: 1000000}, {ID: "claude-opus-4-8", Label: "Claude Opus 4.8", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, {ID: "claude-opus-4-7", Label: "Claude Opus 4.7", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, @@ -355,6 +357,8 @@ var providers = []Provider{ // Llama 3.3 70B entry kept unchanged — LiteLLM tracks only // per-region Llama 3 entries; standalone 3.3 not yet listed. Models: []Model{ + {ID: "anthropic.claude-opus-5", Label: "Claude Opus 5 (Bedrock)", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, + {ID: "anthropic.claude-sonnet-5", Label: "Claude Sonnet 5 (Bedrock)", InputPer1k: 0.003, OutputPer1k: 0.015, CacheReadPer1k: 0.0003, CacheCreationPer1k: 0.00375, ContextWindow: 1000000}, {ID: "anthropic.claude-opus-4-8", Label: "Claude Opus 4.8 (Bedrock)", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, {ID: "anthropic.claude-opus-4-7", Label: "Claude Opus 4.7 (Bedrock)", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, {ID: "anthropic.claude-opus-4-6", Label: "Claude Opus 4.6 (Bedrock)", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, @@ -406,6 +410,8 @@ var providers = []Provider{ // exists — the router denies unmeterable publishers rather than forward // them uncounted. Models: []Model{ + {ID: "claude-opus-5", Label: "Claude Opus 5 (Vertex)", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, + {ID: "claude-sonnet-5", Label: "Claude Sonnet 5 (Vertex)", InputPer1k: 0.003, OutputPer1k: 0.015, CacheReadPer1k: 0.0003, CacheCreationPer1k: 0.00375, ContextWindow: 1000000}, {ID: "claude-fable-5", Label: "Claude Fable 5 (Vertex)", InputPer1k: 0.010, OutputPer1k: 0.050, CacheReadPer1k: 0.001, CacheCreationPer1k: 0.0125, ContextWindow: 1000000}, {ID: "claude-opus-4-8", Label: "Claude Opus 4.8 (Vertex)", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, {ID: "claude-opus-4-7", Label: "Claude Opus 4.7 (Vertex)", InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625, ContextWindow: 1000000}, diff --git a/management/internals/modules/agentnetwork/catalog/catalog_test.go b/management/internals/modules/agentnetwork/catalog/catalog_test.go new file mode 100644 index 000000000..e4e887e6f --- /dev/null +++ b/management/internals/modules/agentnetwork/catalog/catalog_test.go @@ -0,0 +1,36 @@ +package catalog + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestClaudeLineupSelectable pins the models Claude Code resolves to by +// default. A model absent from the lineup can't be ticked on a provider +// record, so llm_router denies it as not-routable and the operator has no +// way to authorise the client's own default. +func TestClaudeLineupSelectable(t *testing.T) { + for providerID, wanted := range map[string][]string{ + "anthropic_api": {"claude-opus-5", "claude-sonnet-5", "claude-haiku-4-5"}, + "bedrock_api": {"anthropic.claude-opus-5", "anthropic.claude-sonnet-5", "anthropic.claude-haiku-4-5"}, + "vertex_ai_api": {"claude-opus-5", "claude-sonnet-5", "claude-haiku-4-5"}, + } { + provider, ok := Lookup(providerID) + require.True(t, ok, "catalog must define %s", providerID) + + selectable := make(map[string]Model, len(provider.Models)) + for _, m := range provider.Models { + selectable[m.ID] = m + } + for _, id := range wanted { + model, found := selectable[id] + require.True(t, found, "%s must offer %s", providerID, id) + assert.NotEmpty(t, model.Label, "%s/%s needs a label for the picker", providerID, id) + assert.Positive(t, model.InputPer1k, "%s/%s needs an input rate", providerID, id) + assert.Positive(t, model.OutputPer1k, "%s/%s needs an output rate", providerID, id) + assert.Positive(t, model.ContextWindow, "%s/%s needs a context window", providerID, id) + } + } +} diff --git a/management/internals/modules/agentnetwork/pricing/defaults.go b/management/internals/modules/agentnetwork/pricing/defaults.go index c690313bc..315cfe208 100644 --- a/management/internals/modules/agentnetwork/pricing/defaults.go +++ b/management/internals/modules/agentnetwork/pricing/defaults.go @@ -47,17 +47,11 @@ var supplementalDefaults = map[string]map[string]Entry{ "gpt-5-nano": {InputPer1k: 0.00005, OutputPer1k: 0.0004, CachedInputPer1k: 0.000005}, }, "anthropic": { - // claude-opus-5 is not yet in the catalog lineup but gateway / - // grandfathered traffic uses it; priced so it isn't skipped. - "claude-opus-5": {InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625}, // "kimi-k3[1m]" is the 1M-context alias some Claude Code guides // configure against Moonshot's Anthropic-compatible endpoint; // priced identically to kimi-k3 so those requests aren't skipped. "kimi-k3[1m]": {InputPer1k: 0.003, OutputPer1k: 0.015, CacheReadPer1k: 0.0003}, }, - "bedrock": { - "anthropic.claude-opus-5": {InputPer1k: 0.005, OutputPer1k: 0.025, CacheReadPer1k: 0.0005, CacheCreationPer1k: 0.00625}, - }, } var ( diff --git a/management/internals/modules/agentnetwork/pricing/defaults_llm_pricing.example.yaml b/management/internals/modules/agentnetwork/pricing/defaults_llm_pricing.example.yaml index bb1cb09a8..78830ae3c 100644 --- a/management/internals/modules/agentnetwork/pricing/defaults_llm_pricing.example.yaml +++ b/management/internals/modules/agentnetwork/pricing/defaults_llm_pricing.example.yaml @@ -82,6 +82,11 @@ anthropic: output_per_1k: 0.015 cache_read_per_1k: 0.0003 cache_creation_per_1k: 0.00375 + claude-sonnet-5: + input_per_1k: 0.003 + output_per_1k: 0.015 + cache_read_per_1k: 0.0003 + cache_creation_per_1k: 0.00375 kimi-k3: input_per_1k: 0.003 output_per_1k: 0.015 @@ -145,6 +150,11 @@ bedrock: output_per_1k: 0.015 cache_read_per_1k: 0.0003 cache_creation_per_1k: 0.00375 + anthropic.claude-sonnet-5: + input_per_1k: 0.003 + output_per_1k: 0.015 + cache_read_per_1k: 0.0003 + cache_creation_per_1k: 0.00375 meta.llama3-3-70b-instruct: input_per_1k: 0.00072 output_per_1k: 0.00072 diff --git a/management/internals/modules/agentnetwork/pricing/defaults_test.go b/management/internals/modules/agentnetwork/pricing/defaults_test.go index 99c965687..04b6de550 100644 --- a/management/internals/modules/agentnetwork/pricing/defaults_test.go +++ b/management/internals/modules/agentnetwork/pricing/defaults_test.go @@ -116,11 +116,13 @@ func TestDefaultTable_PinnedRates(t *testing.T) { assert.InDelta(t, 0.010, fable.InputPer1k, 1e-9, "claude-fable-5 input") assert.InDelta(t, 0.0125, fable.CacheCreationPer1k, 1e-9, "claude-fable-5 cache creation") - // Supplementals present on their surfaces. + // Every id below must stay priced whichever source provides it: the + // catalog lineup for the current Claude 5 family, supplementalDefaults + // for the ids the dashboard deliberately doesn't offer. for surface, ids := range map[string][]string{ "openai": {"gpt-5", "gpt-5-mini", "gpt-5-nano"}, - "anthropic": {"claude-opus-5", "kimi-k3[1m]", "kimi-k3"}, - "bedrock": {"anthropic.claude-opus-5"}, + "anthropic": {"claude-opus-5", "claude-sonnet-5", "kimi-k3[1m]", "kimi-k3"}, + "bedrock": {"anthropic.claude-opus-5", "anthropic.claude-sonnet-5"}, } { for _, id := range ids { _, ok := table[surface][id]