主人 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 改动前即未格式化,按铁律保留原样未动。
80 lines
2.8 KiB
Go
80 lines
2.8 KiB
Go
package loop
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/agent"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
|
||
)
|
||
|
||
// stepOutcome 是循环对单个模型步的内部视图,由
|
||
// agent 的 *agent.StepResult(非流式)或流式路径构建的等价物
|
||
// 归一化而来。
|
||
type stepOutcome struct {
|
||
final bool
|
||
text string
|
||
toolCalls []agent.ToolCall
|
||
stopReason string
|
||
// modelStopReason 是 provider 对该模型调用的原始 stop/finish
|
||
// 原因(Anthropic max_tokens / end_turn / tool_use),记录在 llm_call
|
||
// span 上,使即使该步本身正常结束,截断也可见。
|
||
modelStopReason string
|
||
// model 是服务该调用的路由模型,在流式路径上可知
|
||
//(该路径自行构建请求),在 agent 路径上为空。它
|
||
// 记录在 llm_call span 的日志事件上。
|
||
model string
|
||
}
|
||
|
||
// step 运行单次模型调用。配置了 OnStream 回调时,它
|
||
// 直接驱动适配器的 ChatStream,把增量串给 OnStream 并
|
||
// 应用循环的护栏;否则委托给 agent 的 RunStep,
|
||
// 由后者运行 agent 自身的护栏并记录自己的 CallRecord。整个
|
||
// 调用被包在 llm_call span 中,使 M9 面板能看到每次 LLM 调用。
|
||
func (l *Loop) step(ctx context.Context, sessionID string, messages []model.Message) (*stepOutcome, error) {
|
||
_, llmSpan := l.span(ctx, "llm.call", trace.SpanKindLLM)
|
||
|
||
var (
|
||
out *stepOutcome
|
||
err error
|
||
)
|
||
// 静音(内部自主流程)绕过流式:它既不流向
|
||
// UI,也不付流式路径的额外开销。正常聊天则流式。
|
||
if l.onStream != nil && !isMutedBroadcast(ctx) {
|
||
out, err = l.streamStep(ctx, messages)
|
||
} else {
|
||
out, err = l.agentStep(ctx, sessionID, messages)
|
||
}
|
||
if err != nil {
|
||
l.spanProp(llmSpan, "error", err.Error())
|
||
l.finishSpan(llmSpan, trace.SpanStatusError)
|
||
return nil, fmt.Errorf("loop: model step: %w", err)
|
||
}
|
||
|
||
l.spanProp(llmSpan, "stop_reason", out.stopReason)
|
||
if out.modelStopReason != "" {
|
||
l.spanProp(llmSpan, "model_stop_reason", out.modelStopReason)
|
||
}
|
||
l.spanProp(llmSpan, "tool_calls", len(out.toolCalls))
|
||
l.recordLLMDone(llmSpan, out, l.agentFor(ctx))
|
||
l.finishSpan(llmSpan, trace.SpanStatusOK)
|
||
return out, nil
|
||
}
|
||
|
||
// agentStep 把非流式步委托给该 turn 的 agent,由后者运行输入
|
||
// 与输出护栏、调用模型并解码所有工具调用。
|
||
func (l *Loop) agentStep(ctx context.Context, sessionID string, messages []model.Message) (*stepOutcome, error) {
|
||
sr, err := l.agentFor(ctx).RunStep(ctx, sessionID, messages)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("loop: agent step: %w", err)
|
||
}
|
||
return &stepOutcome{
|
||
final: sr.Final,
|
||
text: sr.Text,
|
||
toolCalls: sr.ToolCalls,
|
||
stopReason: sr.StopReason,
|
||
modelStopReason: sr.ModelStopReason,
|
||
}, nil
|
||
}
|