@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.d.cts CHANGED
@@ -386,11 +386,34 @@ interface AiResult {
386
386
  readonly text: string;
387
387
  readonly conversationId: string | null;
388
388
  }
389
+ /**
390
+ * Facts about the open conversation the caller already holds (the inbox row
391
+ * and the signed-in reader). Each is sent by its offered name
392
+ * (`messaging.conversation`, mapped-only) beside the transcript; an absent
393
+ * one is omitted, never sent empty. Nothing here changes the transcript.
394
+ */
395
+ interface ConversationAiContext {
396
+ conversationType?: ConversationType | undefined;
397
+ /** The name the reader sees: the group name, or the other person's name. */
398
+ conversationName?: string | undefined;
399
+ conversationCreatedAt?: string | undefined;
400
+ unreadCount?: number | undefined;
401
+ isMuted?: boolean | undefined;
402
+ readerUserId?: string | undefined;
403
+ }
404
+ /**
405
+ * The offered values of `ConversationAiContext`, by name. Pure, so a host that
406
+ * builds its own call can reuse it. `total_loaded_message_count` is the
407
+ * messages the caller loaded BEFORE windowing.
408
+ */
409
+ declare function conversationContextVariables(context: ConversationAiContext | undefined, loadedMessageCount: number): MatrxJsonObject;
389
410
  /** What every capability takes: the conversation, and how to watch the run. */
390
411
  interface AiCallArgs {
391
412
  conversationId: ConversationId;
392
413
  messages: readonly Message[];
393
414
  participants: readonly UserSummary[];
415
+ /** Conversation facts sent by name beside the transcript (optional). */
416
+ context?: ConversationAiContext | undefined;
394
417
  signal?: AbortSignal | undefined;
395
418
  /** The accumulated answer so far, after every streamed chunk. */
396
419
  onText?: ((fullText: string) => void) | undefined;
@@ -1019,11 +1042,18 @@ interface MessagingSnapshot {
1019
1042
  } | null;
1020
1043
  /** Conversations whose last open failed, keyed by id. Cleared on the next open. */
1021
1044
  readonly conversationReadFailures: ReadonlyMap<ConversationId, ConversationReadFailure>;
1045
+ /**
1046
+ * The inbox read FAILED (and no later read succeeded). Without it a failed
1047
+ * first read left `hasLoadedConversations` false forever — a skeleton that
1048
+ * never resolves is a screen telling a lie (RC-B12 round 11).
1049
+ */
1050
+ readonly conversationsLoadError: string | null;
1022
1051
  }
