Q147: the conversation header lists its real members, how each agent replies, and who can read

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-09 00:45:05 -04:00
1 parent 02309546dc
commit 983d37937d
13 files changed
+173 -44

No files matched your search

+11
View File
@@ -204,6 +204,17 @@ test("the pinned CEO conversation is the Messages front door", async () => {
}
await expect(start).toBeVisible();
await expect(chatLog.getByText("General line 0", { exact: true })).toBeVisible();
// The header lists the real members, how each agent replies, and who can read.
await page.getByRole("button", { name: /^Members \(/ }).click();
const roster = page.getByRole("menu");
await expect(roster).toContainText("Everyone in the company can read this channel.");
await expect(roster.locator(".members-roster")).toHaveCSS("overflow-y", "auto");
await expect(roster).toContainText("Replies when @mentioned, in threads it joined, and to messages that name no one");
await page.keyboard.press("Escape");
await page.locator(".convo-item").first().click();
await page.getByRole("button", { name: /^Members \(/ }).click();
await expect(page.getByRole("menu")).toContainText("Replies to every message");
} finally {
await app.close();
}
@@ -41,6 +41,9 @@ describe("a message's reply status", () => {
const status = () => new SnapshotService(connection.db).load().chatReplyStatuses.filter((item) => item.messageId === messageId);
expect(status()).toEqual([{ messageId, agentId: ceoId, state: "queued", detail: null, resumesAt: null }]);
// The CEO answers channel messages that name no one.
const general = (connection.db.prepare("select id from chat_spaces where org_id = ? and name = 'general'").get(orgId) as { id: string }).id;
expect(new SnapshotService(connection.db).load().chatSpaceAnchors.find((item) => item.spaceId === general)).toEqual({ spaceId: general, agentId: ceoId });
// A second message folded into the same queued reply gets the same status.
const follow = connection.transaction(() => new ChatService(connection.db).sendMessage({
orgId, spaceId: dm, threadId: (connection.db.prepare("select thread_id from chat_messages where id = ?").get(messageId) as { thread_id: string }).thread_id,
+37
View File
@@ -0,0 +1,37 @@
import { describe, expect, test } from "vitest";
import { spaceMembers, spaceReaders } from "../../src/renderer/src/pages/chat/chat-helpers";
import type { AgentRecord, ChatMembershipRecord, ChatSpaceRecord, EmployeeRecord } from "../../src/shared/domain";
const ORG = "org_1";
function agent(id: string, name: string): AgentRecord {
return {
id, orgId: ORG, name, role: name, department: "Engineering", modelProviderId: null, modelId: null,
budgetCents: 0, managerAgentId: null, title: name, roleLevel: "staff",
modelStrategy: "explicit", workspaceId: null, heartbeatEnabled: false, heartbeatIntervalSec: 0,
lifecycle: "active", avatarEmoji: null, avatarColor: null, avatarImage: null, createdAt: "2026-01-01T00:00:00Z",
};
}
const employees: EmployeeRecord[] = [{ id: "emp_yang", orgId: ORG, displayName: "Yang", role: "founder", avatarEmoji: null, avatarColor: null, avatarImage: null, createdAt: "2026-01-01T00:00:00Z" }];
const agents = [agent("agt_ceo", "CEO"), agent("agt_dana", "Dana"), agent("agt_eve", "Eve")];
const member = (spaceId: string, principalType: "employee" | "agent", principalId: string): ChatMembershipRecord => ({ spaceId, principalType, principalId, role: "member", muteState: "unmuted" });
const space = (id: string, spaceType: string, visibility: string): ChatSpaceRecord => ({ id, orgId: ORG, spaceType, name: id, topic: "t", visibility, retentionPolicy: "standard", createdAt: "2026-01-01T00:00:00Z" });
describe("who is in a conversation", () => {
test("lists every member, spoken or not, with how each agent replies", () => {
const memberships = [member("eng", "employee", "emp_yang"), member("eng", "agent", "agt_ceo"), member("eng", "agent", "agt_dana"), member("dm", "employee", "emp_yang"), member("dm", "agent", "agt_dana")];
expect(spaceMembers(space("eng", "department", "workspace"), memberships, employees, agents, "agt_ceo")).toEqual([
{ id: "emp_yang", name: "Yang", bot: false, duty: "Reads and writes" },
{ id: "agt_ceo", name: "CEO", bot: true, duty: "Replies when @mentioned, in threads it joined, and to messages that name no one" },
{ id: "agt_dana", name: "Dana", bot: true, duty: "Replies when @mentioned and in threads it joined" },
]);
expect(spaceMembers(space("dm", "direct", "restricted"), memberships, employees, agents, null).map((item) => item.duty)).toEqual(["Reads and writes", "Replies to every message"]);
});
test("says who can read beyond the member list", () => {
expect(spaceReaders(space("eng", "department", "workspace"))).toBe("Everyone in the company can read this channel.");
expect(spaceReaders(space("ops", "project", "restricted"))).toBe("Only members can read this channel.");
expect(spaceReaders(space("dm", "direct", "restricted"))).toBe("Only the people in this conversation can read it.");
});
});