@ai-matrx/chat 0.7.27 → 0.7.29

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,28 @@
1
1
  # @ai-matrx/chat
2
2
 
3
+ ## 0.7.29
4
+ ### the agents messenger
5
+
6
+ - **`messenger/agents/AgentsMessenger`: "agents you know" on the messenger shell.** A short roster —
7
+ the starter seats `MESSENGER_STARTER_MANDATE_KEYS` (messenger.answer_anything, chat.default_new_chat,
8
+ personal_staff.front_line, resolved through the mandate resolver) plus agents the person added, minus
9
+ seats they removed — and pinned threads as their own rows. Per-person state is
10
+ `platform.user_entity_state.metadata.messenger`, written only through `platform.ues_merge_metadata`.
11
+ The thread body is THE chat room (`ChatRoomClient`); the header title is the thread dropdown (current,
12
+ past, + New chat, Pin); "Manage agents" adds through THE agent picker. Pure rules in
13
+ `messenger/agents/roster`. Consumer action: mount it (matrx-frontend: `/messenger/agents`).
14
+ - **`ChatRoomClient`: `onOpenConversation` and `surfaceBasePath` props.** A host that keeps the open
15
+ conversation in its own state receives the persisted / fork / retry id instead of a `router.replace`.
16
+ Defaults unchanged. Consumer action: none.
17
+ - **Messenger contract:** menu items take `detail`, `checked`, `keepOpen`; a source may return
18
+ `renderMain` (a screen in the thread area); a contact with no title entries opens details.
19
+
20
+ ## 0.7.28
21
+
22
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
23
+ `git diff npm/chat/v0.7.27..npm/chat/v0.7.28 -- apps/shared/chat`).
24
+ No source changes intended and no consumer action required.
25
+
3
26
  ## 0.7.27
4
27
  ### Unreleased
5
28
 
