PranitInitial commit439f83c3 months agoHistory
863 lines · 26.8 KB · Zig
RawDownload
const std = @import("std");const types = @import("../shared/types.zig");const sort_utils = @import("../shared/sort_utils.zig"); const Allocator = std.mem.Allocator; const max_model_bytes: usize = 1024;const max_models: usize = 128; pub const Scope = enum {    session,    hours_24,    days_7,    days_30,     pub fn label(self: Scope) []const u8 {        return switch (self) {            .session => "Session",            .hours_24 => "24 hours",            .days_7 => "7 days",            .days_30 => "30 days",        };    }     pub fn cliValue(self: Scope) ?[]const u8 {        return switch (self) {            .session => null,            .hours_24 => "24h",            .days_7 => "7d",            .days_30 => "30d",        };    }     fn durationMs(self: Scope) ?i64 {        return switch (self) {            .session => null,            .hours_24 => std.time.ms_per_hour * 24,            .days_7 => std.time.ms_per_day * 7,            .days_30 => std.time.ms_per_day * 30,        };    }     pub fn previous(self: Scope) Scope {        return switch (self) {            .session => .session,            .hours_24 => .session,            .days_7 => .hours_24,            .days_30 => .days_7,        };    }     pub fn next(self: Scope) Scope {        return switch (self) {            .session => .hours_24,            .hours_24 => .days_7,            .days_7 => .days_30,            .days_30 => .days_30,        };    }}; pub fn formatUtcDate(buf: *[24]u8, timestamp_ms: i64) []const u8 {    if (timestamp_ms < 0) return "Unknown";    const seconds: u64 = @intCast(@divFloor(timestamp_ms, std.time.ms_per_s));    const epoch_seconds: std.time.epoch.EpochSeconds = .{ .secs = seconds };    const year_day = epoch_seconds.getEpochDay().calculateYearDay();    const month_day = year_day.calculateMonthDay();    const month = switch (month_day.month.numeric()) {        1 => "Jan",        2 => "Feb",        3 => "Mar",        4 => "Apr",        5 => "May",        6 => "Jun",        7 => "Jul",        8 => "Aug",        9 => "Sep",        10 => "Oct",        11 => "Nov",        12 => "Dec",        else => return "Unknown",    };    return std.fmt.bufPrint(        buf,        "{s} {d}, {d}",        .{ month, month_day.day_index + 1, year_day.year },    ) catch "Unknown";} pub const Completeness = enum {    complete,    pending,    incomplete,    legacy,}; pub const Coverage = enum {    not_started,    partial,    full,}; pub const Incident = struct {    occurred_at_ms: i64,    completeness: Completeness,}; pub const PendingMarker = struct {    id: []u8,    observed_at_ms: i64,     pub fn deinit(self: *PendingMarker, alloc: Allocator) void {        alloc.free(self.id);        self.* = undefined;    }     pub fn dupe(self: PendingMarker, alloc: Allocator) Allocator.Error!PendingMarker {        return .{            .id = try alloc.dupe(u8, self.id),            .observed_at_ms = self.observed_at_ms,        };    }     pub fn eql(first: PendingMarker, second: PendingMarker) bool {        return std.mem.eql(u8, first.id, second.id) and            first.observed_at_ms == second.observed_at_ms;    }}; pub const GenerationFact = struct {    id: []u8,    created_at_ms: i64,    model: []u8,    input_tokens: u64,    output_tokens: u64,    cache_read_tokens: u64,    cache_write_tokens: u64,    reasoning_tokens: ?u64,    billable_web_search_calls: u64 = 0,    total_cost: f64,     pub fn deinit(self: *GenerationFact, alloc: Allocator) void {        alloc.free(self.id);        alloc.free(self.model);        self.* = undefined;    }     pub fn dupe(self: GenerationFact, alloc: Allocator) Allocator.Error!GenerationFact {        const id = try alloc.dupe(u8, self.id);        errdefer alloc.free(id);        return .{            .id = id,            .created_at_ms = self.created_at_ms,            .model = try alloc.dupe(u8, self.model),            .input_tokens = self.input_tokens,            .output_tokens = self.output_tokens,            .cache_read_tokens = self.cache_read_tokens,            .cache_write_tokens = self.cache_write_tokens,            .reasoning_tokens = self.reasoning_tokens,            .billable_web_search_calls = self.billable_web_search_calls,            .total_cost = self.total_cost,        };    }     pub fn eql(first: GenerationFact, second: GenerationFact) bool {        return std.mem.eql(u8, first.id, second.id) and            first.created_at_ms == second.created_at_ms and            std.mem.eql(u8, first.model, second.model) and            first.input_tokens == second.input_tokens and            first.output_tokens == second.output_tokens and            first.cache_read_tokens == second.cache_read_tokens and            first.cache_write_tokens == second.cache_write_tokens and            first.reasoning_tokens == second.reasoning_tokens and            first.billable_web_search_calls == second.billable_web_search_calls and            first.total_cost == second.total_cost;    }}; pub const ProfileEvent = union(enum) {    generation: GenerationFact,    pending: PendingMarker,    incident: Incident,}; pub const Totals = struct {    total_tokens: u64,    input_tokens: u64,    output_tokens: u64,    cache_read_tokens: u64,    cache_write_tokens: u64,    reasoning_tokens: ?u64,    request_count: ?u64,    total_cost: f64,}; pub const ModelUsage = struct {    model: []u8,    totals: Totals,     pub fn deinit(self: *ModelUsage, alloc: Allocator) void {        alloc.free(self.model);        self.* = undefined;    }}; pub const SessionActivity = struct {    api_duration_complete: bool,    wall_duration_complete: bool,    code_complete: bool,    api_duration_ms: u64,    wall_duration_ms: u64,    lines_added: u64,    lines_removed: u64,}; pub const SessionModelSource = struct {    model: []const u8,    total_cost: f64,    input_tokens: u64,    output_tokens: u64,    cache_read_tokens: u64,    cache_write_tokens: u64,    reasoning_tokens: ?u64,    request_count: ?u64,}; pub const SessionSource = struct {    snapshot_time_ms: i64,    session_started_at_ms: i64,    completeness: Completeness,    total_cost: f64,    input_tokens: u64,    output_tokens: u64,    cache_read_tokens: u64,    cache_write_tokens: u64,    reasoning_tokens: ?u64,    request_count: ?u64,    models: []const SessionModelSource,    activity: SessionActivity,}; pub const Snapshot = struct {    scope: Scope,    snapshot_time_ms: i64,    window_start_ms: i64,    coverage_started_at_ms: ?i64,    coverage: Coverage,    completeness: Completeness,    totals: ?Totals,    models: []ModelUsage,    session_activity: ?SessionActivity = null,     pub fn deinit(self: *Snapshot, alloc: Allocator) void {        for (self.models) |*model| model.deinit(alloc);        alloc.free(self.models);        self.* = undefined;    }}; pub const BuildError = Allocator.Error || error{    InvalidGenerationFact,    InvalidSnapshotTime,    UsageCapacityExceeded,    UsageOverflow,}; const MutableTotals = struct {    input_tokens: u64 = 0,    output_tokens: u64 = 0,    cache_read_tokens: u64 = 0,    cache_write_tokens: u64 = 0,    reasoning_tokens: ?u64 = 0,    request_count: u64 = 0,    total_cost: f64 = 0,     fn add(self: *MutableTotals, fact: GenerationFact) error{UsageOverflow}!void {        self.input_tokens = std.math.add(u64, self.input_tokens, fact.input_tokens) catch            return error.UsageOverflow;        self.output_tokens = std.math.add(u64, self.output_tokens, fact.output_tokens) catch            return error.UsageOverflow;        self.cache_read_tokens = std.math.add(            u64,            self.cache_read_tokens,            fact.cache_read_tokens,        ) catch return error.UsageOverflow;        self.cache_write_tokens = std.math.add(            u64,            self.cache_write_tokens,            fact.cache_write_tokens,        ) catch return error.UsageOverflow;        self.request_count = std.math.add(u64, self.request_count, 1) catch            return error.UsageOverflow;        self.reasoning_tokens = if (self.reasoning_tokens) |current|            if (fact.reasoning_tokens) |reasoning|                std.math.add(u64, current, reasoning) catch return error.UsageOverflow            else                null        else            null;        const next_cost = self.total_cost + fact.total_cost;        if (!std.math.isFinite(next_cost)) return error.UsageOverflow;        self.total_cost = next_cost;    }     fn freeze(self: MutableTotals, request_count_available: bool) error{UsageOverflow}!Totals {        return .{            .total_tokens = std.math.add(                u64,                self.input_tokens,                self.output_tokens,            ) catch return error.UsageOverflow,            .input_tokens = self.input_tokens,            .output_tokens = self.output_tokens,            .cache_read_tokens = self.cache_read_tokens,            .cache_write_tokens = self.cache_write_tokens,            .reasoning_tokens = if (self.request_count == 0)                null            else                self.reasoning_tokens,            .request_count = if (request_count_available) self.request_count else null,            .total_cost = self.total_cost,        };    }}; const MutableModel = struct {    model: []u8,    totals: MutableTotals = .{},     fn deinit(self: *MutableModel, alloc: Allocator) void {        alloc.free(self.model);        self.* = undefined;    }}; /// Converts an authoritative session aggregate into the same owned projection/// used by rolling usage. Session arithmetic is copied, never reconstructed/// from the model rows.pub fn buildSessionSnapshot(    alloc: Allocator,    source: SessionSource,) BuildError!Snapshot {    if (source.snapshot_time_ms < 0 or        source.session_started_at_ms < 0 or        source.session_started_at_ms > source.snapshot_time_ms or        !std.math.isFinite(source.total_cost) or        source.total_cost < 0 or        source.cache_read_tokens > source.input_tokens or        source.cache_write_tokens > source.input_tokens)    {        return error.InvalidSnapshotTime;    }    if (source.reasoning_tokens) |reasoning| {        if (reasoning > source.output_tokens) return error.InvalidGenerationFact;    }     if (source.completeness == .legacy) {        var snapshot = try emptySnapshot(            alloc,            .session,            source.snapshot_time_ms,            source.session_started_at_ms,            source.session_started_at_ms,            .full,            source.completeness,        );        snapshot.session_activity = source.activity;        return snapshot;    }    if (source.models.len > max_models) return error.UsageCapacityExceeded;     const total_tokens = std.math.add(        u64,        source.input_tokens,        source.output_tokens,    ) catch return error.UsageOverflow;    const models = try alloc.alloc(ModelUsage, source.models.len);    errdefer alloc.free(models);    var built_models: usize = 0;    errdefer for (models[0..built_models]) |*model| model.deinit(alloc);    for (source.models, 0..) |source_model, index| {        if (source_model.model.len == 0 or            source_model.model.len > max_model_bytes or            !std.math.isFinite(source_model.total_cost) or            source_model.total_cost < 0 or            source_model.cache_read_tokens > source_model.input_tokens or            source_model.cache_write_tokens > source_model.input_tokens)        {            return error.InvalidGenerationFact;        }        if (source_model.reasoning_tokens) |reasoning| {            if (reasoning > source_model.output_tokens) {                return error.InvalidGenerationFact;            }        }        for (source_model.model) |byte| {            if (byte < 0x21 or byte > 0x7e) {                return error.InvalidGenerationFact;            }        }        models[index] = .{            .model = try alloc.dupe(u8, source_model.model),            .totals = .{                .total_tokens = std.math.add(                    u64,                    source_model.input_tokens,                    source_model.output_tokens,                ) catch return error.UsageOverflow,                .input_tokens = source_model.input_tokens,                .output_tokens = source_model.output_tokens,                .cache_read_tokens = source_model.cache_read_tokens,                .cache_write_tokens = source_model.cache_write_tokens,                .reasoning_tokens = source_model.reasoning_tokens,                .request_count = source_model.request_count,                .total_cost = source_model.total_cost,            },        };        built_models += 1;    }    sort_utils.sort(ModelUsage, models, {}, modelUsageLessThan);     return .{        .scope = .session,        .snapshot_time_ms = source.snapshot_time_ms,        .window_start_ms = source.session_started_at_ms,        .coverage_started_at_ms = source.session_started_at_ms,        .coverage = .full,        .completeness = source.completeness,        .totals = .{            .total_tokens = total_tokens,            .input_tokens = source.input_tokens,            .output_tokens = source.output_tokens,            .cache_read_tokens = source.cache_read_tokens,            .cache_write_tokens = source.cache_write_tokens,            .reasoning_tokens = source.reasoning_tokens,            .request_count = source.request_count,            .total_cost = source.total_cost,        },        .models = models,        .session_activity = source.activity,    };} pub fn validateFact(fact: GenerationFact) error{InvalidGenerationFact}!void {    if (!types.validGatewayGenerationId(fact.id) or        fact.created_at_ms < 0 or        fact.model.len == 0 or        fact.model.len > max_model_bytes or        !std.math.isFinite(fact.total_cost) or        fact.total_cost < 0 or        fact.cache_read_tokens > fact.input_tokens or        fact.cache_write_tokens > fact.input_tokens)    {        return error.InvalidGenerationFact;    }    if (fact.reasoning_tokens) |reasoning| {        if (reasoning > fact.output_tokens) return error.InvalidGenerationFact;    }    for (fact.model) |byte| {        if (byte < 0x21 or byte > 0x7e) return error.InvalidGenerationFact;    }} pub fn validatePendingMarker(    marker: PendingMarker,) error{InvalidPendingMarker}!void {    if (!types.validGatewayGenerationId(marker.id) or marker.observed_at_ms < 0) {        return error.InvalidPendingMarker;    }} pub fn validateIncident(incident: Incident) error{InvalidUsageIncident}!void {    if (incident.occurred_at_ms < 0 or        (incident.completeness != .pending and            incident.completeness != .incomplete))    {        return error.InvalidUsageIncident;    }} /// Builds an owned rolling snapshot from validated facts and an explicit time./// The caller must call `Snapshot.deinit`.pub fn buildRollingSnapshot(    alloc: Allocator,    scope: Scope,    snapshot_time_ms: i64,    coverage_started_at_ms: ?i64,    facts: []const GenerationFact,    incidents: []const Incident,) BuildError!Snapshot {    const duration_ms = scope.durationMs() orelse return error.InvalidSnapshotTime;    if (snapshot_time_ms < 0) return error.InvalidSnapshotTime;    const window_start_ms = std.math.sub(i64, snapshot_time_ms, duration_ms) catch        return error.InvalidSnapshotTime;    var visible_coverage_started_at_ms = coverage_started_at_ms;    if (coverage_started_at_ms) |started_at_ms| {        if (started_at_ms < 0) return error.InvalidSnapshotTime;        if (started_at_ms > snapshot_time_ms) {            visible_coverage_started_at_ms = null;        }

Lines 1–500 of 863.