@ai-matrx/messaging 0.14.0 → 0.15.1

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/dist/react.cjs CHANGED
@@ -75,6 +75,7 @@ __export(react_exports, {
75
75
  asOrganizationId: () => asOrganizationId,
76
76
  asUserId: () => asUserId,
77
77
  composeFence: () => composeFence,
78
+ conversationContextVariables: () => conversationContextVariables,
78
79
  conversationTopic: () => conversationTopic,
79
80
  createActionRegistry: () => createActionRegistry,
80
81
  createMemoryOutboxStorage: () => createMemoryOutboxStorage,
@@ -379,6 +380,20 @@ ${JSON.stringify(references, null, 2)}
379
380
  }
380
381
 
381
382
  // src/core/ai.ts
383
+ function conversationContextVariables(context, loadedMessageCount) {
384
+ const values = {
385
+ total_loaded_message_count: loadedMessageCount
386
+ };
387
+ if (context === void 0) return values;
388
+ if (context.conversationType) values.conversation_type = context.conversationType;
389
+ if (context.conversationName) values.conversation_name = context.conversationName;
390
+ if (context.conversationCreatedAt)
391
+ values.conversation_created_at = context.conversationCreatedAt;
392
+ if (typeof context.unreadCount === "number") values.unread_count = context.unreadCount;
393
+ if (typeof context.isMuted === "boolean") values.is_muted = context.isMuted;
394
+ if (context.readerUserId) values.reader_user_id = context.readerUserId;
395
+ return values;
396
+ }
382
397
  function unreadCutoff(messages, unreadCount) {
383
398
  if (unreadCount <= 0) return null;
384
399
  const index = messages.length - unreadCount - 1;
@@ -468,7 +483,8 @@ function createMessagingAi(options) {
468
483
  transcript_message_count: transcript.length,
469
484
  // Honest about the cut, so an agent can say "showing the last 200".
470
485
  transcript_truncated: args.messages.length > transcript.length,
471
- ...args.since != null ? { unread_since: args.since } : {}
486
+ ...args.since != null ? { unread_since: args.since } : {},
487
+ ...conversationContextVariables(args.context, args.messages.length)
472
488
  };
473
489
  }
474
490
  function configured(capability) {
@@ -983,6 +999,7 @@ function createMessagingStore() {
983
999
  let threads = /* @__PURE__ */ new Map();
984
1000
  let activeConversationId = null;
985
1001
  let conversationReadFailures = /* @__PURE__ */ new Map();
1002
+ let conversationsLoadError = null;
986
1003
  const listeners = /* @__PURE__ */ new Set();
987
1004
  let cached = null;
988
1005
  function snapshot() {
@@ -996,7 +1013,8 @@ function createMessagingStore() {
996
1013
  totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length,
997
1014
  archiveFilter,
998
1015
  archivedCount,
999
- conversationReadFailures
1016
+ conversationReadFailures,
1017
+ conversationsLoadError
1000
1018
  };
1001
1019
  return cached;
1002
1020
  }
@@ -1041,6 +1059,12 @@ function createMessagingStore() {
1041
1059
  conversations = normalizeConversations(items);
1042
1060
  hasMoreConversations = hasMore;
1043
1061
  hasLoadedConversations = true;
1062
+ conversationsLoadError = null;
1063
+ emit();
1064
+ },
1065
+ setConversationsLoadError(message) {
1066
+ if (message === conversationsLoadError) return;
1067
+ conversationsLoadError = message;
1044
1068
  emit();
1045
1069
  },
1046
1070
  setArchiveFilter(next) {
@@ -1273,10 +1297,20 @@ function createMessagingEngine(options) {
1273
1297
  }
1274
1298
  async function reloadInbox() {
1275
1299
  if (disposed) return;
1276
- const page = await repository.listConversations({
1277
- limit: conversationPageSize,
1278
- archived: store.snapshot().archiveFilter
1279
- });
1300
+ let page;
1301
+ try {
1302
+ page = await repository.listConversations({
1303
+ limit: conversationPageSize,
1304
+ archived: store.snapshot().archiveFilter
1305
+ });
1306
+ } catch (error) {
1307
+ if (!disposed) {
1308
+ store.setConversationsLoadError(
1309
+ error instanceof Error ? error.message : typeof error === "string" ? error : "The conversation list could not be read."
1310
+ );
1311
+ }
1312
+ throw error;
1313
+ }
1280
1314
  if (disposed) return;
1281
1315
  conversationCursor = page.nextCursor;
1282
1316
  store.setConversations(page.items, page.hasMore);
@@ -1361,6 +1395,13 @@ function createMessagingEngine(options) {
1361
1395
  }
1362
1396
  });
1363
1397
  },
1398
+ async refreshInbox() {
1399
+ try {
1400
+ await reloadInbox();
1401
+ } catch (error) {
1402
+ reportError(error, "inboxRefresh");
1403
+ }
1404
+ },
1364
1405
  async setArchiveFilter(next) {
1365
1406
  if (next === store.snapshot().archiveFilter) return;
1366
1407
  store.setArchiveFilter(next);
@@ -2504,7 +2545,11 @@ function useConversations() {
2504
2545
  hasMore: snapshot?.hasMoreConversations ?? false,
2505
2546
  // "Not loaded yet" is a FACT from the store, never a guess. Showing
2506
2547
  // "No conversations yet" before the first read is a screen telling a lie.
2507
- isInitialLoading: snapshot === null || !snapshot.hasLoadedConversations,
2548
+ isInitialLoading: snapshot === null || !snapshot.hasLoadedConversations && snapshot.conversationsLoadError === null,
2549
+ loadError: snapshot?.conversationsLoadError ?? null,
2550
+ retry: () => {
2551
+ void host?.engine.refreshInbox();
2552
+ },
2508
2553
  totalUnreadConversations: snapshot?.totalUnreadConversations ?? 0,
2509
2554
  loadMore: () => {
2510
2555
  void host?.engine.loadMoreConversations();
@@ -2709,6 +2754,14 @@ function useMessagingAi(conversationId) {
2709
2754
  conversationId,
2710
2755
  messages: conversation.messages,
2711
2756
  participants: conversation.participants,
2757
+ context: {
2758
+ conversationType: conversation.summary?.conversation.type,
2759
+ conversationName: conversation.summary?.displayName,
2760
+ conversationCreatedAt: conversation.summary?.conversation.createdAt,
2761
+ unreadCount: conversation.summary?.unreadCount,
2762
+ isMuted: conversation.summary?.isMuted,
2763
+ readerUserId: host?.identity.userId || void 0
2764
+ },
2712
2765
  signal: controller.signal,
2713
2766
  // Live progress. Aborted runs stop painting immediately — a cancelled
2714
2767
  // answer must not keep growing on screen.
@@ -3086,6 +3139,7 @@ function EmptyState(props) {
3086
3139
  }
3087
3140
 
3088
3141
  // src/react/components.tsx
3142
+ var import_design_system = require("@ai-matrx/design-system");
3089
3143
  var import_jsx_runtime4 = require("react/jsx-runtime");
3090
3144
  var AI_LABELS = {
3091
3145
  catchUp: "Catch me up",
@@ -3103,7 +3157,9 @@ function ConversationList(props) {
3103
3157
  activeConversationId,
3104
3158
  archiveFilter,
3105
3159
  setArchiveFilter,
3106
- archivedCount
3160
+ archivedCount,
3161
+ loadError,
3162
+ retry
3107
3163
  } = useConversations();
3108
3164
  const RowChrome = useMessagingHost()?.wrapConversationRow ?? null;
3109
3165
  const [query, setQuery] = (0, import_react5.useState)("");
@@ -3168,7 +3224,20 @@ function ConversationList(props) {
3168
3224
  }
3169
3225
  ) }) : null,
3170
3226
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-msg__scroll", children: [
3171
- isInitialLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ConversationSkeleton, {}) : visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3227
+ isInitialLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ConversationSkeleton, {}) : loadError !== null && visible.length === 0 ? (
3228
+ // A failed read resolves to the failure — never a skeleton forever,
3229
+ // never "No conversations yet" (RC-B12 round 11). ErrorBox is the
3230
+ // design-system error slot: the host fills it with its menu.
3231
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3232
+ ReadFailureBox,
3233
+ {
3234
+ title: "Couldn't load your conversations",
3235
+ message: loadError,
3236
+ operation: "List your conversations",
3237
+ onRetry: retry
3238
+ }
3239
+ )
3240
+ ) : visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3172
3241
  EmptyState,
3173
3242
  {
3174
3243
  title: query.length > 0 ? "No matches" : showingArchive ? "No archived conversations" : "No conversations yet",
@@ -3345,10 +3414,11 @@ function ConversationView(props) {
3345
3414
  body: "It doesn't exist, or you aren't a member of it."
3346
3415
  }
3347
3416
  ) : conversation.error !== null && messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3348
- EmptyState,
3417
+ ReadFailureBox,
3349
3418
  {
3350
3419
  title: "Couldn't load this conversation",
3351
- body: "Check your connection, then open it again."
3420
+ message: conversation.error.message || "Check your connection, then open it again.",
3421
+ operation: "Open this conversation"
3352
3422
  }
3353
3423
  ) : messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(EmptyState, { title: "No messages yet", body: "Say something to get started." }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-msg__messages", children: [
3354
3424
  conversation.hasMoreOlder ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -3679,4 +3749,27 @@ function MessagingInbox(props) {
3679
3749
  }
3680
3750
  );
3681
3751
  }
3752
+ function ReadFailureBox({
3753
+ title,
3754
+ message,
3755
+ operation,
3756
+ onRetry
3757
+ }) {
3758
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-msg__empty", role: "alert", children: [
3759
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3760
+ import_design_system.ErrorBox,
3761
+ {
3762
+ as: "div",
3763
+ title,
3764
+ message,
3765
+ operation,
3766
+ origin: "messaging",
3767
+ style: { color: "var(--mx-msg-danger)", fontWeight: 600 },
3768
+ children: title
3769
+ }
3770
+ ),
3771
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: message }),
3772
+ onRetry ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "mx-msg__button mx-msg__button--ghost", onClick: onRetry, children: "Try again" }) : null
3773
+ ] });
3774
+ }
3682
3775
  //# sourceMappingURL=react.cjs.map