1023
1052
  interface MessagingStore {
1024
1053
  snapshot(): MessagingSnapshot;
1025
1054
  subscribe(listener: (snapshot: MessagingSnapshot) => void): () => void;
1026
1055
  setConversations(items: readonly ConversationSummary[], hasMore: boolean): void;
1056
+ setConversationsLoadError(message: string | null): void;
1027
1057
  /**
1028
1058
  * Switch the archive axis. Clears the list and marks it UNLOADED: the rows
1029
1059
  * on screen belong to the old filter, and leaving them there while the new
@@ -1133,6 +1163,8 @@ interface MessagingEngine {
1133
1163
  * refreshes the archived count the reveal label prints.
1134
1164
  */
1135
1165
  setArchiveFilter(next: MessagingArchiveFilter): Promise<void>;
1166
+ /** Read the inbox again (the failed-read view's Try again). Never throws; a failure lands in the snapshot. */
1167
+ refreshInbox(): Promise<void>;
1136
1168
  /** Re-read how many archived conversations exist, for the reveal's label. */
1137
1169
  refreshArchivedCount(): Promise<void>;
1138
1170
  /** Open a conversation: load its thread and subscribe to its channel. */
@@ -1376,6 +1408,10 @@ interface UseConversationsResult {
1376
1408
  hasMore: boolean;
1377
1409
  /** True only on the FIRST load; a refresh must not blank the list. */
1378
1410
  isInitialLoading: boolean;
1411
+ /** The inbox read failed; the list shows the failure (never a skeleton forever, never "empty"). */
1412
+ loadError: string | null;
1413
+ /** Read the inbox again. */
1414
+ retry: () => void;
1379
1415
  totalUnreadConversations: number;
1380
1416
  loadMore: () => void;
1381
1417
  select: (id: ConversationId) => void;
@@ -1862,4 +1898,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
1862
1898
  /** Serialize picked references into a fence the platform's other readers accept. */
1863
1899
  declare function composeFence(references: readonly MatrxReference[]): string;
1864
1900
 
1865
- export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, AgentTag, type AiCallArgs, type AiCapability, type AiResult, AlertIcon, type Attachment, Avatar, BotIcon, CheckIcon, ChevronLeftIcon, type ClientMessageId, ClockIcon, CloseIcon, Composer, type ComposerInputRenderProps, type Conversation, type ConversationCursor, type ConversationId, ConversationList, type ConversationListProps, type ConversationReadFailure, type ConversationRowWrapperProps, ConversationSkeleton, type ConversationSummary, type ConversationThread, type ConversationType, ConversationView, type ConversationViewProps, DEFAULT_MESSAGING_ARCHIVE_FILTER, type DeliveryState, DeliveryTick, DoubleCheckIcon, type DraftMessage, EmptyState, type EngineDiagnostic, type IncomingMessageContext, type JsonObject, type JsonValue, LinkIcon, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, MessageActionChips, type MessageActionRenderProps, type MessageActionRenderer, MessageBubble, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessageWrapperProps, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingArchiveFilter, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingHost, type MessagingIdentity, MessagingInbox, type MessagingInboxProps, MessagingProvider, type MessagingProviderProps, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, PaperclipIcon, type Participant, type ParticipantRole, PlusIcon, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, ReferenceCard, type ReferenceRenderer, ReplyIcon, type RepositoryOptions, SERVER_SESSION_IDENTITY, type SchemaLike, SearchIcon, SendIcon, type SessionIdentity, type SessionIdentitySnapshot, type SessionResolver, SparklesIcon, type SupabaseLike, TABLES, type TextSegment, TypingDots, type UseComposerResult, type UseConversationResult, type UseConversationsResult, type UseMessageActionResult, type UseMessagingAiResult, type UseTypistsResult, type UserId, type UserSummary, UsersIcon, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createSessionIdentity, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, toMessagingArchiveFilter, unreadCutoff, useComposer, useConversation, useConversations, useMessageAction, useMessagingAi, useMessagingHost, useMessagingSnapshot, useOnlineUserIds, useRequiredMessagingHost, useTypists };
1901
+ export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, AgentTag, type AiCallArgs, type AiCapability, type AiResult, AlertIcon, type Attachment, Avatar, BotIcon, CheckIcon, ChevronLeftIcon, type ClientMessageId, ClockIcon, CloseIcon, Composer, type ComposerInputRenderProps, type Conversation, type ConversationAiContext, type ConversationCursor, type ConversationId, ConversationList, type ConversationListProps, type ConversationReadFailure, type ConversationRowWrapperProps, ConversationSkeleton, type ConversationSummary, type ConversationThread, type ConversationType, ConversationView, type ConversationViewProps, DEFAULT_MESSAGING_ARCHIVE_FILTER, type DeliveryState, DeliveryTick, DoubleCheckIcon, type DraftMessage, EmptyState, type EngineDiagnostic, type IncomingMessageContext, type JsonObject, type JsonValue, LinkIcon, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, MessageActionChips, type MessageActionRenderProps, type MessageActionRenderer, MessageBubble, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessageWrapperProps, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingArchiveFilter, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingHost, type MessagingIdentity, MessagingInbox, type MessagingInboxProps, MessagingProvider, type MessagingProviderProps, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, PaperclipIcon, type Participant, type ParticipantRole, PlusIcon, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, ReferenceCard, type ReferenceRenderer, ReplyIcon, type RepositoryOptions, SERVER_SESSION_IDENTITY, type SchemaLike, SearchIcon, SendIcon, type SessionIdentity, type SessionIdentitySnapshot, type SessionResolver, SparklesIcon, type SupabaseLike, TABLES, type TextSegment, TypingDots, type UseComposerResult, type UseConversationResult, type UseConversationsResult, type UseMessageActionResult, type UseMessagingAiResult, type UseTypistsResult, type UserId, type UserSummary, UsersIcon, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationContextVariables, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createSessionIdentity, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, toMessagingArchiveFilter, unreadCutoff, useComposer, useConversation, useConversations, useMessageAction, useMessagingAi, useMessagingHost, useMessagingSnapshot, useOnlineUserIds, useRequiredMessagingHost, useTypists };
package/dist/react.d.ts CHANGED
@@ -386,11 +386,34 @@ interface AiResult {
386
386
  readonly text: string;
387
387
  readonly conversationId: string | null;
388
388
  }
