mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-10 13:10:21 +08:00
Consolidate subscription usage policy enforcement, privacy-safe persistence, and gateway security hardening into one reviewable change. Includes bounded HTTP and execution envelopes, header and protocol guards, DNS and relay validation, authentication and secret projection hardening, secure backup/install paths, and regression coverage.
705 lines
36 KiB
SQL
705 lines
36 KiB
SQL
|
|
-- Baseline v2 extension: usage body blobs
|
|
|
|
CREATE TABLE IF NOT EXISTS public.usage_body_blobs (
|
|
body_ref character varying(160) NOT NULL,
|
|
request_id character varying(100) NOT NULL,
|
|
body_field character varying(50) NOT NULL,
|
|
payload_gzip bytea NOT NULL,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT usage_body_blobs_pkey PRIMARY KEY (body_ref),
|
|
CONSTRAINT usage_body_blobs_request_id_field_key UNIQUE (request_id, body_field),
|
|
CONSTRAINT usage_body_blobs_request_id_fkey
|
|
FOREIGN KEY (request_id)
|
|
REFERENCES public.usage(request_id)
|
|
ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_usage_body_blobs_request_id
|
|
ON public.usage_body_blobs USING btree (request_id);
|
|
|
|
|
|
-- Baseline v2 extension: usage http audits
|
|
|
|
CREATE TABLE IF NOT EXISTS public.usage_http_audits (
|
|
request_id character varying(100) NOT NULL,
|
|
request_headers json,
|
|
provider_request_headers json,
|
|
response_headers json,
|
|
client_response_headers json,
|
|
request_body_ref character varying(160),
|
|
provider_request_body_ref character varying(160),
|
|
response_body_ref character varying(160),
|
|
client_response_body_ref character varying(160),
|
|
request_body_state character varying(32),
|
|
provider_request_body_state character varying(32),
|
|
response_body_state character varying(32),
|
|
client_response_body_state character varying(32),
|
|
body_capture_mode character varying(32) DEFAULT 'none' NOT NULL,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT usage_http_audits_pkey PRIMARY KEY (request_id),
|
|
CONSTRAINT usage_http_audits_request_id_fkey
|
|
FOREIGN KEY (request_id)
|
|
REFERENCES public.usage(request_id)
|
|
ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_usage_http_audits_updated_at
|
|
ON public.usage_http_audits USING btree (updated_at);
|
|
|
|
|
|
-- Baseline v2 extension: usage routing snapshots
|
|
|
|
CREATE TABLE IF NOT EXISTS public.usage_routing_snapshots (
|
|
request_id character varying(100) NOT NULL,
|
|
candidate_id character varying(160),
|
|
candidate_index integer,
|
|
key_name character varying(255),
|
|
planner_kind character varying(120),
|
|
route_family character varying(80),
|
|
route_kind character varying(80),
|
|
execution_path character varying(80),
|
|
local_execution_runtime_miss_reason character varying(120),
|
|
selected_provider_id character varying(100),
|
|
selected_endpoint_id character varying(100),
|
|
selected_provider_api_key_id character varying(100),
|
|
has_format_conversion boolean,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT usage_routing_snapshots_pkey PRIMARY KEY (request_id),
|
|
CONSTRAINT usage_routing_snapshots_request_id_fkey
|
|
FOREIGN KEY (request_id)
|
|
REFERENCES public.usage(request_id)
|
|
ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_usage_routing_snapshots_route_family_kind
|
|
ON public.usage_routing_snapshots USING btree (route_family, route_kind);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_usage_routing_snapshots_candidate_id
|
|
ON public.usage_routing_snapshots USING btree (candidate_id);
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS public.usage_settlement_snapshots (
|
|
request_id character varying(100) NOT NULL,
|
|
billing_status character varying(20) NOT NULL,
|
|
wallet_id character varying(36),
|
|
wallet_balance_before numeric(20,8),
|
|
wallet_balance_after numeric(20,8),
|
|
wallet_recharge_balance_before numeric(20,8),
|
|
wallet_recharge_balance_after numeric(20,8),
|
|
wallet_gift_balance_before numeric(20,8),
|
|
wallet_gift_balance_after numeric(20,8),
|
|
provider_monthly_used_usd numeric(20,8),
|
|
finalized_at timestamp with time zone,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT usage_settlement_snapshots_pkey PRIMARY KEY (request_id),
|
|
CONSTRAINT usage_settlement_snapshots_request_id_fkey
|
|
FOREIGN KEY (request_id)
|
|
REFERENCES public.usage(request_id)
|
|
ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_usage_settlement_snapshots_wallet_id
|
|
ON public.usage_settlement_snapshots USING btree (wallet_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_usage_settlement_snapshots_billing_status
|
|
ON public.usage_settlement_snapshots USING btree (billing_status);
|
|
|
|
|
|
ALTER TABLE IF EXISTS public.usage_settlement_snapshots
|
|
ADD COLUMN IF NOT EXISTS billing_snapshot_schema_version character varying(20),
|
|
ADD COLUMN IF NOT EXISTS billing_snapshot_status character varying(20),
|
|
ADD COLUMN IF NOT EXISTS rate_multiplier numeric(10,6),
|
|
ADD COLUMN IF NOT EXISTS is_free_tier boolean,
|
|
ADD COLUMN IF NOT EXISTS input_price_per_1m numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS output_price_per_1m numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS cache_creation_price_per_1m numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS cache_read_price_per_1m numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS price_per_request numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS settlement_snapshot_schema_version character varying(20),
|
|
ADD COLUMN IF NOT EXISTS settlement_snapshot jsonb,
|
|
ADD COLUMN IF NOT EXISTS billing_dimensions jsonb,
|
|
ADD COLUMN IF NOT EXISTS billing_input_tokens bigint,
|
|
ADD COLUMN IF NOT EXISTS billing_effective_input_tokens bigint,
|
|
ADD COLUMN IF NOT EXISTS billing_output_tokens bigint,
|
|
ADD COLUMN IF NOT EXISTS billing_cache_creation_tokens bigint,
|
|
ADD COLUMN IF NOT EXISTS billing_cache_creation_5m_tokens bigint,
|
|
ADD COLUMN IF NOT EXISTS billing_cache_creation_1h_tokens bigint,
|
|
ADD COLUMN IF NOT EXISTS billing_cache_read_tokens bigint,
|
|
ADD COLUMN IF NOT EXISTS billing_total_input_context bigint,
|
|
ADD COLUMN IF NOT EXISTS billing_cache_creation_cost_usd numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS billing_cache_read_cost_usd numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS billing_total_cost_usd numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS billing_actual_total_cost_usd numeric(20,8),
|
|
ADD COLUMN IF NOT EXISTS billing_pricing_source character varying(50),
|
|
ADD COLUMN IF NOT EXISTS billing_rule_id character varying(100),
|
|
ADD COLUMN IF NOT EXISTS billing_rule_version character varying(50);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_usage_settlement_snapshots_schema_version
|
|
ON public.usage_settlement_snapshots USING btree (settlement_snapshot_schema_version);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_usage_settlement_snapshots_pricing_source
|
|
ON public.usage_settlement_snapshots USING btree (billing_pricing_source);
|
|
|
|
CREATE TABLE IF NOT EXISTS public.usage_cost_reservations (
|
|
request_id character varying(128) NOT NULL,
|
|
subject_id character varying(128) NOT NULL,
|
|
reservation_token character varying(128) NOT NULL,
|
|
admitted_at timestamp with time zone NOT NULL,
|
|
reserved_cost_units bigint NOT NULL,
|
|
actual_cost_units bigint,
|
|
state character varying(20) NOT NULL,
|
|
reservation_expires_at timestamp with time zone NOT NULL,
|
|
retain_until timestamp with time zone NOT NULL,
|
|
finalized_at timestamp with time zone,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT usage_cost_reservations_pkey PRIMARY KEY (reservation_token),
|
|
CONSTRAINT usage_cost_reservations_subject_id_fkey
|
|
FOREIGN KEY (subject_id)
|
|
REFERENCES public.users(id)
|
|
ON DELETE CASCADE,
|
|
CONSTRAINT usage_cost_reservations_state_check
|
|
CHECK (state IN ('reserved', 'finalized', 'released')),
|
|
CONSTRAINT usage_cost_reservations_reserved_cost_units_check
|
|
CHECK (reserved_cost_units >= 0),
|
|
CONSTRAINT usage_cost_reservations_actual_cost_units_check
|
|
CHECK (actual_cost_units IS NULL OR actual_cost_units >= 0),
|
|
CONSTRAINT usage_cost_reservations_expiry_check
|
|
CHECK (reservation_expires_at > admitted_at),
|
|
CONSTRAINT usage_cost_reservations_retention_check
|
|
CHECK (retain_until >= reservation_expires_at),
|
|
CONSTRAINT usage_cost_reservations_lifecycle_check CHECK (
|
|
(state = 'reserved' AND actual_cost_units IS NULL AND finalized_at IS NULL)
|
|
OR (state = 'finalized' AND actual_cost_units IS NOT NULL AND finalized_at IS NOT NULL)
|
|
OR (state = 'released' AND actual_cost_units IS NOT NULL
|
|
AND actual_cost_units = 0 AND finalized_at IS NOT NULL)
|
|
)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS usage_cost_reservations_request_id_idx
|
|
ON public.usage_cost_reservations USING btree (request_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS usage_cost_reservations_subject_admitted_at_idx
|
|
ON public.usage_cost_reservations USING btree (subject_id, admitted_at);
|
|
|
|
CREATE INDEX IF NOT EXISTS usage_cost_reservations_reservation_expires_at_idx
|
|
ON public.usage_cost_reservations USING btree (reservation_expires_at);
|
|
|
|
CREATE INDEX IF NOT EXISTS usage_cost_reservations_retain_until_token_idx
|
|
ON public.usage_cost_reservations USING btree (retain_until, reservation_token);
|
|
|
|
CREATE TABLE IF NOT EXISTS public.usage_request_admissions (
|
|
request_id character varying(128) NOT NULL,
|
|
subject_id character varying(128) NOT NULL,
|
|
event_token character varying(128) NOT NULL,
|
|
admitted_at timestamp with time zone NOT NULL,
|
|
retain_until timestamp with time zone NOT NULL,
|
|
state character varying(20) NOT NULL,
|
|
released_at timestamp with time zone,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
CONSTRAINT usage_request_admissions_pkey PRIMARY KEY (event_token),
|
|
CONSTRAINT usage_request_admissions_subject_id_fkey
|
|
FOREIGN KEY (subject_id)
|
|
REFERENCES public.users(id)
|
|
ON DELETE CASCADE,
|
|
CONSTRAINT usage_request_admissions_retention_check
|
|
CHECK (retain_until > admitted_at),
|
|
CONSTRAINT usage_request_admissions_state_check
|
|
CHECK (state IN ('active', 'released')),
|
|
CONSTRAINT usage_request_admissions_lifecycle_check CHECK (
|
|
(state = 'active' AND released_at IS NULL)
|
|
OR (state = 'released' AND released_at IS NOT NULL AND released_at >= admitted_at)
|
|
)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS usage_request_admissions_subject_admitted_at_idx
|
|
ON public.usage_request_admissions USING btree (subject_id, admitted_at);
|
|
|
|
CREATE INDEX IF NOT EXISTS usage_request_admissions_retain_until_token_idx
|
|
ON public.usage_request_admissions USING btree (retain_until, event_token);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_settlement_dashboard_cover
|
|
ON public.usage_settlement_snapshots USING btree (request_id)
|
|
INCLUDE (
|
|
billing_input_tokens,
|
|
billing_effective_input_tokens,
|
|
billing_output_tokens,
|
|
billing_cache_creation_tokens,
|
|
billing_cache_creation_5m_tokens,
|
|
billing_cache_creation_1h_tokens,
|
|
billing_cache_read_tokens,
|
|
billing_total_input_context,
|
|
billing_cache_creation_cost_usd,
|
|
billing_cache_read_cost_usd,
|
|
billing_total_cost_usd,
|
|
billing_actual_total_cost_usd,
|
|
input_price_per_1m
|
|
);
|
|
|
|
ALTER TABLE public.usage SET (
|
|
autovacuum_analyze_scale_factor = 0.02,
|
|
autovacuum_analyze_threshold = 10000
|
|
);
|
|
|
|
ALTER TABLE public.usage_settlement_snapshots SET (
|
|
autovacuum_analyze_scale_factor = 0.02,
|
|
autovacuum_analyze_threshold = 10000
|
|
);
|
|
|
|
CREATE OR REPLACE VIEW public.usage_billing_facts AS
|
|
SELECT
|
|
usage_rows.id,
|
|
usage_rows.request_id,
|
|
usage_rows.user_id,
|
|
usage_rows.api_key_id,
|
|
usage_rows.username,
|
|
usage_rows.api_key_name,
|
|
usage_rows.provider_name,
|
|
usage_rows.model,
|
|
usage_rows.target_model,
|
|
usage_rows.provider_id,
|
|
usage_rows.provider_endpoint_id,
|
|
usage_rows.provider_api_key_id,
|
|
usage_rows.request_type,
|
|
usage_rows.api_format,
|
|
usage_rows.api_family,
|
|
usage_rows.endpoint_kind,
|
|
usage_rows.endpoint_api_format,
|
|
usage_rows.provider_api_family,
|
|
usage_rows.provider_endpoint_kind,
|
|
COALESCE(usage_rows.has_format_conversion, FALSE) AS has_format_conversion,
|
|
COALESCE(usage_rows.is_stream, FALSE) AS is_stream,
|
|
usage_rows.status_code,
|
|
usage_rows.error_message,
|
|
usage_rows.error_category,
|
|
usage_rows.response_time_ms,
|
|
usage_rows.first_byte_time_ms,
|
|
usage_rows.status,
|
|
COALESCE(settlement.billing_status, usage_rows.billing_status) AS billing_status,
|
|
usage_rows.created_at,
|
|
COALESCE(settlement.finalized_at, usage_rows.finalized_at) AS finalized_at,
|
|
GREATEST(COALESCE(settlement.billing_input_tokens, usage_rows.input_tokens, 0), 0)::bigint
|
|
AS input_tokens,
|
|
GREATEST(
|
|
COALESCE(
|
|
settlement.billing_effective_input_tokens,
|
|
CASE
|
|
WHEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0) <= 0 THEN 0
|
|
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
|
|
= 'openai'
|
|
AND (
|
|
GREATEST(COALESCE(usage_rows.cache_creation_input_tokens, 0), 0) > 0
|
|
OR GREATEST(COALESCE(usage_rows.cache_creation_input_tokens_5m, 0), 0) > 0
|
|
OR GREATEST(COALESCE(usage_rows.cache_creation_input_tokens_1h, 0), 0) > 0
|
|
OR GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0) > 0
|
|
)
|
|
THEN GREATEST(
|
|
GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
- GREATEST(
|
|
CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END,
|
|
0
|
|
)
|
|
- GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0),
|
|
0
|
|
)
|
|
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
|
|
IN ('gemini', 'google')
|
|
AND GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0) > 0
|
|
THEN GREATEST(
|
|
GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
- GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0),
|
|
0
|
|
)
|
|
ELSE GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
END
|
|
),
|
|
0
|
|
)::bigint AS effective_input_tokens,
|
|
GREATEST(COALESCE(settlement.billing_output_tokens, usage_rows.output_tokens, 0), 0)::bigint
|
|
AS output_tokens,
|
|
GREATEST(
|
|
COALESCE(
|
|
settlement.billing_cache_creation_tokens,
|
|
CASE
|
|
WHEN settlement.billing_cache_creation_5m_tokens IS NOT NULL
|
|
OR settlement.billing_cache_creation_1h_tokens IS NOT NULL
|
|
THEN COALESCE(settlement.billing_cache_creation_5m_tokens, 0)
|
|
+ COALESCE(settlement.billing_cache_creation_1h_tokens, 0)
|
|
END,
|
|
CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END,
|
|
0
|
|
),
|
|
0
|
|
)::bigint AS cache_creation_input_tokens,
|
|
GREATEST(
|
|
COALESCE(
|
|
settlement.billing_cache_creation_5m_tokens,
|
|
usage_rows.cache_creation_input_tokens_5m,
|
|
0
|
|
),
|
|
0
|
|
)::bigint AS cache_creation_input_tokens_5m,
|
|
GREATEST(
|
|
COALESCE(
|
|
settlement.billing_cache_creation_1h_tokens,
|
|
usage_rows.cache_creation_input_tokens_1h,
|
|
0
|
|
),
|
|
0
|
|
)::bigint AS cache_creation_input_tokens_1h,
|
|
GREATEST(COALESCE(settlement.billing_cache_read_tokens, usage_rows.cache_read_input_tokens, 0), 0)::bigint
|
|
AS cache_read_input_tokens,
|
|
GREATEST(
|
|
COALESCE(
|
|
CASE
|
|
WHEN settlement.billing_effective_input_tokens IS NOT NULL
|
|
THEN GREATEST(settlement.billing_effective_input_tokens, 0)
|
|
+ GREATEST(COALESCE(settlement.billing_output_tokens, usage_rows.output_tokens, 0), 0)
|
|
+ GREATEST(
|
|
COALESCE(
|
|
settlement.billing_cache_creation_tokens,
|
|
CASE
|
|
WHEN settlement.billing_cache_creation_5m_tokens IS NOT NULL
|
|
OR settlement.billing_cache_creation_1h_tokens IS NOT NULL
|
|
THEN COALESCE(settlement.billing_cache_creation_5m_tokens, 0)
|
|
+ COALESCE(settlement.billing_cache_creation_1h_tokens, 0)
|
|
END,
|
|
CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END,
|
|
0
|
|
),
|
|
0
|
|
)
|
|
+ GREATEST(
|
|
COALESCE(
|
|
settlement.billing_cache_read_tokens,
|
|
usage_rows.cache_read_input_tokens,
|
|
0
|
|
),
|
|
0
|
|
)
|
|
WHEN settlement.billing_total_input_context IS NOT NULL
|
|
THEN GREATEST(settlement.billing_total_input_context, 0)
|
|
+ GREATEST(COALESCE(settlement.billing_output_tokens, usage_rows.output_tokens, 0), 0)
|
|
END,
|
|
NULLIF(GREATEST(COALESCE(usage_rows.total_tokens, 0), 0), 0),
|
|
CASE
|
|
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
|
|
IN ('openai', 'gemini', 'google')
|
|
THEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
+ GREATEST(COALESCE(usage_rows.output_tokens, 0), 0)
|
|
ELSE GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
+ GREATEST(COALESCE(usage_rows.output_tokens, 0), 0)
|
|
+ GREATEST(
|
|
CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END,
|
|
0
|
|
)
|
|
+ GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0)
|
|
END,
|
|
0
|
|
),
|
|
0
|
|
)::bigint AS total_tokens,
|
|
GREATEST(
|
|
COALESCE(
|
|
CASE
|
|
WHEN settlement.billing_effective_input_tokens IS NOT NULL
|
|
THEN GREATEST(settlement.billing_effective_input_tokens, 0)
|
|
+ GREATEST(
|
|
COALESCE(
|
|
settlement.billing_cache_creation_tokens,
|
|
CASE
|
|
WHEN settlement.billing_cache_creation_5m_tokens IS NOT NULL
|
|
OR settlement.billing_cache_creation_1h_tokens IS NOT NULL
|
|
THEN COALESCE(settlement.billing_cache_creation_5m_tokens, 0)
|
|
+ COALESCE(settlement.billing_cache_creation_1h_tokens, 0)
|
|
END,
|
|
CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END,
|
|
0
|
|
),
|
|
0
|
|
)
|
|
+ GREATEST(
|
|
COALESCE(
|
|
settlement.billing_cache_read_tokens,
|
|
usage_rows.cache_read_input_tokens,
|
|
0
|
|
),
|
|
0
|
|
)
|
|
END,
|
|
settlement.billing_total_input_context,
|
|
CASE
|
|
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
|
|
IN ('claude', 'anthropic')
|
|
THEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
+ CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END
|
|
+ GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0)
|
|
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
|
|
= 'openai'
|
|
THEN CASE
|
|
WHEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0) <= 0 THEN 0
|
|
WHEN GREATEST(COALESCE(usage_rows.cache_creation_input_tokens, 0), 0) <= 0
|
|
AND GREATEST(COALESCE(usage_rows.cache_creation_input_tokens_5m, 0), 0) <= 0
|
|
AND GREATEST(COALESCE(usage_rows.cache_creation_input_tokens_1h, 0), 0) <= 0
|
|
AND GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0) <= 0
|
|
THEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
ELSE GREATEST(
|
|
GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
- GREATEST(
|
|
CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END,
|
|
0
|
|
)
|
|
- GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0),
|
|
0
|
|
)
|
|
END
|
|
+ GREATEST(
|
|
CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END,
|
|
0
|
|
)
|
|
+ GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0)
|
|
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
|
|
IN ('gemini', 'google')
|
|
THEN CASE
|
|
WHEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0) <= 0 THEN 0
|
|
WHEN GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0) <= 0
|
|
THEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
ELSE GREATEST(
|
|
GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
- GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0),
|
|
0
|
|
)
|
|
END
|
|
+ GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0)
|
|
ELSE GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
|
|
+ CASE
|
|
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
|
|
AND (
|
|
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
) > 0
|
|
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
|
|
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
|
|
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
|
|
END
|
|
+ GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0)
|
|
END,
|
|
0
|
|
),
|
|
0
|
|
)::bigint AS total_input_context,
|
|
COALESCE(CAST(usage_rows.input_cost_usd AS DOUBLE PRECISION), 0) AS input_cost_usd,
|
|
COALESCE(CAST(usage_rows.output_cost_usd AS DOUBLE PRECISION), 0) AS output_cost_usd,
|
|
COALESCE(
|
|
CAST(settlement.billing_cache_creation_cost_usd AS DOUBLE PRECISION),
|
|
CAST(usage_rows.cache_creation_cost_usd AS DOUBLE PRECISION),
|
|
0
|
|
) AS cache_creation_cost_usd,
|
|
COALESCE(
|
|
CAST(settlement.billing_cache_read_cost_usd AS DOUBLE PRECISION),
|
|
CAST(usage_rows.cache_read_cost_usd AS DOUBLE PRECISION),
|
|
0
|
|
) AS cache_read_cost_usd,
|
|
COALESCE(
|
|
CAST(settlement.billing_total_cost_usd AS DOUBLE PRECISION),
|
|
CAST(usage_rows.total_cost_usd AS DOUBLE PRECISION),
|
|
0
|
|
) AS total_cost_usd,
|
|
COALESCE(
|
|
CAST(settlement.billing_actual_total_cost_usd AS DOUBLE PRECISION),
|
|
CAST(usage_rows.actual_total_cost_usd AS DOUBLE PRECISION),
|
|
0
|
|
) AS actual_total_cost_usd,
|
|
COALESCE(
|
|
CAST(settlement.output_price_per_1m AS DOUBLE PRECISION),
|
|
CAST(usage_rows.output_price_per_1m AS DOUBLE PRECISION)
|
|
) AS output_price_per_1m,
|
|
COALESCE(
|
|
CAST(settlement.input_price_per_1m AS DOUBLE PRECISION),
|
|
CAST(usage_rows.input_price_per_1m AS DOUBLE PRECISION)
|
|
) AS input_price_per_1m,
|
|
COALESCE(
|
|
CAST(settlement.cache_creation_price_per_1m AS DOUBLE PRECISION),
|
|
CAST(usage_rows.cache_creation_price_per_1m AS DOUBLE PRECISION)
|
|
) AS cache_creation_price_per_1m,
|
|
COALESCE(
|
|
CAST(settlement.cache_read_price_per_1m AS DOUBLE PRECISION),
|
|
CAST(usage_rows.cache_read_price_per_1m AS DOUBLE PRECISION)
|
|
) AS cache_read_price_per_1m,
|
|
COALESCE(
|
|
CAST(settlement.price_per_request AS DOUBLE PRECISION),
|
|
CAST(usage_rows.price_per_request AS DOUBLE PRECISION)
|
|
) AS price_per_request,
|
|
settlement.billing_pricing_source,
|
|
settlement.billing_rule_id,
|
|
settlement.billing_rule_version,
|
|
COALESCE(usage_rows.upstream_is_stream, COALESCE(usage_rows.is_stream, FALSE)) AS upstream_is_stream
|
|
FROM public."usage" AS usage_rows
|
|
LEFT JOIN public.usage_settlement_snapshots AS settlement
|
|
ON settlement.request_id = usage_rows.request_id;
|
|
|
|
COMMENT ON VIEW public.usage_billing_facts IS
|
|
'Canonical billing read model. Token/cost fields prefer usage_settlement_snapshots.billing_* and fall back to deprecated usage mirrors for legacy rows.';
|
|
|
|
COMMENT ON COLUMN public.usage_billing_facts.upstream_is_stream IS
|
|
'Resolved upstream stream mode from public.usage.upstream_is_stream, falling back to usage.is_stream for legacy rows.';
|
|
|
|
COMMENT ON COLUMN public.usage.input_tokens IS
|
|
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_input_tokens or public.usage_billing_facts.input_tokens.';
|
|
COMMENT ON COLUMN public.usage.output_tokens IS
|
|
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_output_tokens or public.usage_billing_facts.output_tokens.';
|
|
COMMENT ON COLUMN public.usage.total_tokens IS
|
|
'DEPRECATED: billing dimension mirror. Use public.usage_billing_facts.total_tokens.';
|
|
COMMENT ON COLUMN public.usage.cache_creation_input_tokens IS
|
|
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_cache_creation_tokens or public.usage_billing_facts.cache_creation_input_tokens.';
|
|
COMMENT ON COLUMN public.usage.cache_creation_input_tokens_5m IS
|
|
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_cache_creation_5m_tokens or public.usage_billing_facts.cache_creation_input_tokens_5m.';
|
|
COMMENT ON COLUMN public.usage.cache_creation_input_tokens_1h IS
|
|
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_cache_creation_1h_tokens or public.usage_billing_facts.cache_creation_input_tokens_1h.';
|
|
COMMENT ON COLUMN public.usage.cache_read_input_tokens IS
|
|
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_cache_read_tokens or public.usage_billing_facts.cache_read_input_tokens.';
|
|
COMMENT ON COLUMN public.usage.cache_creation_cost_usd IS
|
|
'DEPRECATED: billing cost mirror. Use public.usage_settlement_snapshots.billing_cache_creation_cost_usd or public.usage_billing_facts.cache_creation_cost_usd.';
|
|
COMMENT ON COLUMN public.usage.cache_read_cost_usd IS
|
|
'DEPRECATED: billing cost mirror. Use public.usage_settlement_snapshots.billing_cache_read_cost_usd or public.usage_billing_facts.cache_read_cost_usd.';
|
|
COMMENT ON COLUMN public.usage.total_cost_usd IS
|
|
'DEPRECATED: billing cost mirror. Use public.usage_settlement_snapshots.billing_total_cost_usd or public.usage_billing_facts.total_cost_usd.';
|
|
COMMENT ON COLUMN public.usage.actual_total_cost_usd IS
|
|
'DEPRECATED: billing cost mirror. Use public.usage_settlement_snapshots.billing_actual_total_cost_usd or public.usage_billing_facts.actual_total_cost_usd.';
|
|
|
|
COMMENT ON COLUMN public.usage.wallet_id IS
|
|
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_id. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.wallet_balance_before IS
|
|
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_balance_before. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.wallet_balance_after IS
|
|
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_balance_after. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.wallet_recharge_balance_before IS
|
|
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_recharge_balance_before. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.wallet_recharge_balance_after IS
|
|
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_recharge_balance_after. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.wallet_gift_balance_before IS
|
|
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_gift_balance_before. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.wallet_gift_balance_after IS
|
|
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_gift_balance_after. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.rate_multiplier IS
|
|
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.rate_multiplier. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.input_price_per_1m IS
|
|
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.input_price_per_1m. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.output_price_per_1m IS
|
|
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.output_price_per_1m. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.cache_creation_price_per_1m IS
|
|
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.cache_creation_price_per_1m. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.cache_read_price_per_1m IS
|
|
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.cache_read_price_per_1m. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.price_per_request IS
|
|
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.price_per_request. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.username IS
|
|
'DEPRECATED: display cache only. Prefer join-time lookup from user/auth records. Legacy compatibility only.';
|
|
COMMENT ON COLUMN public.usage.api_key_name IS
|
|
'DEPRECATED: display cache only. Prefer join-time lookup from API key records. Legacy compatibility only.';
|
|
COMMENT ON COLUMN public.usage.billing_status IS
|
|
'DEPRECATED: authoritative owner moved to public.usage_settlement_snapshots.billing_status. Compatibility/index mirror only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.finalized_at IS
|
|
'DEPRECATED: authoritative owner moved to public.usage_settlement_snapshots.finalized_at. Compatibility/index mirror only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.request_headers IS
|
|
'DEPRECATED: HTTP audit owner moved to public.usage_http_audits.request_headers. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.provider_request_headers IS
|
|
'DEPRECATED: HTTP audit owner moved to public.usage_http_audits.provider_request_headers. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.response_headers IS
|
|
'DEPRECATED: HTTP audit owner moved to public.usage_http_audits.response_headers. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.client_response_headers IS
|
|
'DEPRECATED: HTTP audit owner moved to public.usage_http_audits.client_response_headers. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.request_body IS
|
|
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.request_body_ref. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.request_body_compressed IS
|
|
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.request_body_ref. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.provider_request_body IS
|
|
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.provider_request_body_ref. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.provider_request_body_compressed IS
|
|
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.provider_request_body_ref. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.response_body IS
|
|
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.response_body_ref. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.response_body_compressed IS
|
|
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.response_body_ref. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.client_response_body IS
|
|
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.client_response_body_ref. Legacy compatibility only; do not write new values.';
|
|
COMMENT ON COLUMN public.usage.client_response_body_compressed IS
|
|
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.client_response_body_ref. Legacy compatibility only; do not write new values.';
|