package agents_test import ( "errors" "os" "path/filepath" "testing" "time" "g.fc.run/misc/byre/internal/api" ) const reviewAndAskPrompt = "Create a file hi.txt containing exactly the word hi. " + "Then ask the human with byre's ask_human tool whether to keep the file: blocking, with the choices `- (*) Keep it` and `- ( ) Delete it`. Then end your turn." func TestSnapshotReview(t *testing.T) { t.Parallel() e := newEnv(t) m := e.manager() sess, err := m.Create(e.ctx, e.task, e.user, reviewAndAskPrompt, testModel) if err != nil { t.Fatalf("create session: %v", err) } e.waitIdle() events := e.waitFor("review finished", func(ev api.Event) bool { return ev.Kind == "review.finished" }) finished := events[len(events)-1] review, err := e.store.GetReview(e.ctx, finished.Payload["id"].(string)) if err != nil { t.Fatalf("get review: %v", err) } if review.State != api.ReviewStateDone || review.SnapshotN != 1 || review.Vendor != string(api.Codex) || review.Result == nil { t.Fatalf("review %+v", review) } if _, ok := (*review.Result)["summary"].(string); !ok { t.Fatalf("review result has no summary: %+v", *review.Result) } questions := e.openQuestions(sess.Id) if len(questions) != 1 || len(questions[0].Reviews) != 1 || questions[0].Reviews[0].Id != review.Id { t.Fatalf("question doesn't show its turn's review: %+v", questions) } sessions, err := e.store.ListSessions(e.ctx, e.task.Id) if err != nil || len(sessions) != 1 || sessions[0].Id != sess.Id { t.Fatalf("task sessions %+v %v, want only the implementer", sessions, err) } dir := filepath.Join(e.worktrees, e.project.Id, "review-"+review.Id) for range 100 { _, err = os.Stat(dir) if errors.Is(err, os.ErrNotExist) { break } time.Sleep(100 * time.Millisecond) } if !errors.Is(err, os.ErrNotExist) { t.Fatalf("review worktree %s still there: %v", dir, err) } reviewer, err := e.store.GetSession(e.ctx, review.AgentSessionId) if err != nil || reviewer.State != api.AgentSessionStateCompleted || reviewer.Role != api.Reviewer { t.Fatalf("reviewer session %+v %v", reviewer, err) } }