Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions llm_policy/candidate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ local function validate_model(family, m, providers)
if type(s.provider) ~= "string" or providers[s.provider] == nil then
return "models." .. family .. ".served_by[" .. i .. "].provider does not resolve"
end
local price_in = s.price_in_usd_per_mtok
if price_in == nil then price_in = s.price_in end
local price_out = s.price_out_usd_per_mtok
if price_out == nil then price_out = s.price_out end
if (price_in == nil) ~= (price_out == nil) then
return "models." .. family .. ".served_by[" .. i .. "] prices must set input and output together"
end
if price_in ~= nil then
if type(price_in) ~= "number" or type(price_out) ~= "number" then
return "models." .. family .. ".served_by[" .. i .. "] prices must be numbers"
end
if price_in < 0 or price_out < 0 then
return "models." .. family .. ".served_by[" .. i .. "] prices must be non-negative"
end
end
end
if type(m.capabilities) ~= "table" then
return "models." .. family .. ".capabilities required"
Expand Down Expand Up @@ -94,10 +109,18 @@ function C.build_candidate_matrix(providers, models)
for _, served in ipairs(m.served_by) do
local p = providers[served.provider]
if p ~= nil and p.discovery == "static" then
local price_in = served.price_in_usd_per_mtok
if price_in == nil then price_in = served.price_in end
local price_out = served.price_out_usd_per_mtok
if price_out == nil then price_out = served.price_out end
list[#list + 1] = {
provider_id = served.provider,
model_family = family,
served_model_id = served.provider_model_id or family,
price_in = price_in,
price_out = price_out,
price_source = served.price_source or served.pricing_source,
price_basis = served.price_basis,
capabilities = m.capabilities,
quality_hint = m.static_quality_hint,
tier = p.tier or "fallback",
Expand Down
53 changes: 53 additions & 0 deletions tests/unit/price_enrichment.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,38 @@ local METRICS = {
},
}

local function config_with_catalog_prices()
return {
providers = {
cheap_p = { discovery = "static", base_url = "http://cheap",
api_kind = "openai_compatible", auth_env = "K1", tier = "partner" },
pricey_p = { discovery = "static", base_url = "http://pricey",
api_kind = "openai_compatible", auth_env = "K2", tier = "partner" },
},
models = {
m1 = {
served_by = {
{ provider = "cheap_p",
price_in_usd_per_mtok = 0.2, price_out_usd_per_mtok = 1.0,
price_source = "operator_config", price_basis = "effective_usd_per_mtok" },
{ provider = "pricey_p",
price_in_usd_per_mtok = 5.0, price_out_usd_per_mtok = 20.0,
price_source = "operator_config", price_basis = "effective_usd_per_mtok" },
},
capabilities = { context = 8000 },
static_quality_hint = 0.7,
},
},
profiles = {
default = {
filter = { price_max = { input = 1.0, output = 5.0 } },
retry_policy = "balanced",
},
},
retry_policies = { balanced = { unknown = { action = "next_candidate" } } },
}
end

t.test("price_max filter rejects candidates priced over the ceiling", function()
r.reset()
host = { log = function() end, env = function() return nil end,
Expand All @@ -58,6 +90,27 @@ t.test("price_max filter rejects candidates priced over the ceiling", function()
t.truthy(why, "rejection recorded for pricey_p")
end)

t.test("static served_by prices make providers routable without metrics", function()
r.reset()
host = { log = function() end, env = function() return nil end,
now_ms = function() return 0 end, sleep_ms = function() end }
assert(router.init(config_with_catalog_prices(), { models = {} }))
local ranked, err, rejected = router.rank({ prompt = "x", profile = "default" })
t.falsy(err)
t.eq(#ranked, 1, "only the catalog-priced in-ceiling candidate survives")
local cand = ranked[1].candidate
t.eq(cand.provider_id, "cheap_p")
t.eq(cand.price_in, 0.2)
t.eq(cand.price_out, 1.0)
t.eq(cand.price_source, "operator_config")

local why = nil
for _, rej in ipairs(rejected) do
if rej.provider == "pricey_p" then why = rej.reason end
end
t.truthy(why, "over-ceiling catalog-priced candidate is rejected")
end)

t.test("marketplace candidates carry offer prices into filtering", function()
r.reset()
host = {
Expand Down