Files
Agent-System-Backend/internal/runmgr/material_retrieve_test.go
T

153 lines
5.7 KiB
Go

package runmgr
import (
"strings"
"testing"
core "agent-system-core"
)
func materialRetrievalContext(t *testing.T) *runCtx {
t.Helper()
c := checkpointEnvironment(t)
card, err := c.mgr.st.GetCard(c.run.Owner, c.task.cardID)
if err != nil || card.Task == nil || len(card.Task.Inputs) != 1 {
t.Fatalf("trusted material input missing: card=%+v err=%v", card, err)
}
input := card.Task.Inputs[0]
c.attachments = []core.ParsedDocument{{
Meta: core.DocMeta{Filename: "决定.txt", Parser: "builtin:txt", Origin: &core.DocumentOrigin{
ArtifactID: core.ID(input.ArtifactID), ContentHash: input.ContentHash, ParserRevision: input.ParserRevision,
}},
Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "上线六月"}},
}}
return c
}
func TestMaterialAttachmentFallbackQuery(t *testing.T) {
c := materialRetrievalContext(t)
hits, err := c.Retrieve(core.RetrievalQuery{Text: "决定.txt 上线 日期"})
if err != nil || len(hits) != 1 {
t.Fatalf("current material was not recovered from a combined query: hits=%+v err=%v", hits, err)
}
hit := hits[0].Doc
if hit.Ref != string(c.attachments[0].Meta.Origin.ArtifactID) ||
hit.ProjectID != c.run.ProjectID || hit.Owner != c.run.Owner ||
hit.Title != "决定.txt" || !strings.Contains(hit.Chunk, "上线六月") {
t.Fatalf("fallback lost the current attachment identity or text: %+v", hit)
}
}
func TestMaterialAttachmentFallbackNeedsExactFilename(t *testing.T) {
c := materialRetrievalContext(t)
for _, tc := range []struct {
query string
want int
}{
{"决定.txt 上线 日期", 1},
{`"决定.txt" 上线`, 1},
{"非决定.txt 上线", 0},
{"决定.txt备份 上线", 0},
{"前缀-决定.txt 上线", 0},
} {
hits, err := c.materialAttachmentFallback(core.RetrievalQuery{ProjectID: c.run.ProjectID, Text: tc.query})
if err != nil || len(hits) != tc.want {
t.Fatalf("query %q matched %d current attachments; want %d (err=%v)", tc.query, len(hits), tc.want, err)
}
}
}
func TestMaterialAttachmentFallbackScope(t *testing.T) {
for _, tc := range []struct {
name string
change func(*runCtx)
}{
{"other-subagent", func(c *runCtx) { c.subAgent = "agent.sub.general" }},
{"other-owner", func(c *runCtx) { c.run.Owner = "another-owner" }},
{"other-project", func(c *runCtx) { c.run.ProjectID = "another-project" }},
{"duplicate-name", func(c *runCtx) {
other := c.attachments[0]
origin := *other.Meta.Origin
origin.ArtifactID = "art_other"
other.Meta.Origin = &origin
c.attachments = append(c.attachments, other)
}},
} {
t.Run(tc.name, func(t *testing.T) {
c := materialRetrievalContext(t)
before, err := c.Retrieve(core.RetrievalQuery{Text: "决定.txt 上线 日期"})
if err != nil || len(before) != 1 {
t.Fatalf("control material was unavailable before scope change: hits=%+v err=%v", before, err)
}
tc.change(c)
hits, err := c.Retrieve(core.RetrievalQuery{Text: "决定.txt 上线 日期"})
if len(hits) != 0 {
t.Fatalf("out-of-scope attachment leaked: hits=%+v err=%v", hits, err)
}
})
}
}
func TestMaterialAttachmentFallbackVersionDrift(t *testing.T) {
for _, tc := range []struct {
name string
change func(*testing.T, *runCtx)
}{
{"changed-content", func(t *testing.T, c *runCtx) {
t.Helper()
if err := c.mgr.st.UpdateArtifactContent(string(c.run.Owner), string(c.attachments[0].Meta.Origin.ArtifactID), []byte("上线七月")); err != nil {
t.Fatal(err)
}
}},
{"changed-parser-revision", func(_ *testing.T, c *runCtx) {
c.attachments[0].Meta.Origin.ParserRevision = "different-parser"
}},
} {
t.Run(tc.name, func(t *testing.T) {
c := materialRetrievalContext(t)
before, err := c.Retrieve(core.RetrievalQuery{Text: "决定.txt 上线 日期"})
if err != nil || len(before) != 1 {
t.Fatalf("control material was unavailable before version change: hits=%+v err=%v", before, err)
}
tc.change(t, c)
hits, err := c.Retrieve(core.RetrievalQuery{Text: "决定.txt 上线 日期"})
if len(hits) != 0 {
t.Fatalf("stale material was returned: hits=%+v err=%v", hits, err)
}
})
}
}
func TestMaterialAttachmentFallbackRespectsResourceAllow(t *testing.T) {
c := materialRetrievalContext(t)
c.mgr.SetKnowledgeResourceAllow(func(owner string, doc core.KnowledgeDoc) bool {
return owner == string(c.run.Owner) && doc.Ref == string(c.attachments[0].Meta.Origin.ArtifactID)
})
allowed, err := c.Retrieve(core.RetrievalQuery{Text: "决定.txt 上线 日期"})
if err != nil || len(allowed) != 1 {
t.Fatalf("authorized current material was unavailable: hits=%+v err=%v", allowed, err)
}
c.mgr.SetKnowledgeResourceAllow(func(string, core.KnowledgeDoc) bool { return false })
denied, err := c.Retrieve(core.RetrievalQuery{Text: "决定.txt 上线 日期"})
if err != nil || len(denied) != 0 {
t.Fatalf("resource policy was bypassed by fallback: hits=%+v err=%v", denied, err)
}
}
func TestMaterialExcerptKeepsMatchedBeginning(t *testing.T) {
full := "上线六月" + strings.Repeat("附", 20) + "后续结论"
docs := []core.ParsedDocument{{
Meta: core.DocMeta{Filename: "长文.txt", Origin: &core.DocumentOrigin{ArtifactID: "art_long"}},
Blocks: []core.DocBlock{{Type: core.BlockPara, Text: full}},
}}
eff := core.EffectiveSettings{"context": map[string]any{"maxAttachmentChars": float64(4)}}
got := materialExcerpt(full, "长文.txt 上线", "长文.txt", docs, "art_long", eff, 10)
if want := "上线六月" + strings.Repeat("附", 6); got != want {
t.Fatalf("matched start lost or exceeded the result limit: got %q want %q", got, want)
}
got = materialExcerpt(full, "长文.txt", "长文.txt", docs, "art_long", eff, 10)
if want := strings.Repeat("附", 10); got != want {
t.Fatalf("filename-only retrieval did not start after the inline prefix: got %q want %q", got, want)
}
}