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.
5 files+24−100/5 viewed
| 885 | 885 | - It leaves the Agents list, the People directory, the sidebar's **Agents** | |
| 886 | 886 | section, **New message** and `@` autocomplete, and its handle is free for | |
| 887 | 887 | 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 | |
| 891 | 892 | agents](/guides/chat/#archived-and-deleted-agents) in the chat guide. | |
| 892 | 893 | - Its sessions, replies, memory, routines and spend are kept, and its | |
| 893 | 894 | computer's disk for 30 days. |
| 239 | 239 | ||
| 240 | 240 | | Where | What you see | | |
| 241 | 241 | | --- | --- | | |
| 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. | | |
| 243 | 243 | | 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. | | |
| 244 | 244 | | 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. | | |
| 245 | 245 | | Its messages | Keep its name and face, everywhere. | | |
| 246 | 246 | ||
| 247 | 247 | 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 | |
| 250 | 251 | messages, there and in channels, show under the name it had, marked | |
| 251 | 252 | **Deleted agent**. | |
| 252 | 253 |
| 86 | 86 | if (sidebar) setMutedConversations(sidebar.entries.filter((e) => e.muted).map((e) => e.channel.id)); | |
| 87 | 87 | }, [sidebar]); | |
| 88 | 88 | 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); | |
| 90 | 92 | const { pinned, channels, people, agents: agentConversations } = sections(shown); | |
| 91 | 93 | const { agentDms } = sections(entries); | |
| 92 | 94 | const loading = !data; |
| 178 | 178 | assert.deepEqual(unreadTotals(all), { unread: 3, mentions: 1 }); | |
| 179 | 179 | }); | |
| 180 | 180 | ||
| 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", () => { | |
| 182 | 182 | const archived = { ...bot, id: "a2", name: "scribe", display_name: "Scribe", archived_at: "2026-10-08T09:00:00Z", archived_by: "ana" }; | |
| 183 | 183 | const all = [ | |
| 184 | 184 | entry("d1", { kind: "dm", title: "reviewer", others: [bot], last: "2026-10-02T00:00:00Z" }), | |
| ⋯ | |||
| 194 | 194 | assert.deepEqual(agents.map((e) => e.title), ["scribe", "reviewer, scribe", "reviewer", "triage"]); | |
| 195 | 195 | assert.deepEqual(all.map((e) => archivedAgentsDm(e)?.name ?? null), [null, "scribe", null, null, "triage"]); | |
| 196 | 196 | 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"]); | |
| 197 | 201 | // The agents you haven't talked to yet: live ones without a conversation, g1t first; never an archived one. | |
| 198 | 202 | const roster = [ | |
| 199 | 203 | { id: "a1", handle: "reviewer", display_name: "Reviewer", role: "Reviews", builtin: false, archived_at: null }, | |
| 151 | 151 | export type ChatFilter = "all" | "unread" | "mentions"; | |
| 152 | 152 | ||
| 153 | 153 | /** 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[] { | |
| 155 | 161 | const q = query.trim().toLowerCase().replace(/^[#@]/, ""); | |
| 156 | 162 | return entries.filter((entry) => { | |
| 157 | 163 | if (filter === "unread" && entry.unread === 0 && entry.mentions === 0) return false; | |
| 158 | 164 | if (filter === "mentions" && entry.mentions === 0) return false; | |
| 159 | − | if (!q) return true; | |
| 165 | + | if (!q) return entry.channel.id === current || !archivedAgentsDm(entry); | |
| 160 | 166 | if (entry.title.toLowerCase().includes(q)) return true; | |
| 161 | 167 | return entry.others.some((member) => member.name.toLowerCase().includes(q) || member.display_name.toLowerCase().includes(q)); | |
| 162 | 168 | }); |