mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 02:36:01 -10:00
Accumulated work from the branch, carried across the rebase onto origin/studio and merged with what landed there in the meantime. Storage: a workspace can name where its state lives, and the server tracks the one relocation it may be running (internal/storage, config/storage_roots, serve/storage, the Storage panel). Composer intake: what a drop or a long paste becomes is one pure function — payload in, action out — so "what happens if I drop a folder" is a test rather than a branch of an onDrop handler. It sits on the drop router that landed upstream: that one answers which pane a drop hit, this one answers what it means and says so before the pointer is released. A paste long enough to bury the composer becomes a chip beside it instead. Session: the checkpoint agreement and the lineage/torn-log recovery cases, plus the conflict diagnostic learning where two transcripts parted and which roles stood there — a position and a role tell a local reshape from a foreign write without recording any content. Model refs: the default-model write checks the live catalog, so an extension model the runtime knows can be persisted as the default.
91 lines
2.8 KiB
Go
91 lines
2.8 KiB
Go
package control
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"reasonix/internal/agent"
|
|
"reasonix/internal/store"
|
|
)
|
|
|
|
type snapshotConflictDiagnostic struct {
|
|
At time.Time `json:"at"`
|
|
BranchID string `json:"branch_id"`
|
|
Mode string `json:"mode"`
|
|
Outcome string `json:"outcome"`
|
|
Kind string `json:"kind,omitempty"`
|
|
DiskMessages int `json:"disk_messages,omitempty"`
|
|
SnapshotMessages int `json:"snapshot_messages,omitempty"`
|
|
BaseRevision int64 `json:"base_revision,omitempty"`
|
|
DiskRevision int64 `json:"disk_revision,omitempty"`
|
|
RecoveryBranchID string `json:"recovery_branch_id,omitempty"`
|
|
ExistingRecovery bool `json:"existing_recovery,omitempty"`
|
|
// DivergedAt and the two roles say where the transcripts parted and what
|
|
// stood there: an assistant turn that became a tool row is a local reshape,
|
|
// two different assistant turns are two writers. No content is recorded.
|
|
DivergedAt int `json:"diverged_at"`
|
|
DiskRole string `json:"disk_role,omitempty"`
|
|
SnapshotRole string `json:"snapshot_role,omitempty"`
|
|
}
|
|
|
|
// conflictDiagDedup bounds repeated conflict event log lines for the same
|
|
// {path, disk revision} key within a process.
|
|
var conflictDiagDedup sync.Map // key -> struct{}
|
|
|
|
func appendSnapshotConflictDiagnostic(path, mode, outcome string, saveErr error, recoveryPath string, existing bool) {
|
|
path = strings.TrimSpace(path)
|
|
if path == "" {
|
|
return
|
|
}
|
|
var diskRev int64
|
|
var conflict *agent.SessionSnapshotConflictError
|
|
if errors.As(saveErr, &conflict) && conflict != nil {
|
|
diskRev = conflict.DiskRevision
|
|
}
|
|
dedupKey := path + "\x00" + outcome + "\x00" + strconv.FormatInt(diskRev, 10)
|
|
if _, loaded := conflictDiagDedup.LoadOrStore(dedupKey, struct{}{}); loaded {
|
|
return
|
|
}
|
|
rec := snapshotConflictDiagnostic{
|
|
At: time.Now(),
|
|
BranchID: agent.BranchID(path),
|
|
Mode: mode,
|
|
Outcome: outcome,
|
|
DivergedAt: -1,
|
|
}
|
|
if conflict != nil {
|
|
rec.Kind = string(conflict.Kind)
|
|
rec.DiskMessages = conflict.ExistingMessages
|
|
rec.SnapshotMessages = conflict.SnapshotMessages
|
|
rec.BaseRevision = conflict.BaseRevision
|
|
rec.DiskRevision = conflict.DiskRevision
|
|
rec.DivergedAt = conflict.DivergedAt
|
|
rec.DiskRole = conflict.DiskRole
|
|
rec.SnapshotRole = conflict.SnapshotRole
|
|
}
|
|
if recoveryPath != "" {
|
|
rec.RecoveryBranchID = agent.BranchID(recoveryPath)
|
|
rec.ExistingRecovery = existing
|
|
}
|
|
data, err := json.Marshal(rec)
|
|
if err != nil {
|
|
return
|
|
}
|
|
logPath := store.SessionConflictLog(path)
|
|
if err := os.MkdirAll(filepath.Dir(logPath), 0o755); err != nil {
|
|
return
|
|
}
|
|
f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer f.Close()
|
|
_, _ = f.Write(append(data, '\n'))
|
|
}
|