From 87ab7159d527c994b0794dff4f49af62f9ae3eca Mon Sep 17 00:00:00 2001 From: yzhkali <63027222+yzhkali@users.noreply.github.com> Date: Sun, 31 May 2026 13:30:04 +0000 Subject: [PATCH] Add JSON tags to ledger totals --- internal/storage/sqlite_test.go | 24 ++++++++++++++++++++++++ internal/storage/store.go | 10 +++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/internal/storage/sqlite_test.go b/internal/storage/sqlite_test.go index 0c3ac0f..679b3f3 100644 --- a/internal/storage/sqlite_test.go +++ b/internal/storage/sqlite_test.go @@ -2,6 +2,7 @@ package storage import ( "context" + "encoding/json" "errors" "path/filepath" "testing" @@ -148,6 +149,29 @@ func TestLedgerAndTotals(t *testing.T) { if d := totals.Dollars; d < 0.0359 || d > 0.0361 { t.Errorf("totals.Dollars = %v, want ~0.036", d) } + + raw, err := json.Marshal(totals) + if err != nil { + t.Fatal(err) + } + var payload map[string]any + if err := json.Unmarshal(raw, &payload); err != nil { + t.Fatal(err) + } + for _, key := range []string{"runId", "calls", "promptTokens", "completionTokens", "dollars"} { + if _, ok := payload[key]; !ok { + t.Fatalf("marshaled totals missing %q: %s", key, raw) + } + } + if _, ok := payload["RunID"]; ok { + t.Fatalf("marshaled totals uses Go field names: %s", raw) + } + if payload["runId"] != "run-3" || payload["calls"] != float64(2) || payload["promptTokens"] != float64(300) || payload["completionTokens"] != float64(130) { + t.Fatalf("marshaled totals = %s", raw) + } + if d := payload["dollars"].(float64); d < 0.0359 || d > 0.0361 { + t.Fatalf("marshaled dollars = %v, want ~0.036", d) + } } func TestToolCall(t *testing.T) { diff --git a/internal/storage/store.go b/internal/storage/store.go index 370514c..af007ae 100644 --- a/internal/storage/store.go +++ b/internal/storage/store.go @@ -113,11 +113,11 @@ type ApprovalRecord struct { // LedgerTotals aggregates spend for audit/reporting. type LedgerTotals struct { - RunID string - Calls int64 - PromptTokens int64 - CompletionTokens int64 - Dollars float64 + RunID string `json:"runId"` + Calls int64 `json:"calls"` + PromptTokens int64 `json:"promptTokens"` + CompletionTokens int64 `json:"completionTokens"` + Dollars float64 `json:"dollars"` } // Store is the durable backend. Implementations must be safe for concurrent use.