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
77 lines
2.4 KiB
Go
77 lines
2.4 KiB
Go
package native
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git-ssh.u1680832.nyat.app/weichen/Agent-Native.git/exec"
|
|
"git-ssh.u1680832.nyat.app/weichen/Agent-Native.git/runtime/llm"
|
|
)
|
|
|
|
func TestBackendCompactBeforeRun(t *testing.T) {
|
|
dir := t.TempDir()
|
|
// 预置一份超阈值的长转录(系统消息 + 12 条历史)。
|
|
transcript := filepath.Join(dir, ".agentx", "transcript.jsonl")
|
|
if err := os.MkdirAll(filepath.Dir(transcript), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var b strings.Builder
|
|
b.WriteString(`{"role":"system","content":"sys"}` + "\n")
|
|
for i := 0; i < 12; i++ {
|
|
b.WriteString(`{"role":"user","content":"` + strings.Repeat("x", 400) + `"}` + "\n")
|
|
}
|
|
if err := os.WriteFile(transcript, []byte(b.String()), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var sawSummary bool
|
|
// 注入式捕获:验证 Run 收到的消息里有摘要标记。
|
|
bk2 := New(Options{
|
|
ModelOptions: ModelOptions{
|
|
Model: "fake",
|
|
Stream: captureFirstStream(&sawSummary),
|
|
},
|
|
SessionOptions: SessionOptions{
|
|
Compact: &CompactConfig{ThresholdChars: 1000, KeepLastN: 3, Summarizer: func(ctx context.Context, messages []llm.Message) (string, error) {
|
|
return "预置历史摘要", nil
|
|
}},
|
|
},
|
|
})
|
|
res, err := bk2.Execute(context.Background(), exec.Request{
|
|
WorkDir: dir, Prompt: "继续", Targets: []string{"output.md"},
|
|
ToolProfile: exec.ToolProfileReasoning,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if res.Success && !sawSummary {
|
|
t.Fatal("compaction should have run before the loop")
|
|
}
|
|
data, _ := os.ReadFile(transcript)
|
|
if !strings.Contains(string(data), "预置历史摘要") || !strings.Contains(string(data), `"type":"compaction"`) {
|
|
t.Fatalf("transcript should keep history and append a compaction entry, got:\n%.400s", data)
|
|
}
|
|
if !strings.Contains(string(data), `"role":"system"`) {
|
|
t.Fatal("compaction must not rewrite the original transcript")
|
|
}
|
|
}
|
|
|
|
func captureFirstStream(saw *bool) llm.StreamFunc {
|
|
return func(ctx context.Context, model string, messages []llm.Message, decls []llm.ToolDecl, opts llm.StreamOptions) <-chan llm.Event {
|
|
for _, m := range messages {
|
|
if strings.Contains(m.Content, "[conversation summary]") {
|
|
*saw = true
|
|
}
|
|
}
|
|
ch := make(chan llm.Event, 4)
|
|
go func() {
|
|
defer close(ch)
|
|
ch <- llm.Event{Kind: llm.KindMessageEnd, Message: llm.Message{Role: llm.RoleAssistant, Content: "压缩后续写完成", StopReason: llm.StopEnd}}
|
|
}()
|
|
return ch
|
|
}
|
|
}
|