Files
aego/tests/integration/agent_authorized_test.go
sanspie 5eb1832907
ci-platforms / darwin amd64 smoke (push) Skipped
ci / build (amd64, linux, ubuntu-24.04) (push) Failing after 15m28s
ci / release (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
ci-platforms / darwin arm64 smoke (push) Skipped
ci / checks (push) Successful in 7m47s
Complete Stage 12 for v0.12.0
2026-11-05 11:46:53 +03:00

159 lines
4.4 KiB
Go

//go:build aego_gltest
package integration
import (
"crypto/rand"
"os"
"runtime"
"strings"
"testing"
"time"
"aego/app/agentui/backend"
"aego/app/edit"
"aego/core/log"
"aego/editor/core/agentui"
"aego/editor/core/command"
agentpanel "aego/editor/panels/agent"
"aego/project"
)
func TestAuthorizedAgentExplainsActiveProjectAndCapturesGame(t *testing.T) {
for _, provider := range []string{"codex", "claude"} {
t.Run(provider, func(t *testing.T) {
if os.Getenv("AEGO_LIVE_EDITOR_PROVIDER") != provider {
t.Skip("opt in with AEGO_LIVE_EDITOR_PROVIDER=" + provider + " on a machine with a signed-in CLI and GL33")
}
runtime.LockOSThread()
defer runtime.UnlockOSThread()
root := copyExample(t, "platformer")
p, err := project.Load(root)
if err != nil {
t.Fatal(err)
}
b, err := backend.ForProvider(provider)
if err != nil {
t.Fatal(err)
}
s, err := edit.Open(p, edit.Config{Hidden: true, NoWatch: true, Logger: log.Nop(), AgentBackend: b}, combatModule{})
if err != nil {
t.Fatal(err)
}
defer s.Close()
if !s.Step() {
t.Fatal("editor stopped during initialization")
}
s.App.SetAgentSettings(agentui.ProviderSettings{Provider: provider, Command: os.Getenv("AEGO_LIVE_EDITOR_CLI"), Model: os.Getenv("AEGO_LIVE_EDITOR_MODEL")})
ctx := s.App.Context()
d, err := ctx.Docs.Open(bridgeScene)
if err != nil {
t.Fatal(err)
}
sc := d.Scene()
marker := "Pilot" + rand.Text()[:8]
actor := sc.Find(sc.Root(), "Player")
if actor.IsZero() {
t.Fatal("Player missing")
}
sc.SetName(actor, marker)
ctx.Select(sc.ID(actor))
panel := s.App.Agent()
s.App.Workspace().Show(agentpanel.ID)
pump := func() {
deadline := time.Now().Add(3 * time.Minute)
for panel.Busy() && time.Now().Before(deadline) {
s.Step()
time.Sleep(4 * time.Millisecond)
}
if panel.Busy() {
t.Fatal("provider turn timed out")
}
}
logs := func() []agentui.Entry {
names, err := agentui.List(root)
if err != nil || len(names) != 1 {
t.Fatalf("transcripts: %v %v", names, err)
}
entries, err := agentui.Load(root, names[0])
if err != nil {
t.Fatal(err)
}
return entries
}
panel.ExplainScene()
pump()
entries := logs()
seenScript := false
for _, e := range entries {
if e.Kind == "result" && e.Tool == "script_read" && !e.Failed {
seenScript = true
}
}
seenMarker := transcriptHasText(entries, marker)
if !seenMarker || !seenScript {
for _, e := range entries {
if e.Kind == "text" || e.Kind == "call" || e.Kind == "error" {
t.Logf("transcript: kind=%s tool=%s message=%s delta=%v text=%q", e.Kind, e.Tool, e.MessageID, e.Delta, e.Text)
}
}
t.Fatalf("provider did not name the unsaved actor and read its script: %v %v", seenMarker, seenScript)
}
if _, depth := d.History.Top(); depth != 0 {
t.Fatal("Explain changed History")
}
if err := ctx.Commands.Run(command.PlayStart); err != nil {
t.Fatal(err)
}
for range 10 {
s.Step()
}
panel.Submit("Show me what the player sees now. Use editor_view_capture with view=game.")
pump()
for _, e := range logs() {
if e.Kind == "result" && e.Tool == "editor_view_capture" && !e.Failed && len(e.Images) > 0 {
return
}
}
t.Fatal("no real Game View image returned in this conversation")
})
}
}
// Codex streams an answer as separate deltas, which can split a node name.
// Reassemble each message independently instead of searching individual chunks.
func transcriptHasText(entries []agentui.Entry, want string) bool {
parts := map[string]string{}
for _, e := range entries {
if e.Kind != "text" {
continue
}
if !e.Delta {
if strings.Contains(e.Text, want) {
return true
}
continue
}
parts[e.MessageID] += e.Text
if strings.Contains(parts[e.MessageID], want) {
return true
}
}
return false
}
func TestTranscriptHasTextAcrossDeltas(t *testing.T) {
entries := []agentui.Entry{
{Kind: "text", MessageID: "a", Delta: true, Text: "Pilot"},
{Kind: "text", MessageID: "b", Delta: true, Text: "other"},
{Kind: "text", MessageID: "a", Delta: true, Text: "123"},
{Kind: "text", Text: "complete"},
}
if !transcriptHasText(entries, "Pilot123") || !transcriptHasText(entries, "complete") {
t.Fatal("streamed or complete message was not found")
}
if transcriptHasText(entries, "Pilotother") {
t.Fatal("text from separate messages was merged")
}
}