mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 02:36:01 -10:00
148 lines
5.7 KiB
Go
148 lines
5.7 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"reasonix/internal/base/testenv"
|
|
"reasonix/internal/contract/event"
|
|
"reasonix/internal/contract/provider"
|
|
"reasonix/internal/contract/tool"
|
|
"reasonix/internal/state/sessionstore"
|
|
)
|
|
|
|
func archiveAgent(t *testing.T, sess *sessionstore.Session, sink event.Sink) (*Agent, *countingProvider, string) {
|
|
t.Helper()
|
|
prov := &countingProvider{reply: "## Standing facts\n- a summarizer was asked"}
|
|
dir := testenv.TempDir(t)
|
|
a := New(prov, tool.NewRegistry(), sess, Options{
|
|
ContextWindow: 200_000, CompactRatio: 0.8, SessionPath: filepath.Join(dir, "session.jsonl"),
|
|
WorkspaceID: "ws", ModelRef: "p/m",
|
|
ArchiveDir: testenv.TempDir(t),
|
|
}, sink)
|
|
return a, prov, dir
|
|
}
|
|
|
|
// A fold is archived, not summarized: no summarizer request is made, the
|
|
// folded span lands verbatim in a file beside the transcript, and what stays in
|
|
// context is a pointer to it.
|
|
func TestAnArchivedFoldMakesNoSummarizerCallAndPointsAtTheFile(t *testing.T) {
|
|
sess := foldableSessionOverForce(60)
|
|
for i := range sess.Messages {
|
|
if sess.Messages[i].Role == provider.RoleAssistant {
|
|
sess.Messages[i].Content = "decided: keep the public API stable"
|
|
}
|
|
}
|
|
var done event.Compaction
|
|
a, prov, dir := archiveAgent(t, sess, event.FuncSink(func(e event.Event) {
|
|
if e.Kind == event.CompactionDone {
|
|
done = e.Compaction
|
|
}
|
|
}))
|
|
|
|
verdict, err := a.CompactNow(context.Background(), CompactRequest{Instructions: "the API contract"})
|
|
if err != nil {
|
|
t.Fatalf("CompactNow: %v", err)
|
|
}
|
|
if !verdict.Compacted() {
|
|
t.Fatalf("verdict = %+v, want a fold", verdict)
|
|
}
|
|
if len(prov.got) != 0 {
|
|
t.Fatalf("an archived fold made %d summarizer request(s)", len(prov.got))
|
|
}
|
|
|
|
pointer := done.Summary
|
|
if !strings.Contains(pointer, "archived, not summarized") || !strings.Contains(pointer, "read_file") {
|
|
t.Fatalf("the pointer does not tell the model to read the archive:\n%s", pointer)
|
|
}
|
|
if !strings.Contains(pointer, "the API contract") {
|
|
t.Fatalf("the pointer dropped the requested focus:\n%s", pointer)
|
|
}
|
|
|
|
files, err := filepath.Glob(filepath.Join(dir, "session.outputs", "fold-*.md"))
|
|
if err != nil || len(files) != 1 {
|
|
t.Fatalf("archive files = %v (%v), want exactly one beside the transcript", files, err)
|
|
}
|
|
if !strings.Contains(pointer, files[0]) {
|
|
t.Fatalf("the pointer does not name %s:\n%s", files[0], pointer)
|
|
}
|
|
body, err := os.ReadFile(files[0])
|
|
if err != nil || !strings.Contains(string(body), "decided: keep the public API stable") {
|
|
t.Fatalf("the archive does not hold the folded work verbatim (%v)", err)
|
|
}
|
|
visible := a.window().modelVisibleMessages()
|
|
if len(visible) >= len(sess.Messages) {
|
|
t.Fatalf("nothing left the context: %d visible of %d", len(visible), len(sess.Messages))
|
|
}
|
|
for _, m := range visible {
|
|
if m.Role == provider.RoleSystem && strings.Contains(m.Content, "a summarizer was asked") {
|
|
t.Fatal("a summarizer digest reached the context")
|
|
}
|
|
}
|
|
}
|
|
|
|
// What the host keeps for display only never reaches the model, so it never
|
|
// reaches the archive the model reads back either.
|
|
func TestAnArchiveNeverHoldsLocalOnlyOutput(t *testing.T) {
|
|
sess := foldableSessionOverForce(60)
|
|
local := provider.Message{Role: provider.RoleAssistant, Content: "local-only output that must stay out", LocalOnly: true}
|
|
sess.Messages = append(sess.Messages[:20], append([]provider.Message{local}, sess.Messages[20:]...)...)
|
|
a, _, _ := archiveAgent(t, sess, event.Discard)
|
|
|
|
if _, err := a.CompactNow(context.Background(), CompactRequest{}); err != nil {
|
|
t.Fatalf("CompactNow: %v", err)
|
|
}
|
|
files, _ := filepath.Glob(filepath.Join(a.window().outputsDir(), "fold-*.md"))
|
|
if len(files) == 0 {
|
|
t.Fatal("no archive written")
|
|
}
|
|
for _, f := range files {
|
|
body, err := os.ReadFile(f)
|
|
if err != nil || strings.Contains(string(body), "local-only output that must stay out") {
|
|
t.Fatalf("the archive %s holds display-only output (%v)", f, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Nothing of the conversation is held back: after a fold between turns the
|
|
// context is the system prompt and the one pointer, the first user turn, the
|
|
// recent turns and the user's own words included, and the archive has them all.
|
|
func TestAFoldRetainsNothingButThePointer(t *testing.T) {
|
|
sess := &sessionstore.Session{Messages: []provider.Message{
|
|
{Role: provider.RoleSystem, Content: "sys"},
|
|
{Role: provider.RoleUser, Content: "FIRST-TURN codeword blue-whale"},
|
|
{Role: provider.RoleAssistant, Content: "ok " + strings.Repeat("filler ", 200)},
|
|
{Role: provider.RoleUser, Content: "SECOND-TURN deadline friday"},
|
|
{Role: provider.RoleAssistant, Content: "noted " + strings.Repeat("filler ", 200)},
|
|
{Role: provider.RoleUser, Content: "LAST-TURN owner lin"},
|
|
{Role: provider.RoleAssistant, Content: "done " + strings.Repeat("filler ", 200)},
|
|
}}
|
|
a, _, dir := archiveAgent(t, sess, event.Discard)
|
|
verdict, err := a.CompactNow(context.Background(), CompactRequest{})
|
|
if err != nil || !verdict.Compacted() {
|
|
t.Fatalf("CompactNow = %+v, %v; want a fold", verdict, err)
|
|
}
|
|
visible := a.window().modelVisibleMessages()
|
|
if len(visible) != 2 || visible[0].Role != provider.RoleSystem || !isCompactionSummary(visible[1]) {
|
|
t.Fatalf("visible = %+v, want the system prompt and one pointer", visible)
|
|
}
|
|
for _, word := range []string{"blue-whale", "friday", "owner lin"} {
|
|
if strings.Contains(visible[1].Content, word) {
|
|
t.Fatalf("the pointer carries %q; it must only point", word)
|
|
}
|
|
}
|
|
files, _ := filepath.Glob(filepath.Join(dir, "session.outputs", "fold-*.md"))
|
|
if len(files) != 1 {
|
|
t.Fatalf("archive files = %v", files)
|
|
}
|
|
body, _ := os.ReadFile(files[0])
|
|
for _, word := range []string{"blue-whale", "friday", "owner lin"} {
|
|
if !strings.Contains(string(body), word) {
|
|
t.Fatalf("the archive lost %q", word)
|
|
}
|
|
}
|
|
}
|