v0.0.5: context compaction, minimal config, retry/search/code symbols/diff/status/test commands
This commit is contained in:
+116
-1
@@ -2,9 +2,15 @@ package tui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"agentu/internal/agent"
|
||||
"agentu/internal/llm"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
@@ -82,6 +88,20 @@ func TestModelMetaRendersBelowInput(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestModelMetaRendersContextUsage(t *testing.T) {
|
||||
assistant := agent.New(agent.Options{Model: "test-model", MaxContextTokens: 1000})
|
||||
assistant.SetMessages([]llm.Message{{Role: llm.RoleUser, Content: strings.Repeat("x", 800)}})
|
||||
m := newModel(context.Background(), assistant, Options{ModelName: "test-model"})
|
||||
next, _ := m.Update(tea.WindowSizeMsg{Width: 120, Height: 30})
|
||||
rendered := next.(model).modelMetaView()
|
||||
|
||||
for _, want := range []string{"ctx ~", "/1k", "%"} {
|
||||
if !strings.Contains(rendered, want) {
|
||||
t.Fatalf("model meta missing %q:\n%s", want, rendered)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitialViewDoesNotRenderTopNote(t *testing.T) {
|
||||
m := newModel(context.Background(), nil, Options{ModelName: "test-model"})
|
||||
next, _ := m.Update(tea.WindowSizeMsg{Width: 100, Height: 30})
|
||||
@@ -264,13 +284,108 @@ func TestSlashCommandSuggestions(t *testing.T) {
|
||||
m.afterInputChanged()
|
||||
|
||||
rendered := m.View()
|
||||
for _, want := range []string{"/clear reset context", "/exit quit", "/model model/provider/thinking"} {
|
||||
for _, want := range []string{"/clear reset context", "/compact compress context", "/exit quit", "/model model/provider/thinking"} {
|
||||
if !strings.Contains(rendered, want) {
|
||||
t.Fatalf("rendered suggestions missing %q:\n%s", want, rendered)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type tuiCompactProvider struct{}
|
||||
|
||||
func (tuiCompactProvider) ChatStream(ctx context.Context, req llm.ChatRequest, emit func(llm.StreamEvent) error) error {
|
||||
return emit(llm.StreamEvent{Content: "summary from tui"})
|
||||
}
|
||||
|
||||
func TestCompactCommand(t *testing.T) {
|
||||
assistant := agent.New(agent.Options{Provider: tuiCompactProvider{}, Model: "test", SystemPrompt: "system"})
|
||||
assistant.SetMessages([]llm.Message{
|
||||
{Role: llm.RoleSystem, Content: "system"},
|
||||
{Role: llm.RoleUser, Content: "old question 1"},
|
||||
{Role: llm.RoleAssistant, Content: "old answer 1"},
|
||||
{Role: llm.RoleUser, Content: "old question 2"},
|
||||
{Role: llm.RoleAssistant, Content: "old answer 2"},
|
||||
{Role: llm.RoleUser, Content: "recent question 1"},
|
||||
{Role: llm.RoleAssistant, Content: "recent answer 1"},
|
||||
{Role: llm.RoleUser, Content: "recent question 2"},
|
||||
{Role: llm.RoleAssistant, Content: "recent answer 2"},
|
||||
})
|
||||
m := newModel(context.Background(), assistant, Options{ModelName: "test-model"})
|
||||
|
||||
out, err := m.handleLocalCommand("/compact")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if out != "Context compacted." {
|
||||
t.Fatalf("output = %q", out)
|
||||
}
|
||||
if !strings.Contains(messageContents(assistant.Messages()), "[context summary]") {
|
||||
t.Fatalf("messages missing summary: %#v", assistant.Messages())
|
||||
}
|
||||
}
|
||||
|
||||
func messageContents(messages []llm.Message) string {
|
||||
var b strings.Builder
|
||||
for _, msg := range messages {
|
||||
b.WriteString(msg.Content)
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func TestWorkflowStatusDiffAndTestCommands(t *testing.T) {
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
t.Skip("git not installed")
|
||||
}
|
||||
dir := t.TempDir()
|
||||
runInDir(t, dir, "git", "init")
|
||||
runInDir(t, dir, "git", "config", "user.email", "agentu@example.test")
|
||||
runInDir(t, dir, "git", "config", "user.name", "agentu")
|
||||
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module example.com/p1\n\ngo 1.26\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "main_test.go"), []byte("package p1\n\nimport \"testing\"\n\nfunc TestOK(t *testing.T) {}\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runInDir(t, dir, "git", "add", ".")
|
||||
runInDir(t, dir, "git", "commit", "-m", "init")
|
||||
if err := os.WriteFile(filepath.Join(dir, "main_test.go"), []byte("package p1\n\nimport \"testing\"\n\nfunc TestOK(t *testing.T) { t.Log(\"changed\") }\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
m := newModel(context.Background(), nil, Options{ModelName: "test-model", WorkingDir: dir})
|
||||
status, err := m.handleStatusCommand(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(status, "main_test.go") {
|
||||
t.Fatalf("status missing changed file:\n%s", status)
|
||||
}
|
||||
diff, err := m.handleDiffCommand(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(diff, "changed") {
|
||||
t.Fatalf("diff missing changed content:\n%s", diff)
|
||||
}
|
||||
out, err := m.handleTestCommand(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(out, "$ go test ./...") {
|
||||
t.Fatalf("test output missing default command:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func runInDir(t *testing.T, dir string, name string, args ...string) {
|
||||
t.Helper()
|
||||
cmd := exec.Command(name, args...)
|
||||
cmd.Dir = dir
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatalf("%s %v failed: %v\n%s", name, args, err, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModelCommand(t *testing.T) {
|
||||
m := newModel(context.Background(), nil, Options{ModelName: "test-model", Yolo: true})
|
||||
m.input.SetValue("/model")
|
||||
|
||||
Reference in New Issue
Block a user