Files
Agent-System-Backend/internal/runtime/work_checkpoint.go
T
weichen 13e880feec Publish validated material findings during background work
Why: Real source-backed discoveries should reach the same task card before the slow channel completes.

Evidence: SELF receipts record runtime and manager checkpoint red-green tests, scoped source/version checks, privacy filtering, quota corrections, and SQLite/PG regressions; fixed composition and live comparison follow.

Impact: Adds a local material-only checkpoint sink with no summary model calls, uses version witnesses for source commits, and preserves existing reading and notification paths.

Refs: fast-slow-u2-u3 Tasks 6 and 7; test-only live HTTP harness bounds shared provider requests without approving HITL
2026-10-13 02:29:23 +00:00

68 lines
3.6 KiB
Go

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) 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 和原文片段;分析判断写明前提。长材料在形成阶段结果时发布,不额外调用摘要模型;不要为了进度凑发现。普通发布最多6次。需要更正以前发现时用 corrects 填其 findingKey。此工具不创建确认按钮,也不表示暂停执行。", 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":6,"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"}}}}}}}}}`)}
}
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()}
}
if err := rc.(WorkCheckpointSink).PublishWorkCheckpoint(candidate); err != nil {
return agenttools.Result{IsError: true, Content: fmt.Sprintf("阶段发现未发布,已有成果保留:%v", err)}
}
return agenttools.Result{Content: "阶段发现已保存到当前任务卡。继续处理剩余工作;发布成功只表示来源片段和归属通过校验,不表示分析结论已独立核实。"}
}