fix(agent): Agent 运行 - 重复读取改为软收敛并保留可纠正的媒体失败原因
重复只读和同版本识图不再把运行标成失败,下一步暂时收起只读工具。媒体能力错误改为可纠正,准入失败保留安全原因。
This commit is contained in:
@@ -169,6 +169,31 @@ func cloudAgentToolResult(runID string, state *cloudAgentRuntime, call cloudAgen
|
||||
return exhausted
|
||||
}
|
||||
|
||||
func cloudAgentMarkReadLoopNudge(state *cloudAgentRuntime, call cloudAgentCall, count int) {
|
||||
if state == nil || state.ReadLoopNudge {
|
||||
return
|
||||
}
|
||||
state.ReadLoopNudge = true
|
||||
state.ReadLoopToolName = call.Function.Name
|
||||
state.ReadLoopCount = max(1, count)
|
||||
}
|
||||
|
||||
func cloudAgentApplyReadLoopNudge(canonical *canonicalAgentRequest, state *cloudAgentRuntime) {
|
||||
if state == nil || !state.ReadLoopNudge {
|
||||
return
|
||||
}
|
||||
toolName := state.ReadLoopToolName
|
||||
if toolName == "" {
|
||||
toolName = "只读工具"
|
||||
}
|
||||
canonical.Tools = cloudAgentToolsWithoutReadTools(canonical.Tools)
|
||||
// 提示只进入下一次模型输入,避免插入尚未收齐结果的工具批次或堆积历史。
|
||||
canonical.Messages = append(append([]map[string]any(nil), canonical.Messages...), cloudAgentRuntimeMessage(cloudAgentRuntimeContext{
|
||||
Kind: cloudAgentContextReadLoop,
|
||||
Detail: fmt.Sprintf("%s 触发读取收敛(读取或回放计数 %d);本次模型请求暂时不提供只读工具,运行状态仍为 running。", toolName, max(1, state.ReadLoopCount)),
|
||||
}))
|
||||
}
|
||||
|
||||
// cloudAgentCompactSupersededReadResult bounds repeated snapshots without
|
||||
// changing the transcript shape. A newer read with the same cache key makes an
|
||||
// older canvas projection stale; keep the old tool message for provider pairing,
|
||||
@@ -389,30 +414,22 @@ func (s *Service) advanceCloudAgentReadBatch(run *model.CloudAgentExecution, sta
|
||||
for _, item := range outcomes {
|
||||
var readLoopErr *cloudAgentReadLoopError
|
||||
if errors.As(item.err, &readLoopErr) {
|
||||
// A provider tool-call turn is atomic from the transcript's point of
|
||||
// view: every declared tool_call_id needs a tool message, even when a
|
||||
// read guard terminates the run. Record the triggering error and then
|
||||
// explicit skipped receipts before appending run_failed, otherwise a
|
||||
// later resume/replay produces an invalid provider transcript.
|
||||
cloudAgentToolResult(current.ID, state, item.call, item.result, item.err)
|
||||
for state.CallIndex < len(state.Calls) {
|
||||
pending := state.Calls[state.CallIndex]
|
||||
cloudAgentToolResult(current.ID, state, pending,
|
||||
map[string]any{"skipped": true, "reason": readLoopErr.reasonCode()},
|
||||
nil)
|
||||
}
|
||||
current.Status = "failed"
|
||||
current.FailureMessage = truncateRunes(readLoopErr.Error(), 1000)
|
||||
cloudAgentDropInterjections(run.ID, "本轮已结束:"+truncateRunes(current.FailureMessage, 120), state)
|
||||
reason := readLoopErr.reasonCode()
|
||||
state.event(run.ID, "run_failed", map[string]any{
|
||||
"text": current.FailureMessage, "reason": reason,
|
||||
"toolName": item.call.Function.Name, "readCount": readLoopErr.Count,
|
||||
})
|
||||
// 只收敛触发护栏的读取;同批剩余调用仍由调度器处理,不能吞掉写操作。
|
||||
cloudAgentToolResult(current.ID, state, item.call, map[string]any{
|
||||
"readLoopGuard": true,
|
||||
"message": "重复只读调用已软收敛,请使用已有结果继续;运行仍可继续",
|
||||
}, nil)
|
||||
cloudAgentMarkReadLoopNudge(state, item.call, readLoopErr.Count)
|
||||
break
|
||||
}
|
||||
cloudAgentRecordToolResult(current, state, item.call, item.result, item.err)
|
||||
}
|
||||
if state.ReadLoopNudge && len(outcomes) > 0 {
|
||||
state.event(run.ID, "read_loop_guard", map[string]any{
|
||||
"text": "重复只读调用已软收敛,运行继续",
|
||||
"toolName": state.ReadLoopToolName, "readCount": state.ReadLoopCount,
|
||||
})
|
||||
}
|
||||
return cloudAgentSave(current, state)
|
||||
})
|
||||
return true, err
|
||||
@@ -675,7 +692,12 @@ func (s *Service) advanceCloudAgentTool(run *model.CloudAgentExecution, state *c
|
||||
if allowed && call.Function.Name == "canvas_inspect_image" && state.Request.VisionEnabled {
|
||||
inspectionResult, inspectionErr = s.prepareCloudAgentImageInspection(run.UserID, state.Request.CanvasID, state, call)
|
||||
if errors.Is(inspectionErr, errCloudAgentImageInspectionBudget) {
|
||||
return s.failCloudAgent(run, state, cloudAgentImageInspectionBudgetMessage)
|
||||
inspectionErr = &cloudAgentReadLoopError{
|
||||
ToolName: "canvas_inspect_image",
|
||||
Count: state.cloudAgentImageInspectionCalls() + 1,
|
||||
Budget: true,
|
||||
ReasonCode: "vision_read_budget_exceeded",
|
||||
}
|
||||
}
|
||||
}
|
||||
// Service-backed reads may open resources or use domain repositories.
|
||||
@@ -731,6 +753,9 @@ func (s *Service) advanceCloudAgentTool(run *model.CloudAgentExecution, state *c
|
||||
}
|
||||
state.ImageInspectionReads[inspection.CacheKey]++
|
||||
}
|
||||
if inspection.Receipt["repeat"] == true {
|
||||
cloudAgentMarkReadLoopNudge(state, call, state.ImageInspectionReads[inspection.CacheKey])
|
||||
}
|
||||
}
|
||||
}
|
||||
case call.Function.Name == "skill_read_file", call.Function.Name == "model_list", call.Function.Name == "image_annotation_render", call.Function.Name == "canvas_read_text":
|
||||
@@ -745,13 +770,13 @@ func (s *Service) advanceCloudAgentTool(run *model.CloudAgentExecution, state *c
|
||||
}
|
||||
var readLoopErr *cloudAgentReadLoopError
|
||||
if errors.As(toolErr, &readLoopErr) {
|
||||
cloudAgentRecordToolResult(current, state, call, result, toolErr)
|
||||
current.Status = "failed"
|
||||
current.FailureMessage = truncateRunes(readLoopErr.Error(), 1000)
|
||||
cloudAgentDropInterjections(run.ID, "本轮已结束:"+truncateRunes(current.FailureMessage, 120), state)
|
||||
reason := readLoopErr.reasonCode()
|
||||
state.event(run.ID, "run_failed", map[string]any{
|
||||
"text": current.FailureMessage, "reason": reason,
|
||||
cloudAgentRecordToolResult(current, state, call, map[string]any{
|
||||
"readLoopGuard": true,
|
||||
"message": "重复只读调用已软收敛,请使用已有结果继续;运行仍可继续",
|
||||
}, nil)
|
||||
cloudAgentMarkReadLoopNudge(state, call, readLoopErr.Count)
|
||||
state.event(run.ID, "read_loop_guard", map[string]any{
|
||||
"text": "重复只读调用已软收敛,运行继续",
|
||||
"toolName": call.Function.Name, "readCount": readLoopErr.Count,
|
||||
})
|
||||
return cloudAgentSave(current, state)
|
||||
@@ -774,6 +799,12 @@ func (s *Service) advanceCloudAgentTool(run *model.CloudAgentExecution, state *c
|
||||
return cloudAgentSave(current, state)
|
||||
}
|
||||
cloudAgentRecordToolResult(current, state, call, result, toolErr)
|
||||
if state.ReadLoopNudge {
|
||||
state.event(run.ID, "read_loop_guard", map[string]any{
|
||||
"text": "重复只读调用已软收敛,运行继续",
|
||||
"toolName": state.ReadLoopToolName, "readCount": state.ReadLoopCount,
|
||||
})
|
||||
}
|
||||
return cloudAgentSave(current, state)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user