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
+111
-111
@@ -13,95 +13,95 @@ import (
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
|
||||
)
|
||||
|
||||
// ToolExecutionMode tokens accepted by Options.ToolExecution. Empty selects
|
||||
// toolExecParallel.
|
||||
// Options.ToolExecution 接受的 ToolExecutionMode 取值。为空时选用
|
||||
// toolExecParallel。
|
||||
const (
|
||||
toolExecParallel = "parallel"
|
||||
toolExecSequential = "sequential"
|
||||
)
|
||||
|
||||
// criticalToolLoopTerminalReason is surfaced as Result.Text and on every blocked
|
||||
// call when the critical-tool-loop safety net stops the run.
|
||||
// criticalToolLoopTerminalReason 在关键工具循环安全网停止
|
||||
// run 时,作为 Result.Text 与每个被拦截调用的文本浮出。
|
||||
const criticalToolLoopTerminalReason = "critical tool-loop detected: an identical tool call was repeated across rounds; the run is stopping"
|
||||
|
||||
// ToolCallVeto is returned by a CallAdmit hook to block a single call.
|
||||
// ToolCallVeto 由 CallAdmit 钩子返回,用于拦截单个调用。
|
||||
type ToolCallVeto struct {
|
||||
Block bool
|
||||
Reason string
|
||||
}
|
||||
|
||||
// ToolOutcome is the normalized result of executing one tool call. It is what an
|
||||
// after-call / after-outcome hook observes and may rewrite before the loop
|
||||
// renders it back to the model.
|
||||
// ToolOutcome 是一次工具调用执行的归一化结果。它正是
|
||||
// after-call / after-outcome 钩子所观察、并可能在循环把它
|
||||
// 回渲给模型之前改写的东西。
|
||||
type ToolOutcome struct {
|
||||
// Result is the value the tool returned (nil on failure or skip).
|
||||
// Result 是工具返回的值(失败或跳过时为 nil)。
|
||||
Result any
|
||||
// Err is non-nil when the call failed to execute; it is nil on success.
|
||||
// Err 在调用执行失败时非 nil;成功时为 nil。
|
||||
Err error
|
||||
// ErrKind classifies a failure as tool.KindArgumentValidation or
|
||||
// tool.KindExecution (the task's errorKind status classification). Empty on
|
||||
// success.
|
||||
// ErrKind 把失败归类为 tool.KindArgumentValidation 或
|
||||
// tool.KindExecution(任务 errorKind 状态分类)。成功时为
|
||||
// 空。
|
||||
ErrKind string
|
||||
// Skipped is true when the call never executed (duplicate / blocked / vetoed).
|
||||
// Skipped 在调用从未执行(重复 / 被拦截 / 被否决)时为 true。
|
||||
Skipped bool
|
||||
// Reason is a human-readable explanation for a skipped call.
|
||||
// Reason 是被跳过调用的人类可读解释。
|
||||
Reason string
|
||||
// Terminate, when set by a hook, signals that the whole round should stop
|
||||
// once every call in the batch is also marked terminate.
|
||||
// Terminate 由钩子设置时,表示一旦该批中每个调用都被
|
||||
// 标记 terminate,整轮就应停止。
|
||||
Terminate bool
|
||||
}
|
||||
|
||||
// ToolLoopHooks groups the optional per-batch / per-call tool-loop hooks. Every
|
||||
// field is nil-tolerant. These are the extension points the loop keeps open for
|
||||
// "敏感操作代审" (design/11 batch admission) and the future async-tool path, so
|
||||
// the audit layer and the loop are decoupled.
|
||||
// ToolLoopHooks 归组可选的按批次 / 按调用工具循环钩子。每个
|
||||
// 字段都容忍 nil。这些是循环为「敏感操作代审」(design/11
|
||||
// 批次准入)以及未来的异步工具路径保留的扩展点,使
|
||||
// 审计层与循环解耦。
|
||||
type ToolLoopHooks struct {
|
||||
// BatchAdmit is called once per batch before any call executes. Returning
|
||||
// (false, reason) blocks the whole batch: every call becomes a skipped result
|
||||
// carrying reason. nil = always admit.
|
||||
// BatchAdmit 在任何调用执行前每批调用一次。返回
|
||||
// (false, reason) 会拦截整批:每个调用都变成携带 reason 的
|
||||
// 跳过结果。为 nil = 总是准入。
|
||||
BatchAdmit func(ctx context.Context, calls []agent.ToolCall) (bool, string)
|
||||
// CallAdmit is called per call before it executes. A non-nil veto with
|
||||
// Block=true blocks that single call. nil = always admit.
|
||||
// CallAdmit 在每个调用执行前对它调用一次。非 nil 且
|
||||
// Block=true 的否决会拦截该单个调用。为 nil = 总是准入。
|
||||
CallAdmit func(ctx context.Context, call agent.ToolCall) *ToolCallVeto
|
||||
// AfterCall rewrites a call's outcome after the tool executes. A nil return
|
||||
// keeps the original. It runs before AfterOutcome.
|
||||
// AfterCall 在工具执行后改写调用的结果。返回 nil
|
||||
// 则保持原样。它在 AfterOutcome 之前运行。
|
||||
AfterCall func(ctx context.Context, call agent.ToolCall, outcome ToolOutcome) *ToolOutcome
|
||||
// AfterOutcome observes/rewrites the finalized outcome (after AfterCall and
|
||||
// after any skip/block decision) immediately before the result is rendered
|
||||
// back to the model. nil = keep the outcome.
|
||||
// AfterOutcome 观察/改写最终结果(在 AfterCall 与
|
||||
// 任何跳过/拦截决策之后),就在结果被回渲给
|
||||
// 模型之前。为 nil = 保持结果。
|
||||
AfterOutcome func(ctx context.Context, call agent.ToolCall, outcome ToolOutcome) *ToolOutcome
|
||||
}
|
||||
|
||||
// toolRunResult is the outcome of running one tool batch.
|
||||
// toolRunResult 是运行一个工具批次的结果。
|
||||
type toolRunResult struct {
|
||||
messages []model.Message
|
||||
executed int
|
||||
terminate bool
|
||||
}
|
||||
|
||||
// toolLoopState carries the per-run state of the critical-tool-loop safety net.
|
||||
// It is scoped to a single Run call, so concurrent runs never share it.
|
||||
// toolLoopState 携带关键工具循环安全网的每次 run 状态。
|
||||
// 它作用域限于单次 Run 调用,因此并发 run 绝不共享它。
|
||||
type toolLoopState struct {
|
||||
criticalSeen bool // a critical loop was already reported this run
|
||||
prevFP map[string]bool // fingerprints seen in the immediately previous batch
|
||||
criticalSeen bool // 本次 run 已报告过关键循环
|
||||
prevFP map[string]bool // 紧邻上一批中见过的指纹
|
||||
}
|
||||
|
||||
// toolCallAction is the execution decision for one call after classification.
|
||||
// toolCallAction 是一个调用经分类后的执行决策。
|
||||
type toolCallAction struct {
|
||||
run bool // execute the call
|
||||
reason string // when run==false, the human reason fed back to the model
|
||||
run bool // 执行该调用
|
||||
reason string // run==false 时,回灌给模型的人类可读原因
|
||||
}
|
||||
|
||||
// runToolCalls executes a batch of model-requested tool calls. It classifies
|
||||
// duplicate invocations (the critical-tool-loop safety net), applies the optional
|
||||
// batch/per-call hooks, runs the surviving calls in parallel (bounded) or
|
||||
// serially, and feeds every outcome back as a RoleTool message in the original
|
||||
// call order. It returns the number of calls actually invoked (executed), the
|
||||
// updated message slice, and whether the round should terminate.
|
||||
// runToolCalls 执行一批模型请求的工具调用。它分类重复
|
||||
// 调用(关键工具循环安全网)、应用可选的
|
||||
// 批次/按调用钩子、以并行(有界)或串行方式运行存活的调用,
|
||||
// 并按原始调用顺序把每个结果作为 RoleTool 消息回灌。
|
||||
// 它返回实际调用的数量(executed)、更新后的消息切片,
|
||||
// 以及该轮是否应终止。
|
||||
//
|
||||
// Invocation is delegated to the dispatched tool, which applies the per-tool
|
||||
// deadline; a missing dispatcher is fed back as an error so the loop never
|
||||
// panics or crashes on an unhandled call.
|
||||
// 调用被委托给被分派的工具,由后者应用每工具
|
||||
// 截止时间;缺少 dispatcher 时以错误形式回灌,使循环绝不
|
||||
// 对未处理的调用 panic 或崩溃。
|
||||
func (l *Loop) runToolCalls(ctx context.Context, messages []model.Message, calls []agent.ToolCall, st *toolLoopState) (toolRunResult, error) {
|
||||
d := l.dispatcher()
|
||||
res := toolRunResult{messages: messages}
|
||||
@@ -114,16 +114,16 @@ func (l *Loop) runToolCalls(ctx context.Context, messages []model.Message, calls
|
||||
res.terminate = true
|
||||
}
|
||||
|
||||
// Security gate (design/11 §3): a group/stranger session may invoke only
|
||||
// tools whose editable marker allows that environment (default closed). A
|
||||
// disallowed call never executes; it is fed back as a not_allowed soft result
|
||||
// and recorded to the audit sink. It is the final authority over the batch —
|
||||
// a later audit hook may tighten but never re-admit a denied tool.
|
||||
// 安全门(design/11 §3):群聊/陌生人会话只能调用
|
||||
// 其可编辑标记允许该环境的工具(默认关闭)。不被允许的
|
||||
// 调用绝不执行;它以 not_allowed 软结果回灌
|
||||
// 并记录到审计 sink。它是该批的最终权威 ——
|
||||
// 后续的审计钩子可以收紧,但绝不重新放行被拒的工具。
|
||||
if d != nil {
|
||||
l.applyToolSecurityGate(ctx, d, calls, actions)
|
||||
}
|
||||
|
||||
// BatchAdmit hook (audit / political review): block the whole batch.
|
||||
// BatchAdmit 钩子(审计 / 政治审查):拦截整批。
|
||||
if l.hooks.BatchAdmit != nil {
|
||||
if ok, reason := l.hooks.BatchAdmit(ctx, calls); !ok {
|
||||
if reason == "" {
|
||||
@@ -135,7 +135,7 @@ func (l *Loop) runToolCalls(ctx context.Context, messages []model.Message, calls
|
||||
}
|
||||
}
|
||||
|
||||
// CallAdmit hook: per-call veto over the calls we intend to run.
|
||||
// CallAdmit 钩子:对我们打算运行的调用逐个否决。
|
||||
if l.hooks.CallAdmit != nil {
|
||||
for i := range calls {
|
||||
if !actions[i].run {
|
||||
@@ -151,9 +151,9 @@ func (l *Loop) runToolCalls(ctx context.Context, messages []model.Message, calls
|
||||
}
|
||||
}
|
||||
|
||||
// Decide serial vs parallel: explicit sequential mode, or any call whose tool
|
||||
// is declared sequential (a single sequential marker makes the whole group
|
||||
// serial, matching OpenClaw's launchParallelToolCalls).
|
||||
// 决定串行还是并行:显式串行模式,或任一调用的工具
|
||||
// 被声明为串行(单个串行标记即让整组
|
||||
// 串行,与 OpenClaw 的 launchParallelToolCalls 一致)。
|
||||
sequential := l.toolExec == toolExecSequential
|
||||
if !sequential && d != nil {
|
||||
for i := range calls {
|
||||
@@ -187,7 +187,7 @@ func (l *Loop) runToolCalls(ctx context.Context, messages []model.Message, calls
|
||||
res.executed += len(idxs)
|
||||
}
|
||||
|
||||
// AfterCall hook (only for calls that actually executed).
|
||||
// AfterCall 钩子(仅对实际执行过的调用)。
|
||||
if l.hooks.AfterCall != nil {
|
||||
for i := range calls {
|
||||
if outcomes[i].Skipped {
|
||||
@@ -199,7 +199,7 @@ func (l *Loop) runToolCalls(ctx context.Context, messages []model.Message, calls
|
||||
}
|
||||
}
|
||||
|
||||
// AfterOutcome hook (runs on every finalized outcome, skipped or not).
|
||||
// AfterOutcome 钩子(对每个最终结果运行,无论是否跳过)。
|
||||
if l.hooks.AfterOutcome != nil {
|
||||
for i := range calls {
|
||||
if after := l.hooks.AfterOutcome(ctx, calls[i], outcomes[i]); after != nil {
|
||||
@@ -208,31 +208,31 @@ func (l *Loop) runToolCalls(ctx context.Context, messages []model.Message, calls
|
||||
}
|
||||
}
|
||||
|
||||
// A hook may ask to terminate the round by marking every call terminate
|
||||
// (OpenClaw's shouldTerminateToolBatch).
|
||||
// 钩子可以把每个调用都标记为 terminate 来要求终止本轮
|
||||
// (OpenClaw 的 shouldTerminateToolBatch)。
|
||||
if !res.terminate && shouldTerminateBatch(outcomes) {
|
||||
res.terminate = true
|
||||
}
|
||||
|
||||
// Render the assistant tool-call turn (native providers require it so the
|
||||
// following tool_result can be correlated) plus every result, in call order so
|
||||
// the model sees a stable feed.
|
||||
// 渲染 assistant 工具调用轮(原生 provider 需要它以让
|
||||
// 后续 tool_result 能被关联),后接每个结果,按调用顺序
|
||||
// 排列,使模型看到稳定的回灌。
|
||||
res.messages = appendToolCallHistory(res.messages, calls, outcomes)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// classifyToolBatch partitions a batch into run/skip decisions, enforcing the
|
||||
// critical-tool-loop safety net:
|
||||
// classifyToolBatch 把一批调用划分为运行/跳过决策,执行
|
||||
// 关键工具循环安全网:
|
||||
//
|
||||
// - A call identical (same name + arguments) to one earlier in the same batch
|
||||
// is skipped with a duplicate hint (never executes).
|
||||
// - A call identical to one from a previous round is a critical-loop repeat:
|
||||
// the first occurrence blocks the repeated call and sets criticalSeen, so the
|
||||
// model gets a turn to reassess; a second consecutive occurrence terminates
|
||||
// the whole run.
|
||||
// - 与同批中更早的一个调用完全相同(同名 + 同参数)的
|
||||
// 调用被跳过并给出重复提示(绝不执行)。
|
||||
// - 与上一轮某个调用完全相同的调用是关键的循环重复:
|
||||
// 第一次出现会拦截该重复调用并置位 criticalSeen,使
|
||||
// 模型有一轮重新评估;连续第二次出现则终止
|
||||
// 整个 run。
|
||||
//
|
||||
// It returns (actions, terminate). When terminate is true every call is blocked
|
||||
// with criticalToolLoopTerminalReason and the round must end.
|
||||
// 它返回 (actions, terminate)。terminate 为 true 时每个调用
|
||||
// 都以 criticalToolLoopTerminalReason 拦截,且该轮必须结束。
|
||||
func classifyToolBatch(st *toolLoopState, calls []agent.ToolCall) ([]toolCallAction, bool) {
|
||||
seen := make(map[string]bool, len(calls))
|
||||
actions := make([]toolCallAction, len(calls))
|
||||
@@ -240,7 +240,7 @@ func classifyToolBatch(st *toolLoopState, calls []agent.ToolCall) ([]toolCallAct
|
||||
for i, call := range calls {
|
||||
fp := toolFingerprint(call)
|
||||
if seen[fp] {
|
||||
// Duplicate of a call already in this batch.
|
||||
// 与同批中已有调用的重复。
|
||||
if st.prevFP[fp] {
|
||||
actions[i] = toolCallAction{run: false, reason: repeatedCallReason()}
|
||||
repeat = true
|
||||
@@ -251,7 +251,7 @@ func classifyToolBatch(st *toolLoopState, calls []agent.ToolCall) ([]toolCallAct
|
||||
}
|
||||
seen[fp] = true
|
||||
if st.prevFP[fp] {
|
||||
// Repeated from the previous round — a critical loop.
|
||||
// 与上一轮的重复 —— 一个关键循环。
|
||||
actions[i] = toolCallAction{run: false, reason: repeatedCallReason()}
|
||||
repeat = true
|
||||
} else {
|
||||
@@ -259,8 +259,8 @@ func classifyToolBatch(st *toolLoopState, calls []agent.ToolCall) ([]toolCallAct
|
||||
}
|
||||
}
|
||||
|
||||
// Remember which fingerprints were live this round for the next round's
|
||||
// cross-round repeat detection.
|
||||
// 记住本轮哪些指纹是活跃的,供下一轮的
|
||||
// 跨轮重复检测使用。
|
||||
st.prevFP = seen
|
||||
|
||||
terminate := false
|
||||
@@ -277,9 +277,9 @@ func classifyToolBatch(st *toolLoopState, calls []agent.ToolCall) ([]toolCallAct
|
||||
return actions, terminate
|
||||
}
|
||||
|
||||
// invokeOne executes a single tool call under its per-tool deadline, emitting a
|
||||
// tool span, streaming tool_execution_update progress and normalizing the
|
||||
// outcome.
|
||||
// invokeOne 在其每工具截止时间下执行单个工具调用,发出一个
|
||||
// tool span、流式输出 tool_execution_update 进度并归一化
|
||||
// 结果。
|
||||
func (l *Loop) invokeOne(ctx context.Context, d *tool.Dispatcher, tc agent.ToolCall) ToolOutcome {
|
||||
if d == nil {
|
||||
return ToolOutcome{Err: fmt.Errorf("no tool dispatcher configured for %q", tc.Name), ErrKind: tool.KindExecution}
|
||||
@@ -305,10 +305,10 @@ func (l *Loop) invokeOne(ctx context.Context, d *tool.Dispatcher, tc agent.ToolC
|
||||
return out
|
||||
}
|
||||
|
||||
// emitToolExecution forwards a tool_execution_update progress event to the
|
||||
// frontend when the loop is on the streaming path (OnStream configured); it is a
|
||||
// no-op otherwise (muted internal passes skip it too). phase is a short label
|
||||
// like "start" or "end:error".
|
||||
// emitToolExecution 在循环处于流式路径(配置了 OnStream)时把
|
||||
// tool_execution_update 进度事件转发给前端;否则为空操作
|
||||
// (被静音的内部流程也会跳过它)。phase 是一个短标签,
|
||||
// 如 "start" 或 "end:error"。
|
||||
func (l *Loop) emitToolExecution(ctx context.Context, name, phase string) {
|
||||
if l.onStream == nil || isMutedBroadcast(ctx) {
|
||||
return
|
||||
@@ -319,11 +319,11 @@ func (l *Loop) emitToolExecution(ctx context.Context, name, phase string) {
|
||||
l.onStream(ev)
|
||||
}
|
||||
|
||||
// invokeParallel runs calls at idxs concurrently, capped at the loop's
|
||||
// parallelism, writing each outcome back into out at its call index so callers
|
||||
// can render results in the original order. The semaphore bounds concurrency and
|
||||
// in-flight goroutines release their slot on completion, so a canceled context
|
||||
// (which makes every Invoke return promptly) cannot leak goroutines.
|
||||
// invokeParallel 并发运行 idxs 处的调用,上限为循环的
|
||||
// 并行度,并把每个结果写回 out 的对应调用索引处,使调用方
|
||||
// 能按原始顺序渲染结果。信号量限制并发,在途
|
||||
// goroutine 完成时释放其槽位,因此被取消的 context
|
||||
// (它使每个 Invoke 迅速返回)不会泄露 goroutine。
|
||||
func (l *Loop) invokeParallel(ctx context.Context, d *tool.Dispatcher, calls []agent.ToolCall, idxs []int, out []ToolOutcome) {
|
||||
if len(idxs) == 0 {
|
||||
return
|
||||
@@ -342,7 +342,7 @@ func (l *Loop) invokeParallel(ctx context.Context, d *tool.Dispatcher, calls []a
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// returned by classifyToolBatch for the two skip reasons.
|
||||
// 由 classifyToolBatch 为两种跳过原因返回。
|
||||
func duplicateCallReason() string {
|
||||
return "duplicate call with identical arguments already issued in this batch"
|
||||
}
|
||||
@@ -351,7 +351,7 @@ func repeatedCallReason() string {
|
||||
return "already used with identical arguments in a previous round; do not repeat it"
|
||||
}
|
||||
|
||||
// skippedOutcome builds a Skipped outcome carrying the human reason.
|
||||
// skippedOutcome 构建一个携带人类可读原因的 Skipped 结果。
|
||||
func skippedOutcome(reason string) ToolOutcome {
|
||||
if reason == "" {
|
||||
reason = "tool call skipped"
|
||||
@@ -359,8 +359,8 @@ func skippedOutcome(reason string) ToolOutcome {
|
||||
return ToolOutcome{Skipped: true, Reason: reason}
|
||||
}
|
||||
|
||||
// shouldTerminateBatch reports whether every call in the batch asked to terminate
|
||||
// (OpenClaw's shouldTerminateToolBatch), so a hook can stop the round.
|
||||
// shouldTerminateBatch 报告该批中每个调用是否都要求终止
|
||||
// (OpenClaw 的 shouldTerminateToolBatch),使钩子能停止本轮。
|
||||
func shouldTerminateBatch(outcomes []ToolOutcome) bool {
|
||||
if len(outcomes) == 0 {
|
||||
return false
|
||||
@@ -373,9 +373,9 @@ func shouldTerminateBatch(outcomes []ToolOutcome) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// toolFingerprint canonicalizes a tool call (name + args) so identical calls can
|
||||
// be detected. Args are JSON-marshaled, so equivalent objects with different key
|
||||
// orders collapse to the same fingerprint; a marshal failure falls back to %v.
|
||||
// toolFingerprint 规范化一个工具调用(name + args),使相同调用
|
||||
// 可被检测。Args 被 JSON 序列化,因此键序不同的等价对象
|
||||
// 会塌缩为同一指纹;序列化失败则回退到 %v。
|
||||
func toolFingerprint(call agent.ToolCall) string {
|
||||
b, err := json.Marshal(call.Args)
|
||||
if err != nil {
|
||||
@@ -384,9 +384,9 @@ func toolFingerprint(call agent.ToolCall) string {
|
||||
return call.Name + "\x00" + string(b)
|
||||
}
|
||||
|
||||
// errorKind classifies an invocation error into a tool.Kind* label so the model
|
||||
// can distinguish an argument-validation failure (re-issue a corrected call) from
|
||||
// an execution failure. A nil error yields "" (success).
|
||||
// errorKind 把调用错误归类为 tool.Kind* 标签,使模型
|
||||
// 能区分参数校验失败(重新发出修正后的调用)与
|
||||
// 执行失败。nil 错误产出 ""(成功)。
|
||||
func errorKind(err error) string {
|
||||
if err == nil {
|
||||
return ""
|
||||
@@ -401,8 +401,8 @@ func errorKind(err error) string {
|
||||
return tool.KindExecution
|
||||
}
|
||||
|
||||
// dispatcher returns the loop's tool dispatcher, falling back to the agent's own
|
||||
// when the loop was not given one.
|
||||
// dispatcher 返回循环的工具 dispatcher;循环未被给予时
|
||||
// 回退到 agent 自身的。
|
||||
func (l *Loop) dispatcher() *tool.Dispatcher {
|
||||
if l.tools != nil {
|
||||
return l.tools
|
||||
@@ -413,16 +413,16 @@ func (l *Loop) dispatcher() *tool.Dispatcher {
|
||||
return nil
|
||||
}
|
||||
|
||||
// toolResultMessage renders a tool call's outcome as a RoleTool message ready to
|
||||
// be fed back to the model. Skipped calls carry their reason; failures carry a
|
||||
// structured {kind,message} so the LLM can react appropriately; success carries
|
||||
// the value.
|
||||
// toolResultMessage 把工具调用的结果渲染为可回灌给模型的
|
||||
// RoleTool 消息。被跳过的调用携带其原因;失败携带
|
||||
// 结构化的 {kind,message},使 LLM 能恰当应对;成功携带
|
||||
// 该值。
|
||||
func toolResultMessage(tc agent.ToolCall, out ToolOutcome) model.Message {
|
||||
return model.Message{Role: model.RoleTool, ToolCallName: tc.Name,
|
||||
Content: []model.Content{{Type: model.ContentTypeText, Text: toolResultText(tc, out)}}}
|
||||
}
|
||||
|
||||
// toolResultText renders the text payload of a tool result message.
|
||||
// toolResultText 渲染工具结果消息的文本载荷。
|
||||
func toolResultText(tc agent.ToolCall, out ToolOutcome) string {
|
||||
switch {
|
||||
case out.Skipped:
|
||||
@@ -442,9 +442,9 @@ func toolResultText(tc agent.ToolCall, out ToolOutcome) string {
|
||||
}
|
||||
}
|
||||
|
||||
// formatToolResult renders a tool return value as text for the model. Strings are
|
||||
// passed through (an empty string becomes "empty"); everything else is JSON
|
||||
// encoded, falling back to a plain %v render on an encoding error.
|
||||
// formatToolResult 把工具返回值渲染为给模型的文本。字符串
|
||||
// 直通(空字符串变为 "empty");其他一切都 JSON
|
||||
// 编码,编码出错时回退到朴素的 %v 渲染。
|
||||
func formatToolResult(result any) string {
|
||||
switch v := result.(type) {
|
||||
case nil:
|
||||
|
||||
Reference in new issue
Block a user