Skip to content

Add an "AI Chats" sidebar section listing conversations with a "+ New chat" button #2153

Closed

Description

@malibio

Summary

Add an "AI Chats" section to the navigation sidebar, listing the user's existing ai-chat nodes with a "+ New chat" button at the bottom.

This is its own top-level section — a sibling of Collections and Schema Types, not an entry inside Schema Types. It gets its own collapsible header in the sidebar, expanding and collapsing the same way those two do. Do not implement this by adding ai-chat to SIDENAV_CORE_TYPES; see Why below.

Why

ai-chat currently has no sidebar presence at all. It is not in SIDENAV_CORE_TYPES (packages/desktop-app/src/lib/stores/schemas.svelte.ts:24, which holds only task, project, skill, person, agent-guidance), so it does not appear under Schema Types the way other entity types do. Today the only user-facing way to start a conversation is the /ai-chat slash command.

That matters because core#2152 removes /ai-chat — entity types are not slash-creatable per the rule recorded in core#2133 / core#2151. This issue should land before core#2152 removes the slash command, or there will be a window with no user-facing way to create a chat.

A dedicated top-level section is required rather than adding ai-chat to SIDENAV_CORE_TYPES. Conversations are a primary, frequently-revisited surface and deserve their own place in the sidebar, and the generic Schema Types route would list chats in a query-table type view rather than as a browsable conversation list with an inline create button. ai-chat should stay out of SIDENAV_CORE_TYPES.

Design

Mirror the Collections section (navigation-sidebar.svelte:380–523) — it is the existing pattern that has both a list and a create affordance.

Section shell

  • Collapsible.Root with open={aiChatsExpanded} / onOpenChange={setAiChatsExpanded}
  • Collapsible.Trigger with class="nav-item", an aria-label that flips between Expand AI Chats / Collapse AI Chats, a nav-icon svg, and <span class="nav-label">AI Chats</span>
  • A collapsed-sidebar branch showing just the icon, matching the {:else} arm the other sections use
  • Use the existing aiSquare icon already registered for this type (design/icons/registry.ts:121) rather than a new inline svg, if it fits the nav-icon treatment

Expansion state

Add aiChatsExpanded to packages/desktop-app/src/lib/stores/layout.svelte.ts alongside collectionsExpanded / schemaTypesExpanded — the interface field, the default (false), the persisted-hydration line (persisted.aiChatsExpanded ?? false), the setAiChatsExpanded method, and the module-level export. Expansion state is persisted, so this must round-trip like the others.

Chat list

Load via backendAdapter.queryNodes({ nodeType: 'ai-chat' }). Follow the collections.svelte.ts store shape (a data store with a load* method, loaded from onMount in the sidebar alongside loadCollections() / loadSchemas()).

  • Display each chat's content as its label, falling back to something like "Untitled chat" when empty — chats are created with empty content and titles are generated later (see core#1698, idle-gated background titling), so blank names are the normal early state, not an edge case
  • Clicking a chat opens it in a tab. Reuse the existing tab-reuse logic in handleSchemaClick (:247): if a tab for that nodeId exists, setActiveTab; otherwise addTab into getTargetPaneId(). Note that helper hardcodes nodeType: 'query'; a chat tab needs to route to AiChatNodeViewer, so pass the right type rather than copying it verbatim
  • Decide ordering and cap — most-recently-modified first, and a sensible limit with overflow handling, since an unbounded list will not stay small. queryNodes accepts a limit

"+ New chat"

Bottom of the expanded list, styled like the + New collection button (:509–517).

Unlike collections, no name prompt — collections need an inline input because a name is required up front; a chat's title comes from its content later. Clicking should create immediately and open the new chat.

createSchemaInstance('ai-chat') (services/schema-authoring.ts:42) already does the right thing: it mints the node and returns it hydrated. ai-chat is not in NAME_AS_CONTENT_TYPES, so content starts empty, which is correct here. Defaults are safe — nodeToAiChatNode fills status ?? 'active' and messages: [] (types/ai-chat-node.ts:101), so a bare create needs no seeded properties.

Handle the create-in-flight state (disable the button, surface failures) the way Collections does with createBusy / createError.