@@ -43,6 +43,22 @@ interface ChatRoomClientProps {
43
43
  * mid-sentence in.
44
44
  */
45
45
  buildConversationHref?: (conversationId: string) => string;
46
+ /**
47
+ * How this room OPENS a conversation it moved to — the fresh chat's id once
48
+ * it persists, and fork / retry / delete targets. Default:
49
+ * `router.replace(buildConversationHref(id))`, the route-owned rooms.
50
+ *
51
+ * A host that keeps the open conversation in its own state rather than in
52
+ * the URL (the messenger's agents source, where a thread is a row and a
53
+ * dropdown, not a path) passes this and owns the switch; the room never
54
+ * navigates for it.
55
+ */
56
+ onOpenConversation?: (conversationId: string) => void;
57
+ /**
58
+ * The page path pattern this room registers for its surface (action bars
59
+ * read it to know they are on a page). Default `/chat/[conversationId]`.
60
+ */
61
+ surfaceBasePath?: string;
46
62
  /**
47
63
  * THE MANDATE DOOR for this room. When the surface knows WHICH JOB it is
48
64
  * (`/chat/new` is the `chat.default_new_chat` mandate), pass the key: the
@@ -116,5 +132,5 @@ interface ChatRoomClientProps {
116
132
  * (`ready: false`) and we load the existing conversation. The prop is the
117
133
  * single source of truth — no parallel state.
118
134
  */
119
- export declare function ChatRoomClient({ agentId, audience, conversationId: conversationIdProp, landingContent, aboveInput, buildConversationHref, mandateKey, variablesPanelStyle, sandboxBinding, conversationMaterialization, sourceFeature, composer: composerOptions, }: ChatRoomClientProps): import("react").JSX.Element;
135
+ export declare function ChatRoomClient({ agentId, audience, conversationId: conversationIdProp, landingContent, aboveInput, buildConversationHref, onOpenConversation, surfaceBasePath, mandateKey, variablesPanelStyle, sandboxBinding, conversationMaterialization, sourceFeature, composer: composerOptions, }: ChatRoomClientProps): import("react").JSX.Element;
120
136
  export {};
@@ -2,7 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { logFailure } from "../../../ui/expectedRefusal.js";
4
4
  import { usePreparedResourceSeed } from "./usePreparedResourceSeed.js";
5
- import { Suspense, useEffect, useRef, useState } from "react";
5
+ import { Suspense, useCallback, useEffect, useRef, useState } from "react";
6
6
  import { shallowEqual } from "react-redux";
7
7
  import { useRouter, useSearchParams } from "../../../host/navigation.js";
8
8
  import { commitUrlParams } from "@ai-matrx/kit/url-state";
@@ -64,6 +64,7 @@ import { selectUserId, isNotAuthenticatedError } from "../../../host/identity.js
64
64
  import { selectOrganizationId } from "../../../host/org.js";
65
65
  import { selectAuthReady } from "../../../host/identity.js";
66
66
  const defaultConversationHref = (conversationId) => `/chat/${conversationId}`;
67
+ const DEFAULT_SURFACE_BASE_PATH = "/chat/[conversationId]";
67
68
  const SOURCE_FEATURE = "chat";
68
69
  const CHAT_INITIAL_MESSAGE_LIMIT = 12;
69
70
  function ChatRoomClient({
@@ -73,6 +74,8 @@ function ChatRoomClient({
73
74
  landingContent,
74
75
  aboveInput,
75
76
  buildConversationHref = defaultConversationHref,
77
+ onOpenConversation,
78
+ surfaceBasePath = DEFAULT_SURFACE_BASE_PATH,
76
79
  mandateKey,
77
80
  variablesPanelStyle,
78
81
  sandboxBinding = null,
@@ -100,13 +103,20 @@ function ChatRoomClient({
100
103
  registerSurface({
101
104
  surfaceKey,
102
105
  kind: "page",
103
- basePath: "/chat/[conversationId]"
106
+ basePath: surfaceBasePath
104
107
  })
105
108
  );
106
109
  return () => {
107
110
  dispatch(unregisterSurface(surfaceKey));
108
111
  };
109
- }, [dispatch, surfaceKey]);
112
+ }, [dispatch, surfaceKey, surfaceBasePath]);
113
+ const openConversation = useCallback(
114
+ (id) => {
115
+ if (onOpenConversation) onOpenConversation(id);
116
+ else router.replace(buildConversationHref(id));
117
+ },
118
+ [onOpenConversation, router, buildConversationHref]
119
+ );
110
120
  const executionPayload = useAppSelector(
111
121
  (state) => selectAgentExecutionPayload(state, agentId)
112
122
  );
@@ -194,9 +204,9 @@ function ChatRoomClient({
194
204
  const pendingNavigation = useAppSelector(selectPendingNavigation(surfaceKey));
195
205
  useEffect(() => {
196
206
  if (!pendingNavigation) return;
197
- router.replace(buildConversationHref(pendingNavigation.conversationId));
207
+ openConversation(pendingNavigation.conversationId);
198
208
  dispatch(clearPendingNavigation({ surfaceKey }));
199
- }, [pendingNavigation, router, dispatch, surfaceKey, buildConversationHref]);
209
+ }, [pendingNavigation, dispatch, surfaceKey, openConversation]);
200
210
  const draftInputEntryReady = useAppSelector(
201
211
  (state) => liveConversationId ? selectUserInputEntryExists(liveConversationId)(state) : false
202
212
  );
@@ -401,7 +411,7 @@ function ChatRoomClient({
401
411
  const focusNow = store.getState().conversationFocus?.bySurface[surfaceKey]?.input ?? null;
402
412
  if (focusNow !== target) return;
403
413
  promotedRef.current = target;
404
- router.replace(buildConversationHref(target));
414
+ openConversation(target);
405
415
  })();
406
416
  return () => {
407
417
  ctrl.abort();
@@ -410,10 +420,9 @@ function ChatRoomClient({
410
420
  }, [
411
421
  readyToPromote,
412
422
  liveConversationId,
413
- router,
414
423
  store,
415
424
  surfaceKey,
416
- buildConversationHref
425
+ openConversation
417
426
  ]);
418
427
  const conversationId = conversationIdProp ?? liveConversationId ?? null;
419
428
  const canRenderLandingDuringInit = !!landingContent && !conversationIdProp && !!conversationId;
@@ -154,7 +154,7 @@ function MessengerContactList({
154
154
  }
155
155
  ) : /* @__PURE__ */ jsx("span", {})
156
156
  ] }),
