Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/agent/core/transcript_buffer.go
3433 views
1
package core
2
3
import (
4
"fmt"
5
"strings"
6
"sync"
7
)
8
9
const defaultTruncationBanner = "\n…(truncated)\n"
10
11
type TranscriptBuffer struct {
12
mu sync.Mutex
13
max int
14
b []byte
15
banner []byte
16
}
17
18
func NewTranscriptBuffer(maxBytes int) *TranscriptBuffer {
19
if maxBytes < 0 {
20
maxBytes = 0
21
}
22
return &TranscriptBuffer{
23
max: maxBytes,
24
b: make([]byte, 0, minInt(maxBytes, 4096)),
25
banner: []byte(defaultTruncationBanner),
26
}
27
}
28
29
func (t *TranscriptBuffer) AppendString(s string) {
30
if t == nil || s == "" {
31
return
32
}
33
34
t.mu.Lock()
35
defer t.mu.Unlock()
36
37
if t.max <= 0 {
38
t.b = t.b[:0]
39
return
40
}
41
42
// Normalize: keep entries line-oriented
43
if !strings.HasSuffix(s, "\n") {
44
s += "\n"
45
}
46
47
t.b = append(t.b, s...)
48
t.enforceCapLocked()
49
}
50
51
func (t *TranscriptBuffer) Appendf(format string, args ...any) {
52
t.AppendString(fmt.Sprintf(format, args...))
53
}
54
55
func (t *TranscriptBuffer) String() string {
56
if t == nil {
57
return ""
58
}
59
t.mu.Lock()
60
defer t.mu.Unlock()
61
return string(t.b)
62
}
63
64
func (t *TranscriptBuffer) Len() int {
65
if t == nil {
66
return 0
67
}
68
t.mu.Lock()
69
defer t.mu.Unlock()
70
return len(t.b)
71
}
72
73
func (t *TranscriptBuffer) Reset() {
74
if t == nil {
75
return
76
}
77
t.mu.Lock()
78
defer t.mu.Unlock()
79
t.b = t.b[:0]
80
}
81
82
func (t *TranscriptBuffer) enforceCapLocked() {
83
if len(t.b) <= t.max {
84
return
85
}
86
87
// Keep most recent bytes.
88
keep := t.b[len(t.b)-t.max:]
89
t.b = append(t.b[:0], keep...)
90
91
// Prepend banner if we can and it's not already there.
92
if len(t.banner) < t.max && !hasPrefixBytes(t.b, t.banner) {
93
need := len(t.banner)
94
if len(t.b)+need > t.max {
95
extra := (len(t.b) + need) - t.max
96
if extra < len(t.b) {
97
t.b = t.b[extra:]
98
} else {
99
t.b = t.b[:0]
100
}
101
}
102
tmp := make([]byte, 0, t.max)
103
tmp = append(tmp, t.banner...)
104
tmp = append(tmp, t.b...)
105
t.b = tmp
106
}
107
}
108
109
func hasPrefixBytes(b, prefix []byte) bool {
110
if len(prefix) == 0 {
111
return true
112
}
113
if len(b) < len(prefix) {
114
return false
115
}
116
for i := 0; i < len(prefix); i++ {
117
if b[i] != prefix[i] {
118
return false
119
}
120
}
121
return true
122
}
123
124
func minInt(a, b int) int {
125
if a < b {
126
return a
127
}
128
return b
129
}
130
131