Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements. Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate. Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable. Refs: Versioned dependencies U1/U3; feature/dependency-workspace
114 lines
4.5 KiB
Go
114 lines
4.5 KiB
Go
package runtime
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
agentllm "git-ssh.u1680832.nyat.app/weichen/Agent-Native.git/runtime/llm"
|
|
agentsession "git-ssh.u1680832.nyat.app/weichen/Agent-Native.git/runtime/session"
|
|
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/ctxasm"
|
|
core "git-ssh.u1680832.nyat.app/weichen/Agent-System-Core.git"
|
|
)
|
|
|
|
func textPart(s string) core.Message {
|
|
return core.Message{Role: core.RoleUser, Parts: []core.Part{{Type: core.PartText, Text: s}}}
|
|
}
|
|
|
|
// 指纹只随结构改写变化:正常追加不动,排除/变体切换必动。
|
|
func TestContextRevisionStableOnAppendAndChangesOnDivergence(t *testing.T) {
|
|
base := []core.Message{
|
|
{ID: "m1"}, {ID: "m2"},
|
|
}
|
|
r0 := contextRevision(base)
|
|
if r0 != contextRevision(append(append([]core.Message{}, base...), core.Message{ID: "m3"})) {
|
|
t.Fatal("append must not change revision")
|
|
}
|
|
excluded := append([]core.Message{}, base...)
|
|
excluded[1].Excluded = true
|
|
if contextRevision(excluded) == r0 {
|
|
t.Fatal("exclude must change revision")
|
|
}
|
|
variant := append(append([]core.Message{}, base...), core.Message{ID: "m3", VariantGroup: "g1", VariantIndex: 1})
|
|
if contextRevision(variant) == r0 {
|
|
t.Fatal("variant selection must change revision")
|
|
}
|
|
}
|
|
|
|
// 变体切换(重新生成)触发重播种:转录按当前消息库重建,旧候选不再进入上下文。
|
|
func TestTranscriptReseedsOnVariantSwitch(t *testing.T) {
|
|
sandbox := t.TempDir()
|
|
hist := []core.Message{
|
|
{ID: "m1", Role: core.RoleUser, Parts: []core.Part{{Type: core.PartText, Text: "写纪要"}}},
|
|
{ID: "m2", Role: core.RoleAssistant, VariantGroup: "g1", VariantIndex: 0, Parts: []core.Part{{Type: core.PartText, Text: "旧候选"}}},
|
|
}
|
|
var requests [][]agentllm.Message
|
|
base := scriptStream(textTurns("新候选", "再来一版"), nil)
|
|
r := &LLMRunner{Stream: func(ctx context.Context, model string, msgs []agentllm.Message, tools []agentllm.ToolDecl, opts agentllm.StreamOptions) <-chan agentllm.Event {
|
|
requests = append(requests, append([]agentllm.Message{}, msgs...))
|
|
return base(ctx, model, msgs, tools, opts)
|
|
}}
|
|
rc := &fakeRunCtx{ctx: context.Background(), sandbox: sandbox,
|
|
prof: core.AgentProfile{Model: core.ModelRoute{Chat: "test-model"}}, history: hist}
|
|
if err := r.Execute(rc); err != nil {
|
|
t.Fatalf("first Execute: %v", err)
|
|
}
|
|
if !strings.Contains(joinReq(requests[0]), "旧候选") {
|
|
t.Fatalf("seed run must include the then-current variant: %s", joinReq(requests[0]))
|
|
}
|
|
// 用户重新生成:新候选成为 g1 的选中变体(index 1),指纹变化 ⇒ 重播种。
|
|
rc.history = append(append([]core.Message{}, hist...),
|
|
core.Message{ID: "m3", Role: core.RoleUser, Parts: []core.Part{{Type: core.PartText, Text: "换一版"}}},
|
|
core.Message{ID: "m4", Role: core.RoleAssistant, VariantGroup: "g1", VariantIndex: 1, Parts: []core.Part{{Type: core.PartText, Text: "新候选"}}},
|
|
)
|
|
if err := r.Execute(rc); err != nil {
|
|
t.Fatalf("second Execute: %v", err)
|
|
}
|
|
sess, err := agentsession.Open(filepath.Join(sandbox, ".agentx", "transcript.jsonl"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
loaded, err := sess.Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
joined := ""
|
|
for _, m := range loaded {
|
|
joined += m.Content + "\n"
|
|
}
|
|
if strings.Contains(joined, "旧候选") {
|
|
t.Fatalf("reseed must drop the superseded variant: %s", joined)
|
|
}
|
|
if !strings.Contains(joined, "新候选") {
|
|
t.Fatalf("reseed must keep the selected variant: %s", joined)
|
|
}
|
|
}
|
|
|
|
// 非播种 run 的首个请求注入一次环境刷新与新命中模块;播种 run 不注入
|
|
// (系统段已含)。用 JSON 兼容方式探请求文本。
|
|
func joinReq(msgs []agentllm.Message) string {
|
|
var b strings.Builder
|
|
for _, m := range msgs {
|
|
b.WriteString(m.Content)
|
|
b.WriteString("\n")
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func TestBuildCurrentUserCarriesAttachmentsAndKnowledge(t *testing.T) {
|
|
doc := core.ParsedDocument{
|
|
Meta: core.DocMeta{Filename: "会议.docx"},
|
|
Blocks: []core.DocBlock{{Type: core.BlockPara, Text: "结论先入库。"}},
|
|
}
|
|
kn := []core.RetrievalHit{{Doc: core.KnowledgeDoc{Title: "知识", Source: "upload", Chunk: "片段"}}}
|
|
got := ctxasm.BuildCurrentUser(core.EffectiveSettings{}, core.Message{Parts: []core.Part{{Type: core.PartText, Text: "总结"}}}, []core.ParsedDocument{doc}, kn, &ctxasm.Report{})
|
|
for _, want := range []string{"总结", "会议.docx", "结论先入库。", "[相关知识]", "片段"} {
|
|
if !strings.Contains(got.Content, want) {
|
|
t.Fatalf("current user missing %q: %s", want, got.Content)
|
|
}
|
|
}
|
|
}
|
|
|
|
var _ = agentllm.Message{}
|