@ai-matrx/chat 0.4.8 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @ai-matrx/chat
2
2
 
3
+ ## 0.4.9 — the shell chat remembers each page's own chat, and its title menu lists your conversations
4
+
5
+ - `shellChatHome`: outside boards and Education, the conversation is remembered PER PAGE
6
+ (`shellChatPageSurfaceKey(pathname)`), not one conversation following the person site-wide. A page
7
+ never chatted on starts fresh; open / closed stays remembered per page family.
8
+ - `ChatPanelTitleMenu`: a Popover with New chat · Rename · Open in full chat over the person's
9
+ conversations (`ConversationHistorySidebar`, searchable, opened in place). New required prop
10
+ `onOpenConversation(conversationId, agentId)`; the shell dock passes `openExisting`.
11
+
12
+ Consumer action: none (the dock is inside the package).
13
+
3
14
  ## 0.4.8
4
15
 
5
16
  Automatic changed-only republish (docs/metadata drift since the last tag — see
@@ -1,6 +1,8 @@
1
1
  /** The panel's chat name: its real title, else "New chat". */
2
2
  export declare function useChatPanelTitle(conversationId: string | null): string;
3
- export declare function ChatPanelTitleMenu({ conversationId, onNewChat, }: {
3
+ export declare function ChatPanelTitleMenu({ conversationId, onNewChat, onOpenConversation, }: {
4
4
  conversationId: string | null;
5
5
  onNewChat: () => void;
6
+ /** Open a listed conversation IN this panel. */
7
+ onOpenConversation: (conversationId: string, agentId?: string | null) => void;
6
8
  }): import("react").JSX.Element;
@@ -1,20 +1,18 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
3
4
  import { ChevronDown, ExternalLink, PencilLine, Plus } from "lucide-react";
4
5
  import { AppLink } from "../../host/ui-slots.js";
5
- import {
6
- DropdownMenu,
7
- DropdownMenuContent,
8
- DropdownMenuItem,
9
- DropdownMenuSeparator,
10
- DropdownMenuTrigger
11
- } from "@ai-matrx/design-system";
6
+ import { Popover, PopoverContent, PopoverTrigger } from "@ai-matrx/design-system";
12
7
  import { useAppSelector } from "../../store/hooks.js";
13
8
  import { selectConversationTitle } from "../../agents/redux/execution-system/conversations/conversations.selectors.js";
14
9
  import { selectConversationListItemById } from "../../agents/redux/conversation-list/conversation-list.selectors.js";
15
10
  import { conversationRenameOpener } from "../../agents/components/conversation-actions/rename/conversationRenameOpener.js";
16
11
  import { conversationTitleText } from "../../utils/content-ir/surfaces/kind-text-label.js";
17
- import { Button } from "@ai-matrx/design-system/controls";
12
+ import { Button, Tile } from "@ai-matrx/design-system/controls";
13
+ import { ConversationHistorySidebar } from "../../agents/components/conversation-history/ConversationHistorySidebar.js";
14
+ const PANEL_HISTORY_SCOPE = "chat-panel-menu";
15
+ const ALL_AGENTS = [];
18
16
  function useChatRealTitle(conversationId) {
19
17
  const conversationTitle = useAppSelector(
20
18
  (state) => conversationId ? selectConversationTitle(conversationId)(state) : null
@@ -29,35 +27,69 @@ function useChatPanelTitle(conversationId) {
29
27
  }
30
28
  function ChatPanelTitleMenu({
31
29
  conversationId,
32
- onNewChat
30
+ onNewChat,
31
+ onOpenConversation
33
32
  }) {
33
+ const [open, setOpen] = useState(false);
34
34
  const realTitle = useChatRealTitle(conversationId);
35
35
  const title = realTitle ?? "New chat";
36
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
37
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "quiet", iconEnd: /* @__PURE__ */ jsx(ChevronDown, {}), className: "min-w-0", title, children: title }) }),
38
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-56", children: [
39
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: onNewChat, children: [
40
- /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }),
41
- "New chat"
42
- ] }),
43
- conversationId ? /* @__PURE__ */ jsxs(Fragment, { children: [
44
- /* @__PURE__ */ jsxs(
45
- DropdownMenuItem,
46
- {
47
- onSelect: () => void conversationRenameOpener.open({ conversationId, title: realTitle }),
48
- children: [
49
- /* @__PURE__ */ jsx(PencilLine, { className: "mr-2 h-4 w-4" }),
50
- "Rename"
51
- ]
52
- }
53
- ),
54
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
55
- /* @__PURE__ */ jsx(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs(AppLink, { href: `/chat/${conversationId}`, children: [
56
- /* @__PURE__ */ jsx(ExternalLink, { className: "mr-2 h-4 w-4" }),
57
- "Open in full chat"
58
- ] }) })
59
- ] }) : null
60
- ] })
36
+ const close = () => setOpen(false);
37
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
38
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "quiet", iconEnd: /* @__PURE__ */ jsx(ChevronDown, {}), className: "min-w-0", title, children: title }) }),
39
+ /* @__PURE__ */ jsxs(
40
+ PopoverContent,
41
+ {
42
+ align: "start",
43
+ sideOffset: 6,
44
+ className: "flex h-[min(70dvh,560px)] w-80 flex-col overflow-hidden p-1",
45
+ children: [
46
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-col", children: [
47
+ /* @__PURE__ */ jsx(
48
+ Tile,
49
+ {
50
+ variant: "quiet",
51
+ icon: /* @__PURE__ */ jsx(Plus, {}),
52
+ title: "New chat",
53
+ onClick: () => {
54
+ close();
55
+ onNewChat();
56
+ }
57
+ }
58
+ ),
59
+ conversationId ? /* @__PURE__ */ jsxs(Fragment, { children: [
60
+ /* @__PURE__ */ jsx(
61
+ Tile,
62
+ {
63
+ variant: "quiet",
64
+ icon: /* @__PURE__ */ jsx(PencilLine, {}),
65
+ title: "Rename",
66
+ onClick: () => {
67
+ close();
68
+ void conversationRenameOpener.open({ conversationId, title: realTitle });
69
+ }
70
+ }
71
+ ),
72
+ /* @__PURE__ */ jsx(Tile, { variant: "quiet", icon: /* @__PURE__ */ jsx(ExternalLink, {}), title: "Open in full chat", asChild: true, children: /* @__PURE__ */ jsx(AppLink, { href: `/chat/${conversationId}`, onClick: close }) })
73
+ ] }) : null
74
+ ] }),
75
+ /* @__PURE__ */ jsx("div", { className: "mx-1 my-1 h-px shrink-0 bg-border", role: "separator" }),
76
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsx(
77
+ ConversationHistorySidebar,
78
+ {
79
+ variant: "dense",
80
+ scopeId: PANEL_HISTORY_SCOPE,
81
+ agentIds: ALL_AGENTS,
82
+ activeConversationId: conversationId,
83
+ openInPlace: true,
84
+ onOpenConversation: (conv) => {
85
+ close();
86
+ onOpenConversation(conv.conversationId, conv.agentId ?? null);
87
+ }
88
+ }
89
+ ) })
90
+ ]
91
+ }
92
+ )
61
93
  ] });
