loop: preserve cumulative usage across conversation compaction

conversation: add optional CumulativeUsage parameter to New function

Update CompactConversation to preserve cumulative usage statistics when
resetting the conversation, preventing usage numbers from being lost during
compaction.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s11dcb84790847494k
diff --git a/loop/agent.go b/loop/agent.go
index 092181b..5c36bcf 100644
--- a/loop/agent.go
+++ b/loop/agent.go
@@ -622,9 +622,12 @@
 	contextWindow := a.config.Service.TokenContextWindow()
 	currentContextSize := lastUsage.InputTokens + lastUsage.CacheReadInputTokens + lastUsage.CacheCreationInputTokens
 
+	// Preserve cumulative usage across compaction
+	cumulativeUsage := a.convo.CumulativeUsage()
+
 	// Reset conversation state but keep all other state (git, working dir, etc.)
 	a.firstMessageIndex = len(a.history)
-	a.convo = a.initConvo()
+	a.convo = a.initConvoWithUsage(&cumulativeUsage)
 
 	a.mu.Unlock()
 
@@ -1205,8 +1208,13 @@
 // It must not be called until all agent fields are initialized,
 // particularly workingDir and git.
 func (a *Agent) initConvo() *conversation.Convo {
+	return a.initConvoWithUsage(nil)
+}
+
+// initConvoWithUsage initializes the conversation with optional preserved usage.
+func (a *Agent) initConvoWithUsage(usage *conversation.CumulativeUsage) *conversation.Convo {
 	ctx := a.config.Context
-	convo := conversation.New(ctx, a.config.Service)
+	convo := conversation.New(ctx, a.config.Service, usage)
 	convo.PromptCaching = true
 	convo.Budget = a.config.Budget
 	convo.SystemPrompt = a.renderSystemPrompt()