返回 DeepSeek-Reasonix
context_read.go
根目录 / desktop / context_read.go
1 package main
2
3 import (
4 "strings"
5
6 "reasonix/internal/control"
7 )
8
9 // contextRead binds every field in an overview response to one runtime. Reads
10 // must never re-key the tab's telemetry: an old read can finish after navigation.
11 type contextRead struct {
12 tabID string
13 tab *WorkspaceTab
14 ctrl control.SessionAPI
15 generation uint64
16 sessionID string
17 storedPath string
18 controllerPath string
19 workspaceRoot string
20 telemetry tabTelemetrySnapshot
21 runtime sessionRuntime
22 }
23
24 // sessionRuntime splits runtime into finished turns and the running turn's
25 // start, so a reader can keep counting between snapshots.
26 type sessionRuntime struct {
27 completedMs int64
28 turnStartedAt int64
29 }
30
31 func (a *App) captureContextRead(tabID string) contextRead {
32 a.mu.RLock()
33 if strings.TrimSpace(tabID) == "" {
34 tabID = a.activeTabID
35 }
36 tab := a.tabByIDLocked(tabID)
37 if tab == nil {
38 a.mu.RUnlock()
39 return contextRead{}
40 }
41 r := contextRead{tabID: tabID, tab: tab, ctrl: tab.Ctrl, generation: tab.SessionGeneration,
42 sessionID: tab.SessionID, storedPath: tab.SessionPath, workspaceRoot: tab.WorkspaceRoot}
43 tab.telemMu.Lock()
44 key := tab.telemetrySessionKey
45 r.telemetry = tab.displayTelemetrySnapshotLocked()
46 r.runtime = sessionRuntime{completedMs: tab.usageTelemetry.ElapsedMs, turnStartedAt: tab.usageTelemetry.activeTurnStartedAt}
47 tab.telemMu.Unlock()
48 a.mu.RUnlock()
49 if r.ctrl != nil {
50 r.controllerPath = r.ctrl.SessionPath()
51 if r.controllerPath != "" && sessionRuntimeKey(r.controllerPath) != key {
52 // A legacy /new can rotate before the next event re-keys telemetry.
53 // Read its sidecar without mutating the live tab or wallet overlay.
54 r.telemetry = loadTelemetry(r.controllerPath + ".telemetry.json")
55 r.runtime = sessionRuntime{completedMs: r.telemetry.Usage.ElapsedMs}
56 }
57 }
58 return r
59 }
60
61 func (r contextRead) current(a *App) bool {
62 if r.tab == nil {
63 return false
64 }
65 // Controller methods stay outside App.mu; some can re-enter the host.
66 if r.ctrl != nil && r.ctrl.SessionPath() != r.controllerPath {
67 return false
68 }
69 a.mu.RLock()
70 defer a.mu.RUnlock()
71 return a.tabs[r.tabID] == r.tab && !r.tab.removed && r.tab.Ctrl == r.ctrl &&
72 r.tab.SessionGeneration == r.generation && r.tab.SessionID == r.sessionID &&
73 r.tab.SessionPath == r.storedPath
74 }
75
75 lines GO