@ai-matrx/messaging 0.10.1 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.cjs CHANGED
@@ -73,6 +73,7 @@ __export(react_exports, {
73
73
  createOutbox: () => createOutbox,
74
74
  createReadCache: () => createReadCache,
75
75
  createWebOutboxStorage: () => createWebOutboxStorage,
76
+ effectiveActorKey: () => effectiveActorKey,
76
77
  extractReferences: () => extractReferences,
77
78
  formatConversationTime: () => formatConversationTime,
78
79
  formatDateSeparator: () => formatDateSeparator,
@@ -2048,18 +2049,20 @@ function groupMessages(messages, args = {}) {
2048
2049
  let current = null;
2049
2050
  let previousDay = null;
2050
2051
  for (const message of messages) {
2052
+ const actorKey = args.actorKey?.(message) ?? `principal:${message.senderId}`;
2051
2053
  const day = message.createdAt.slice(0, 10);
2052
2054
  const startsNewDay = day !== previousDay;
2053
2055
  previousDay = day;
2054
2056
  const last = current?.messages.at(-1);
2055
2057
  const withinWindow = last !== void 0 && Math.abs(Date.parse(message.createdAt) - Date.parse(last.createdAt)) <= windowMs;
2056
- if (current !== null && current.senderId === message.senderId && withinWindow && !startsNewDay) {
2058
+ if (current !== null && current.senderId === message.senderId && current.actorKey === actorKey && withinWindow && !startsNewDay) {
2057
2059
  current.messages.push(message);
2058
2060
  continue;
2059
2061
  }
2060
2062
  if (current !== null) groups.push(current);
2061
2063
  current = {
2062
2064
  senderId: message.senderId,
2065
+ actorKey,
2063
2066
  messages: [message],
2064
2067
  dateSeparator: startsNewDay ? formatDateSeparator(message.createdAt, now, args.locale) : null
2065
2068
  };
@@ -2381,19 +2384,36 @@ var import_react5 = require("react");
2381
2384
 
2382
2385
  // src/core/actor.ts
2383
2386
  function readActorHint(metadata) {
2384
- const raw = metadata["actor"];
2385
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
2386
- const record = raw;
2387
- const agentId = record["agentId"] ?? record["agent_id"];
2388
- if (typeof agentId !== "string" || agentId.length === 0) return null;
2389
- const name = record["agentName"] ?? record["agent_name"];
2390
- const avatar = record["agentAvatarUrl"] ?? record["agent_avatar_url"];
2387
+ const envelope = metadata;
2388
+ const raw = envelope["actor"];
2389
+ if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) {
2390
+ const record = raw;
2391
+ const agentId = record["agentId"] ?? record["agent_id"];
2392
+ if (typeof agentId !== "string" || agentId.length === 0) return null;
2393
+ const name2 = record["agentName"] ?? record["agent_name"];
2394
+ const avatar2 = record["agentAvatarUrl"] ?? record["agent_avatar_url"];
2395
+ return {
2396
+ agentId,
2397
+ ...typeof name2 === "string" && name2.length > 0 ? { agentName: name2 } : {},
2398
+ ...typeof avatar2 === "string" && avatar2.length > 0 ? { agentAvatarUrl: avatar2 } : {}
2399
+ };
2400
+ }
2401
+ const actorKind = envelope["actor_kind"] ?? envelope["actorKind"];
2402
+ if (actorKind !== "agent") return null;
2403
+ const id = envelope["actor_id"] ?? envelope["actorId"];
2404
+ const name = envelope["actor_label"] ?? envelope["actorLabel"];
2405
+ const avatar = envelope["actor_avatar_url"] ?? envelope["actorAvatarUrl"];
2391
2406
  return {
2392
- agentId,
2407
+ ...typeof id === "string" && id.length > 0 ? { agentId: id } : {},
2393
2408
  ...typeof name === "string" && name.length > 0 ? { agentName: name } : {},
2394
2409
  ...typeof avatar === "string" && avatar.length > 0 ? { agentAvatarUrl: avatar } : {}
2395
2410
  };
2396
2411
  }
2412
+ function effectiveActorKey(message) {
2413
+ const hint = readActorHint(message.metadata);
2414
+ if (hint === null) return `principal:${message.senderId}`;
2415
+ return `agent:${hint.agentId ?? hint.agentName ?? "anonymous"}`;
2416
+ }
2397
2417
  function resolveActor(message, sender) {
2398
2418
  const hint = readActorHint(message.metadata);
2399
2419
  const humanName = sender?.displayName ?? message.senderId;
@@ -2789,7 +2809,7 @@ function ConversationView(props) {
2789
2809
  );
2790
2810
  const anyOnline = others.some((participant) => online.has(participant.userId));
2791
2811
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `mx-msg__thread${props.className !== void 0 ? ` ${props.className}` : ""}`, children: [
2792
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "mx-msg__header", children: [
2812
+ props.showHeader !== false ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "mx-msg__header", children: [
2793
2813
  props.onBack !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2794
2814
  "button",
2795
2815
  {
@@ -2824,8 +2844,8 @@ function ConversationView(props) {
2824
2844
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UsersIcon, {})
2825
2845
  }
2826
2846
  ) : null })
2827
- ] }),
2828
- ai.available.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-msg__ai-bar", children: ai.available.map((capability) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2847
+ ] }) : null,
2848
+ props.showAi !== false && ai.available.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-msg__ai-bar", children: ai.available.map((capability) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2829
2849
  "button",