157
- /* @__PURE__ */ jsx("div", { className: "shrink-0 px-3 pb-2", children: /* @__PURE__ */ jsxs("label", { className: "flex h-9 w-full min-w-0 items-center gap-2 rounded-full border border-border bg-background px-3 text-muted-foreground focus-within:border-ring", children: [
157
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 px-3 pb-2", children: /* @__PURE__ */ jsxs("div", { className: "flex h-9 w-full min-w-0 items-center gap-2 rounded-full border border-border bg-background px-3 text-muted-foreground focus-within:border-ring", children: [
158
158
  /* @__PURE__ */ jsx(Search, { className: "h-4 w-4 shrink-0" }),
159
159
  /* @__PURE__ */ jsx(
160
160
  "input",
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { Check } from "lucide-react";
3
4
  import {
4
5
  ContextMenu,
5
6
  ContextMenuContent,
@@ -12,6 +13,7 @@ import {
12
13
  DropdownMenuSeparator,
13
14
  DropdownMenuTrigger
14
15
  } from "@ai-matrx/design-system";
16
+ import { cn } from "@ai-matrx/design-system/cn";
15
17
  import { isMenuSeparator } from "./contract.js";
16
18
  function Entries({ entries, kind }) {
17
19
  const Item = kind === "context" ? ContextMenuItem : DropdownMenuItem;
@@ -23,12 +25,18 @@ function Entries({ entries, kind }) {
23
25
  Item,
24
26
  {
25
27
  disabled: entry.disabled,
26
- onSelect: () => entry.onSelect(),
28
+ onSelect: (event) => {
29
+ if (entry.keepOpen) event.preventDefault();
30
+ entry.onSelect();
31
+ },
27
32
  className: entry.destructive ? "text-destructive focus:text-destructive" : void 0,
28
33
  "data-menu-item": entry.id,
34
+ "data-checked": entry.checked ? "" : void 0,
29
35
  children: [
30
36
  Icon ? /* @__PURE__ */ jsx(Icon, { className: "mr-2 h-4 w-4 shrink-0" }) : null,
31
- /* @__PURE__ */ jsx("span", { className: "truncate", children: entry.label })
37
+ /* @__PURE__ */ jsx("span", { className: cn("min-w-0 flex-1 truncate", entry.checked && "font-medium"), children: entry.label }),
38
+ entry.detail ? /* @__PURE__ */ jsx("span", { className: "ml-3 shrink-0 text-[12px] text-muted-foreground", children: entry.detail }) : null,
39
+ entry.checked ? /* @__PURE__ */ jsx(Check, { className: "ml-2 h-4 w-4 shrink-0 text-primary", "aria-label": "Current" }) : null
32
40
  ]
33
41
  },
34
42
  entry.id
@@ -49,7 +57,7 @@ function MessengerDropdownMenu({
49
57
  }) {
50
58
  return /* @__PURE__ */ jsxs(DropdownMenu, { modal: false, children: [
51
59
  /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: trigger }),
52
- /* @__PURE__ */ jsx(DropdownMenuContent, { align, className: "min-w-48", children: /* @__PURE__ */ jsx(Entries, { entries: entries(), kind: "dropdown" }) })
60
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align, className: "max-h-[min(70vh,32rem)] min-w-48 max-w-[22rem] overflow-y-auto", children: /* @__PURE__ */ jsx(Entries, { entries: entries(), kind: "dropdown" }) })
53
61
  ] });
54
62
  }
55
63
  export {
@@ -28,7 +28,8 @@ function MessengerShell({ source, className }) {
28
28
  const filter = source.filters?.find((f) => f.id === filterId) ?? null;
29
29
  const contacts = useMemo(() => visibleContacts(source.contacts, query, filter), [source.contacts, query, filter]);
30
30
  const active = source.contacts.find((c) => c.id === source.activeContactId) ?? null;
31
- const showThread = pane === "thread" && active !== null;
31
+ const main = source.renderMain?.() ?? null;
32
+ const showThread = main !== null || pane === "thread" && active !== null;
32
33
  const shellSource = useMemo(
33
34
  () => ({
34
35
  ...source,
@@ -69,7 +70,7 @@ function MessengerShell({ source, className }) {
69
70
  )
70
71
  }
71
72
  ),
72
- /* @__PURE__ */ jsx("main", { className: cn("flex min-h-0 min-w-0 flex-1 flex-col", !showThread && "max-md:hidden"), "aria-label": "Conversation", children: active ? /* @__PURE__ */ jsxs(Fragment, { children: [
73
+ /* @__PURE__ */ jsx("main", { className: cn("flex min-h-0 min-w-0 flex-1 flex-col", !showThread && "max-md:hidden"), "aria-label": "Conversation", children: main !== null ? /* @__PURE__ */ jsx("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", "data-messenger-main": true, children: main }) : active ? /* @__PURE__ */ jsxs(Fragment, { children: [
73
74
  /* @__PURE__ */ jsx(
74
75
  MessengerThreadHeader,
75
76
  {
@@ -85,7 +86,7 @@ function MessengerShell({ source, className }) {
85
86
  /* @__PURE__ */ jsx(MessageCircle, { className: "h-10 w-10", strokeWidth: 1.25 }),
86
87
  /* @__PURE__ */ jsx("span", { className: "text-[14px]", children: "Pick a conversation" })
87
88
  ] }) }),
88
- active && renderDetails && detailsOpen ? /* @__PURE__ */ jsxs(
89
+ main === null && active && renderDetails && detailsOpen ? /* @__PURE__ */ jsxs(
89
90
  "aside",
90
91
  {
91
92
  "aria-label": "Details",
@@ -14,7 +14,7 @@ function MessengerThreadHeader({
14
14
  }) {
15
15
  const info = source.header(contact);
16
16
  const headerMenu = source.headerMenu;
17
- const titleMenu = source.titleMenu;
17
+ const titleMenu = source.titleMenu && source.titleMenu(contact).length > 0 ? source.titleMenu : void 0;
18
18
  const titleBlock = /* @__PURE__ */ jsxs(Fragment, { children: [
19
19
  /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1", children: [
20
20
  /* @__PURE__ */ jsx("span", { className: "truncate text-[15px] font-semibold text-foreground", "data-header-title": true, children: info.title }),
@@ -0,0 +1,20 @@
1
+ import type { MessengerAvatar } from "../contract.js";
2
+ import { type ThreadSummary } from "./roster.js";
3
+ export interface AgentDetailsPanelProps {
4
+ readonly agentId: string;
5
+ readonly name: string;
6
+ readonly description: string | null;
7
+ readonly modelId: string | null;
8
+ readonly avatar?: MessengerAvatar;
9
+ /** What seat this agent fills ("Starter"), shown under the name. */
10
+ readonly seatLabel: string | null;
11
+ readonly threads: readonly ThreadSummary[];
12
+ readonly currentConversationId: string | null;
13
+ readonly pinnedIds: ReadonlySet<string>;
14
+ readonly hasMore: boolean;
15
+ readonly onLoadMore: () => void;
16
+ readonly onOpenThread: (conversationId: string) => void;
17
+ readonly onOpenAgent: () => void;
18
+ readonly onEditAgent: () => void;
19
+ }
20
+ export declare function AgentDetailsPanel(props: AgentDetailsPanelProps): import("react").JSX.Element;
@@ -0,0 +1,98 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Brain, ExternalLink, History, MessageSquareText, Pencil, Pin, Settings2 } from "lucide-react";
4
+ import { MessengerDetails } from "../MessengerDetails.js";
5
+ import { useModelLabel } from "../../agents/identity/model-catalog.js";
6
+ import {
7
+ useHasChatWindowOpener,
8
+ useOpenAgentMemoryWindow,
9
+ useOpenAgentRunHistoryWindow,
10
+ useOpenAgentSettingsWindow
11
+ } from "../../host/window-openers.js";
12
+ import { relativeDate, threadTitle } from "./roster.js";
13
+ function DoorRow({ icon: Icon, label, onClick }) {
14
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
15
+ "button",
16
+ {
17
+ type: "button",
18
+ onClick,
19
+ className: "flex w-full min-w-0 items-center gap-3 rounded-lg px-2 py-2 text-left text-[14px] text-foreground hover:bg-accent",
20
+ children: [
21
+ /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
22
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: label })
23
+ ]
24
+ }
25
+ ) });
26
+ }
27
+ function AgentDetailsPanel(props) {
28
+ const modelLabel = useModelLabel(props.modelId);
29
+ const hasSettings = useHasChatWindowOpener("openAgentSettingsWindow");
30
+ const hasMemory = useHasChatWindowOpener("openAgentMemoryWindow");
31
+ const hasHistory = useHasChatWindowOpener("openAgentRunHistoryWindow");
32
+ const openSettings = useOpenAgentSettingsWindow();
33
+ const openMemory = useOpenAgentMemoryWindow();
34
+ const openHistory = useOpenAgentRunHistoryWindow();
35
+ const details = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
36
+ /* @__PURE__ */ jsxs("dl", { className: "flex flex-col gap-3 px-2 pt-1 text-[13px]", children: [
37
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
38
+ /* @__PURE__ */ jsx("dt", { className: "text-[12px] text-muted-foreground", children: "Model" }),
39
+ /* @__PURE__ */ jsx("dd", { className: "truncate text-foreground", children: modelLabel ?? (props.modelId ? "Loading\u2026" : "Default") })
40
+ ] }),
41
+ props.description ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
42
+ /* @__PURE__ */ jsx("dt", { className: "text-[12px] text-muted-foreground", children: "About" }),
43
+ /* @__PURE__ */ jsx("dd", { className: "line-clamp-4 text-foreground", children: props.description })
44
+ ] }) : null
45
+ ] }),
46
+ /* @__PURE__ */ jsxs("ul", { className: "flex flex-col", children: [
47
+ /* @__PURE__ */ jsx(DoorRow, { icon: ExternalLink, label: "Open agent", onClick: props.onOpenAgent }),
48
+ /* @__PURE__ */ jsx(DoorRow, { icon: Pencil, label: "Edit agent", onClick: props.onEditAgent }),
49
+ hasSettings ? /* @__PURE__ */ jsx(DoorRow, { icon: Settings2, label: "Settings", onClick: () => openSettings({ initialAgentId: props.agentId }) }) : null,
50
+ hasMemory ? /* @__PURE__ */ jsx(DoorRow, { icon: Brain, label: "Memory", onClick: () => openMemory() }) : null,
51
+ hasHistory ? /* @__PURE__ */ jsx(DoorRow, { icon: History, label: "Run history", onClick: () => openHistory({ agentId: props.agentId }) }) : null
52
+ ] })
53
+ ] });
54
+ const threads = /* @__PURE__ */ jsxs("ul", { className: "flex flex-col", children: [
55
+ props.threads.length === 0 ? /* @__PURE__ */ jsx("li", { className: "px-2 py-3 text-[13px] text-muted-foreground", children: "No chats yet" }) : null,
56
+ props.threads.map((thread) => {
57
+ const current = thread.conversationId === props.currentConversationId;
58
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
59
+ "button",
60
+ {
61
+ type: "button",
62
+ onClick: () => props.onOpenThread(thread.conversationId),
63
+ "aria-current": current ? "true" : void 0,
64
+ className: "flex w-full min-w-0 items-center gap-3 rounded-lg px-2 py-2 text-left hover:bg-accent " + (current ? "bg-accent/70" : ""),
65
+ children: [
66
+ props.pinnedIds.has(thread.conversationId) ? /* @__PURE__ */ jsx(Pin, { className: "h-4 w-4 shrink-0 rotate-45 text-muted-foreground", "aria-label": "Pinned" }) : /* @__PURE__ */ jsx(MessageSquareText, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
67
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-[14px] text-foreground", children: threadTitle(thread) }),
68
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[12px] text-muted-foreground", children: relativeDate(thread.updatedAt) })
69
+ ]
70
+ }
71
+ ) }, thread.conversationId);
72
+ }),
73
+ props.hasMore ? /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
74
+ "button",
75
+ {
76
+ type: "button",
77
+ onClick: props.onLoadMore,
78
+ className: "w-full rounded-lg px-2 py-2 text-left text-[13px] text-muted-foreground hover:bg-accent hover:text-foreground",
79
+ children: "Show more"
80
+ }
81
+ ) }) : null
82
+ ] });
83
+ return /* @__PURE__ */ jsx(
84
+ MessengerDetails,
85
+ {
86
+ name: props.name,
87
+ avatar: props.avatar,
88
+ subtitle: props.seatLabel ?? void 0,
89
+ tabs: [
90
+ { id: "details", label: "Details", content: details },
91
+ { id: "threads", label: "Threads", content: threads }
92
+ ]
93
+ }
94
+ );
95
+ }
96
+ export {
97
+ AgentDetailsPanel
98
+ };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * THE AGENTS SOURCE — "agents you know": a short, curated roster of agents
3
+ * (the starter seats + agents the person added − seats they removed) and the
4
+ * threads the person pinned, as a MessengerSource on the shared shell.
5
+ *
6
+ * - Roster: `MESSENGER_STARTER_MANDATE_KEYS` resolved through the ONE mandate
7
+ * resolver (`useMandateSet`), merged with the person's
8
+ * `platform.user_entity_state.metadata.messenger` rows (./roster.ts).
9
+ * - Listing: the chat package's own conversation-history reads
10
+ * (`fetchConversationHistory`, one scope per roster agent) — no parallel query layer.
11
+ * - Thread body: THE chat room, `ChatRoomClient` (streaming, tools, composer,
12
+ * renderer). The room never navigates here: it hands the persisted id back
13
+ * through `onOpenConversation`. A seat with ONE fixed thread (the Chief of
14
+ * Staff) mounts the host's own door for it via `renderSeatRoom`.
15
+ * - Header title: the thread dropdown (current, past, + New chat, Pin).
16
+ *
17
+ * `<AgentsMessenger>` is the shell + this source + the rename dialog.
18
+ * Doc: ../FEATURE.md.
19
+ */
20
+ import { type ReactNode } from "react";
21
+ import type { MessengerProfile, MessengerSource } from "../contract.js";
22
+ import { type MessengerStarterKey } from "./roster.js";
23
+ /** Where the person is: an agent and its open thread (null = a new chat). */
24
+ export interface AgentsMessengerLocation {
25
+ readonly agentId: string | null;
26
+ readonly conversationId: string | null;
27
+ }
28
+ export interface AgentsMessengerOptions {
29
+ /** The list title. Default "Agents". */
30
+ readonly title?: string;
31
+ readonly profile?: MessengerProfile;
32
+ /** Open on this agent / thread (the host's deep link). */
33
+ readonly initialLocation?: AgentsMessengerLocation;
34
+ /** Every move, so the host can keep its URL in step (replaceState, never a navigation). */
35
+ readonly onLocationChange?: (location: AgentsMessengerLocation) => void;
36
+ /** An absolute link to a place in this messenger (Copy link). */
37
+ readonly linkTo?: (location: AgentsMessengerLocation) => string;
38
+ /** Doors onto the rest of the app. Defaults are matrx-frontend's routes. */
39
+ readonly hrefs?: {
40
+ readonly agent?: (agentId: string) => string;
41
+ readonly editAgent?: (agentId: string) => string;
42
+ readonly conversation?: (conversationId: string) => string;
43
+ };
44
+ /**
45
+ * A seat whose thread is fixed by its own door (the Chief of Staff's ONE
46
+ * staff thread): the host returns that room. Null / absent: the chat room.
47
+ */
48
+ readonly renderSeatRoom?: (seat: {
49
+ mandateKey: MessengerStarterKey;
50
+ agentId: string;
51
+ }) => ReactNode | null;
52
+ }
53
+ export interface AgentsMessengerModel {
54
+ readonly source: MessengerSource;
55
+ /** Dialogs the source opens (Rename). Render beside the shell. */
56
+ readonly overlays: ReactNode;
57
+ }
58
+ export declare function useAgentsMessengerSource(options?: AgentsMessengerOptions): AgentsMessengerModel;
59
+ export interface AgentsMessengerProps extends AgentsMessengerOptions {
60
+ readonly className?: string;
61
+ }
62
+ /** The agents messenger: the shared shell over the agents source, plus its dialogs. */
63
+ export declare function AgentsMessenger({ className, ...options }: AgentsMessengerProps): import("react").JSX.Element;