389
+ /**
390
+ * Facts about the open conversation the caller already holds (the inbox row
391
+ * and the signed-in reader). Each is sent by its offered name
392
+ * (`messaging.conversation`, mapped-only) beside the transcript; an absent
393
+ * one is omitted, never sent empty. Nothing here changes the transcript.
394
+ */
395
+ interface ConversationAiContext {
396
+ conversationType?: ConversationType | undefined;
397
+ /** The name the reader sees: the group name, or the other person's name. */
398
+ conversationName?: string | undefined;
399
+ conversationCreatedAt?: string | undefined;
400
+ unreadCount?: number | undefined;
401
+ isMuted?: boolean | undefined;
402
+ readerUserId?: string | undefined;
403
+ }
404
+ /**
405
+ * The offered values of `ConversationAiContext`, by name. Pure, so a host that
406
+ * builds its own call can reuse it. `total_loaded_message_count` is the
407
+ * messages the caller loaded BEFORE windowing.
408
+ */
409
+ declare function conversationContextVariables(context: ConversationAiContext | undefined, loadedMessageCount: number): MatrxJsonObject;
389
410
  /** What every capability takes: the conversation, and how to watch the run. */
390
411
  interface AiCallArgs {
391
412
  conversationId: ConversationId;
392
413
  messages: readonly Message[];
393
414
  participants: readonly UserSummary[];
415
+ /** Conversation facts sent by name beside the transcript (optional). */
416
+ context?: ConversationAiContext | undefined;
394
417
  signal?: AbortSignal | undefined;
395
418
  /** The accumulated answer so far, after every streamed chunk. */
396
419
  onText?: ((fullText: string) => void) | undefined;
@@ -1019,11 +1042,18 @@ interface MessagingSnapshot {
1019
1042
  } | null;
1020
1043
  /** Conversations whose last open failed, keyed by id. Cleared on the next open. */
1021
1044
  readonly conversationReadFailures: ReadonlyMap<ConversationId, ConversationReadFailure>;
1045
+ /**
1046
+ * The inbox read FAILED (and no later read succeeded). Without it a failed
1047
+ * first read left `hasLoadedConversations` false forever — a skeleton that
1048
+ * never resolves is a screen telling a lie (RC-B12 round 11).
1049
+ */
1050
+ readonly conversationsLoadError: string | null;
1022
1051
  }
