Why: Updated or missing sources must remain visible as limitations, and comparison calls need stable prompt grouping. Evidence: SELF card/server suites and live-tag compilation pass. Impact: Adds neutral source limitations and refines test-only provider accounting. Refs: fast-slow-u2-u3 Tasks 6 and 7
99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
package cardsvc
|
|
|
|
import (
|
|
core "agent-system-core"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
)
|
|
|
|
// Task source authorization is conservative: same owner and same project.
|
|
// The host rechecks it on every fresh read and stream replay, without an ACL cache.
|
|
func (s *Service) taskSourceState(owner, project string, src core.TaskSourceRef) string {
|
|
art, e := s.st.GetArtifact(owner, src.ArtifactID)
|
|
if e != nil || art.ProjectID != project {
|
|
return "unavailable"
|
|
}
|
|
data, e := s.st.ArtifactContent(owner, src.ArtifactID)
|
|
if e != nil {
|
|
return "unavailable"
|
|
}
|
|
sum := sha256.Sum256(data)
|
|
if hex.EncodeToString(sum[:]) != src.ContentHash {
|
|
return "changed"
|
|
}
|
|
return "available"
|
|
}
|
|
func (s *Service) VisibleTaskCard(owner string, c core.ActivityCard) core.ActivityCard {
|
|
if c.Task == nil {
|
|
return c
|
|
}
|
|
task := *c.Task
|
|
denied := false
|
|
changed := false
|
|
if _, e := s.st.GetCard(owner, c.ID); e != nil {
|
|
denied = true
|
|
}
|
|
refs := append([]core.TaskSourceRef(nil), task.Inputs...)
|
|
for _, f := range task.Findings {
|
|
refs = append(refs, f.Sources...)
|
|
}
|
|
for _, src := range refs {
|
|
switch s.taskSourceState(owner, c.ProjectID, src) {
|
|
case "unavailable":
|
|
denied = true
|
|
case "changed":
|
|
changed = true
|
|
}
|
|
}
|
|
// Result refs must also be owned and accessible before exposing generated names.
|
|
for _, ref := range task.ResultRefs {
|
|
if ref.ArtifactID != "" {
|
|
a, e := s.st.GetArtifact(owner, ref.ArtifactID)
|
|
if e != nil || a.ProjectID != c.ProjectID {
|
|
denied = true
|
|
}
|
|
}
|
|
}
|
|
if !denied && !changed {
|
|
return c
|
|
}
|
|
task.Goal = ""
|
|
task.Focus = ""
|
|
task.Coverage = ""
|
|
task.Remaining = ""
|
|
task.NextStep = ""
|
|
task.Conclusion = ""
|
|
task.CheckpointKeys = nil
|
|
task.Limitations = nil
|
|
task.Phase.Label = ""
|
|
task.Actions = nil
|
|
task.ResultRefs = nil
|
|
if denied {
|
|
c.Title = "后台任务"
|
|
task.Title = c.Title
|
|
task.Inputs = nil
|
|
task.Findings = nil
|
|
task.Conclusion = "相关来源当前不可用,结果暂不展示"
|
|
task.Limitations = []string{"相关来源当前不可用,请核实访问权限与文件状态"}
|
|
task.Remaining = "请核实材料访问权限与文件是否仍可读取"
|
|
} else {
|
|
task.Findings = append([]core.TaskFinding(nil), task.Findings...)
|
|
for i := range task.Findings {
|
|
f := &task.Findings[i]
|
|
f.Status = "superseded"
|
|
f.Sources = append([]core.TaskSourceRef(nil), f.Sources...)
|
|
for j := range f.Sources {
|
|
f.Sources[j].Availability = s.taskSourceState(owner, c.ProjectID, f.Sources[j])
|
|
}
|
|
}
|
|
task.Conclusion = "依据文件已更新,当前结论需要重新核验"
|
|
task.Limitations = []string{"依据文件已更新,历史发现不能直接作为当前结论"}
|
|
task.Remaining = "展开历史记录可查看处理时的合法引用;当前文件与当时版本可能不同"
|
|
}
|
|
task.OutcomeCompleteness = "partial"
|
|
c.Task = &task
|
|
c.Actions = nil
|
|
c.Body = task.SummaryBody()
|
|
return c
|
|
}
|