Acceptance Criteria

  • "AI Chats" renders as its own top-level sidebar section, a sibling of Collections and Schema Types — not nested under Schema Types
  • ai-chat is NOT added to SIDENAV_CORE_TYPES; it does not appear in the Schema Types list
  • The section expands/collapses like Collections and Schema Types
  • aiChatsExpanded added to the layout store and persists across restarts
  • Collapsed-sidebar state shows the icon-only variant consistent with the other sections
  • Expanded section lists existing ai-chat nodes, most-recent-first, with a defined limit
  • Chats with empty content show a readable placeholder label
  • Clicking a chat opens it in a tab via AiChatNodeViewer; an already-open chat activates its existing tab instead of duplicating it
  • "+ New chat" creates an ai-chat node immediately (no name prompt) and opens it
  • Create failures surface an error and re-enable the button
  • New chats appear in the list without requiring a restart
  • Tests: layout-store persistence of the new flag, and the list/create behavior of the section
  • No raw console.* — use createLogger

Related

  • core#2152 — removes /ai-chat; this issue should land first
  • core#2133 / core#2151 — the primitives-plus-task slash-command rule and its recorded exceptions
  • core#1698 — auto-generated chat titles, which is what makes blank chat names temporary

Activity

  1. added a commit that references this issue on Aug 20, 2026
    dc387ff
  2. mstomar125 commented on Aug 20, 2026

    @mstomar125
    Contributor

    Done — merged in PR #2178 (squashed, merge SHA dc387ff3c750f5a860a2fb0f50b82e4c4cc331be).

    What shipped

    • New top-level "AI Chats" sidebar section in navigation-sidebar.svelte, a sibling of Collections and Schema Types (ai-chat was NOT added to SIDENAV_CORE_TYPES).
    • New aiChatsData store (stores/ai-chats.svelte.ts): loads via backendAdapter.queryNodes({ nodeType: 'ai-chat' }) (fetched unbounded, then sorted client-side by modifiedAt and capped at 50 for display — see note below on why the fetch itself isn't limited), and createChat() backed by createSchemaInstance('ai-chat') with createBusy/createError for the "+ New chat" button's in-flight/failure states.
    • layout.svelte.ts gained aiChatsExpanded (interface field, default false, persisted-hydration, setAiChatsExpanded, module export); layout-persistence-service.ts bumped to schema version 4 with a v3→v4 migration.
    • Clicking a chat reuses the tab-reuse pattern from handleSchemaClick, routed to nodeType: 'ai-chat' so it opens via AiChatNodeViewer. Empty-content chats show "Untitled chat".
    • database.svelte.ts reloads aiChatsData on database switch, mirroring collectionsData/schemasData.

    An adversarial review (code-review skill) caught 2 real correctness bugs that were fixed before merge:

    • createChat() had no guard against a database switch landing mid-create, so a new chat could be written into a store now representing a different database — fixed with a #generation counter mirroring collectionsData's guard around createCollection.
    • The original fetch passed limit: 50 to queryNodes before sorting; since the backend query has no order-by, that could silently truncate away genuinely-recent chats once a user passed 50 total. Fixed by fetching unbounded and slicing to the display cap only after sorting (matches collectionsData.loadCollections()'s own unbounded fetch).

    Acceptance criteria

    • "AI Chats" renders as its own top-level sidebar section, sibling of Collections and Schema Types
    • ai-chat NOT added to SIDENAV_CORE_TYPES
    • Section expands/collapses like Collections and Schema Types
    • aiChatsExpanded added to layout store, persists across restarts
    • Collapsed-sidebar state shows icon-only variant consistent with other sections
    • Expanded section lists existing ai-chat nodes, most-recent-first, with a defined limit
    • Chats with empty content show a readable placeholder label
    • Clicking a chat opens it via AiChatNodeViewer; already-open chat activates existing tab instead of duplicating
    • "+ New chat" creates immediately (no name prompt) and opens it
    • Create failures surface an error and re-enable the button
    • New chats appear in the list without requiring a restart
    • Tests: layout-store persistence of the new flag, and list/create behavior
    • No raw console.* — uses createLogger

    This lands before core#2152 (removal of /ai-chat), so there's no gap in how users create chats.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions