Files
Agent-System-Backend/internal/runtime/work_checkpoint.go
T

98 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package runtime
import (
agentllm "agent-native/runtime/llm"
agenttools "agent-native/runtime/tools"
core "agent-system-core"
"bytes"
"encoding/json"
"fmt"
"io"
)
const workCheckpointTool = "publish_work_checkpoint"
type WorkCheckpointSink interface {
PublishWorkCheckpoint(core.WorkCheckpointCandidate) (string, error)
}
func checkpointEnabled(rc RunCtx) bool {
if capability, ok := rc.(interface{ WorkCheckpointAvailable() bool }); ok && !capability.WorkCheckpointAvailable() {
return false
}
src, ok := rc.(interface{ SubagentID() string })
if !ok || src.SubagentID() != materialSubagentID {
return false
}
if _, ok = rc.(WorkCheckpointSink); !ok {
return false
}
if !rc.Profile().Tools.ToolAllowed(workCheckpointTool) || rc.Profile().Tools.NeedsConfirm(workCheckpointTool) {
return false
}
for _, tool := range rc.Tools() {
if tool.Name == workCheckpointTool {
return false
}
}
return true
}
func checkpointDecl() agentllm.ToolDecl {
return agentllm.ToolDecl{Name: workCheckpointTool, Description: "及时保存本次材料整理的阶段发现。只引用已提供的 sourceId/blockIndex 和连续原文短引;material_record 由宿主展示原句。数字、决定状态和分期归属若没有原文直接关系,须提供可核对的 evidence:direct_relation 指向明确原句;difference 给出 total/phase 与差额;unresolved_relation 给出 total/phase/dependent 并让宿主判断范围。sourceIndex 是本条 findings.sources 的零起始索引。宿主会把不能证明的判断改为待确认并在工具结果说明,不得把推测写成已批准或确定归属。不额外调用摘要模型;每次发布1至3条新发现,最多6次;更正旧发现时用 corrects。本工具不创建确认按钮或暂停执行。", Parameters: json.RawMessage(`{
"type":"object","additionalProperties":false,"required":["checkpointId","phaseId","findings"],
"properties":{
"checkpointId":{"type":"string"},
"phaseId":{"type":"string","enum":["reading","crosscheck","summarizing","draft-ready"]},
"focus":{"type":"string"},"remaining":{"type":"string"},"nextStep":{"type":"string"},
"findings":{"type":"array","minItems":1,"maxItems":3,"items":{
"type":"object","additionalProperties":false,"required":["findingKey","text","kind","sources"],
"properties":{
"findingKey":{"type":"string"},"text":{"type":"string"},"impact":{"type":"string"},
"kind":{"type":"string","enum":["material_record","analysis","provisional","needs_user"]},
"assumptions":{"type":"string"},"corrects":{"type":"string"},
"sources":{"type":"array","minItems":1,"items":{"type":"object","additionalProperties":false,
"required":["sourceId","blockIndex","quote"],"properties":{
"sourceId":{"type":"string"},"blockIndex":{"type":"integer","minimum":0},
"quote":{"type":"string","description":"同一段落连续出现的原文短句"}}}},
"evidence":{"type":"object","additionalProperties":false,"required":["mode","premises"],"properties":{
"mode":{"type":"string","enum":["direct_relation","difference","unresolved_relation"]},
"premises":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"object","additionalProperties":false,
"required":["role","sourceIndex"],"properties":{
"role":{"type":"string","enum":["total","phase","dependent","direct_relation"]},
"sourceIndex":{"type":"integer","minimum":0},"value":{"type":"integer","minimum":0,"maximum":1000000}}}},
"result":{"type":"integer","minimum":0,"maximum":1000000}}}
}}}
}
}`)}
}
func publishCheckpoint(rc RunCtx, args string) agenttools.Result {
if !checkpointEnabled(rc) {
return agenttools.Result{IsError: true, Content: "检查点发布不适用于当前任务或工具策略不允许"}
}
if len(args) > 16*1024 {
return agenttools.Result{IsError: true, Content: "检查点超过16KiB;已有成果保留"}
}
var candidate core.WorkCheckpointCandidate
d := json.NewDecoder(bytes.NewBufferString(args))
d.DisallowUnknownFields()
if err := d.Decode(&candidate); err != nil {
return agenttools.Result{IsError: true, Content: err.Error()}
}
var extra any
if err := d.Decode(&extra); err != io.EOF {
return agenttools.Result{IsError: true, Content: "检查点只接受一个JSON对象"}
}
if err := core.ValidateWorkCheckpoint(candidate); err != nil {
return agenttools.Result{IsError: true, Content: err.Error()}
}
receipt, err := rc.(WorkCheckpointSink).PublishWorkCheckpoint(candidate)
if err != nil {
return agenttools.Result{IsError: true, Content: fmt.Sprintf("阶段发现未发布,已有成果保留:%v", err)}
}
content := "阶段发现已保存到当前任务卡。继续处理剩余工作;发布成功只表示来源片段通过校验,不表示分析结论已独立核实。"
if receipt != "" {
content += " " + receipt
}
return agenttools.Result{Content: content}
}