@@ -124,33 +124,43 @@ func (m *Manager) Append(role, content string) error {
124124//
125125// "1 个 turn" 的定义:一条 user message 加它后续的 assistant 回复(可能多条 assistant
126126// 段或被工具调用插开,但本会话文件只记 content,所以约等于 1 个 user + 1 个 assistant)。
127- // 实现简化:反向数 user 出现次数到 n,从该 user 起截断。
127+ //
128+ // 实现:文件按日期降序遍历,每个文件读完后从尾部反向扫,边扫边累积。
129+ // 一旦凑够 n 个 user 立即返回,避免把 180 天历史全读进内存。
130+ // 热路径(N=20 且当天就够)只读 1 个文件;稀疏使用时回退到读多个文件。
128131func (m * Manager ) LoadRecentTurns (n int ) []Entry {
129132 if n <= 0 {
130133 return nil
131134 }
132135 files , _ := filepath .Glob (filepath .Join (m .rootDir , "*.jsonl" ))
133- sort .Strings (files ) // 升序;旧 → 新
134- var all []Entry
135- for _ , f := range files {
136- all = append (all , readJSONL (f )... )
137- }
138- if len (all ) == 0 {
139- return nil
140- }
141- // 反向数 user,凑够 n 个就在 user 之前切
136+ sort .Sort (sort .Reverse (sort .StringSlice (files ))) // 新 → 旧
137+
138+ // collected 按"新到旧"顺序累积(反向序),最后整体翻转一次成时间正序。
139+ var collected []Entry
142140 userCount := 0
143- cut := 0
144- for i := len (all ) - 1 ; i >= 0 ; i -- {
145- if all [i ].Role == "user" {
146- userCount ++
147- if userCount == n {
148- cut = i
149- break
141+ for _ , fp := range files {
142+ entries := readJSONL (fp )
143+ for i := len (entries ) - 1 ; i >= 0 ; i -- {
144+ collected = append (collected , entries [i ])
145+ if entries [i ].Role == "user" {
146+ userCount ++
147+ if userCount >= n {
148+ reverseEntries (collected )
149+ return collected
150+ }
150151 }
151152 }
152153 }
153- return all [cut :]
154+ // 历史不够 n turn,把已有的全返回
155+ reverseEntries (collected )
156+ return collected
157+ }
158+
159+ // reverseEntries 就地翻转 slice,O(n) 无分配。
160+ func reverseEntries (s []Entry ) {
161+ for i , j := 0 , len (s )- 1 ; i < j ; i , j = i + 1 , j - 1 {
162+ s [i ], s [j ] = s [j ], s [i ]
163+ }
154164}
155165
156166// Search 在当前 session 下扫描所有 jsonl,按关键词命中。
0 commit comments