Carry evidence through built-in generation retries

This commit is contained in:
2026-10-13 16:56:56 +00:00
parent d91afc61a4
commit c5aed7a451
6 changed files with 372 additions and 27 deletions

View File

@@ -28,7 +28,7 @@ type Recorder struct {
capacityWait time.Duration
generationDuration time.Duration
retryDelay time.Duration
usage usageTotals
usage UsageAccumulator
}
// Selection contains resolved identities only. Unresolved fields stay empty.
@@ -79,8 +79,7 @@ func New(observer domain.ExecutionObserver) (*Recorder, error) {
}
func newRecorder(runID string, now func() time.Time, observer domain.ExecutionObserver) *Recorder {
return &Recorder{runID: runID, startedAt: now(), now: now, observer: observer,
usage: newUsageTotals()}
return &Recorder{runID: runID, startedAt: now(), now: now, observer: observer}
}
// NewRunID creates the identity shared by observations and successful results.
@@ -119,7 +118,7 @@ func (r *Recorder) Attempt(data AttemptData) {
r.lastRepairGeneration = data.Generation
}
r.generationDuration = addDuration(r.generationDuration, data.GenerationDuration)
r.usage.add(data.Usage, data.UsagePresence)
r.usage.Add(data.Usage, data.UsagePresence)
}
event := r.event(domain.ExecutionAttempt)
event.Generation = data.Generation
@@ -171,7 +170,7 @@ func (r *Recorder) Finish(data FinishData) {
if event.Duration < 0 {
event.Duration = 0
}
event.Usage = r.usage.snapshot(r.attempts)
event.Usage = r.usage.Observed()
r.deliver(event)
}
@@ -243,7 +242,29 @@ type usageTotals struct {
prompt, completion, total, cached, cacheWrite usageField
}
func newUsageTotals() usageTotals {
// UsageAccumulator combines presence-aware usage across dispatched attempts.
// Its zero value represents no dispatched attempts.
type UsageAccumulator struct {
totals usageTotals
attempts uint64
}
// Add includes the usage reported by one dispatched attempt.
func (u *UsageAccumulator) Add(usage domain.TokenUsage, presence *domain.TokenUsagePresence) {
if u.attempts == 0 {
u.totals = completeUsageTotals()
}
u.attempts++
u.totals.add(usage, presence)
}
// Observed returns aggregate counts, marking every field known and complete
// when no attempt has been added.
func (u UsageAccumulator) Observed() domain.ObservedTokenUsage {
return u.totals.snapshot(u.attempts)
}
func completeUsageTotals() usageTotals {
return usageTotals{prompt: usageField{complete: true}, completion: usageField{complete: true},
total: usageField{complete: true}, cached: usageField{complete: true}, cacheWrite: usageField{complete: true}}
}