返回 DeepSeek-Reasonix
transcript_metadata.go
根目录 / internal / session / transcript_metadata.go
1 package session
2
3 import (
4 "encoding/json"
5 "reasonix/internal/provider"
6 )
7
8 // Transcript metadata retains only input identities and bounded previews, never
9 // assistant/tool bodies. It remains available when display history is external.
10 type transcriptInput struct {
11 ID string
12 TurnID string
13 Preview string
14 }
15
16 func applyTranscriptMetadata(p *Projection, commit Commit, ev Event) {
17 switch ev.Kind {
18 case "history/replace", "legacy/import":
19 p.TranscriptInputs = nil
20 p.HiddenTurns = nil
21 p.RetractedInputs = nil
22 p.RejectedToolResults = nil
23 messages, err := replacementEventMessages(ev, ev.Payload)
24 if err != nil {
25 return
26 }
27 for _, m := range messages {
28 noteTranscriptInput(p, "", m)
29 noteRejectedToolResult(p, m)
30 }
31 case "message/complete", "message/upsert":
32 var body struct {
33 Message provider.Message `json:"message"`
34 }
35 if json.Unmarshal(ev.Payload, &body) != nil {
36 return
37 }
38 if body.Message.LocalOnly || body.Message.Role != provider.RoleAssistant {
39 for i := range p.Turns {
40 if p.Turns[i].MessageID == body.Message.ID {
41 p.Turns[i].MessageID = ""
42 }
43 }
44 }
45 noteTranscriptInput(p, commit.TurnID, body.Message)
46 noteRejectedToolResult(p, body.Message)
47 case "message/retract":
48 ids, err := retractedMessageIDs(ev, ev.Payload)
49 if err != nil {
50 return
51 }
52 for _, id := range ids {
53 delete(p.RejectedToolResults, id)
54 for i := 0; i < len(p.TranscriptInputs); i++ {
55 input := p.TranscriptInputs[i]
56 if input.ID != id {
57 continue
58 }
59 if input.TurnID != "" {
60 if p.RetractedInputs == nil {
61 p.RetractedInputs = map[string]string{}
62 }
63 p.RetractedInputs[id] = input.TurnID
64 if p.HiddenTurns == nil {
65 p.HiddenTurns = map[string]bool{}
66 }
67 p.HiddenTurns[input.TurnID] = true
68 }
69 p.TranscriptInputs = append(p.TranscriptInputs[:i], p.TranscriptInputs[i+1:]...)
70 break
71 }
72 for i := range p.Turns {
73 if p.Turns[i].MessageID == id {
74 p.Turns[i].MessageID = ""
75 }
76 }
77 }
78 }
79 }
80
81 func noteTranscriptInput(p *Projection, turnID string, m provider.Message) {
82 // A repair may restore an identity outside any active turn. Retain the
83 // original ownership across retraction/checkpoints rather than attaching
84 // it to the repair's empty (or unrelated) turn.
85 if original, ok := p.RetractedInputs[m.ID]; ok && m.Role == provider.RoleUser {
86 turnID = original
87 delete(p.RetractedInputs, m.ID)
88 }
89 for i := range p.TranscriptInputs {
90 if p.TranscriptInputs[i].ID == m.ID {
91 p.TranscriptInputs[i].Preview = catalogMessagePreview(m)
92 return
93 }
94 }
95 if m.Role != provider.RoleUser {
96 return
97 }
98 p.TranscriptInputs = append(p.TranscriptInputs, transcriptInput{ID: m.ID, TurnID: turnID, Preview: catalogMessagePreview(m)})
99 delete(p.HiddenTurns, turnID)
100 }
101
102 func visibleBoundaryCount(p Projection, endedOnly bool) int {
103 count := 0
104 for _, t := range p.Turns {
105 if !p.HiddenTurns[t.TurnID] && (!endedOnly || t.EndSequence != 0) {
106 count++
107 }
108 }
109 return count
110 }
111
111 lines GO