1023
1052
  interface MessagingStore {
1024
1053
  snapshot(): MessagingSnapshot;
1025
1054
  subscribe(listener: (snapshot: MessagingSnapshot) => void): () => void;
1026
1055
  setConversations(items: readonly ConversationSummary[], hasMore: boolean): void;
1056
+ setConversationsLoadError(message: string | null): void;
1027
1057
  /**
1028
1058
  * Switch the archive axis. Clears the list and marks it UNLOADED: the rows
1029
1059
  * on screen belong to the old filter, and leaving them there while the new
@@ -1133,6 +1163,8 @@ interface MessagingEngine {
1133
1163
  * refreshes the archived count the reveal label prints.
1134
1164
  */
1135
1165
  setArchiveFilter(next: MessagingArchiveFilter): Promise<void>;
1166
+ /** Read the inbox again (the failed-read view's Try again). Never throws; a failure lands in the snapshot. */
1167
+ refreshInbox(): Promise<void>;
1136
1168
  /** Re-read how many archived conversations exist, for the reveal's label. */
1137
1169
  refreshArchivedCount(): Promise<void>;
1138
1170
  /** Open a conversation: load its thread and subscribe to its channel. */
@@ -1376,6 +1408,10 @@ interface UseConversationsResult {
1376
1408
  hasMore: boolean;
1377
1409
  /** True only on the FIRST load; a refresh must not blank the list. */
1378
1410
  isInitialLoading: boolean;
1411
+ /** The inbox read failed; the list shows the failure (never a skeleton forever, never "empty"). */
1412
+ loadError: string | null;
1413
+ /** Read the inbox again. */
1414
+ retry: () => void;
1379
1415
  totalUnreadConversations: number;
1380
1416
  loadMore: () => void;
1381
1417
  select: (id: ConversationId) => void;
@@ -1862,4 +1898,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
1862
1898
  /** Serialize picked references into a fence the platform's other readers accept. */
1863
1899
  declare function composeFence(references: readonly MatrxReference[]): string;
1864
1900
 
1865
- export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, AgentTag, type AiCallArgs, type AiCapability, type AiResult, AlertIcon, type Attachment, Avatar, BotIcon, CheckIcon, ChevronLeftIcon, type ClientMessageId, ClockIcon, CloseIcon, Composer, type ComposerInputRenderProps, type Conversation, type ConversationCursor, type ConversationId, ConversationList, type ConversationListProps, type ConversationReadFailure, type ConversationRowWrapperProps, ConversationSkeleton, type ConversationSummary, type ConversationThread, type ConversationType, ConversationView, type ConversationViewProps, DEFAULT_MESSAGING_ARCHIVE_FILTER, type DeliveryState, DeliveryTick, DoubleCheckIcon, type DraftMessage, EmptyState, type EngineDiagnostic, type IncomingMessageContext, type JsonObject, type JsonValue, LinkIcon, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, MessageActionChips, type MessageActionRenderProps, type MessageActionRenderer, MessageBubble, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessageWrapperProps, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingArchiveFilter, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingHost, type MessagingIdentity, MessagingInbox, type MessagingInboxProps, MessagingProvider, type MessagingProviderProps, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, PaperclipIcon, type Participant, type ParticipantRole, PlusIcon, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, ReferenceCard, type ReferenceRenderer, ReplyIcon, type RepositoryOptions, SERVER_SESSION_IDENTITY, type SchemaLike, SearchIcon, SendIcon, type SessionIdentity, type SessionIdentitySnapshot, type SessionResolver, SparklesIcon, type SupabaseLike, TABLES, type TextSegment, TypingDots, type UseComposerResult, type UseConversationResult, type UseConversationsResult, type UseMessageActionResult, type UseMessagingAiResult, type UseTypistsResult, type UserId, type UserSummary, UsersIcon, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createSessionIdentity, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, toMessagingArchiveFilter, unreadCutoff, useComposer, useConversation, useConversations, useMessageAction, useMessagingAi, useMessagingHost, useMessagingSnapshot, useOnlineUserIds, useRequiredMessagingHost, useTypists };
1901
+ export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, AgentTag, type AiCallArgs, type AiCapability, type AiResult, AlertIcon, type Attachment, Avatar, BotIcon, CheckIcon, ChevronLeftIcon, type ClientMessageId, ClockIcon, CloseIcon, Composer, type ComposerInputRenderProps, type Conversation, type ConversationAiContext, type ConversationCursor, type ConversationId, ConversationList, type ConversationListProps, type ConversationReadFailure, type ConversationRowWrapperProps, ConversationSkeleton, type ConversationSummary, type ConversationThread, type ConversationType, ConversationView, type ConversationViewProps, DEFAULT_MESSAGING_ARCHIVE_FILTER, type DeliveryState, DeliveryTick, DoubleCheckIcon, type DraftMessage, EmptyState, type EngineDiagnostic, type IncomingMessageContext, type JsonObject, type JsonValue, LinkIcon, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, MessageActionChips, type MessageActionRenderProps, type MessageActionRenderer, MessageBubble, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessageWrapperProps, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingArchiveFilter, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingHost, type MessagingIdentity, MessagingInbox, type MessagingInboxProps, MessagingProvider, type MessagingProviderProps, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, PaperclipIcon, type Participant, type ParticipantRole, PlusIcon, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, ReferenceCard, type ReferenceRenderer, ReplyIcon, type RepositoryOptions, SERVER_SESSION_IDENTITY, type SchemaLike, SearchIcon, SendIcon, type SessionIdentity, type SessionIdentitySnapshot, type SessionResolver, SparklesIcon, type SupabaseLike, TABLES, type TextSegment, TypingDots, type UseComposerResult, type UseConversationResult, type UseConversationsResult, type UseMessageActionResult, type UseMessagingAiResult, type UseTypistsResult, type UserId, type UserSummary, UsersIcon, asClientMessageId, asConversationId, asMessageId, asOrganizationId, asUserId, composeFence, conversationContextVariables, conversationTopic, createActionRegistry, createMemoryOutboxStorage, createMessagingAi, createMessagingEngine, createMessagingRepository, createMessagingStore, createOutbox, createReadCache, createSessionIdentity, createWebOutboxStorage, effectiveActorKey, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, toMessagingArchiveFilter, unreadCutoff, useComposer, useConversation, useConversations, useMessageAction, useMessagingAi, useMessagingHost, useMessagingSnapshot, useOnlineUserIds, useRequiredMessagingHost, useTypists };
package/dist/react.js CHANGED
@@ -270,6 +270,20 @@ ${JSON.stringify(references, null, 2)}
270
270
  }
