- 只翻注释/文档字符串:`go/scanner` 剥注释后按 token 序列+literal 逐 token 比对,**54/54 文件 SAME**;
改动文件总行数与 HEAD 漂移 = 0(严格 1:1,无合并/拆行)
- 裁决编号与 design 节号逐字保留(03.4.1/03.4.2/03.4.3/14.4.1/14.4.5/07.4.2-4、design/04 §3.1/§3.2 等);
`chat_template_kwargs` / `enable_thinking` / `reasoning_effort` / `thinking:{type}` 字段名与形状说明未动
- 存疑译法(已登记):`persona` 在叙事语境用「角色」、标识符语境保留 `persona`(仓库既有模块本身混用);
`rung`→「级」;`provider` 存在「提供商/提供者」两种落笔(可按需一键统一)
- 复核:build/vet 绿 + 两包测试绿;gofmt 干净;残留英文注释 0 条
- 既有存量(未修,只报告):`model/anthropic_test.go` 612 行 >500;`applyAnthropicEvent` 115 行 >80
48 lines
1.8 KiB
Go
48 lines
1.8 KiB
Go
package backthink
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
|
|
)
|
|
|
|
// LoopThinker 把 *loop.Loop 适配为 Thinker。它是生产接线,
|
|
// 让一次自主后台轮驱动完整的工具循环(记忆
|
|
// 注入、模型步骤、IoT/日历/提醒等工具调用),同时看到
|
|
// 主会话的最近对话并在 owner 环境下运行。
|
|
type LoopThinker struct {
|
|
loop *loop.Loop
|
|
recent recentProvider
|
|
}
|
|
|
|
// NewLoopThinker 把 l 包装成基于给定最近消息提供者的 Thinker
|
|
// (生产中是 *history.Store;nil 会让思考降级为仅用引导提示词,
|
|
// 见 mainContext)。
|
|
func NewLoopThinker(l *loop.Loop, recent recentProvider) *LoopThinker {
|
|
return &LoopThinker{loop: l, recent: recent}
|
|
}
|
|
|
|
// Think 经被包装的 loop 跑一轮无人值守思考并返回
|
|
// 结论文本。它继承主会话的最近对话作为输入
|
|
// 上下文,并注入 owner 会话环境(MemWritable=true、ActorOwner、
|
|
// 完整工具集),因此该次思考能读写记忆并调用工具。loop 的
|
|
// Run 会话 id 是本服务自己的(不是主会话 id),所以该次思考绝不会
|
|
// 与活跃主会话的持久化检查点存储冲突(design/20)。
|
|
// 未注入 loop 时返回 ErrNoLoop。
|
|
func (t *LoopThinker) Think(ctx context.Context, sessionID, trigger string) (string, error) {
|
|
if t.loop == nil {
|
|
return "", ErrNoLoop
|
|
}
|
|
recent := mainContext(ctx, t.recent)
|
|
messages := thinkInput(recent, trigger)
|
|
envCtx := loop.WithSessionEnv(ctx, loop.OwnerEnv())
|
|
// 静音 UI 广播:后台反思不得把其中间
|
|
// 推理泄漏进面向用户的 chat 流(它只需要结论)。
|
|
res, err := t.loop.Run(loop.WithMutedBroadcast(envCtx), sessionID, messages)
|
|
if err != nil {
|
|
return "", fmt.Errorf("backthink: think: %w", err)
|
|
}
|
|
return res.Text, nil
|
|
}
|