@ai-matrx/messaging 0.10.1 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/dist/index.cjs +41 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +41 -10
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +77 -24
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +21 -2
- package/dist/react.d.ts +21 -2
- package/dist/react.js +83 -25
- package/dist/react.js.map +1 -1
- package/package.json +2 -2
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,
|
|
@@ -1303,6 +1304,11 @@ function createMessagingEngine(options) {
|
|
|
1303
1304
|
if (openChannels.has(id) || disposed) return;
|
|
1304
1305
|
const handle = manager.open({
|
|
1305
1306
|
topic: conversationTopic(id),
|
|
1307
|
+
// Presence callbacks are JOIN-TIME in supabase-js. Declare the
|
|
1308
|
+
// read-only room shape on the first holder (the engine) so the
|
|
1309
|
+
// composer/typist/online hooks can attach without forcing a rebuild
|
|
1310
|
+
// after this durable channel has already subscribed.
|
|
1311
|
+
presence: { publish: false, state: {} },
|
|
1306
1312
|
postgresChanges: [
|
|
1307
1313
|
{
|
|
1308
1314
|
event: "*",
|
|
@@ -2048,18 +2054,20 @@ function groupMessages(messages, args = {}) {
|
|
|
2048
2054
|
let current = null;
|
|
2049
2055
|
let previousDay = null;
|
|
2050
2056
|
for (const message of messages) {
|
|
2057
|
+
const actorKey = args.actorKey?.(message) ?? `principal:${message.senderId}`;
|
|
2051
2058
|
const day = message.createdAt.slice(0, 10);
|
|
2052
2059
|
const startsNewDay = day !== previousDay;
|
|
2053
2060
|
previousDay = day;
|
|
2054
2061
|
const last = current?.messages.at(-1);
|
|
2055
2062
|
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) {
|
|
2063
|
+
if (current !== null && current.senderId === message.senderId && current.actorKey === actorKey && withinWindow && !startsNewDay) {
|
|
2057
2064
|
current.messages.push(message);
|
|
2058
2065
|
continue;
|
|
2059
2066
|
}
|
|
2060
2067
|
if (current !== null) groups.push(current);
|
|
2061
2068
|
current = {
|
|
2062
2069
|
senderId: message.senderId,
|
|
2070
|
+
actorKey,
|
|
2063
2071
|
messages: [message],
|
|
2064
2072
|
dateSeparator: startsNewDay ? formatDateSeparator(message.createdAt, now, args.locale) : null
|
|
2065
2073
|
};
|
|
@@ -2381,19 +2389,38 @@ var import_react5 = require("react");
|
|
|
2381
2389
|
|
|
2382
2390
|
// src/core/actor.ts
|
|
2383
2391
|
function readActorHint(metadata) {
|
|
2384
|
-
const
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2392
|
+
const envelope = metadata;
|
|
2393
|
+
const raw = envelope["actor"];
|
|
2394
|
+
if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) {
|
|
2395
|
+
const record = raw;
|
|
2396
|
+
const agentId = record["agentId"] ?? record["agent_id"];
|
|
2397
|
+
if (typeof agentId !== "string" || agentId.length === 0) return null;
|
|
2398
|
+
const name2 = record["agentName"] ?? record["agent_name"];
|
|
2399
|
+
const avatar2 = record["agentAvatarUrl"] ?? record["agent_avatar_url"];
|
|
2400
|
+
return {
|
|
2401
|
+
agentId,
|
|
2402
|
+
showPrincipalAttribution: true,
|
|
2403
|
+
...typeof name2 === "string" && name2.length > 0 ? { agentName: name2 } : {},
|
|
2404
|
+
...typeof avatar2 === "string" && avatar2.length > 0 ? { agentAvatarUrl: avatar2 } : {}
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
const actorKind = envelope["actor_kind"] ?? envelope["actorKind"];
|
|
2408
|
+
if (actorKind !== "agent") return null;
|
|
2409
|
+
const id = envelope["actor_id"] ?? envelope["actorId"];
|
|
2410
|
+
const name = envelope["actor_label"] ?? envelope["actorLabel"];
|
|
2411
|
+
const avatar = envelope["actor_avatar_url"] ?? envelope["actorAvatarUrl"];
|
|
2391
2412
|
return {
|
|
2392
|
-
|
|
2413
|
+
showPrincipalAttribution: false,
|
|
2414
|
+
...typeof id === "string" && id.length > 0 ? { agentId: id } : {},
|
|
2393
2415
|
...typeof name === "string" && name.length > 0 ? { agentName: name } : {},
|
|
2394
2416
|
...typeof avatar === "string" && avatar.length > 0 ? { agentAvatarUrl: avatar } : {}
|
|
2395
2417
|
};
|
|
2396
2418
|
}
|
|
2419
|
+
function effectiveActorKey(message) {
|
|
2420
|
+
const hint = readActorHint(message.metadata);
|
|
2421
|
+
if (hint === null) return `principal:${message.senderId}`;
|
|
2422
|
+
return `agent:${hint.agentId ?? hint.agentName ?? "anonymous"}`;
|
|
2423
|
+
}
|
|
2397
2424
|
function resolveActor(message, sender) {
|
|
2398
2425
|
const hint = readActorHint(message.metadata);
|
|
2399
2426
|
const humanName = sender?.displayName ?? message.senderId;
|
|
@@ -2405,7 +2432,11 @@ function resolveActor(message, sender) {
|
|
|
2405
2432
|
displayName: hint.agentName ?? "Agent",
|
|
2406
2433
|
avatarUrl: hint.agentAvatarUrl ?? null,
|
|
2407
2434
|
isAgent: true,
|
|
2408
|
-
|
|
2435
|
+
// The nested envelope explicitly models an agent acting on behalf of a
|
|
2436
|
+
// session principal. Platform event rows use the flat actor envelope as
|
|
2437
|
+
// the complete presentation identity; surfacing their audit writer as
|
|
2438
|
+
// "via Human" wrongly re-attaches that person to an automated event.
|
|
2439
|
+
onBehalfOfName: hint.showPrincipalAttribution ? humanName : null,
|
|
2409
2440
|
principalUserId: message.senderId
|
|
2410
2441
|
};
|
|
2411
2442
|
}
|
|
@@ -2789,7 +2820,7 @@ function ConversationView(props) {
|
|
|
2789
2820
|
);
|
|
2790
2821
|
const anyOnline = others.some((participant) => online.has(participant.userId));
|
|
2791
2822
|
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: [
|
|
2823
|
+
props.showHeader !== false ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "mx-msg__header", children: [
|
|
2793
2824
|
props.onBack !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2794
2825
|
"button",
|
|
2795
2826
|
{
|
|
@@ -2824,8 +2855,8 @@ function ConversationView(props) {
|
|
|
2824
2855
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UsersIcon, {})
|
|
2825
2856
|
}
|
|
2826
2857
|
) : 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)(
|
|
2858
|
+
] }) : null,
|
|
2859
|
+
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
2860
|
"button",
|
|
2830
2861
|
{
|
|
2831
2862
|
type: "button",
|
|
@@ -2839,7 +2870,7 @@ function ConversationView(props) {
|
|
|
2839
2870
|
},
|
|
2840
2871
|
capability
|
|
2841
2872
|
)) }) : 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: [
|
|
2873
|
+
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
2874
|
/* @__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
2875
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2845
2876
|
"span",
|
|
@@ -2848,7 +2879,7 @@ function ConversationView(props) {
|
|
|
2848
2879
|
style: { display: "block", height: 11, width: "72%" }
|
|
2849
2880
|
}
|
|
2850
2881
|
)
|
|
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: [
|
|
2882
|
+
] }) }) : 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
2883
|
ai.result.text,
|
|
2853
2884
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2854
2885
|
"button",
|
|
@@ -2873,26 +2904,24 @@ function ConversationView(props) {
|
|
|
2873
2904
|
children: "Load earlier messages"
|
|
2874
2905
|
}
|
|
2875
2906
|
) : null,
|
|
2876
|
-
groupMessages(messages).map((group) => {
|
|
2907
|
+
groupMessages(messages, { actorKey: effectiveActorKey }).map((group) => {
|
|
2877
2908
|
const first = group.messages[0];
|
|
2878
2909
|
if (first === void 0) return null;
|
|
2879
|
-
const isMine = group.senderId === selfId;
|
|
2880
2910
|
const sender = conversation.participants.find(
|
|
2881
2911
|
(participant) => participant.userId === group.senderId
|
|
2882
2912
|
) ?? null;
|
|
2913
|
+
const actor = resolveActor(first, sender);
|
|
2914
|
+
const isMine = group.senderId === selfId && !actor.isAgent;
|
|
2883
2915
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
2884
2916
|
group.dateSeparator !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-msg__day", children: group.dateSeparator }) : null,
|
|
2885
2917
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2886
2918
|
MessageGroupView,
|
|
2887
2919
|
{
|
|
2888
2920
|
messages: group.messages,
|
|
2889
|
-
|
|
2921
|
+
actor,
|
|
2890
2922
|
isMine,
|
|
2891
2923
|
onRetry: conversation.retry,
|
|
2892
2924
|
onReply: composer.setReplyTo,
|
|
2893
|
-
pendingIds: new Set(
|
|
2894
|
-
conversation.pending.filter((entry) => entry.state === "failed").map((entry) => entry.clientMessageId)
|
|
2895
|
-
),
|
|
2896
2925
|
failedEntryIdByClientId: new Map(
|
|
2897
2926
|
conversation.pending.map((entry) => [entry.clientMessageId, entry.id])
|
|
2898
2927
|
)
|
|
@@ -2905,13 +2934,20 @@ function ConversationView(props) {
|
|
|
2905
2934
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TypingDots, {}),
|
|
2906
2935
|
typists.label
|
|
2907
2936
|
] }) : null }),
|
|
2908
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2937
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2938
|
+
ComposerView,
|
|
2939
|
+
{
|
|
2940
|
+
composer,
|
|
2941
|
+
disabled: false,
|
|
2942
|
+
...props.renderComposerInput !== void 0 ? { renderInput: props.renderComposerInput } : {}
|
|
2943
|
+
}
|
|
2944
|
+
)
|
|
2909
2945
|
] });
|
|
2910
2946
|
}
|
|
2911
2947
|
function MessageGroupView(props) {
|
|
2912
2948
|
const first = props.messages[0];
|
|
2913
2949
|
if (first === void 0) return null;
|
|
2914
|
-
const actor =
|
|
2950
|
+
const actor = props.actor;
|
|
2915
2951
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `mx-msg__group${props.isMine ? " mx-msg__group--mine" : ""}`, children: [
|
|
2916
2952
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2917
2953
|
Avatar,
|
|
@@ -3098,7 +3134,24 @@ function ComposerView(props) {
|
|
|
3098
3134
|
}
|
|
3099
3135
|
)
|
|
3100
3136
|
] }) : null,
|
|
3101
|
-
|
|
3137
|
+
props.renderInput !== void 0 ? props.renderInput({
|
|
3138
|
+
value: composer.value,
|
|
3139
|
+
disabled: props.disabled,
|
|
3140
|
+
canSend: composer.canSend,
|
|
3141
|
+
placeholder: "Write a reply\u2026",
|
|
3142
|
+
onChange: (value) => {
|
|
3143
|
+
composer.setValue(value);
|
|
3144
|
+
composer.onKeystroke();
|
|
3145
|
+
},
|
|
3146
|
+
onKeyDown: (event) => {
|
|
3147
|
+
if (event.key !== "Enter" || event.shiftKey) return;
|
|
3148
|
+
const isTouch = typeof globalThis.matchMedia === "function" && globalThis.matchMedia("(pointer: coarse)").matches;
|
|
3149
|
+
if (isTouch) return;
|
|
3150
|
+
event.preventDefault();
|
|
3151
|
+
composer.send();
|
|
3152
|
+
},
|
|
3153
|
+
onSubmit: composer.send
|
|
3154
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mx-msg__composer-row", children: [
|
|
3102
3155
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3103
3156
|
"textarea",
|
|
3104
3157
|
{
|