271
271
 
272
272
  // src/core/ai.ts
273
+ function conversationContextVariables(context, loadedMessageCount) {
274
+ const values = {
275
+ total_loaded_message_count: loadedMessageCount
276
+ };
277
+ if (context === void 0) return values;
278
+ if (context.conversationType) values.conversation_type = context.conversationType;
279
+ if (context.conversationName) values.conversation_name = context.conversationName;
280
+ if (context.conversationCreatedAt)
281
+ values.conversation_created_at = context.conversationCreatedAt;
282
+ if (typeof context.unreadCount === "number") values.unread_count = context.unreadCount;
283
+ if (typeof context.isMuted === "boolean") values.is_muted = context.isMuted;
284
+ if (context.readerUserId) values.reader_user_id = context.readerUserId;
285
+ return values;
286
+ }
273
287
  function unreadCutoff(messages, unreadCount) {
274
288
  if (unreadCount <= 0) return null;
275
289
  const index = messages.length - unreadCount - 1;
@@ -359,7 +373,8 @@ function createMessagingAi(options) {
359
373
  transcript_message_count: transcript.length,
360
374
  // Honest about the cut, so an agent can say "showing the last 200".
361
375
  transcript_truncated: args.messages.length > transcript.length,
362
- ...args.since != null ? { unread_since: args.since } : {}
376
+ ...args.since != null ? { unread_since: args.since } : {},
377
+ ...conversationContextVariables(args.context, args.messages.length)
363
378
  };
364
379
  }
