@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/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # Changelog — `@ai-matrx/messaging`
2
2
 
3
+ ## 0.15.1
4
+ ### Unreleased
5
+
6
+ ### Added
7
+
8
+ - `AiCallArgs.context` (`ConversationAiContext`) and
9
+ `conversationContextVariables()`: the four conversation intelligences now send
10
+ the `messaging.conversation` offered values by name — `conversation_type`,
11
+ `conversation_name`, `conversation_created_at`, `unread_count`, `is_muted`,
12
+ `reader_user_id`, and always `total_loaded_message_count` — beside the
13
+ existing variables, which are unchanged. `useMessagingAi` fills the context
14
+ from the inbox row and the host identity. Absent facts are omitted.
15
+
16
+ ### Consumer action
17
+
18
+ - None — optional field. A host calling `createMessagingAi` directly may pass
19
+ `context` to supply the same facts.
20
+
21
+ ## 0.15.0
22
+
23
+ ### Fixed
24
+
25
+ - **A failed inbox read is never a skeleton forever, and never "empty"** (RC-B12
26
+ round 11). When the first conversation-list read failed,
27
+ `hasLoadedConversations` stayed false and the list showed its skeleton for as
28
+ long as it was open. The store now carries `conversationsLoadError`; the list
29
+ resolves to "Couldn't load your conversations" with a **Try again**
30
+ (`useConversations().retry`, `engine.refreshInbox()`), and "No conversations
31
+ yet" only follows a read that succeeded.
32
+ - **Read failures render through the design-system error slot.** "Couldn't load
33
+ this conversation" and the inbox failure are drawn with `ErrorBox` from
34
+ `@ai-matrx/design-system` (new dependency), so the host fills them with its
35
+ error actions — in AI Matrx, the Alchemy Menu. They were `EmptyState`s before,
36
+ in the same grey as "No messages yet".
37
+
38
+ ### Added
39
+
40
+ - `MessagingSnapshot.conversationsLoadError`, `MessagingStore.setConversationsLoadError`,
41
+ `MessagingEngine.refreshInbox()`, `useConversations().loadError` / `.retry`.
42
+
43
+ ## 0.14.1
44
+
45
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
46
+ `git diff npm/messaging/v0.14.0..npm/messaging/v0.14.1 -- apps/shared/messaging`).
47
+ No source changes intended and no consumer action required.
48
+
3
49
  ## 0.14.0
4
50
 
5
51
  ### Changed
@@ -811,3 +857,4 @@ consumer):
811
857
  sign-in reports `session-unavailable` instead of recovering.
812
858
  - This package supersedes host code that talks to `communication.dm_*` directly. Anything still
813
859
  reading those tables outside the package should be moved onto it or deleted.
