package session import "agent-native/runtime/llm" const ( // DefaultKeepToolResults 是运行内清理时保留的最近工具结果条数。 DefaultKeepToolResults = 5 // DefaultContextWindow 是未配置模型窗口时的保守字符数。 DefaultContextWindow = 32000 // DefaultOutputReserve 是留给模型输出的字符预留。 DefaultOutputReserve = 4096 // DefaultContextBuffer 是窗口估算的余量,避免贴着上限才清理。 DefaultContextBuffer = 1024 ) // EstimateChars 用字符数近似这次请求的体积。 func EstimateChars(msgs []llm.Message) int { n := 0 for _, m := range msgs { n += len([]rune(m.Content)) for _, c := range m.ToolCalls { n += len([]rune(c.Name)) + len([]rune(c.Arguments)) } } return n } // NeedsClear 在估算超过「窗口 − 输出预留 − 缓冲」时返回真。 // window ≤ 0 时用保守默认值。 func NeedsClear(estimate, window, outputReserve, buffer int) bool { if window <= 0 { window = DefaultContextWindow } room := window - outputReserve - buffer if room < 1 { room = 1 } return estimate > room } // ClearOldToolResults 把最近 keep 条之前的工具结果换成占位。 // 消息条数、顺序和 tool_call 配对都不变;占位写明完整结果仍在会话记录里。 // keep ≤ 0 时保留默认的 5 条。返回的切片不与输入共享被改写的消息。 func ClearOldToolResults(msgs []llm.Message, keep int) []llm.Message { if keep <= 0 { keep = DefaultKeepToolResults } out := append([]llm.Message{}, msgs...) var toolIdx []int for i, m := range out { if m.Role == llm.RoleTool { toolIdx = append(toolIdx, i) } } if len(toolIdx) <= keep { return out } for _, i := range toolIdx[:len(toolIdx)-keep] { name := out[i].Name if name == "" { name = "工具" } loc := "会话记录" if out[i].ToolCallID != "" { loc = "会话记录中的调用 " + out[i].ToolCallID } out[i].Content = "旧工具结果已清理。完整内容见" + loc + "(" + name + ")。" } return out }