docs(runtime): internal/runtime/loop 44 个文件注释改中文(逐行 1:1,代码零字节改动)
主人 2026-10-03 拍板「注释一律中文」;本模块按长期分批协议(一个模块一次派工)执行。 注释行数 1329 → 1329 逐行 1:1(含中文 33 → 1304);行尾注释 5 条一并译。 校验:机械校验(非注释改动行)= 空;独立 Go AST 程序(剥注释复渲)证明 44/44 文件代码全等; 全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。 gofmt:capacity_loop_test.go / flow.go 改动前即未格式化,按铁律保留原样未动。
This commit is contained in:
1 parent
355f81d04a
commit
91e8d7a029
44 files changed
+1315
-1315
No files matched your search
@@ -9,70 +9,70 @@ import (
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
||||
)
|
||||
|
||||
// Compaction tuning constants. These bound the compactor so it stays
|
||||
// deterministic and offline: the summary is capped, the recent tail is a share
|
||||
// of the budget, and very short conversations are left alone even when they
|
||||
// exceed the budget (design §1.3 上下文溢出压缩).
|
||||
// 压缩调优常量。它们界定 compactor,使其保持确定性与
|
||||
// 离线:摘要被限额、近期尾部占预算的一个比例,
|
||||
// 且极短的对话即使超出预算也原样不动
|
||||
// (design §1.3 上下文溢出压缩)。
|
||||
const (
|
||||
// DefaultMaxContextTokens is the context budget a caller can assign to
|
||||
// Options.MaxContextTokens to enable overflow compaction (design §1.3).
|
||||
// DefaultMaxContextTokens 是调用方可赋给
|
||||
// Options.MaxContextTokens 以启用溢出压缩的上下文预算(design §1.3)。
|
||||
DefaultMaxContextTokens = 32768
|
||||
|
||||
// keepRecentFraction is the share of the budget reserved for the recent tail
|
||||
// during compaction; the remainder is left for the summary message and prompt.
|
||||
// keepRecentFraction 是压缩时为近期尾部保留的
|
||||
// 预算比例;余下部分留给摘要消息与提示词。
|
||||
keepRecentFraction = 0.5
|
||||
|
||||
// minKeepTokens is the floor for the recent-tail budget so a tiny
|
||||
// MaxContextTokens does not force every turn into the summary.
|
||||
// minKeepTokens 是近期尾部预算的下限,使极小的
|
||||
// MaxContextTokens 不会把每个 turn 都逼进摘要。
|
||||
minKeepTokens = 128
|
||||
|
||||
// summaryMarker tags a compaction summary system message so the compactor can
|
||||
// recognize an existing summary prefix and preserve (merge into) it rather
|
||||
// than re-summarize it on a later compaction.
|
||||
// summaryMarker 标记压缩摘要系统消息,使 compactor 能
|
||||
// 识别已存在的摘要前缀并保留(并入)它,
|
||||
// 而不是在后续压缩中重新摘要。
|
||||
summaryMarker = "[前文摘要 · history summary]"
|
||||
|
||||
// maxSummaryChars caps the compaction summary so repeated compactions cannot
|
||||
// inflate the summary without bound (design §1.3 摘要容量上限).
|
||||
// maxSummaryChars 限制压缩摘要,使反复压缩无法
|
||||
// 无界地膨胀摘要(design §1.3 摘要容量上限)。
|
||||
maxSummaryChars = 4000
|
||||
|
||||
// minCompactMessages is the smallest conversation the compactor will touch; a
|
||||
// shorter one is left alone even when it is over budget.
|
||||
// minCompactMessages 是 compactor 会触碰的最小对话;
|
||||
// 更短的即使超出预算也原样不动。
|
||||
minCompactMessages = 3
|
||||
|
||||
// messageOverheadTokens is the per-message token overhead charged for the role
|
||||
// and separator tokens the provider adds around each message.
|
||||
// messageOverheadTokens 是每条消息的 token 开销,对应 provider
|
||||
// 在每条消息周围添加的角色与分隔符 token。
|
||||
messageOverheadTokens = 4
|
||||
|
||||
// imageTokens is the rough token charge for a single image part.
|
||||
// imageTokens 是单个图像部件的粗略 token 计数。
|
||||
imageTokens = 1000
|
||||
|
||||
// charsPerToken is the character-to-token divisor used by the offline estimate.
|
||||
// charsPerToken 是离线估算使用的字符到 token 除数。
|
||||
charsPerToken = 4
|
||||
|
||||
// summarySampleChars bounds the per-message text sampled into a naive summary.
|
||||
// summarySampleChars 限制被抽样进朴素摘要的每条消息文本长度。
|
||||
summarySampleChars = 120
|
||||
)
|
||||
|
||||
// Compactor compacts an over-budget conversation by summarizing older turns into
|
||||
// a single leading summary message while preserving the recent tail — including
|
||||
// the trailing tool results — unmodified (design §1.3, aligned with OpenClaw's
|
||||
// context-engine). It is injected through Options.Compactor so a caller can swap
|
||||
// in an LLM-backed summarizer; the loop ships a structural default that never
|
||||
// calls a model.
|
||||
// Compactor 通过把更早的轮次摘要成单条前导摘要消息来压缩
|
||||
// 超预算的对话,同时原样保留近期尾部 —— 包括
|
||||
// 尾部的工具结果(design §1.3,与 OpenClaw 的
|
||||
// context-engine 对齐)。它经 Options.Compactor 注入,使调用方能
|
||||
// 换成 LLM 支持的摘要器;循环自带一个绝不调用
|
||||
// 模型的结构化默认实现。
|
||||
type Compactor interface {
|
||||
// Compact returns messages with older turns compressed into a leading summary
|
||||
// when the estimated tokens exceed budget. It returns the input unchanged when
|
||||
// the messages already fit within budget or there is nothing safe to
|
||||
// summarize. ctx is the abort signal: a canceled context stops compaction and
|
||||
// returns a wrapped context.Canceled so the caller can bail out.
|
||||
// Compact 在估算 token 超过 budget 时返回把更早轮次压缩为
|
||||
// 一条前导摘要的 messages。消息本来就在预算内,或
|
||||
// 没有可安全摘要的内容时,它原样返回输入。
|
||||
// ctx 是中止信号:被取消的 context 停止压缩并
|
||||
// 返回包装过的 context.Canceled,使调用方能退出。
|
||||
Compact(ctx context.Context, messages []model.Message, budget int) ([]model.Message, error)
|
||||
}
|
||||
|
||||
// defaultCompactor is the built-in structural compactor. It is stateless and
|
||||
// safe for concurrent use.
|
||||
// defaultCompactor 是内置的结构化 compactor。它无状态,
|
||||
// 且并发安全。
|
||||
type defaultCompactor struct{}
|
||||
|
||||
// Compact implements Compactor.
|
||||
// Compact 实现 Compactor。
|
||||
func (defaultCompactor) Compact(ctx context.Context, messages []model.Message, budget int) ([]model.Message, error) {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
@@ -83,8 +83,8 @@ func (defaultCompactor) Compact(ctx context.Context, messages []model.Message, b
|
||||
return compactMessages(ctx, messages, budget)
|
||||
}
|
||||
|
||||
// compactMessages is the shared compaction implementation. It never mutates the
|
||||
// input slices; a compacted result is always freshly allocated.
|
||||
// compactMessages 是共享的压缩实现。它绝不改写
|
||||
// 输入切片;压缩结果始终是新分配的。
|
||||
func compactMessages(ctx context.Context, messages []model.Message, budget int) ([]model.Message, error) {
|
||||
if budget <= 0 || len(messages) < minCompactMessages {
|
||||
return messages, nil
|
||||
@@ -97,7 +97,7 @@ func compactMessages(ctx context.Context, messages []model.Message, budget int)
|
||||
keepTokens := max(int(float64(budget)*keepRecentFraction), minKeepTokens)
|
||||
keepStart := findKeepStart(messages, prefixEnd, keepTokens)
|
||||
if keepStart <= prefixEnd {
|
||||
// Everything is being kept; there is no safe prefix to summarize.
|
||||
// 全部内容都被保留;没有可安全摘要的前缀。
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
@@ -125,9 +125,9 @@ func compactMessages(ctx context.Context, messages []model.Message, budget int)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// summaryPrefixEnd returns the count of leading compaction-summary messages,
|
||||
// which are never re-summarized. It is 0 (no summary) or 1 (a single summary
|
||||
// prefix), since compaction always emits exactly one leading summary.
|
||||
// summaryPrefixEnd 返回前导压缩摘要消息的数量,
|
||||
// 它们绝不再次被摘要。取值为 0(无摘要)或 1(单条摘要
|
||||
// 前缀),因为压缩始终只产出一条前导摘要。
|
||||
func summaryPrefixEnd(messages []model.Message) int {
|
||||
if len(messages) == 0 || messages[0].Role != model.RoleSystem {
|
||||
return 0
|
||||
@@ -138,12 +138,12 @@ func summaryPrefixEnd(messages []model.Message) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// findKeepStart returns the index of the first message to keep given that the
|
||||
// recent tail should fit within keepTokens. It always keeps whole turns: a turn
|
||||
// starts at a user message and runs to the next user message. It scores turns
|
||||
// from the back, so the most recent turns survive and a trailing tool result is
|
||||
// never sliced apart. When no user turn exists (unusual), it keeps nothing extra
|
||||
// and returns from, so nothing is summarized.
|
||||
// findKeepStart 在近期尾部应装入 keepTokens 的前提下,
|
||||
// 返回第一条要保留的消息索引。它始终保留完整的 turn:一个 turn
|
||||
// 从用户消息开始,直到下一条用户消息。它从后往前
|
||||
// 给 turn 计分,因此最近的 turn 得以存活,尾部的工具结果
|
||||
// 绝不被切开。不存在用户 turn 时(少见),它不额外保留任何东西
|
||||
// 并从 from 返回,因此什么也不被摘要。
|
||||
func findKeepStart(messages []model.Message, from, keepTokens int) int {
|
||||
n := len(messages)
|
||||
turns := make([]int, 0, 8)
|
||||
@@ -173,10 +173,10 @@ func findKeepStart(messages []model.Message, from, keepTokens int) int {
|
||||
return keptStart
|
||||
}
|
||||
|
||||
// estimateContextTokens returns a conservative token estimate for messages. It is
|
||||
// a heuristic (chars ÷ charsPerToken with a per-message and per-image overhead)
|
||||
// so it stays dependency-free and offline, but it is monotonic enough to drive
|
||||
// the compact decision.
|
||||
// estimateContextTokens 返回 messages 的保守 token 估算。它是
|
||||
// 启发式(字符 ÷ charsPerToken,加上每条消息与每个图像的开销),
|
||||
// 因此无依赖且离线,但单调性足够驱动
|
||||
// 压缩决策。
|
||||
func estimateContextTokens(messages []model.Message) int {
|
||||
total := 0
|
||||
for _, m := range messages {
|
||||
@@ -193,9 +193,9 @@ func estimateContextTokens(messages []model.Message) int {
|
||||
return total
|
||||
}
|
||||
|
||||
// estimateStringTokens is the character-level token estimate for one text string,
|
||||
// weighting wide (CJK) runes double and dividing by charsPerToken. An empty string
|
||||
// costs nothing; a non-empty one costs at least one token.
|
||||
// estimateStringTokens 是单个文本字符串的字符级 token 估算,
|
||||
// 把宽字符(CJK)rune 计为双倍权重再除以 charsPerToken。空字符串
|
||||
// 不花费任何 token;非空至少花费一个 token。
|
||||
func estimateStringTokens(s string) int {
|
||||
if s == "" {
|
||||
return 0
|
||||
@@ -214,10 +214,10 @@ func estimateStringTokens(s string) int {
|
||||
return t
|
||||
}
|
||||
|
||||
// buildSummary renders a compact structural summary of the given messages: a role
|
||||
// distribution plus the most recent user and assistant text. It is the default
|
||||
// (offline, no-model) summarizer; a caller that wants a semantic digest injects
|
||||
// its own Compactor instead.
|
||||
// buildSummary 渲染给定 messages 的紧凑结构化摘要:角色
|
||||
// 分布,加上最近的用户与 assistant 文本。它是默认的
|
||||
// (离线、不调模型)摘要器;想要语义化摘要的调用方
|
||||
// 改为注入自己的 Compactor。
|
||||
func buildSummary(messages []model.Message) string {
|
||||
if len(messages) == 0 {
|
||||
return ""
|
||||
@@ -260,8 +260,8 @@ func buildSummary(messages []model.Message) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// capSummary truncates s to at most max runes, appending a "..." marker when it
|
||||
// had to cut. It is rune-safe so it never slices a multi-byte rune in half.
|
||||
// capSummary 把 s 截断到至多 max 个 rune,需要裁剪时追加 "..." 标记。
|
||||
// 它是 rune 安全的,因此绝不把多字节 rune 切成两半。
|
||||
func capSummary(s string, max int) string {
|
||||
runes := []rune(s)
|
||||
if len(runes) <= max {
|
||||
@@ -273,7 +273,7 @@ func capSummary(s string, max int) string {
|
||||
return string(runes[:max-3]) + "..."
|
||||
}
|
||||
|
||||
// truncateRunes shortens s to at most n runes, Unicode-safe.
|
||||
// truncateRunes 把 s 缩短到至多 n 个 rune,Unicode 安全。
|
||||
func truncateRunes(s string, n int) string {
|
||||
runes := []rune(s)
|
||||
if len(runes) <= n {
|
||||
|
||||
Reference in new issue
Block a user