860
+
package/dist/index.cjs CHANGED
@@ -34,6 +34,7 @@ __export(src_exports, {
34
34
  asOrganizationId: () => asOrganizationId,
35
35
  asUserId: () => asUserId,
36
36
  composeFence: () => composeFence,
37
+ conversationContextVariables: () => conversationContextVariables,
37
38
  conversationTopic: () => conversationTopic,
38
39
  createActionRegistry: () => createActionRegistry,
39
40
  createMemoryOutboxStorage: () => createMemoryOutboxStorage,
@@ -395,6 +396,20 @@ ${JSON.stringify(references, null, 2)}
395
396
  }
396
397
 
397
398
  // src/core/ai.ts
399
+ function conversationContextVariables(context, loadedMessageCount) {
400
+ const values = {
401
+ total_loaded_message_count: loadedMessageCount
402
+ };
403
+ if (context === void 0) return values;
404
+ if (context.conversationType) values.conversation_type = context.conversationType;
405
+ if (context.conversationName) values.conversation_name = context.conversationName;
406
+ if (context.conversationCreatedAt)
407
+ values.conversation_created_at = context.conversationCreatedAt;
408
+ if (typeof context.unreadCount === "number") values.unread_count = context.unreadCount;
409
+ if (typeof context.isMuted === "boolean") values.is_muted = context.isMuted;
410
+ if (context.readerUserId) values.reader_user_id = context.readerUserId;
411
+ return values;
412
+ }
398
413
  function unreadCutoff(messages, unreadCount) {
399
414
  if (unreadCount <= 0) return null;
400
415
  const index = messages.length - unreadCount - 1;
@@ -484,7 +499,8 @@ function createMessagingAi(options) {
484
499
  transcript_message_count: transcript.length,
485
500
  // Honest about the cut, so an agent can say "showing the last 200".
486
501
  transcript_truncated: args.messages.length > transcript.length,
487
- ...args.since != null ? { unread_since: args.since } : {}
502
+ ...args.since != null ? { unread_since: args.since } : {},
503
+ ...conversationContextVariables(args.context, args.messages.length)
488
504
  };
489
505
  }
490
506
  function configured(capability) {
@@ -1045,6 +1061,7 @@ function createMessagingStore() {
1045
1061
  let threads = /* @__PURE__ */ new Map();
1046
1062
  let activeConversationId = null;
1047
1063
  let conversationReadFailures = /* @__PURE__ */ new Map();
1064
+ let conversationsLoadError = null;
1048
1065
  const listeners = /* @__PURE__ */ new Set();
1049
1066
  let cached = null;
1050
1067
  function snapshot() {
@@ -1058,7 +1075,8 @@ function createMessagingStore() {
1058
1075
  totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length,
1059
1076
  archiveFilter,
1060
1077
  archivedCount,
1061
- conversationReadFailures
1078
+ conversationReadFailures,
1079
+ conversationsLoadError
1062
1080
  };
1063
1081
  return cached;
1064
1082
  }
@@ -1103,6 +1121,12 @@ function createMessagingStore() {
1103
1121
  conversations = normalizeConversations(items);
1104
1122
  hasMoreConversations = hasMore;
1105
1123
  hasLoadedConversations = true;
1124
+ conversationsLoadError = null;
1125
+ emit();
1126
+ },
1127
+ setConversationsLoadError(message) {
1128
+ if (message === conversationsLoadError) return;
1129
+ conversationsLoadError = message;
1106
1130
  emit();
1107
1131
  },
1108
1132
  setArchiveFilter(next) {
@@ -1335,10 +1359,20 @@ function createMessagingEngine(options) {
1335
1359
  }
1336
1360
  async function reloadInbox() {
1337
1361
  if (disposed) return;
1338
- const page = await repository.listConversations({
1339
- limit: conversationPageSize,
1340
- archived: store.snapshot().archiveFilter
1341
- });
1362
+ let page;
1363
+ try {
1364
+ page = await repository.listConversations({
1365
+ limit: conversationPageSize,
1366
+ archived: store.snapshot().archiveFilter
1367
+ });
1368
+ } catch (error) {
1369
+ if (!disposed) {
1370
+ store.setConversationsLoadError(
1371
+ error instanceof Error ? error.message : typeof error === "string" ? error : "The conversation list could not be read."
1372
+ );
1373
+ }
1374
+ throw error;
1375
+ }
1342
1376
  if (disposed) return;
1343
1377
  conversationCursor = page.nextCursor;
1344
1378
  store.setConversations(page.items, page.hasMore);
@@ -1423,6 +1457,13 @@ function createMessagingEngine(options) {
1423
1457
  }
1424
1458
  });
1425
1459
  },
1460
+ async refreshInbox() {
1461
+ try {
1462
+ await reloadInbox();
1463
+ } catch (error) {
1464
+ reportError(error, "inboxRefresh");
1465
+ }
1466
+ },
1426
1467
  async setArchiveFilter(next) {
1427
1468
  if (next === store.snapshot().archiveFilter) return;
1428
1469
  store.setArchiveFilter(next);