153 lines
5.7 KiB
Go
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)
|
|
}
|
|
}
|