@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/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { MatrxTransport } from '@ai-matrx/agents/matrx';
1
+ import { MatrxJsonObject, MatrxTransport } from '@ai-matrx/agents/matrx';
2
2
  import { RealtimeClientLike, RealtimeManager } from '@ai-matrx/realtime';
3
3
 
4
4
  /**
@@ -309,21 +309,47 @@ declare function resolveActor(message: Message, sender: UserSummary | null): Act
309
309
  * every conversation it touches. Every call below sends `variables` and either
310
310
  * a short human-shaped `user_input` or none.
311
311
  *
312
- * 🚨 **AGENT DEFINITIONS LIVE IN THE DATABASE.** The package takes agent IDs as
313
- * injected identity. When an id is not configured the capability reports
314
- * `unavailable` WITH the remedy it never silently no-ops, and the UI hides
315
- * the action rather than offering a dead button (no dead ends).
312
+ * 🚨 **AGENT DEFINITIONS LIVE IN THE DATABASE.** The package takes an injected
313
+ * IDENTITY per capability the database agent id and the settings that came
314
+ * with it and nothing else. When an identity is not configured the capability
315
+ * reports `unavailable` WITH the remedy; it never silently no-ops, and the UI
316
+ * hides the action rather than offering a dead button (no dead ends).
317
+ *
318
+ * 🚨 **AN IDENTITY IS BOTH HALVES.** A host that resolves a capability's agent
319
+ * from its own switching layer resolves a PAIR: which agent, and the settings
320
+ * that layer decided for it. Taking only the id silently drops the settings
321
+ * half, so `configOverrides` rides with the id and is sent verbatim as the
322
+ * turn's `config_overrides`.
323
+ *
324
+ * 🚨 **A RUN THE USER WATCHES STREAMS.** Every call takes `onText` and reports
325
+ * the accumulated answer as it arrives. A skeleton that sits until a run
326
+ * finishes is a spinner standing in for an answer; the caller renders the
327
+ * partial text instead.
316
328
  */
317
329
 
318
330
  /**
319
- * Which platform agent backs each capability. Every field is a DATABASE row id
320
- * supplied by the host; an omitted one disables exactly that capability.
331
+ * WHO fulfils one capability, as the host resolved it. Both halves travel
332
+ * together: an id alone is half an answer whenever the host's switching layer
333
+ * also decided settings for the job.
334
+ */
335
+ interface MessagingAgentIdentity {
336
+ /** The DATABASE agent row id. Never a name, never a prompt. */
337
+ readonly agentId: string;
338
+ /**
339
+ * The settings half, in LLMParams shape, sent verbatim as the turn's
340
+ * `config_overrides`. `null`/omitted = the agent's own settings stand.
341
+ */
342
+ readonly configOverrides?: MatrxJsonObject | null | undefined;
343
+ }
344
+ /**
345
+ * Which platform agent backs each capability. Every field is an identity the
346
+ * host injects; an omitted one disables exactly that capability.
321
347
  */
322
348
  interface MessagingAgents {
323
- readonly catchUp?: string | undefined;
324
- readonly summarize?: string | undefined;
325
- readonly actionItems?: string | undefined;
326
- readonly draftReply?: string | undefined;
349
+ readonly catchUp?: MessagingAgentIdentity | undefined;
350
+ readonly summarize?: MessagingAgentIdentity | undefined;
351
+ readonly actionItems?: MessagingAgentIdentity | undefined;
352
+ readonly draftReply?: MessagingAgentIdentity | undefined;
327
353
  }
