package agents_test import ( "fmt" "strings" "testing" "time" "g.fc.run/misc/byre/internal/api" "g.fc.run/misc/byre/internal/store" ) func leadIdle(ev api.Event) bool { return ev.Kind == "session.state" && ev.Owner != nil && ev.Payload["state"] == string(api.AgentSessionStateIdle) } func TestLeadSignalsAndShow(t *testing.T) { t.Parallel() e := newEnv(t) m := e.manager() lead, err := m.MessageLead(e.ctx, e.user, "Reply with the single word ready.", testModel, nil) if err != nil { t.Fatalf("message lead: %v", err) } if lead.Owner != login || lead.TaskId != "" || lead.Role != api.Lead { t.Fatalf("lead session %+v", lead) } e.waitFor("lead idle", leadIdle) worker := api.AgentSession{ Id: store.NewID(), TaskId: e.task.Id, Vendor: api.Claude, VendorSessionId: store.NewID(), State: api.AgentSessionStateIdle, Role: api.Implementer, CreatedBy: login, CreatedAt: time.Now().UTC(), } err = e.store.CreateSession(e.ctx, worker, e.project.Id) if err != nil { t.Fatalf("create worker session: %v", err) } err = e.store.CreateInboxItem(e.ctx, api.InboxItem{ Id: store.NewID(), ProjectId: e.project.Id, TaskId: e.task.Id, AgentSessionId: worker.Id, ThreadId: "t1", Kind: api.Report, Priority: api.Fyi, Payload: map[string]any{"text": "Finished the parser. The tests pass."}, State: api.Open, CreatedAt: time.Now().UTC(), Responses: []api.InboxResponse{}, }) if err != nil { t.Fatalf("file report: %v", err) } created := e.waitFor("inbox.created", func(ev api.Event) bool { return ev.Kind == "inbox.created" }) m.Observe(created[len(created)-1]) signalled := e.waitFor("signal delivered", func(ev api.Event) bool { return ev.Kind == "user.message" && ev.Owner != nil && ev.Actor == "byre" }) text := signalled[len(signalled)-1].Payload["text"].(string) if !strings.Contains(text, "Finished the parser") || !strings.Contains(text, e.task.Id) { t.Fatalf("signal text %q", text) } e.waitFor("lead idle after signal", leadIdle) _, err = m.MessageLead(e.ctx, e.user, "Call the show tool with task_id "+e.task.Id+", tabs [\"inbox\"] and tab \"inbox\". Then say done.", "", nil) if err != nil { t.Fatalf("message lead: %v", err) } e.waitFor("focus.updated by the lead", func(ev api.Event) bool { return ev.Kind == "focus.updated" && ev.Actor == login+" (lead)" }) f, err := e.store.GetFocus(e.ctx, login) if err != nil { t.Fatalf("get focus: %v", err) } if f.TaskId == nil || *f.TaskId != e.task.Id || f.ProjectId == nil || *f.ProjectId != e.project.Id || f.Tab != api.TabInbox { t.Fatalf("focus %+v", f) } e.waitFor("lead idle after show", leadIdle) m.SetPaneFocus(login, true) _, err = m.MessageLead(e.ctx, e.user, "Call the show tool with task_id "+e.task.Id+", tabs [\"changes\"] and tab \"changes\". Then say done.", "", nil) if err != nil { t.Fatalf("message lead: %v", err) } e.waitFor("show refused", func(ev api.Event) bool { return ev.Kind == "agent.tool_result" && ev.Owner != nil && strings.Contains(fmt.Sprint(ev.Payload), "working in the right pane") }) e.waitFor("lead idle after refused show", leadIdle) f, err = e.store.GetFocus(e.ctx, login) if err != nil { t.Fatalf("get focus: %v", err) } if f.Tab != api.TabInbox { t.Fatalf("focus moved while the pane was focused: %+v", f) } } func TestFocusProject(t *testing.T) { t.Parallel() e := newEnv(t) m := e.manager() err := m.SetFocus(e.ctx, login, api.Focus{ProjectId: &e.project.Id, Tabs: []api.TaskTab{api.TabTodo}, Tab: api.TabTodo}, login) if err != nil { t.Fatalf("focus project: %v", err) } f, err := e.store.GetFocus(e.ctx, login) if err != nil { t.Fatalf("get focus: %v", err) } if f.TaskId != nil || f.ProjectId == nil || *f.ProjectId != e.project.Id || f.Tab != api.TabTodo { t.Fatalf("focus %+v", f) } other := "nope" err = m.SetFocus(e.ctx, login, api.Focus{TaskId: &e.task.Id, ProjectId: &other, Tabs: []api.TaskTab{}, Tab: api.TabTranscript}, login) if err != nil { t.Fatalf("focus task: %v", err) } f, err = e.store.GetFocus(e.ctx, login) if err != nil { t.Fatalf("get focus: %v", err) } if f.TaskId == nil || *f.TaskId != e.task.Id || f.ProjectId == nil || *f.ProjectId != e.project.Id { t.Fatalf("focus %+v", f) } err = m.SetFocus(e.ctx, login, api.Focus{ProjectId: &other, Tabs: []api.TaskTab{}, Tab: api.TabTodo}, login) if err == nil { t.Fatal("focus on an unknown project was accepted") } }