mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-10 16:05:58 +00:00
* feat: track token cost in AI sessions and chats * fix: address review findings on AI cost tracking * fix: price inherited and overridden models at their real rates * fix: stop newer model revisions inheriting an older price * fix: stop a sub-model inheriting its family's price * fix: keep alias suffixes resolving to their model's price * fix: count OpenRouter cache writes and drop unverifiable rates * refactor: move AI spend out of the chat into workspace and user settings * fix: pin the usage workspace per turn and stop inventing cache rates * fix: leave Sonnet 5 unpriced while its promotional rate runs * docs: record the new table in the schema summary and tighten comments * fix: mark estimated AI costs with ~ and drop session grouping Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: name the workspace in the self-scoped AI usage title Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: state that overrides never replace a provider-returned cost Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: let a cleared cache rate inherit again and flag partial totals Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: clear a refused rate's error when the input snaps back Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: stop a revision variant inheriting its base family's rate Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: report AI usage before tools run and price self usage consistently Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: key pricing rows on the model id usage is reported under Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: surface Bedrock and Gemini usage the chat proxy was dropping Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: count Gemini tool-use prompt tokens as input Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat: price flat-rate Gemini Flash models Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: state the tool-use token invariant once Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
43 lines
2.2 KiB
SQL
43 lines
2.2 KiB
SQL
-- Per-workspace AI token spend, accumulated from the chat client. Rows hold token
|
|
-- counts rather than money: prices live in the frontend price table plus the
|
|
-- workspace's `ai_config.model_pricing` overrides and are applied at read time, so
|
|
-- correcting a price also corrects the history. `reported_cost_nano_usd` is the
|
|
-- exception — a few providers (OpenRouter) return what they actually charged, and
|
|
-- that figure wins over the estimate.
|
|
--
|
|
-- Distinct from `feature_usage`, which is anonymous telemetry that leaves the
|
|
-- instance and is pruned after 60 days; spend is per-user and kept.
|
|
CREATE TABLE ai_token_usage (
|
|
workspace_id VARCHAR(50) NOT NULL REFERENCES workspace(id) ON DELETE CASCADE,
|
|
day DATE NOT NULL DEFAULT CURRENT_DATE,
|
|
email VARCHAR(255) NOT NULL,
|
|
provider VARCHAR(50) NOT NULL,
|
|
model VARCHAR(255) NOT NULL,
|
|
-- Empty for chats that are not attached to an AI session.
|
|
session_id VARCHAR(50) NOT NULL DEFAULT '',
|
|
-- Uncached input only; the two cache columns hold the rest of the prompt, so
|
|
-- each column maps to exactly one price and they never double-count.
|
|
input_tokens BIGINT NOT NULL DEFAULT 0,
|
|
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
|
cache_write_tokens BIGINT NOT NULL DEFAULT 0,
|
|
output_tokens BIGINT NOT NULL DEFAULT 0,
|
|
reported_cost_nano_usd BIGINT,
|
|
requests BIGINT NOT NULL DEFAULT 0,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
PRIMARY KEY (workspace_id, day, email, provider, model, session_id)
|
|
);
|
|
|
|
-- The usage listing filters on workspace and a date range; the PK only reaches
|
|
-- `day` through `email`, so it cannot serve that on its own.
|
|
CREATE INDEX idx_ai_token_usage_ws_day ON ai_token_usage (workspace_id, day DESC);
|
|
|
|
GRANT ALL ON ai_token_usage TO windmill_admin;
|
|
GRANT ALL ON ai_token_usage TO windmill_user;
|
|
|
|
-- Both handlers go through the raw pool, so no policy is needed for them to work.
|
|
-- Enabling RLS with an admin-only policy is the backstop: a future query that
|
|
-- reaches this table through UserDB sees nothing rather than every user's spend.
|
|
ALTER TABLE ai_token_usage ENABLE ROW LEVEL SECURITY;
|
|
|
|
CREATE POLICY admin_policy ON ai_token_usage FOR ALL TO windmill_admin USING (true);
|