328
354
  interface MessagingAiOptions {
329
355
  transport: MatrxTransport;
@@ -341,38 +367,44 @@ interface AiResult {
341
367
  readonly text: string;
342
368
  readonly conversationId: string | null;
343
369
  }
370
+ /** What every capability takes: the conversation, and how to watch the run. */
371
+ interface AiCallArgs {
372
+ conversationId: ConversationId;
373
+ messages: readonly Message[];
374
+ participants: readonly UserSummary[];
375
+ signal?: AbortSignal | undefined;
376
+ /** The accumulated answer so far, after every streamed chunk. */
377
+ onText?: ((fullText: string) => void) | undefined;
378
+ }
344
379
  interface MessagingAi {
345
380
  /** Which capabilities this host actually configured. Drives what the UI offers. */
346
381
  available(): readonly AiCapability[];
347
382
  isAvailable(capability: AiCapability): boolean;
348
- catchMeUp(args: {
349
- conversationId: ConversationId;
350
- messages: readonly Message[];
351
- participants: readonly UserSummary[];
383
+ catchMeUp(args: AiCallArgs & {
384
+ /**
385
+ * Exclusive cutoff — only messages after it are sent. `null` means the
386
+ * caller genuinely has no read mark and the whole window applies.
387
+ */
352
388
  since: string | null;
353
- signal?: AbortSignal;
354
- }): Promise<AiResult>;
355
- summarize(args: {
356
- conversationId: ConversationId;
357
- messages: readonly Message[];
358
- participants: readonly UserSummary[];
359
- signal?: AbortSignal;
360
- }): Promise<AiResult>;
361
- extractActionItems(args: {
362
- conversationId: ConversationId;
363
- messages: readonly Message[];
364
- participants: readonly UserSummary[];
365
- signal?: AbortSignal;
366
389
  }): Promise<AiResult>;
367
- draftReply(args: {
368
- conversationId: ConversationId;
369
- messages: readonly Message[];
370
- participants: readonly UserSummary[];
390
+ summarize(args: AiCallArgs): Promise<AiResult>;
391
+ extractActionItems(args: AiCallArgs): Promise<AiResult>;
392
+ draftReply(args: AiCallArgs & {
371
393
  /** What the human asked for, if anything — this IS a human utterance. */
372
394
  instruction?: string | undefined;
373
- signal?: AbortSignal;
374
395
  }): Promise<AiResult>;
375
396
  }
397
+ /**
398
+ * The exclusive cutoff "what did I miss" means, derived from what the store
399
+ * already knows: the message just BEFORE the first unread one. No unread
400
+ * messages, or a loaded window that does not reach back that far, means there
401
+ * is no honest cutoff — the whole window applies, and the caller says so by
402
+ * passing `null` rather than guessing a timestamp.
403
+ *
404
+ * Framework-free on purpose: a Redux or React Native consumer must not have to
405
+ * re-derive what "unread" means.
406
+ */
407
+ declare function unreadCutoff(messages: readonly Message[], unreadCount: number): string | null;
376
408
  declare function createMessagingAi(options: MessagingAiOptions): MessagingAi;
377
409
 
378
410
  /**
@@ -1077,4 +1109,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
1077
1109
  /** Serialize picked references into a fence the platform's other readers accept. */
1078
1110
  declare function composeFence(references: readonly MatrxReference[]): string;
1079
1111
 
1080
- export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, type AiCapability, type AiResult, type Attachment, type ClientMessageId, type Conversation, type ConversationCursor, type ConversationId, type ConversationSummary, type ConversationThread, type ConversationType, type DeliveryState, type DraftMessage, type EngineDiagnostic, type JsonObject, type JsonValue, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingIdentity, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, type Participant, type ParticipantRole, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, type RepositoryOptions, type SchemaLike, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, 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 };
1112
+ export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, type AiCallArgs, type AiCapability, type AiResult, type Attachment, type ClientMessageId, type Conversation, type ConversationCursor, type ConversationId, type ConversationSummary, type ConversationThread, type ConversationType, type DeliveryState, type DraftMessage, type EngineDiagnostic, type JsonObject, type JsonValue, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingIdentity, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, type Participant, type ParticipantRole, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, type RepositoryOptions, type SchemaLike, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, 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 };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { MatrxTransport } from '@ai-matrx/agents/matrx';
1
+ import { MatrxJsonObject, MatrxTransport } from '@ai-matrx/agents/matrx';
2
2
  import { RealtimeClientLike, RealtimeManager } from '@ai-matrx/realtime';
3
3
 
4
4
  /**
@@ -309,21 +309,47 @@ declare function resolveActor(message: Message, sender: UserSummary | null): Act
309
309
  * every conversation it touches. Every call below sends `variables` and either
310
310
  * a short human-shaped `user_input` or none.
311
311
  *
312
- * 🚨 **AGENT DEFINITIONS LIVE IN THE DATABASE.** The package takes agent IDs as
313
- * injected identity. When an id is not configured the capability reports
314
- * `unavailable` WITH the remedy it never silently no-ops, and the UI hides
315
- * the action rather than offering a dead button (no dead ends).
312
+ * 🚨 **AGENT DEFINITIONS LIVE IN THE DATABASE.** The package takes an injected
313
+ * IDENTITY per capability the database agent id and the settings that came
314
+ * with it and nothing else. When an identity is not configured the capability
315
+ * reports `unavailable` WITH the remedy; it never silently no-ops, and the UI
316
+ * hides the action rather than offering a dead button (no dead ends).
317
+ *
318
+ * 🚨 **AN IDENTITY IS BOTH HALVES.** A host that resolves a capability's agent
319
+ * from its own switching layer resolves a PAIR: which agent, and the settings
320
+ * that layer decided for it. Taking only the id silently drops the settings
321
+ * half, so `configOverrides` rides with the id and is sent verbatim as the
322
+ * turn's `config_overrides`.
323
+ *
324
+ * 🚨 **A RUN THE USER WATCHES STREAMS.** Every call takes `onText` and reports
325
+ * the accumulated answer as it arrives. A skeleton that sits until a run
326
+ * finishes is a spinner standing in for an answer; the caller renders the
327
+ * partial text instead.
316
328
  */
317
329
 
318
330
  /**
319
- * Which platform agent backs each capability. Every field is a DATABASE row id
320
- * supplied by the host; an omitted one disables exactly that capability.
331
+ * WHO fulfils one capability, as the host resolved it. Both halves travel
332
+ * together: an id alone is half an answer whenever the host's switching layer
333
+ * also decided settings for the job.
334
+ */
335
+ interface MessagingAgentIdentity {
336
+ /** The DATABASE agent row id. Never a name, never a prompt. */
337
+ readonly agentId: string;
338
+ /**
339
+ * The settings half, in LLMParams shape, sent verbatim as the turn's
340
+ * `config_overrides`. `null`/omitted = the agent's own settings stand.
341
+ */
342
+ readonly configOverrides?: MatrxJsonObject | null | undefined;
343
+ }
344
+ /**
345
+ * Which platform agent backs each capability. Every field is an identity the
346
+ * host injects; an omitted one disables exactly that capability.
321
347
  */
322
348
  interface MessagingAgents {
323
- readonly catchUp?: string | undefined;
324
- readonly summarize?: string | undefined;
325
- readonly actionItems?: string | undefined;
326
- readonly draftReply?: string | undefined;
349
+ readonly catchUp?: MessagingAgentIdentity | undefined;
350
+ readonly summarize?: MessagingAgentIdentity | undefined;
351
+ readonly actionItems?: MessagingAgentIdentity | undefined;
352
+ readonly draftReply?: MessagingAgentIdentity | undefined;
327
353
  }
328
354
  interface MessagingAiOptions {
329
355
  transport: MatrxTransport;
@@ -341,38 +367,44 @@ interface AiResult {
341
367
  readonly text: string;
342
368
  readonly conversationId: string | null;
343
369
  }
370
+ /** What every capability takes: the conversation, and how to watch the run. */
371
+ interface AiCallArgs {
372
+ conversationId: ConversationId;
373
+ messages: readonly Message[];
374
+ participants: readonly UserSummary[];
375
+ signal?: AbortSignal | undefined;
376
+ /** The accumulated answer so far, after every streamed chunk. */
377
+ onText?: ((fullText: string) => void) | undefined;
378
+ }
344
379
  interface MessagingAi {
345
380
  /** Which capabilities this host actually configured. Drives what the UI offers. */
346
381
  available(): readonly AiCapability[];
347
382
  isAvailable(capability: AiCapability): boolean;
348
- catchMeUp(args: {
349
- conversationId: ConversationId;
350
- messages: readonly Message[];
351
- participants: readonly UserSummary[];
383
+ catchMeUp(args: AiCallArgs & {
384
+ /**
385
+ * Exclusive cutoff — only messages after it are sent. `null` means the
386
+ * caller genuinely has no read mark and the whole window applies.
387
+ */
352
388
  since: string | null;
353
- signal?: AbortSignal;
354
- }): Promise<AiResult>;
355
- summarize(args: {
356
- conversationId: ConversationId;
357
- messages: readonly Message[];
358
- participants: readonly UserSummary[];
359
- signal?: AbortSignal;
360
- }): Promise<AiResult>;
361
- extractActionItems(args: {
362
- conversationId: ConversationId;
363
- messages: readonly Message[];
364
- participants: readonly UserSummary[];
365
- signal?: AbortSignal;
366
389
  }): Promise<AiResult>;
367
- draftReply(args: {
368
- conversationId: ConversationId;
369
- messages: readonly Message[];
370
- participants: readonly UserSummary[];
390
+ summarize(args: AiCallArgs): Promise<AiResult>;
391
+ extractActionItems(args: AiCallArgs): Promise<AiResult>;
392
+ draftReply(args: AiCallArgs & {
371
393
  /** What the human asked for, if anything — this IS a human utterance. */
372
394
  instruction?: string | undefined;
373
- signal?: AbortSignal;
374
395
  }): Promise<AiResult>;
375
396
  }
397
+ /**
398
+ * The exclusive cutoff "what did I miss" means, derived from what the store
399
+ * already knows: the message just BEFORE the first unread one. No unread
400
+ * messages, or a loaded window that does not reach back that far, means there
401
+ * is no honest cutoff — the whole window applies, and the caller says so by
402
+ * passing `null` rather than guessing a timestamp.
403
+ *
404
+ * Framework-free on purpose: a Redux or React Native consumer must not have to
405
+ * re-derive what "unread" means.
406
+ */
407
+ declare function unreadCutoff(messages: readonly Message[], unreadCount: number): string | null;
376
408
  declare function createMessagingAi(options: MessagingAiOptions): MessagingAi;
377
409
 
378
410
  /**
@@ -1077,4 +1109,4 @@ declare function summarizeText(content: string, maxLength?: number): string;
1077
1109
  /** Serialize picked references into a fence the platform's other readers accept. */
1078
1110
  declare function composeFence(references: readonly MatrxReference[]): string;
1079
1111
 
1080
- export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, type AiCapability, type AiResult, type Attachment, type ClientMessageId, type Conversation, type ConversationCursor, type ConversationId, type ConversationSummary, type ConversationThread, type ConversationType, type DeliveryState, type DraftMessage, type EngineDiagnostic, type JsonObject, type JsonValue, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingIdentity, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, type Participant, type ParticipantRole, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, type RepositoryOptions, type SchemaLike, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, 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 };
1112
+ export { type ActionChoice, type ActionContext, type ActionHandler, type ActionOutcome, type ActionReceipt, type ActionRegistry, type ActorPresentation, type AiCallArgs, type AiCapability, type AiResult, type Attachment, type ClientMessageId, type Conversation, type ConversationCursor, type ConversationId, type ConversationSummary, type ConversationThread, type ConversationType, type DeliveryState, type DraftMessage, type EngineDiagnostic, type JsonObject, type JsonValue, MESSAGING_EVENTS, MESSAGING_RPC_SCHEMA, MESSAGING_SCHEMA, type MatrxReference, type Message, type MessageAction, type MessageCursor, type MessageGroup, type MessageId, type MessageKind, type MessagingAgentIdentity, type MessagingAgents, type MessagingAi, type MessagingAiOptions, type MessagingEngine, type MessagingEngineOptions, MessagingError, type MessagingErrorCode, type MessagingIdentity, type MessagingRepository, type MessagingSnapshot, type MessagingStore, type MessagingSupabaseClient, type MessagingSupabaseInternal, type OrganizationId, type Outbox, type OutboxEntry, type OutboxOptions, type OutboxStorage, type Page, type Participant, type ParticipantRole, type PostgrestFilterLike, type PostgrestLikeResponse, type PostgrestTableLike, RPCS, type ReadCache, type ReadCacheOptions, type RepositoryOptions, type SchemaLike, type SessionResolver, type SupabaseLike, TABLES, type TextSegment, type UserId, type UserSummary, 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 };
package/dist/index.js CHANGED
@@ -291,6 +291,12 @@ ${JSON.stringify(references, null, 2)}
291
291
  }
292
292
 
293
293
  // src/core/ai.ts
294
+ function unreadCutoff(messages, unreadCount) {
295
+ if (unreadCount <= 0) return null;
296
+ const index = messages.length - unreadCount - 1;
297
+ if (index < 0) return null;
298
+ return messages[index]?.createdAt ?? null;
299
+ }
294
300
  function nameOf(participants, senderId) {
295
301
  return participants.find((p) => p.userId === senderId)?.displayName ?? senderId;
296
302
  }
@@ -311,22 +317,23 @@ function buildTranscript(messages, participants, limit, since) {
311
317
  }
312
318
  function createMessagingAi(options) {
313
319
  const limit = options.maxTranscriptMessages ?? 200;
314
- function agentFor(capability) {
315
- const agentId = options.agents[capability];
316
- if (typeof agentId !== "string" || agentId.length === 0) {
320
+ function identityFor(capability) {
321
+ const identity = options.agents[capability];
322
+ if (identity === void 0 || identity.agentId.length === 0) {
317
323
  throw new MessagingError(
318
324
  "misconfigured",
319
325
  `Messaging AI capability "${capability}" has no agent configured`,
320
- `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.`
326
+ `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.`
321
327
  );
322
328
  }
323
- return agentId;
329
+ return identity;
324
330
  }
325
- async function run(capability, variables, userInput, signal) {
326
- const agentId = agentFor(capability);
331
+ async function run(capability, variables, userInput, signal, onText) {
332
+ const identity = identityFor(capability);
333
+ const overrides = identity.configOverrides;
327
334
  const completed = await runAgentToCompletion(
328
335
  options.transport,
329
- agentId,
336
+ identity.agentId,
330
337
  {
331
338
  ...newEphemeralConversationStart(),
332
339
  organization_id: options.organizationId,
@@ -335,9 +342,15 @@ function createMessagingAi(options) {
335
342
  initiation: "user",
336
343
  // THE USER-INPUT LAW: structured content is NEVER here.
337
344
  ...userInput !== null ? { user_input: userInput } : {},
345
+ // The settings half of the injected identity, verbatim. An absent one
346
+ // is OMITTED rather than sent as null: the agent's own settings stand.
347
+ ...overrides != null ? { config_overrides: overrides } : {},
338
348
  variables
339
349
  },
340
- signal !== void 0 ? { signal } : {}
350
+ {
351
+ ...signal !== void 0 ? { signal } : {},
352
+ ...onText !== void 0 ? { onChunk: onText } : {}
353
+ }
341
354
  );
342
355
  return {
343
356
  capability,
@@ -370,27 +383,26 @@ function createMessagingAi(options) {
370
383
  ...args.since != null ? { unread_since: args.since } : {}
371
384
  };
372
385
  }
386
+ function configured(capability) {
387
+ const identity = options.agents[capability];
388
+ return identity !== void 0 && identity.agentId.length > 0;
389
+ }
373
390
  return {
374
391
  available: () => ["catchUp", "summarize", "actionItems", "draftReply"].filter(
375
- (capability) => {
376
- const id = options.agents[capability];
377
- return typeof id === "string" && id.length > 0;
378
- }
392
+ configured
379
393
  ),
380
- isAvailable(capability) {
381
- const id = options.agents[capability];
382
- return typeof id === "string" && id.length > 0;
383
- },
384
- catchMeUp: (args) => run("catchUp", variablesFor(args), null, args.signal),
385
- summarize: (args) => run("summarize", variablesFor(args), null, args.signal),
386
- extractActionItems: (args) => run("actionItems", variablesFor(args), null, args.signal),
394
+ isAvailable: configured,
395
+ catchMeUp: (args) => run("catchUp", variablesFor(args), null, args.signal, args.onText),
396
+ summarize: (args) => run("summarize", variablesFor(args), null, args.signal, args.onText),
397
+ extractActionItems: (args) => run("actionItems", variablesFor(args), null, args.signal, args.onText),
387
398
  draftReply: (args) => run(
388
399
  "draftReply",
389
400
  variablesFor(args),
390
401
  // The ONE genuine human utterance in this module: what the user asked
391
402
  // the drafter for. Everything else rode `variables`.
392
403
  args.instruction !== void 0 && args.instruction.trim().length > 0 ? args.instruction.trim() : null,
393
- args.signal
404
+ args.signal,
405
+ args.onText
394
406
  )
395
407
  };
396
408
  }
@@ -1871,6 +1883,7 @@ export {
1871
1883
  projectUserSummary,
1872
1884
  resolveActor,
1873
1885
  splitText,
1874
- summarizeText
1886
+ summarizeText,
1887
+ unreadCutoff
1875
1888
  };
1876
1889
  //# sourceMappingURL=index.js.map