mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-11 17:10:38 -10:00
Problem: The full progress and retry implementation expands the main-v2 maintenance surface beyond the reported compaction hang and truncation defects. Root cause: The initial change coupled operation deadlines and failure handling to new runtime, wire, persistence, and UI contracts. Fix: Retain one shared five-minute compaction budget and typed failure recovery without automatic lossy truncation. Remove the new observer/progress protocol, UI, retry API, and receipt fields from the final diff. Preserve the existing range-compression behavior and last committed projection. Keep the complete implementation on a separate branch for independent 2.x evaluation. Verification: Focused Agent/Control and race tests, actual SSE heartbeat parsing under virtual time, nested/chunk budgets, queue cancellation, late completion, partial commits, persistence reopening, pinned Go lint, repolint, and diff checks. The complete root suite and current-head CI provide separate broad evidence.
106 lines
4.2 KiB
Go
106 lines
4.2 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"reasonix/internal/provider"
|
|
)
|
|
|
|
// maintenanceInstall is one free projection rewrite (no summarizer call): the
|
|
// visible view it started from and the projected view replacing it.
|
|
type maintenanceInstall struct {
|
|
trigger, action string
|
|
state CompactionState
|
|
canonical []provider.Message
|
|
transcriptVersion uint64
|
|
visible, projected []provider.Message
|
|
affected int
|
|
}
|
|
|
|
// installMaintenanceProjection CAS-installs a free projection under
|
|
// compactionMu. The caller owns compactionRunMu for the whole maintenance run;
|
|
// canonical storage, including RawContent, is never modified.
|
|
func (a *Agent) installMaintenanceProjection(ctx context.Context, in maintenanceInstall) (bool, error) {
|
|
if ctx == nil {
|
|
ctx = context.Background()
|
|
}
|
|
if err := ctx.Err(); err != nil {
|
|
return false, err
|
|
}
|
|
projected := projectionMessagesPreservingPinnedContext(in.projected)
|
|
projected, _, err := rebasePinnedContextProjection(projected, in.canonical, len(in.canonical))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if err := ctx.Err(); err != nil {
|
|
return false, err
|
|
}
|
|
sourceTokens := a.estimatedVisibleRequestTokens(in.visible)
|
|
resultTokens := a.estimatedVisibleRequestTokens(projected)
|
|
inputHash := a.contextMaintenanceInputHash(modelInputMessages(in.visible))
|
|
outputHash := providerVisibleFingerprint(modelInputMessages(projected))
|
|
projectionVersion := in.state.Projection.ProjectionVersion + 1
|
|
now := time.Now().UTC()
|
|
coveredHash := coveredPrefixHash(in.canonical, len(in.canonical))
|
|
receipt := &ContextMaintenanceReceipt{
|
|
OperationID: fmt.Sprintf("%s-%d-%s", in.action, projectionVersion, outputHash), Status: "applied", Action: in.action,
|
|
Trigger: in.trigger, SourceProjection: in.state.Projection.ProjectionVersion, ProjectionVersion: projectionVersion,
|
|
CoveredCount: len(in.canonical), CoveredPrefixHash: coveredHash, InputHash: inputHash, OutputHash: outputHash,
|
|
InputTokens: sourceTokens, ResultTokens: resultTokens, SavedTokens: max(0, sourceTokens-resultTokens),
|
|
AffectedToolResults: in.affected, CacheBreak: true, CreatedAt: now,
|
|
}
|
|
next := in.state
|
|
next.SchemaVersion = compactionStateSchemaCurrent
|
|
next.TranscriptVersion = in.transcriptVersion
|
|
next.Generation++
|
|
next.PromptCacheKey = a.currentPromptCacheKey()
|
|
next.Projection = ContextProjection{
|
|
Messages: projected, TranscriptVersion: in.transcriptVersion, ProjectionVersion: projectionVersion,
|
|
CoveredCount: len(in.canonical), CoveredPrefixHash: coveredHash, SourceTokens: sourceTokens,
|
|
PinnedContextHash: pinnedContextCoverageHash(in.canonical, len(in.canonical)),
|
|
ProjectionTokens: resultTokens, ViewInputHash: inputHash, ViewOutputHash: outputHash, CreatedAt: now,
|
|
}
|
|
next.LastReceipt = receipt
|
|
next.UpdatedAt = now
|
|
|
|
a.sess.compactionMu.Lock()
|
|
// Cancellation and the projection compare-and-swap share this lock boundary.
|
|
// Once the state is installed, persistence finishes atomically with respect
|
|
// to this batch; cancellation can only prevent a later batch.
|
|
if err := ctx.Err(); err != nil {
|
|
a.sess.compactionMu.Unlock()
|
|
return false, err
|
|
}
|
|
current, currentVersion := a.sess.conversation.snapshotMessagesVersion()
|
|
if currentVersion != in.transcriptVersion || len(current) != len(in.canonical) ||
|
|
coveredPrefixHash(current, len(current)) != coveredHash ||
|
|
a.sess.compactionState.Projection.ProjectionVersion != in.state.Projection.ProjectionVersion ||
|
|
a.sess.compactionState.Generation != in.state.Generation {
|
|
a.sess.compactionMu.Unlock()
|
|
return false, errCompressStaleContext
|
|
}
|
|
previous := a.sess.compactionState
|
|
a.sess.compactionState = next
|
|
accepted, err := a.persistInstalledProjectionLocked(context.Background(), next, current)
|
|
if err != nil {
|
|
if accepted {
|
|
a.sess.checkpointState = "pending"
|
|
a.sess.compactionMu.Unlock()
|
|
return false, &compactionPersistenceError{fmt.Errorf("persist %s projection: %w", in.action, err)}
|
|
}
|
|
a.sess.compactionState = previous
|
|
a.sess.compactionMu.Unlock()
|
|
if errors.Is(err, errCompressStaleContext) {
|
|
return false, err
|
|
}
|
|
return false, &compactionPersistenceError{fmt.Errorf("persist %s projection: %w", in.action, err)}
|
|
}
|
|
a.sess.checkpointState = "applied"
|
|
a.sess.compactionMu.Unlock()
|
|
a.emitContextMaintenance(receipt)
|
|
return true, nil
|
|
}
|