365
380
  function configured(capability) {
@@ -876,6 +891,7 @@ function createMessagingStore() {
876
891
  let threads = /* @__PURE__ */ new Map();
877
892
  let activeConversationId = null;
878
893
  let conversationReadFailures = /* @__PURE__ */ new Map();
894
+ let conversationsLoadError = null;
879
895
  const listeners = /* @__PURE__ */ new Set();
880
896
  let cached = null;
881
897
  function snapshot() {
@@ -889,7 +905,8 @@ function createMessagingStore() {
889
905
  totalUnreadConversations: conversations.filter((item) => item.unreadCount > 0).length,
890
906
  archiveFilter,
891
907
  archivedCount,
892
- conversationReadFailures
908
+ conversationReadFailures,
909
+ conversationsLoadError
893
910
  };
894
911
  return cached;
895
912
  }
@@ -934,6 +951,12 @@ function createMessagingStore() {
934
951
  conversations = normalizeConversations(items);
935
952
  hasMoreConversations = hasMore;
936
953
  hasLoadedConversations = true;
954
+ conversationsLoadError = null;
955
+ emit();
956
+ },
957
+ setConversationsLoadError(message) {
958
+ if (message === conversationsLoadError) return;
959
+ conversationsLoadError = message;
937
960
  emit();
938
961
  },
939
962
  setArchiveFilter(next) {
@@ -1166,10 +1189,20 @@ function createMessagingEngine(options) {
1166
1189
  }
1167
1190
  async function reloadInbox() {
1168
1191
  if (disposed) return;
1169
- const page = await repository.listConversations({
1170
- limit: conversationPageSize,
1171
- archived: store.snapshot().archiveFilter
1172
- });
1192
+ let page;
1193
+ try {
1194
+ page = await repository.listConversations({
1195
+ limit: conversationPageSize,
1196
+ archived: store.snapshot().archiveFilter
1197
+ });
1198
+ } catch (error) {
1199
+ if (!disposed) {
1200
+ store.setConversationsLoadError(
1201
+ error instanceof Error ? error.message : typeof error === "string" ? error : "The conversation list could not be read."
1202
+ );
1203
+ }
1204
+ throw error;
1205
+ }
1173
1206
  if (disposed) return;
1174
1207
  conversationCursor = page.nextCursor;
1175
1208
  store.setConversations(page.items, page.hasMore);
@@ -1254,6 +1287,13 @@ function createMessagingEngine(options) {
1254
1287
  }
1255
1288
  });
1256
1289
  },
1290
+ async refreshInbox() {
1291
+ try {
1292
+ await reloadInbox();
1293
+ } catch (error) {
1294
+ reportError(error, "inboxRefresh");
1295
+ }
1296
+ },
1257
1297
  async setArchiveFilter(next) {
1258
1298
  if (next === store.snapshot().archiveFilter) return;
1259
1299
  store.setArchiveFilter(next);
@@ -2397,7 +2437,11 @@ function useConversations() {
2397
2437
  hasMore: snapshot?.hasMoreConversations ?? false,
2398
2438
  // "Not loaded yet" is a FACT from the store, never a guess. Showing
2399
2439
  // "No conversations yet" before the first read is a screen telling a lie.
2400
- isInitialLoading: snapshot === null || !snapshot.hasLoadedConversations,
2440
+ isInitialLoading: snapshot === null || !snapshot.hasLoadedConversations && snapshot.conversationsLoadError === null,
2441
+ loadError: snapshot?.conversationsLoadError ?? null,
2442
+ retry: () => {
2443
+ void host?.engine.refreshInbox();
2444
+ },
2401
2445
  totalUnreadConversations: snapshot?.totalUnreadConversations ?? 0,
2402
2446
  loadMore: () => {
2403
2447
  void host?.engine.loadMoreConversations();
@@ -2602,6 +2646,14 @@ function useMessagingAi(conversationId) {
2602
2646
  conversationId,
2603
2647
  messages: conversation.messages,
2604
2648
  participants: conversation.participants,
2649
+ context: {
2650
+ conversationType: conversation.summary?.conversation.type,
2651
+ conversationName: conversation.summary?.displayName,
2652
+ conversationCreatedAt: conversation.summary?.conversation.createdAt,
2653
+ unreadCount: conversation.summary?.unreadCount,
2654
+ isMuted: conversation.summary?.isMuted,
2655
+ readerUserId: host?.identity.userId || void 0
2656
+ },
2605
2657
  signal: controller.signal,
2606
2658
  // Live progress. Aborted runs stop painting immediately — a cancelled
2607
2659
  // answer must not keep growing on screen.
@@ -2984,6 +3036,7 @@ function EmptyState(props) {
2984
3036
  }
2985
3037
 
2986
3038
  // src/react/components.tsx
3039
+ import { ErrorBox } from "@ai-matrx/design-system";
2987
3040
  import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
2988
3041
  var AI_LABELS = {
2989
3042
  catchUp: "Catch me up",
@@ -3001,7 +3054,9 @@ function ConversationList(props) {
3001
3054
  activeConversationId,
3002
3055
  archiveFilter,
3003
3056
  setArchiveFilter,
3004
- archivedCount
3057
+ archivedCount,
3058
+ loadError,
3059
+ retry
3005
3060
  } = useConversations();
3006
3061
  const RowChrome = useMessagingHost()?.wrapConversationRow ?? null;
3007
3062
  const [query, setQuery] = useState2("");
@@ -3066,7 +3121,20 @@ function ConversationList(props) {
3066
3121
  }
3067
3122
  ) }) : null,
3068
3123
  /* @__PURE__ */ jsxs2("div", { className: "mx-msg__scroll", children: [
3069
- isInitialLoading ? /* @__PURE__ */ jsx4(ConversationSkeleton, {}) : visible.length === 0 ? /* @__PURE__ */ jsx4(
3124
+ isInitialLoading ? /* @__PURE__ */ jsx4(ConversationSkeleton, {}) : loadError !== null && visible.length === 0 ? (
3125
+ // A failed read resolves to the failure — never a skeleton forever,
3126
+ // never "No conversations yet" (RC-B12 round 11). ErrorBox is the
3127
+ // design-system error slot: the host fills it with its menu.
3128
+ /* @__PURE__ */ jsx4(
3129
+ ReadFailureBox,
3130
+ {
3131
+ title: "Couldn't load your conversations",
3132
+ message: loadError,
3133
+ operation: "List your conversations",
3134
+ onRetry: retry
3135
+ }
3136
+ )
3137
+ ) : visible.length === 0 ? /* @__PURE__ */ jsx4(
3070
3138
  EmptyState,
3071
3139
  {
3072
3140
  title: query.length > 0 ? "No matches" : showingArchive ? "No archived conversations" : "No conversations yet",
@@ -3243,10 +3311,11 @@ function ConversationView(props) {
3243
3311
  body: "It doesn't exist, or you aren't a member of it."
3244
3312
  }
3245
3313
  ) : conversation.error !== null && messages.length === 0 ? /* @__PURE__ */ jsx4(
3246
- EmptyState,
3314
+ ReadFailureBox,
3247
3315
  {
3248
3316
  title: "Couldn't load this conversation",
3249
- body: "Check your connection, then open it again."
3317
+ message: conversation.error.message || "Check your connection, then open it again.",
3318
+ operation: "Open this conversation"
3250
3319
  }
3251
3320
  ) : messages.length === 0 ? /* @__PURE__ */ jsx4(EmptyState, { title: "No messages yet", body: "Say something to get started." }) : /* @__PURE__ */ jsxs2("div", { className: "mx-msg__messages", children: [
3252
3321
  conversation.hasMoreOlder ? /* @__PURE__ */ jsx4(
@@ -3577,6 +3646,29 @@ function MessagingInbox(props) {
3577
3646
  }
3578
3647
  );
3579
3648
  }
3649
+ function ReadFailureBox({
3650
+ title,
3651
+ message,
3652
+ operation,
3653
+ onRetry
3654
+ }) {
3655
+ return /* @__PURE__ */ jsxs2("div", { className: "mx-msg__empty", role: "alert", children: [
3656
+ /* @__PURE__ */ jsx4(
3657
+ ErrorBox,
3658
+ {
3659
+ as: "div",
3660
+ title,
3661
+ message,
3662
+ operation,
3663
+ origin: "messaging",
3664
+ style: { color: "var(--mx-msg-danger)", fontWeight: 600 },
3665
+ children: title
3666
+ }
3667
+ ),
3668
+ /* @__PURE__ */ jsx4("p", { children: message }),
3669
+ onRetry ? /* @__PURE__ */ jsx4("button", { type: "button", className: "mx-msg__button mx-msg__button--ghost", onClick: onRetry, children: "Try again" }) : null
3670
+ ] });
3671
+ }
3580
3672
  export {
3581
3673
  AgentTag,
3582
3674
  AlertIcon,
@@ -3621,6 +3713,7 @@ export {
3621
3713
  asOrganizationId,
3622
3714
  asUserId,
3623
3715
  composeFence,
3716
+ conversationContextVariables,
3624
3717
  conversationTopic,
3625
3718
  createActionRegistry,
3626
3719
  createMemoryOutboxStorage,