@ai-matrx/messaging 0.9.0 → 0.10.0

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
@@ -1,5 +1,5 @@
1
1
  import { ReactNode, ComponentType, SVGProps } from 'react';
2
- import { MatrxTransport } from '@ai-matrx/agents/matrx';
2
+ import { MatrxJsonObject, MatrxTransport } from '@ai-matrx/agents/matrx';
3
3
  import { RealtimeClientLike, RealtimeManager } from '@ai-matrx/realtime';
4
4
 
5
5
  /**
@@ -285,21 +285,47 @@ declare function createActionRegistry(): ActionRegistry;
285
285
  * every conversation it touches. Every call below sends `variables` and either
286
286
  * a short human-shaped `user_input` or none.
287
287
  *
288
- * 🚨 **AGENT DEFINITIONS LIVE IN THE DATABASE.** The package takes agent IDs as
289
- * injected identity. When an id is not configured the capability reports
290
- * `unavailable` WITH the remedy it never silently no-ops, and the UI hides
291
- * the action rather than offering a dead button (no dead ends).
288
+ * 🚨 **AGENT DEFINITIONS LIVE IN THE DATABASE.** The package takes an injected
289
+ * IDENTITY per capability the database agent id and the settings that came
290
+ * with it and nothing else. When an identity is not configured the capability
291
+ * reports `unavailable` WITH the remedy; it never silently no-ops, and the UI
292
+ * hides the action rather than offering a dead button (no dead ends).
293
+ *
294
+ * 🚨 **AN IDENTITY IS BOTH HALVES.** A host that resolves a capability's agent
295
+ * from its own switching layer resolves a PAIR: which agent, and the settings
296
+ * that layer decided for it. Taking only the id silently drops the settings
297
+ * half, so `configOverrides` rides with the id and is sent verbatim as the
298
+ * turn's `config_overrides`.
299
+ *
300
+ * 🚨 **A RUN THE USER WATCHES STREAMS.** Every call takes `onText` and reports
301
+ * the accumulated answer as it arrives. A skeleton that sits until a run
302
+ * finishes is a spinner standing in for an answer; the caller renders the
303
+ * partial text instead.
292
304
  */
293
305
 
294
306
  /**
295
- * Which platform agent backs each capability. Every field is a DATABASE row id
296
- * supplied by the host; an omitted one disables exactly that capability.
307
+ * WHO fulfils one capability, as the host resolved it. Both halves travel
308
+ * together: an id alone is half an answer whenever the host's switching layer
309
+ * also decided settings for the job.
310
+ */
311
+ interface MessagingAgentIdentity {
312
+ /** The DATABASE agent row id. Never a name, never a prompt. */
313
+ readonly agentId: string;
314
+ /**
315
+ * The settings half, in LLMParams shape, sent verbatim as the turn's
316
+ * `config_overrides`. `null`/omitted = the agent's own settings stand.
317
+ */
318
+ readonly configOverrides?: MatrxJsonObject | null | undefined;
319
+ }
320
+ /**
321
+ * Which platform agent backs each capability. Every field is an identity the
322
+ * host injects; an omitted one disables exactly that capability.
297
323
  */
298
324
  interface MessagingAgents {
299
- readonly catchUp?: string | undefined;
300
- readonly summarize?: string | undefined;
301
- readonly actionItems?: string | undefined;
302
- readonly draftReply?: string | undefined;
325
+ readonly catchUp?: MessagingAgentIdentity | undefined;
326
+ readonly summarize?: MessagingAgentIdentity | undefined;
327
+ readonly actionItems?: MessagingAgentIdentity | undefined;
328
+ readonly draftReply?: MessagingAgentIdentity | undefined;
303
329
  }
