mirror of
https://github.com/coder/coder.git
synced 2026-10-31 19:36:41 +08:00
feat: distinguish default and custom AI model prices (#28204)
## Description Prices in `ai_model_prices` come from two places: the price book embedded in each Coder release, and prices set through the experimental CLI (https://github.com/coder/coder/pull/27926). Until now, they were indistinguishable, so the startup seeder re-applied the book over every row, and a price someone set would silently revert on the next restart. This adds a `source` column with values `default` and `custom`, and keeps a row for each. Readers resolve a model to its custom price when one exists and fall back to the book, including the cost path that prices an interception. Keeping both rows means the price book stays current underneath an override, so a future delete can restore it. Note: the endpoint still only accepts models the price book does not cover. Overriding a price the book already carries is handled by the follow-up issue https://linear.app/codercom/issue/AIGOV-594. ## Changes - Add a migration for the `ai_model_price_source` enum and a `source` column, backfilled to `default` and then `NOT NULL`. `source` joins the primary key, so a model can hold one row per source. - Take a `source` parameter on `UpsertAIModelPrices`. Each source keeps its own row, so the price book and a custom price never overwrite each other. - Resolve to the custom price in `GetAIModelPriceByProviderModel` and `GetAIModelPrices`, so both the interception cost snapshot and the list endpoint use it. - Seed the price book as `default`, and write prices set through the endpoint as `custom`. Closes https://linear.app/codercom/issue/AIGOV-592 > [!NOTE] > Initially generated by Claude Opus 5, modified and reviewed by @ssncferreira
This commit is contained in:
Generated
+9
-1
@@ -10,6 +10,11 @@ CREATE TYPE agent_key_scope_enum AS ENUM (
|
||||
'no_user_data'
|
||||
);
|
||||
|
||||
CREATE TYPE ai_model_price_source AS ENUM (
|
||||
'default',
|
||||
'custom'
|
||||
);
|
||||
|
||||
CREATE TYPE ai_provider_type AS ENUM (
|
||||
'openai',
|
||||
'anthropic',
|
||||
@@ -1573,6 +1578,7 @@ CREATE TABLE ai_model_prices (
|
||||
cache_write_price bigint,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
source ai_model_price_source NOT NULL,
|
||||
CONSTRAINT ai_model_prices_cache_read_price_check CHECK ((cache_read_price >= 0)),
|
||||
CONSTRAINT ai_model_prices_cache_write_price_check CHECK ((cache_write_price >= 0)),
|
||||
CONSTRAINT ai_model_prices_input_price_check CHECK ((input_price >= 0)),
|
||||
@@ -1581,6 +1587,8 @@ CREATE TABLE ai_model_prices (
|
||||
|
||||
COMMENT ON TABLE ai_model_prices IS 'Per-model token prices used by AI Bridge to compute interception cost.';
|
||||
|
||||
COMMENT ON COLUMN ai_model_prices.source IS 'Where the price came from: default for the embedded price book, custom for a price set through the API. Both can exist for the same model.';
|
||||
|
||||
CREATE TABLE ai_provider_keys (
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
provider_id uuid NOT NULL,
|
||||
@@ -4315,7 +4323,7 @@ ALTER TABLE ONLY ai_gateway_keys
|
||||
ADD CONSTRAINT ai_gateway_keys_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY ai_model_prices
|
||||
ADD CONSTRAINT ai_model_prices_pkey PRIMARY KEY (provider, model);
|
||||
ADD CONSTRAINT ai_model_prices_pkey PRIMARY KEY (provider, model, source);
|
||||
|
||||
ALTER TABLE ONLY ai_provider_keys
|
||||
ADD CONSTRAINT ai_provider_keys_pkey PRIMARY KEY (id);
|
||||
|
||||
Reference in New Issue
Block a user