feat(loop): Top5#5 上下文溢出压缩 + 每轮 assemble(对齐 OpenClaw context-engine)——Top5 全完成
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 每轮 assemble(transformContext 等价):run.go 每 step 前 assembleContext——依次 Inject(每轮
  重新 Retriever.Inject 不缓存首轮)、WorkingMemory 前置 Summarize、可插拔 TransformContext 投影/
  过滤;生成的 view 交 step,msgs 保持纯对话供工具结果追加,记忆不重复注入、不写回 checkpoint。
- Compactor:结构分支感知压缩——estimateContextTokens 启发式超 MaxContextTokens 且消息≥3 才动;
  findKeepStart 按 user 消息切整轮从后往前累加(至少保留最后一整轮→尾随工具结果绝不切片/不跨轮);
  旧轮 user/assistant 对压成一条 RoleSystem 摘要置顶,既有摘要前缀识别合并防叠;capSummary 上限
  4000 rune;ctx 即 abortSignal(取消返回 ctx.Err,压缩失败仅记日志不中断 run)。
- 选项:Options 增 MaxContextTokens/Compactor/TransformContext,均 nil-tolerant(默认=现有行为,
  零值不压缩);DefaultMaxContextTokens=32768。Compactor 接口预留注入 LLM 摘要。

go build/vet/test -count=1 全绿 + windows/darwin 交叉编译。12 断言覆盖尾随工具结果保留/不跨轮切割/
摘要上限/摘要合并/ctx 取消/每轮重检索/TransformContext 逐轮/超限压缩/默认关闭。-race 受宿主
TSan VMA 限制无法运行(与代码无关)。

**至此 Top5(1~5) 全部完成并推库。**
This commit is contained in:
Aska committed 2026-09-06 18:08:55 +08:00
1 parent 35cb2d3942
commit 648292d035
7 files changed
+709 -31

No files matched your search

+30 -19
View File
@@ -12,6 +12,7 @@
package loop
import (
"context"
"errors"
"io"
"log/slog"
@@ -91,9 +92,12 @@ type Loop struct {
maxRounds int
toolExec string
toolParallelism int
hooks ToolLoopHooks
onStream func(model.StreamEvent)
log *slog.Logger
hooks ToolLoopHooks
onStream func(model.StreamEvent)
maxContextTokens int
compactor Compactor
transformContext func(context.Context, []model.Message, int) []model.Message
log *slog.Logger
}
// New builds a Loop from opts, applying defaults. A non-positive MaxRounds
@@ -114,23 +118,30 @@ func New(opts Options) *Loop {
if toolParallelism <= 0 {
toolParallelism = DefaultToolParallelism
}
compactor := opts.Compactor
if compactor == nil {
compactor = defaultCompactor{}
}
return &Loop{
agent: opts.Agent,
tools: opts.Tools,
memory: opts.Memory,
retriever: opts.Retriever,
working: opts.WorkingMemory,
extractor: opts.Extractor,
checkpoint: opts.Checkpoint,
tracer: opts.Tracer,
guards: opts.Guards,
personaID: opts.PersonaID,
maxRounds: maxRounds,
toolExec: toolExec,
toolParallelism: toolParallelism,
hooks: opts.Hooks,
onStream: opts.OnStream,
log: sourcedLog(opts.Log),
agent: opts.Agent,
tools: opts.Tools,
memory: opts.Memory,
retriever: opts.Retriever,
working: opts.WorkingMemory,
extractor: opts.Extractor,
checkpoint: opts.Checkpoint,
tracer: opts.Tracer,
guards: opts.Guards,
personaID: opts.PersonaID,
maxRounds: maxRounds,
toolExec: toolExec,
toolParallelism: toolParallelism,
hooks: opts.Hooks,
onStream: opts.OnStream,
maxContextTokens: opts.MaxContextTokens,
compactor: compactor,
transformContext: opts.TransformContext,
log: sourcedLog(opts.Log),
}
}