304
330
  interface MessagingAiOptions {
305
331
  transport: MatrxTransport;
@@ -317,38 +343,44 @@ interface AiResult {
317
343
  readonly text: string;
318
344
  readonly conversationId: string | null;
319
345
  }
346
+ /** What every capability takes: the conversation, and how to watch the run. */
347
+ interface AiCallArgs {
348
+ conversationId: ConversationId;
349
+ messages: readonly Message[];
350
+ participants: readonly UserSummary[];
351
+ signal?: AbortSignal | undefined;
352
+ /** The accumulated answer so far, after every streamed chunk. */
353
+ onText?: ((fullText: string) => void) | undefined;
354
+ }
320
355
  interface MessagingAi {
321
356
  /** Which capabilities this host actually configured. Drives what the UI offers. */
322
357
  available(): readonly AiCapability[];
323
358
  isAvailable(capability: AiCapability): boolean;
324
- catchMeUp(args: {
325
- conversationId: ConversationId;
326
- messages: readonly Message[];
327
- participants: readonly UserSummary[];
359
+ catchMeUp(args: AiCallArgs & {
360
+ /**
361
+ * Exclusive cutoff — only messages after it are sent. `null` means the
362
+ * caller genuinely has no read mark and the whole window applies.
363
+ */
328
364
  since: string | null;
329
- signal?: AbortSignal;
330
365
  }): Promise<AiResult>;
331
- summarize(args: {
332
- conversationId: ConversationId;
333
- messages: readonly Message[];
334
- participants: readonly UserSummary[];
335
- signal?: AbortSignal;
336
- }): Promise<AiResult>;
337
- extractActionItems(args: {
338
- conversationId: ConversationId;
339
- messages: readonly Message[];
340
- participants: readonly UserSummary[];
341
- signal?: AbortSignal;
342
- }): Promise<AiResult>;
343
- draftReply(args: {
344
- conversationId: ConversationId;
345
- messages: readonly Message[];
346
- participants: readonly UserSummary[];
366
+ summarize(args: AiCallArgs): Promise<AiResult>;
367
+ extractActionItems(args: AiCallArgs): Promise<AiResult>;
368
+ draftReply(args: AiCallArgs & {
347
369
  /** What the human asked for, if anything — this IS a human utterance. */
348
370
  instruction?: string | undefined;
349
- signal?: AbortSignal;
350
371
  }): Promise<AiResult>;
351
372
  }
373
+ /**
374
+ * The exclusive cutoff "what did I miss" means, derived from what the store
375
+ * already knows: the message just BEFORE the first unread one. No unread
376
+ * messages, or a loaded window that does not reach back that far, means there
377
+ * is no honest cutoff — the whole window applies, and the caller says so by
378
+ * passing `null` rather than guessing a timestamp.
379
+ *
380
+ * Framework-free on purpose: a Redux or React Native consumer must not have to
381
+ * re-derive what "unread" means.
382
+ */
383
+ declare function unreadCutoff(messages: readonly Message[], unreadCount: number): string | null;
352
384
  declare function createMessagingAi(options: MessagingAiOptions): MessagingAi;
353
385
 
354
386
  /**
@@ -947,8 +979,14 @@ interface MessagingProviderProps {
947
979
  * the AI actions then do not render at all (never a dead button).
948
980
  */
949
981
  transport?: MatrxTransport | undefined;
950
- /** Which database agent backs each AI capability. */
982
+ /** Which database agent backs each AI capability, with its settings. */
951
983
  agents?: MessagingAgents | undefined;
984
+ /**
985
+ * How much transcript rides an AI call, in messages. The package's 200 is a
986
+ * starting value, not a taste: a host with a knob for it passes the resolved
987
+ * number so an organization can decide.
988
+ */
989
+ maxTranscriptMessages?: number | undefined;
952
990
  /** Handlers for actionable messages. Registered once per handler identity. */
953
991
  actions?: readonly ActionHandler<never>[] | undefined;
954
992
  /**
@@ -1051,6 +1089,14 @@ declare function useOnlineUserIds(conversationId: ConversationId | null): Readon
1051
1089
  interface UseMessagingAiResult {
1052
1090
  available: readonly AiCapability[];
1053
1091
  isRunning: boolean;
1092
+ /**
1093
+ * The answer as it arrives, while `isRunning`. A surface renders THIS, not a
1094
+ * skeleton: a placeholder that sits until a run finishes is a spinner
1095
+ * standing in for an answer. Empty string until the first chunk lands.
1096
+ */
1097
+ partialText: string;
1098
+ /** Which capability is running (or produced `result`). */
1099
+ activeCapability: AiCapability | null;
1054
1100
  result: AiResult | null;
1055
1101
  error: string | null;
1056
1102
  run: (capability: AiCapability, args?: {
@@ -1458,4 +1504,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
1458
1504
  /** Serialize picked references into a fence the platform's other readers accept. */
1459
1505
  declare function composeFence(references: readonly MatrxReference[]): string;
1460
1506
 
1461
- export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, AgentTag, type AiCapability, type AiResult, AlertIcon, type Attachment, Avatar, BotIcon, CheckIcon, ChevronLeftIcon, type ClientMessageId, ClockIcon, CloseIcon, Composer, type Conversation, type ConversationCursor, type ConversationId, ConversationList, type ConversationListProps, type ConversationRowWrapperProps, ConversationSkeleton, type ConversationSummary, type ConversationThread, type ConversationType, ConversationView, type ConversationViewProps, 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 MessagingAgents, type MessagingAi, type MessagingAiOptions, 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, type SchemaLike, SearchIcon, SendIcon, 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, createWebOutboxStorage, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, useComposer, useConversation, useConversations, useMessageAction, useMessagingAi, useMessagingHost, useMessagingSnapshot, useOnlineUserIds, useRequiredMessagingHost, useTypists };
1507
+ 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 Conversation, type ConversationCursor, type ConversationId, ConversationList, type ConversationListProps, type ConversationRowWrapperProps, ConversationSkeleton, type ConversationSummary, type ConversationThread, type ConversationType, ConversationView, type ConversationViewProps, 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 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, type SchemaLike, SearchIcon, SendIcon, 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, createWebOutboxStorage, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, unreadCutoff, useComposer, useConversation, useConversations, useMessageAction, useMessagingAi, useMessagingHost, useMessagingSnapshot, useOnlineUserIds, useRequiredMessagingHost, useTypists };
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactNode, ComponentType, SVGProps } from 'react';
2
- import { MatrxTransport } from '@ai-matrx/agents/matrx';
2
+ import { MatrxJsonObject, MatrxTransport } from '@ai-matrx/agents/matrx';
3
3
  import { RealtimeClientLike, RealtimeManager } from '@ai-matrx/realtime';
4
4
 
5
5
  /**
@@ -285,21 +285,47 @@ declare function createActionRegistry(): ActionRegistry;
285
285
  * every conversation it touches. Every call below sends `variables` and either
286
286
  * a short human-shaped `user_input` or none.
287
287
  *
288
- * 🚨 **AGENT DEFINITIONS LIVE IN THE DATABASE.** The package takes agent IDs as
289
- * injected identity. When an id is not configured the capability reports
290
- * `unavailable` WITH the remedy it never silently no-ops, and the UI hides
291
- * the action rather than offering a dead button (no dead ends).
288
+ * 🚨 **AGENT DEFINITIONS LIVE IN THE DATABASE.** The package takes an injected
289
+ * IDENTITY per capability the database agent id and the settings that came
290
+ * with it and nothing else. When an identity is not configured the capability
291
+ * reports `unavailable` WITH the remedy; it never silently no-ops, and the UI
292
+ * hides the action rather than offering a dead button (no dead ends).
293
+ *
294
+ * 🚨 **AN IDENTITY IS BOTH HALVES.** A host that resolves a capability's agent
295
+ * from its own switching layer resolves a PAIR: which agent, and the settings
296
+ * that layer decided for it. Taking only the id silently drops the settings
297
+ * half, so `configOverrides` rides with the id and is sent verbatim as the
298
+ * turn's `config_overrides`.
299
+ *
300
+ * 🚨 **A RUN THE USER WATCHES STREAMS.** Every call takes `onText` and reports
301
+ * the accumulated answer as it arrives. A skeleton that sits until a run
302
+ * finishes is a spinner standing in for an answer; the caller renders the
303
+ * partial text instead.
292
304
  */
293
305
 
294
306
  /**
295
- * Which platform agent backs each capability. Every field is a DATABASE row id
296
- * supplied by the host; an omitted one disables exactly that capability.
307
+ * WHO fulfils one capability, as the host resolved it. Both halves travel
308
+ * together: an id alone is half an answer whenever the host's switching layer
309
+ * also decided settings for the job.
310
+ */
311
+ interface MessagingAgentIdentity {
312
+ /** The DATABASE agent row id. Never a name, never a prompt. */
313
+ readonly agentId: string;
314
+ /**
315
+ * The settings half, in LLMParams shape, sent verbatim as the turn's
316
+ * `config_overrides`. `null`/omitted = the agent's own settings stand.
317
+ */
318
+ readonly configOverrides?: MatrxJsonObject | null | undefined;
319
+ }
320
+ /**
321
+ * Which platform agent backs each capability. Every field is an identity the
322
+ * host injects; an omitted one disables exactly that capability.
297
323
  */
298
324
  interface MessagingAgents {
299
- readonly catchUp?: string | undefined;
300
- readonly summarize?: string | undefined;
301
- readonly actionItems?: string | undefined;
302
- readonly draftReply?: string | undefined;
325
+ readonly catchUp?: MessagingAgentIdentity | undefined;
326
+ readonly summarize?: MessagingAgentIdentity | undefined;
327
+ readonly actionItems?: MessagingAgentIdentity | undefined;
328
+ readonly draftReply?: MessagingAgentIdentity | undefined;
303
329
  }
304
330
  interface MessagingAiOptions {
305
331
  transport: MatrxTransport;
@@ -317,38 +343,44 @@ interface AiResult {
317
343
  readonly text: string;
318
344
  readonly conversationId: string | null;
319
345
  }
346
+ /** What every capability takes: the conversation, and how to watch the run. */
347
+ interface AiCallArgs {
348
+ conversationId: ConversationId;
349
+ messages: readonly Message[];
350
+ participants: readonly UserSummary[];
351
+ signal?: AbortSignal | undefined;
352
+ /** The accumulated answer so far, after every streamed chunk. */
353
+ onText?: ((fullText: string) => void) | undefined;
354
+ }
320
355
  interface MessagingAi {
321
356
  /** Which capabilities this host actually configured. Drives what the UI offers. */
322
357
  available(): readonly AiCapability[];
323
358
  isAvailable(capability: AiCapability): boolean;
324
- catchMeUp(args: {
325
- conversationId: ConversationId;
326
- messages: readonly Message[];
327
- participants: readonly UserSummary[];
359
+ catchMeUp(args: AiCallArgs & {
360
+ /**
361
+ * Exclusive cutoff — only messages after it are sent. `null` means the
362
+ * caller genuinely has no read mark and the whole window applies.
363
+ */
328
364
  since: string | null;
329
- signal?: AbortSignal;
330
365
  }): Promise<AiResult>;
331
- summarize(args: {
332
- conversationId: ConversationId;
333
- messages: readonly Message[];
334
- participants: readonly UserSummary[];
335
- signal?: AbortSignal;
336
- }): Promise<AiResult>;
337
- extractActionItems(args: {
338
- conversationId: ConversationId;
339
- messages: readonly Message[];
340
- participants: readonly UserSummary[];
341
- signal?: AbortSignal;
342
- }): Promise<AiResult>;
343
- draftReply(args: {
344
- conversationId: ConversationId;
345
- messages: readonly Message[];
346
- participants: readonly UserSummary[];
366
+ summarize(args: AiCallArgs): Promise<AiResult>;
367
+ extractActionItems(args: AiCallArgs): Promise<AiResult>;
368
+ draftReply(args: AiCallArgs & {
347
369
  /** What the human asked for, if anything — this IS a human utterance. */
348
370
  instruction?: string | undefined;
349
- signal?: AbortSignal;
350
371
  }): Promise<AiResult>;
351
372
  }
373
+ /**
374
+ * The exclusive cutoff "what did I miss" means, derived from what the store
375
+ * already knows: the message just BEFORE the first unread one. No unread
376
+ * messages, or a loaded window that does not reach back that far, means there
377
+ * is no honest cutoff — the whole window applies, and the caller says so by
378
+ * passing `null` rather than guessing a timestamp.
379
+ *
380
+ * Framework-free on purpose: a Redux or React Native consumer must not have to
381
+ * re-derive what "unread" means.
382
+ */
383
+ declare function unreadCutoff(messages: readonly Message[], unreadCount: number): string | null;
352
384
  declare function createMessagingAi(options: MessagingAiOptions): MessagingAi;
353
385
 
354
386
  /**
@@ -947,8 +979,14 @@ interface MessagingProviderProps {
947
979
  * the AI actions then do not render at all (never a dead button).
948
980
  */
949
981
  transport?: MatrxTransport | undefined;
950
- /** Which database agent backs each AI capability. */
982
+ /** Which database agent backs each AI capability, with its settings. */
951
983
  agents?: MessagingAgents | undefined;
984
+ /**
985
+ * How much transcript rides an AI call, in messages. The package's 200 is a
986
+ * starting value, not a taste: a host with a knob for it passes the resolved
987
+ * number so an organization can decide.
988
+ */
989
+ maxTranscriptMessages?: number | undefined;
952
990
  /** Handlers for actionable messages. Registered once per handler identity. */
953
991
  actions?: readonly ActionHandler<never>[] | undefined;
954
992
  /**
@@ -1051,6 +1089,14 @@ declare function useOnlineUserIds(conversationId: ConversationId | null): Readon
1051
1089
  interface UseMessagingAiResult {
1052
1090
  available: readonly AiCapability[];
1053
1091
  isRunning: boolean;
1092
+ /**
1093
+ * The answer as it arrives, while `isRunning`. A surface renders THIS, not a
1094
+ * skeleton: a placeholder that sits until a run finishes is a spinner
1095
+ * standing in for an answer. Empty string until the first chunk lands.
1096
+ */
1097
+ partialText: string;
1098
+ /** Which capability is running (or produced `result`). */
1099
+ activeCapability: AiCapability | null;
1054
1100
  result: AiResult | null;
1055
1101
  error: string | null;
1056
1102
  run: (capability: AiCapability, args?: {
@@ -1458,4 +1504,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
1458
1504
  /** Serialize picked references into a fence the platform's other readers accept. */
1459
1505
  declare function composeFence(references: readonly MatrxReference[]): string;
1460
1506
 
1461
- export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, AgentTag, type AiCapability, type AiResult, AlertIcon, type Attachment, Avatar, BotIcon, CheckIcon, ChevronLeftIcon, type ClientMessageId, ClockIcon, CloseIcon, Composer, type Conversation, type ConversationCursor, type ConversationId, ConversationList, type ConversationListProps, type ConversationRowWrapperProps, ConversationSkeleton, type ConversationSummary, type ConversationThread, type ConversationType, ConversationView, type ConversationViewProps, 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 MessagingAgents, type MessagingAi, type MessagingAiOptions, 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, type SchemaLike, SearchIcon, SendIcon, 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, createWebOutboxStorage, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, useComposer, useConversation, useConversations, useMessageAction, useMessagingAi, useMessagingHost, useMessagingSnapshot, useOnlineUserIds, useRequiredMessagingHost, useTypists };
1507
+ 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 Conversation, type ConversationCursor, type ConversationId, ConversationList, type ConversationListProps, type ConversationRowWrapperProps, ConversationSkeleton, type ConversationSummary, type ConversationThread, type ConversationType, ConversationView, type ConversationViewProps, 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 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, type SchemaLike, SearchIcon, SendIcon, 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, createWebOutboxStorage, extractReferences, formatConversationTime, formatDateSeparator, formatLastSeen, formatMessageTime, formatTypists, groupMessages, inboxTopic, invalidResponse, isSameDay, messagingClientId, normalizeMessagingError, optimisticMessage, participantNames, projectConversationSummary, projectMessage, projectMessageAction, projectParticipantRole, projectUserSummary, resolveActor, splitText, summarizeText, unreadCutoff, useComposer, useConversation, useConversations, useMessageAction, useMessagingAi, useMessagingHost, useMessagingSnapshot, useOnlineUserIds, useRequiredMessagingHost, useTypists };
package/dist/react.js CHANGED
@@ -261,6 +261,12 @@ ${JSON.stringify(references, null, 2)}
261
261
  }
262
262
 
263
263
  // src/core/ai.ts
264
+ function unreadCutoff(messages, unreadCount) {
265
+ if (unreadCount <= 0) return null;
266
+ const index = messages.length - unreadCount - 1;
267
+ if (index < 0) return null;
268
+ return messages[index]?.createdAt ?? null;
269
+ }
264
270
  function nameOf(participants, senderId) {
265
271
  return participants.find((p) => p.userId === senderId)?.displayName ?? senderId;
266
272
  }
@@ -281,22 +287,23 @@ function buildTranscript(messages, participants, limit, since) {
281
287
  }
282
288
  function createMessagingAi(options) {
283
289
  const limit = options.maxTranscriptMessages ?? 200;
284
- function agentFor(capability) {
285
- const agentId = options.agents[capability];
286
- if (typeof agentId !== "string" || agentId.length === 0) {
290
+ function identityFor(capability) {
291
+ const identity = options.agents[capability];
292
+ if (identity === void 0 || identity.agentId.length === 0) {
287
293
  throw new MessagingError(
288
294
  "misconfigured",
289
295
  `Messaging AI capability "${capability}" has no agent configured`,
290
- `Pass agents={{ ${capability}: "<agent-id>" }} to <MessagingProvider>. Agent definitions live in the database, never in this package \u2014 the id is the only part a host injects. Until then the UI hides this action rather than offering a button that cannot work.`
296
+ `Pass agents={{ ${capability}: { agentId: "<agent-id>" } }} to <MessagingProvider>. Agent definitions live in the database, never in this package \u2014 the identity is the only part a host injects. Until then the UI hides this action rather than offering a button that cannot work.`
291
297
  );
292
298
  }
293
- return agentId;
299
+ return identity;
294
300
  }
295
- async function run(capability, variables, userInput, signal) {
296
- const agentId = agentFor(capability);
301
+ async function run(capability, variables, userInput, signal, onText) {
302
+ const identity = identityFor(capability);
303
+ const overrides = identity.configOverrides;
297
304
  const completed = await runAgentToCompletion(
298
305
  options.transport,
299
- agentId,
306
+ identity.agentId,
300
307
  {
301
308
  ...newEphemeralConversationStart(),
302
309
  organization_id: options.organizationId,
@@ -305,9 +312,15 @@ function createMessagingAi(options) {
305
312
  initiation: "user",
306
313
  // THE USER-INPUT LAW: structured content is NEVER here.
307
314
  ...userInput !== null ? { user_input: userInput } : {},
315
+ // The settings half of the injected identity, verbatim. An absent one
316
+ // is OMITTED rather than sent as null: the agent's own settings stand.
317
+ ...overrides != null ? { config_overrides: overrides } : {},
308
318
  variables
309
319
  },
310
- signal !== void 0 ? { signal } : {}
320
+ {
321
+ ...signal !== void 0 ? { signal } : {},
322
+ ...onText !== void 0 ? { onChunk: onText } : {}
323
+ }
311
324
  );
312
325
  return {
313
326
  capability,
@@ -340,27 +353,26 @@ function createMessagingAi(options) {
340
353
  ...args.since != null ? { unread_since: args.since } : {}
341
354
  };
342
355
  }
356
+ function configured(capability) {
357
+ const identity = options.agents[capability];
358
+ return identity !== void 0 && identity.agentId.length > 0;
359
+ }
343
360
  return {
344
361
  available: () => ["catchUp", "summarize", "actionItems", "draftReply"].filter(
345
- (capability) => {
346
- const id = options.agents[capability];
347
- return typeof id === "string" && id.length > 0;
348
- }
362
+ configured
349
363
  ),
350
- isAvailable(capability) {
351
- const id = options.agents[capability];
352
- return typeof id === "string" && id.length > 0;
353
- },
354
- catchMeUp: (args) => run("catchUp", variablesFor(args), null, args.signal),
355
- summarize: (args) => run("summarize", variablesFor(args), null, args.signal),
356
- extractActionItems: (args) => run("actionItems", variablesFor(args), null, args.signal),
364
+ isAvailable: configured,
365
+ catchMeUp: (args) => run("catchUp", variablesFor(args), null, args.signal, args.onText),
366
+ summarize: (args) => run("summarize", variablesFor(args), null, args.signal, args.onText),
367
+ extractActionItems: (args) => run("actionItems", variablesFor(args), null, args.signal, args.onText),
357
368
  draftReply: (args) => run(
358
369
  "draftReply",
359
370
  variablesFor(args),
360
371
  // The ONE genuine human utterance in this module: what the user asked
361
372
  // the drafter for. Everything else rode `variables`.
362
373
  args.instruction !== void 0 && args.instruction.trim().length > 0 ? args.instruction.trim() : null,
363
- args.signal
374
+ args.signal,
375
+ args.onText
364
376
  )
365
377
  };
366
378
  }
@@ -1804,14 +1816,16 @@ function MessagingRuntime(props) {
1804
1816
  }, [engine]);
1805
1817
  const transport = props.transport;
1806
1818
  const agents = props.agents;
1819
+ const maxTranscriptMessages = props.maxTranscriptMessages;
1807
1820
  const ai = useMemo(() => {
1808
1821
  if (transport === void 0 || agents === void 0 || !ready) return null;
1809
1822
  return createMessagingAi({
1810
1823
  transport,
1811
1824
  organizationId,
1812
- agents
1825
+ agents,
1826
+ ...maxTranscriptMessages !== void 0 ? { maxTranscriptMessages } : {}
1813
1827
  });
1814
- }, [transport, agents, ready, organizationId]);
1828
+ }, [transport, agents, ready, organizationId, maxTranscriptMessages]);
1815
1829
  const renderers = props.actionRenderers;
1816
1830
  const rendererMap = useMemo(() => {
1817
1831
  const map = /* @__PURE__ */ new Map();
@@ -2139,6 +2153,10 @@ function useMessagingAi(conversationId) {
2139
2153
  const host = useMessagingHost();
2140
2154
  const conversation = useConversation(conversationId);
2141
2155
  const [isRunning, setRunning] = useState(false);
2156
+ const [partialText, setPartialText] = useState("");
2157
+ const [activeCapability, setActiveCapability] = useState(
2158
+ null
2159
+ );
2142
2160
  const [result, setResult] = useState(null);
2143
2161
  const [error, setError] = useState(null);
2144
2162
  const abortRef = useRef2(null);
@@ -2152,11 +2170,15 @@ function useMessagingAi(conversationId) {
2152
2170
  return {
2153
2171
  available: ai?.available() ?? [],
2154
2172
  isRunning,
2173
+ partialText,
2174
+ activeCapability,
2155
2175
  result,
2156
2176
  error,
2157
2177
  clear: () => {
2158
2178
  setResult(null);
2159
2179
  setError(null);
2180
+ setPartialText("");
2181
+ setActiveCapability(null);
2160
2182
  },
2161
2183
  run: (capability, args = {}) => {
2162
2184
  if (ai === null || conversationId === null) return;
@@ -2165,22 +2187,32 @@ function useMessagingAi(conversationId) {
2165
2187
  abortRef.current = controller;
2166
2188
  setRunning(true);
2167
2189
  setError(null);
2190
+ setResult(null);
2191
+ setPartialText("");
2192
+ setActiveCapability(capability);
2168
2193
  const base = {
2169
2194
  conversationId,
2170
2195
  messages: conversation.messages,
2171
2196
  participants: conversation.participants,
2172
- signal: controller.signal
2197
+ signal: controller.signal,
2198
+ // Live progress. Aborted runs stop painting immediately — a cancelled
2199
+ // answer must not keep growing on screen.
2200
+ onText: (text) => {
2201
+ if (!controller.signal.aborted) setPartialText(text);
2202
+ }
2173
2203
  };
2174
2204
  const call = () => {
2175
2205
  switch (capability) {
2176
- case "catchUp": {
2177
- const summary = conversation.summary;
2178
- const self = summary?.participants.find(
2179
- (participant) => participant.userId === host?.identity.userId
2180
- );
2181
- void self;
2182
- return ai.catchMeUp({ ...base, since: null });
2183
- }
2206
+ case "catchUp":
2207
+ return ai.catchMeUp({
2208
+ ...base,
2209
+ // "What did I miss" is about the UNREAD tail. Sending the whole
2210
+ // window made this capability a second Summarize.
2211
+ since: unreadCutoff(
2212
+ conversation.messages,
2213
+ conversation.summary?.unreadCount ?? 0
2214
+ )
2215
+ });
2184
2216
  case "summarize":
2185
2217
  return ai.summarize(base);
2186
2218
  case "actionItems":
@@ -2703,7 +2735,16 @@ function ConversationView(props) {
2703
2735
  },
2704
2736
  capability
2705
2737
  )) }) : null,
2706
- ai.isRunning ? /* @__PURE__ */ jsx4("p", { className: "mx-msg__ai-output", "aria-busy": "true", children: /* @__PURE__ */ jsx4("span", { className: "mx-msg__skeleton", style: { display: "block", height: 11, width: "72%" } }) }) : ai.error !== null ? /* @__PURE__ */ jsx4("p", { className: "mx-msg__ai-output", style: { color: "var(--mx-msg-danger)" }, children: ai.error }) : ai.result !== null ? /* @__PURE__ */ jsxs2("p", { className: "mx-msg__ai-output", children: [
2738
+ ai.isRunning ? /* @__PURE__ */ jsx4("p", { className: "mx-msg__ai-output", "aria-busy": "true", "aria-live": "polite", children: ai.partialText.length > 0 ? ai.partialText : /* @__PURE__ */ jsxs2(Fragment, { children: [
2739
+ /* @__PURE__ */ jsx4("span", { className: "mx-msg__ai-output-label", children: ai.activeCapability !== null ? `${AI_LABELS[ai.activeCapability]}\u2026` : "Working\u2026" }),
2740
+ /* @__PURE__ */ jsx4(
2741
+ "span",
2742
+ {
2743
+ className: "mx-msg__skeleton",
2744
+ style: { display: "block", height: 11, width: "72%" }
2745
+ }
2746
+ )
2747
+ ] }) }) : ai.error !== null ? /* @__PURE__ */ jsx4("p", { className: "mx-msg__ai-output", style: { color: "var(--mx-msg-danger)" }, children: ai.error }) : ai.result !== null ? /* @__PURE__ */ jsxs2("p", { className: "mx-msg__ai-output", children: [
2707
2748
  ai.result.text,
2708
2749
  /* @__PURE__ */ jsx4(
2709
2750
  "button",
@@ -3106,6 +3147,7 @@ export {
3106
3147
  resolveActor,
3107
3148
  splitText,
3108
3149
  summarizeText,
3150
+ unreadCutoff,
3109
3151
  useComposer,
3110
3152
  useConversation,
3111
3153
  useConversations,