Skip to content

Commit

A conversation with an archived agent leaves Chat's list. Until the agent is restored or deleted for good, its direct message is found by typing its name into Jump to channel or person, and it stays listed only while it is the conversation you are in; the chat and agents guides say so.

syntaqxcommitted Parent10df146Browse files
5 files+24−100/5 viewed
+4−3
885885 - It leaves the Agents list, the People directory, the sidebar's **Agents**
886886 section, **New message** and `@` autocomplete, and its handle is free for
887887 a new agent.
888−- Its conversations stay. A direct message with it is still in Chat's
889− sidebar, dimmed and marked **Archived**, and opens to read; what it said
890− keeps its name and face. See [archived and deleted
888+- Its conversations stay. A direct message with it leaves Chat's sidebar
889+ but is found through **Jump to channel or person** by its name, dimmed
890+ and marked **Archived**, and opens to read; what it said keeps its name
891+ and face. See [archived and deleted
891892 agents](/guides/chat/#archived-and-deleted-agents) in the chat guide.
892893 - Its sessions, replies, memory, routines and spend are kept, and its
893894 computer's disk for 30 days.
+4−3
239239
240240 | Where | What you see |
241241 | --- | --- |
242−| The sidebar's **Agents** section | It is no longer among the agents you haven't talked to yet, and **New message** and `@` autocomplete no longer offer it. A direct message you already had with it stays listed, dimmed, with **Archived** beside its name where its title was. |
242+| The sidebar's **Agents** section | It is no longer among the agents you haven't talked to yet, and **New message** and `@` autocomplete no longer offer it. A direct message you already had with it leaves the list too: type its name in **Jump to channel or person** to find it, and it shows, dimmed, with **Archived** beside its name where its title was, for as long as it is the conversation you are in. |
243243 | A direct message with it alone | The header says it was archived, when and by whom. A note stands where the composer was: everything said stays to read, and an owner can restore it, or delete it for good, under **Archived** on the Agents page. |
244244 | A group message it is in | The composer stays, for the people and live agents there. The archived agent is never woken, never shows as typing, and is not the one an unaddressed message goes to. |
245245 | Its messages | Keep its name and face, everywhere. |
246246
247247 Once an agent is deleted for good, it leaves every channel and every
248−list. A direct message with it stays in its people's sidebar, marked
249−**Deleted**, and opens to read, with a note where the composer was; its
248+list. A direct message with it is found through **Jump to channel or
249+person** by the name it had, marked **Deleted**, and opens to read, with
250+a note where the composer was; its
250251 messages, there and in channels, show under the name it had, marked
251252 **Deleted agent**.
252253
+3−1
8686 if (sidebar) setMutedConversations(sidebar.entries.filter((e) => e.muted).map((e) => e.channel.id));
8787 }, [sidebar]);
8888 const entries = (sidebar?.entries ?? []).map((e) => (pins.has(e.channel.id) ? { ...e, starred: pins.get(e.channel.id)! } : e));
89− const shown = filterEntries(entries, filter, query);
89+ // The open conversation stays listed even when it is one with an archived agent, which Jump to otherwise finds.
90+ const currentId = entries.find((e) => pathname === channelPath(slug, e.channel) || pathname.startsWith(`${channelPath(slug, e.channel)}/`))?.channel.id ?? null;
91+ const shown = filterEntries(entries, filter, query, currentId);
9092 const { pinned, channels, people, agents: agentConversations } = sections(shown);
9193 const { agentDms } = sections(entries);
9294 const loading = !data;
+5−1
178178 assert.deepEqual(unreadTotals(all), { unread: 3, mentions: 1 });
179179 });
180180
181−test("an archived agent's conversation stays listed under Agents, read-only; the agent itself is no longer offered", () => {
181+test("an archived agent's conversation leaves the list until searched for or open; the agent itself is no longer offered", () => {
182182 const archived = { ...bot, id: "a2", name: "scribe", display_name: "Scribe", archived_at: "2026-10-08T09:00:00Z", archived_by: "ana" };
183183 const all = [
184184 entry("d1", { kind: "dm", title: "reviewer", others: [bot], last: "2026-10-02T00:00:00Z" }),
194194 assert.deepEqual(agents.map((e) => e.title), ["scribe", "reviewer, scribe", "reviewer", "triage"]);
195195 assert.deepEqual(all.map((e) => archivedAgentsDm(e)?.name ?? null), [null, "scribe", null, null, "triage"]);
196196 assert.equal(archivedAgentsDm(all[4]!)?.deleted, true);
197+ // Not listed on their own; found by name; kept while open.
198+ assert.deepEqual(filterEntries(all, "all", "").map((e) => e.title), ["reviewer", "ana, scribe", "reviewer, scribe"]);
199+ assert.deepEqual(filterEntries(all, "all", "scri").map((e) => e.title), ["scribe", "ana, scribe", "reviewer, scribe"]);
200+ assert.deepEqual(filterEntries(all, "all", "", "d5").map((e) => e.title), ["reviewer", "ana, scribe", "reviewer, scribe", "triage"]);
197201 // The agents you haven't talked to yet: live ones without a conversation, g1t first; never an archived one.
198202 const roster = [
199203 { id: "a1", handle: "reviewer", display_name: "Reviewer", role: "Reviews", builtin: false, archived_at: null },
+8−2
151151 export type ChatFilter = "all" | "unread" | "mentions";
152152
153153 /** The sidebar's rows that pass the filter and the "Jump to" text. */
154−export function filterEntries(entries: ChatSidebarEntry[], filter: ChatFilter, query: string): ChatSidebarEntry[] {
154+/**
155+ * The conversations the sidebar lists, by filter and by what is typed in
156+ * Jump to. A direct message with archived or deleted agents alone is not
157+ * listed on its own: it is found by typing the agent's name, and stays
158+ * while it is the conversation that is open (`current`, its channel id).
159+ */
160+export function filterEntries(entries: ChatSidebarEntry[], filter: ChatFilter, query: string, current: string | null = null): ChatSidebarEntry[] {
155161 const q = query.trim().toLowerCase().replace(/^[#@]/, "");
156162 return entries.filter((entry) => {
157163 if (filter === "unread" && entry.unread === 0 && entry.mentions === 0) return false;
158164 if (filter === "mentions" && entry.mentions === 0) return false;
159− if (!q) return true;
165+ if (!q) return entry.channel.id === current || !archivedAgentsDm(entry);
160166 if (entry.title.toLowerCase().includes(q)) return true;
161167 return entry.others.some((member) => member.name.toLowerCase().includes(q) || member.display_name.toLowerCase().includes(q));
162168 });