2830
2850
  {
2831
2851
  type: "button",
@@ -2839,7 +2859,7 @@ function ConversationView(props) {
2839
2859
  },
2840
2860
  capability
2841
2861
  )) }) : null,
2842
- ai.isRunning ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mx-msg__ai-output", "aria-busy": "true", "aria-live": "polite", children: ai.partialText.length > 0 ? ai.partialText : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2862
+ props.showAi !== false && ai.isRunning ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mx-msg__ai-output", "aria-busy": "true", "aria-live": "polite", children: ai.partialText.length > 0 ? ai.partialText : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2843
2863
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mx-msg__ai-output-label", children: ai.activeCapability !== null ? `${AI_LABELS[ai.activeCapability]}\u2026` : "Working\u2026" }),
2844
2864
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2845
2865
  "span",
@@ -2848,7 +2868,7 @@ function ConversationView(props) {
2848
2868
  style: { display: "block", height: 11, width: "72%" }
2849
2869
  }
2850
2870
  )
2851
- ] }) }) : ai.error !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mx-msg__ai-output", style: { color: "var(--mx-msg-danger)" }, children: ai.error }) : ai.result !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "mx-msg__ai-output", children: [
2871
+ ] }) }) : props.showAi !== false && ai.error !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "mx-msg__ai-output", style: { color: "var(--mx-msg-danger)" }, children: ai.error }) : props.showAi !== false && ai.result !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "mx-msg__ai-output", children: [
2852
2872
  ai.result.text,
2853
2873
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2854
2874
  "button",
@@ -2873,26 +2893,24 @@ function ConversationView(props) {
2873
2893
  children: "Load earlier messages"
2874
2894
  }
2875
2895
  ) : null,
2876
- groupMessages(messages).map((group) => {
2896
+ groupMessages(messages, { actorKey: effectiveActorKey }).map((group) => {
2877
2897
  const first = group.messages[0];
2878
2898
  if (first === void 0) return null;
2879
- const isMine = group.senderId === selfId;
2880
2899
  const sender = conversation.participants.find(
2881
2900
  (participant) => participant.userId === group.senderId
2882
2901
  ) ?? null;
2902
+ const actor = resolveActor(first, sender);
2903
+ const isMine = group.senderId === selfId && !actor.isAgent;
2883
2904
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
2884
2905
  group.dateSeparator !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-msg__day", children: group.dateSeparator }) : null,
2885
2906
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2886
2907
  MessageGroupView,
2887
2908
  {
2888
2909
  messages: group.messages,
2889
- sender,
2910
+ actor,
2890
2911
  isMine,
2891
2912
  onRetry: conversation.retry,
2892
2913
  onReply: composer.setReplyTo,
2893
- pendingIds: new Set(
2894
- conversation.pending.filter((entry) => entry.state === "failed").map((entry) => entry.clientMessageId)
2895
- ),
2896
2914
  failedEntryIdByClientId: new Map(
2897
2915
  conversation.pending.map((entry) => [entry.clientMessageId, entry.id])
2898
2916
  )
@@ -2905,13 +2923,20 @@ function ConversationView(props) {
2905
2923
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TypingDots, {}),
2906
2924
  typists.label
2907
2925
  ] }) : null }),
2908
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ComposerView, { composer, disabled: false })
2926
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2927
+ ComposerView,
2928
+ {
2929
+ composer,
2930
+ disabled: false,
2931
+ ...props.renderComposerInput !== void 0 ? { renderInput: props.renderComposerInput } : {}
2932
+ }
2933
+ )
2909
2934
  ] });
2910
2935
  }
2911
2936
  function MessageGroupView(props) {
2912
2937
  const first = props.messages[0];
2913
2938
  if (first === void 0) return null;
2914
- const actor = resolveActor(first, props.sender);
2939
+ const actor = props.actor;
2915
2940
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `mx-msg__group${props.isMine ? " mx-msg__group--mine" : ""}`, children: [
2916
2941
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2917
2942
  Avatar,
@@ -3098,7 +3123,24 @@ function ComposerView(props) {
3098
3123
  }
3099
3124
  )
3100
3125
  ] }) : null,
3101
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-msg__composer-row", children: [
3126
+ props.renderInput !== void 0 ? props.renderInput({
3127
+ value: composer.value,
3128
+ disabled: props.disabled,
3129
+ canSend: composer.canSend,
3130
+ placeholder: "Write a reply\u2026",
3131
+ onChange: (value) => {
3132
+ composer.setValue(value);
3133
+ composer.onKeystroke();
3134
+ },
3135
+ onKeyDown: (event) => {
3136
+ if (event.key !== "Enter" || event.shiftKey) return;
3137
+ const isTouch = typeof globalThis.matchMedia === "function" && globalThis.matchMedia("(pointer: coarse)").matches;
3138
+ if (isTouch) return;
3139
+ event.preventDefault();
3140
+ composer.send();
3141
+ },
3142
+ onSubmit: composer.send
3143
+ }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-msg__composer-row", children: [
3102
3144
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3103
3145
  "textarea",
3104
3146
  {