62
94
  }
63
95
  export {
@@ -260,7 +260,7 @@ function ShellChatDock({ initialChat, initialWidth, initialMode = null, signedIn
260
260
  className: "bg-card",
261
261
  children: [
262
262
  /* @__PURE__ */ jsxs("div", { className: "shell-chat-dock-header flex h-11 shrink-0 items-center gap-1 pr-2", children: [
263
- /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(ChatPanelTitleMenu, { conversationId, onNewChat: chat.startNew }) }),
263
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(ChatPanelTitleMenu, { conversationId, onNewChat: chat.startNew, onOpenConversation: chat.openExisting }) }),
264
264
  /* @__PURE__ */ jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsx(ComposerModeSwitch, { size: "panel", initialMode }) }),
265
265
  /* @__PURE__ */ jsx(
266
266
  Button,
@@ -33,8 +33,14 @@ export declare function shellChatWorkspaceId(family: string): string;
33
33
  * chat, on every page).
34
34
  */
35
35
  export declare function shellChatHostedElsewhere(pathname: string): boolean;
36
- /** The shell chat's conversation everywhere no page has its own. */
36
+ /**
37
+ * The shell chat's conversation is remembered PER PAGE (Arman, 2026-10-07: one
38
+ * conversation following the person across the whole site "doesn't make sense
39
+ * … it's confusing"). Each page — one agent's builder, one note — comes back to
40
+ * ITS last chat; a page the person never chatted on starts fresh.
41
+ */
37
42
  export declare const SHELL_CHAT_SURFACE_KEY = "canvas-workspace:shell";
43
+ export declare function shellChatPageSurfaceKey(pathname: string): string;
38
44
  /**
39
45
  * Where the shell's chat lives on a page:
40
46
  * - `layoutId` — its remembered open / closed + docked / floating
@@ -61,8 +67,8 @@ export declare const SHELL_CHAT_CLOSED_BY_DEFAULT_PAGES: readonly RegExp[];
61
67
  * has its conversation, signed-in Education has one. The ids, params and
62
68
  * defaults are exactly the ones those pages used when they drew their own chat
63
69
  * column (ChatCanvasWorkspace, until 2026-10-05), so a person's remembered
64
- * layout and conversation carry over untouched. Every other page shares one
65
- * conversation that follows the person, remembered open / closed per family.
70
+ * layout and conversation carry over untouched. Every other page remembers its
71
+ * OWN conversation (shellChatPageSurfaceKey); open / closed is remembered per family.
66
72
  */
67
73
  export declare function shellChatHome(pathname: string, signedIn: boolean): ShellChatHome;
68
74
  /**
@@ -20,6 +20,10 @@ function shellChatHostedElsewhere(pathname) {
20
20
  return OWN_CHAT_PATHS.some((p) => p.test(pathname));
21
21
  }
22
22
  const SHELL_CHAT_SURFACE_KEY = "canvas-workspace:shell";
23
+ function shellChatPageSurfaceKey(pathname) {
24
+ const page = pathname.split("?")[0].replace(/\/+$/, "") || "/";
25
+ return `${SHELL_CHAT_SURFACE_KEY}:${page}`;
26
+ }
23
27
  const BOARD_PAGE = /^\/board\/(?!all(?:\/|$))([^/]+)\/?$/;
24
28
  const EDUCATION_PAGES = /^\/education(?:\/|$)/;
25
29
  const SHELL_CHAT_CLOSED_BY_DEFAULT_PAGES = [/^\/spaces(?:\/|$)/];
@@ -34,7 +38,7 @@ function shellChatHome(pathname, signedIn) {
34
38
  }
35
39
  return {
36
40
  layoutId: shellChatWorkspaceId(shellChatFamily(pathname)),
37
- surfaceKey: SHELL_CHAT_SURFACE_KEY,
41
+ surfaceKey: shellChatPageSurfaceKey(pathname),
38
42
  // `pageChat`, not `chat`: /code keeps its own `?chat=`.
39
43
  addressParam: "pageChat",
40
44
  defaultOpen: SHELL_CHAT_CLOSED_BY_DEFAULT_PAGES.some((p) => p.test(pathname)) ? false : null
@@ -52,5 +56,6 @@ export {
52
56
  shellChatFamily,
53
57
  shellChatHome,
54
58
  shellChatHostedElsewhere,
59
+ shellChatPageSurfaceKey,
55
60
  shellChatWorkspaceId
56
61
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/chat",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "THE one AI Matrx person-to-agent chat system: the full chat (running agents, conversations, tool calls, streaming, context, surfaces, voice) as per-module subpaths @ai-matrx/chat/<domain>/<module> over a host contract (/host, /host/react) whose only required value is a db; plus the kernel compatibility entries (., /external-store, /matrx, /react, /tools, styles.css, tokens.css) until P28.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -227,25 +227,25 @@
227
227
  "uuid": "^14.0.2",
228
228
  "zod": "^4.6.5",
229
229
  "@ai-matrx/agents": "latest",
230
- "@ai-matrx/alchemy": "latest",
231
- "@ai-matrx/browser-audio": "latest",
232
- "@ai-matrx/content-ir": "latest",
233
230
  "@ai-matrx/associations": "latest",
231
+ "@ai-matrx/browser-audio": "latest",
232
+ "@ai-matrx/alchemy": "latest",
234
233
  "@ai-matrx/canvas": "latest",
235
- "@ai-matrx/design-system": "latest",
234
+ "@ai-matrx/content-ir": "latest",
236
235
  "@ai-matrx/diff": "latest",
237
- "@ai-matrx/kit": "latest",
236
+ "@ai-matrx/content-ir-react": "latest",
237
+ "@ai-matrx/design-system": "latest",
238
+ "@ai-matrx/data": "latest",
239
+ "@ai-matrx/icons": "latest",
238
240
  "@ai-matrx/media": "latest",
239
241
  "@ai-matrx/print": "latest",
242
+ "@ai-matrx/kit": "latest",
240
243
  "@ai-matrx/realtime": "latest",
241
244
  "@ai-matrx/records": "latest",
242
- "@ai-matrx/records-ui": "latest",
243
245
  "@ai-matrx/rich-content": "latest",
244
246
  "@ai-matrx/rich-editor": "latest",
245
- "@ai-matrx/data": "latest",
246
- "@ai-matrx/content-ir-react": "latest",
247
- "@ai-matrx/icons": "latest",
248
- "@ai-matrx/tap-target": "latest"
247
+ "@ai-matrx/tap-target": "latest",
248
+ "@ai-matrx/records-ui": "latest"
249
249
  },
250
250
  "devDependencies": {
251
251
  "@arethetypeswrong/cli": "^0.18.5",