chat 4.19.0 → 4.20.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/{chunk-WAB7KMH4.js → chunk-JW7GYSMH.js} +3 -3
- package/dist/chunk-JW7GYSMH.js.map +1 -0
- package/dist/index.d.ts +134 -5
- package/dist/index.js +217 -46
- package/dist/index.js.map +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/docs/adapters/whatsapp.mdx +222 -0
- package/docs/adapters.mdx +54 -0
- package/docs/api/channel.mdx +15 -0
- package/docs/api/index.mdx +1 -0
- package/docs/api/thread.mdx +50 -0
- package/docs/contributing/building.mdx +1 -0
- package/docs/error-handling.mdx +1 -1
- package/docs/getting-started.mdx +2 -0
- package/docs/guides/durable-chat-sessions-nextjs.mdx +331 -0
- package/docs/guides/meta.json +7 -1
- package/docs/guides/scheduled-posts-neon.mdx +447 -0
- package/docs/index.mdx +3 -1
- package/docs/threads-messages-channels.mdx +17 -0
- package/package.json +1 -1
- package/dist/chunk-WAB7KMH4.js.map +0 -1
- package/dist/{jsx-runtime-BYavlUk9.d.ts → jsx-runtime-C2ATKxHQ.d.ts} +95 -95
package/dist/index.js
CHANGED
|
@@ -59,7 +59,20 @@ import {
|
|
|
59
59
|
toModalElement,
|
|
60
60
|
toPlainText,
|
|
61
61
|
walkAst
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-JW7GYSMH.js";
|
|
63
|
+
|
|
64
|
+
// src/ai.ts
|
|
65
|
+
function toAiMessages(messages, options) {
|
|
66
|
+
const includeNames = options?.includeNames ?? false;
|
|
67
|
+
const sorted = [...messages].sort(
|
|
68
|
+
(a, b) => (a.metadata.dateSent?.getTime() ?? 0) - (b.metadata.dateSent?.getTime() ?? 0)
|
|
69
|
+
);
|
|
70
|
+
return sorted.filter((msg) => msg.text.trim()).map((msg) => {
|
|
71
|
+
const role = msg.author.isMe ? "assistant" : "user";
|
|
72
|
+
const content = includeNames && role === "user" ? `[${msg.author.userName}]: ${msg.text}` : msg.text;
|
|
73
|
+
return { role, content };
|
|
74
|
+
});
|
|
75
|
+
}
|
|
63
76
|
|
|
64
77
|
// src/channel.ts
|
|
65
78
|
import { WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE2, WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE2 } from "@workflow/serde";
|
|
@@ -81,6 +94,42 @@ function hasChatSingleton() {
|
|
|
81
94
|
return _singleton !== null;
|
|
82
95
|
}
|
|
83
96
|
|
|
97
|
+
// src/from-full-stream.ts
|
|
98
|
+
var STREAM_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
99
|
+
"markdown_text",
|
|
100
|
+
"task_update",
|
|
101
|
+
"plan_update"
|
|
102
|
+
]);
|
|
103
|
+
async function* fromFullStream(stream) {
|
|
104
|
+
let needsSeparator = false;
|
|
105
|
+
let hasEmittedText = false;
|
|
106
|
+
for await (const event of stream) {
|
|
107
|
+
if (typeof event === "string") {
|
|
108
|
+
yield event;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (event === null || typeof event !== "object" || !("type" in event)) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const typed = event;
|
|
115
|
+
if (STREAM_CHUNK_TYPES.has(typed.type)) {
|
|
116
|
+
yield event;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const textContent = typed.text ?? typed.delta ?? typed.textDelta;
|
|
120
|
+
if (typed.type === "text-delta" && typeof textContent === "string") {
|
|
121
|
+
if (needsSeparator && hasEmittedText) {
|
|
122
|
+
yield "\n\n";
|
|
123
|
+
}
|
|
124
|
+
needsSeparator = false;
|
|
125
|
+
hasEmittedText = true;
|
|
126
|
+
yield textContent;
|
|
127
|
+
} else if (typed.type === "step-finish") {
|
|
128
|
+
needsSeparator = true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
84
133
|
// src/message.ts
|
|
85
134
|
import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE } from "@workflow/serde";
|
|
86
135
|
var Message = class _Message {
|
|
@@ -301,6 +350,7 @@ var ChannelImpl = class _ChannelImpl {
|
|
|
301
350
|
_adapterName;
|
|
302
351
|
_stateAdapterInstance;
|
|
303
352
|
_name = null;
|
|
353
|
+
_messageHistory;
|
|
304
354
|
constructor(config) {
|
|
305
355
|
this.id = config.id;
|
|
306
356
|
this.isDM = config.isDM ?? false;
|
|
@@ -309,6 +359,7 @@ var ChannelImpl = class _ChannelImpl {
|
|
|
309
359
|
} else {
|
|
310
360
|
this._adapter = config.adapter;
|
|
311
361
|
this._stateAdapterInstance = config.stateAdapter;
|
|
362
|
+
this._messageHistory = config.messageHistory;
|
|
312
363
|
}
|
|
313
364
|
}
|
|
314
365
|
get adapter() {
|
|
@@ -362,14 +413,17 @@ var ChannelImpl = class _ChannelImpl {
|
|
|
362
413
|
get messages() {
|
|
363
414
|
const adapter = this.adapter;
|
|
364
415
|
const channelId = this.id;
|
|
416
|
+
const messageHistory = this._messageHistory;
|
|
365
417
|
return {
|
|
366
418
|
async *[Symbol.asyncIterator]() {
|
|
367
419
|
let cursor;
|
|
420
|
+
let yieldedAny = false;
|
|
368
421
|
while (true) {
|
|
369
422
|
const fetchOptions = { cursor, direction: "backward" };
|
|
370
423
|
const result = adapter.fetchChannelMessages ? await adapter.fetchChannelMessages(channelId, fetchOptions) : await adapter.fetchMessages(channelId, fetchOptions);
|
|
371
424
|
const reversed = [...result.messages].reverse();
|
|
372
425
|
for (const message of reversed) {
|
|
426
|
+
yieldedAny = true;
|
|
373
427
|
yield message;
|
|
374
428
|
}
|
|
375
429
|
if (!result.nextCursor || result.messages.length === 0) {
|
|
@@ -377,6 +431,12 @@ var ChannelImpl = class _ChannelImpl {
|
|
|
377
431
|
}
|
|
378
432
|
cursor = result.nextCursor;
|
|
379
433
|
}
|
|
434
|
+
if (!yieldedAny && messageHistory) {
|
|
435
|
+
const cached = await messageHistory.getMessages(channelId);
|
|
436
|
+
for (let i = cached.length - 1; i >= 0; i--) {
|
|
437
|
+
yield cached[i];
|
|
438
|
+
}
|
|
439
|
+
}
|
|
380
440
|
}
|
|
381
441
|
};
|
|
382
442
|
}
|
|
@@ -422,10 +482,12 @@ var ChannelImpl = class _ChannelImpl {
|
|
|
422
482
|
async post(message) {
|
|
423
483
|
if (isAsyncIterable(message)) {
|
|
424
484
|
let accumulated = "";
|
|
425
|
-
for await (const chunk of message) {
|
|
426
|
-
|
|
485
|
+
for await (const chunk of fromFullStream(message)) {
|
|
486
|
+
if (typeof chunk === "string") {
|
|
487
|
+
accumulated += chunk;
|
|
488
|
+
}
|
|
427
489
|
}
|
|
428
|
-
return this.postSingleMessage(accumulated);
|
|
490
|
+
return this.postSingleMessage({ markdown: accumulated });
|
|
429
491
|
}
|
|
430
492
|
let postable = message;
|
|
431
493
|
if (isJSX(message)) {
|
|
@@ -439,7 +501,15 @@ var ChannelImpl = class _ChannelImpl {
|
|
|
439
501
|
}
|
|
440
502
|
async postSingleMessage(postable) {
|
|
441
503
|
const rawMessage = this.adapter.postChannelMessage ? await this.adapter.postChannelMessage(this.id, postable) : await this.adapter.postMessage(this.id, postable);
|
|
442
|
-
|
|
504
|
+
const sent = this.createSentMessage(
|
|
505
|
+
rawMessage.id,
|
|
506
|
+
postable,
|
|
507
|
+
rawMessage.threadId
|
|
508
|
+
);
|
|
509
|
+
if (this._messageHistory) {
|
|
510
|
+
await this._messageHistory.append(this.id, new Message(sent));
|
|
511
|
+
}
|
|
512
|
+
return sent;
|
|
443
513
|
}
|
|
444
514
|
async postEphemeral(user, message, options) {
|
|
445
515
|
const { fallbackToDM } = options;
|
|
@@ -625,45 +695,49 @@ function extractMessageContent(message) {
|
|
|
625
695
|
throw new Error("Invalid PostableMessage format");
|
|
626
696
|
}
|
|
627
697
|
|
|
698
|
+
// src/message-history.ts
|
|
699
|
+
var DEFAULT_MAX_MESSAGES = 100;
|
|
700
|
+
var DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
701
|
+
var KEY_PREFIX = "msg-history:";
|
|
702
|
+
var MessageHistoryCache = class {
|
|
703
|
+
state;
|
|
704
|
+
maxMessages;
|
|
705
|
+
ttlMs;
|
|
706
|
+
constructor(state, config) {
|
|
707
|
+
this.state = state;
|
|
708
|
+
this.maxMessages = config?.maxMessages ?? DEFAULT_MAX_MESSAGES;
|
|
709
|
+
this.ttlMs = config?.ttlMs ?? DEFAULT_TTL_MS;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Atomically append a message to the history for a thread.
|
|
713
|
+
* Trims to maxMessages (keeps newest) and refreshes TTL.
|
|
714
|
+
*/
|
|
715
|
+
async append(threadId, message) {
|
|
716
|
+
const key = `${KEY_PREFIX}${threadId}`;
|
|
717
|
+
const serialized = message.toJSON();
|
|
718
|
+
serialized.raw = null;
|
|
719
|
+
await this.state.appendToList(key, serialized, {
|
|
720
|
+
maxLength: this.maxMessages,
|
|
721
|
+
ttlMs: this.ttlMs
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Get messages for a thread in chronological order (oldest first).
|
|
726
|
+
*
|
|
727
|
+
* @param threadId - The thread ID
|
|
728
|
+
* @param limit - Optional limit on number of messages to return (returns newest N)
|
|
729
|
+
*/
|
|
730
|
+
async getMessages(threadId, limit) {
|
|
731
|
+
const key = `${KEY_PREFIX}${threadId}`;
|
|
732
|
+
const stored = await this.state.getList(key);
|
|
733
|
+
const sliced = limit && stored.length > limit ? stored.slice(stored.length - limit) : stored;
|
|
734
|
+
return sliced.map((s) => Message.fromJSON(s));
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
|
|
628
738
|
// src/thread.ts
|
|
629
739
|
import { WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE3, WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE3 } from "@workflow/serde";
|
|
630
740
|
|
|
631
|
-
// src/from-full-stream.ts
|
|
632
|
-
var STREAM_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
633
|
-
"markdown_text",
|
|
634
|
-
"task_update",
|
|
635
|
-
"plan_update"
|
|
636
|
-
]);
|
|
637
|
-
async function* fromFullStream(stream) {
|
|
638
|
-
let needsSeparator = false;
|
|
639
|
-
let hasEmittedText = false;
|
|
640
|
-
for await (const event of stream) {
|
|
641
|
-
if (typeof event === "string") {
|
|
642
|
-
yield event;
|
|
643
|
-
continue;
|
|
644
|
-
}
|
|
645
|
-
if (event === null || typeof event !== "object" || !("type" in event)) {
|
|
646
|
-
continue;
|
|
647
|
-
}
|
|
648
|
-
const typed = event;
|
|
649
|
-
if (STREAM_CHUNK_TYPES.has(typed.type)) {
|
|
650
|
-
yield event;
|
|
651
|
-
continue;
|
|
652
|
-
}
|
|
653
|
-
const textContent = typed.text ?? typed.delta ?? typed.textDelta;
|
|
654
|
-
if (typed.type === "text-delta" && typeof textContent === "string") {
|
|
655
|
-
if (needsSeparator && hasEmittedText) {
|
|
656
|
-
yield "\n\n";
|
|
657
|
-
}
|
|
658
|
-
needsSeparator = false;
|
|
659
|
-
hasEmittedText = true;
|
|
660
|
-
yield textContent;
|
|
661
|
-
} else if (typed.type === "step-finish") {
|
|
662
|
-
needsSeparator = true;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
741
|
// src/streaming-markdown.ts
|
|
668
742
|
import remend from "remend";
|
|
669
743
|
var StreamingMarkdownRenderer = class {
|
|
@@ -917,6 +991,8 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
917
991
|
_fallbackStreamingPlaceholderText;
|
|
918
992
|
/** Cached channel instance */
|
|
919
993
|
_channel;
|
|
994
|
+
/** Message history cache (set only for adapters with persistMessageHistory) */
|
|
995
|
+
_messageHistory;
|
|
920
996
|
constructor(config) {
|
|
921
997
|
this.id = config.id;
|
|
922
998
|
this.channelId = config.channelId;
|
|
@@ -930,6 +1006,7 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
930
1006
|
} else {
|
|
931
1007
|
this._adapter = config.adapter;
|
|
932
1008
|
this._stateAdapterInstance = config.stateAdapter;
|
|
1009
|
+
this._messageHistory = config.messageHistory;
|
|
933
1010
|
}
|
|
934
1011
|
if (config.initialMessage) {
|
|
935
1012
|
this._recentMessages = [config.initialMessage];
|
|
@@ -1008,7 +1085,8 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1008
1085
|
id: channelId,
|
|
1009
1086
|
adapter: this.adapter,
|
|
1010
1087
|
stateAdapter: this._stateAdapter,
|
|
1011
|
-
isDM: this.isDM
|
|
1088
|
+
isDM: this.isDM,
|
|
1089
|
+
messageHistory: this._messageHistory
|
|
1012
1090
|
});
|
|
1013
1091
|
}
|
|
1014
1092
|
return this._channel;
|
|
@@ -1020,9 +1098,11 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1020
1098
|
get messages() {
|
|
1021
1099
|
const adapter = this.adapter;
|
|
1022
1100
|
const threadId = this.id;
|
|
1101
|
+
const messageHistory = this._messageHistory;
|
|
1023
1102
|
return {
|
|
1024
1103
|
async *[Symbol.asyncIterator]() {
|
|
1025
1104
|
let cursor;
|
|
1105
|
+
let yieldedAny = false;
|
|
1026
1106
|
while (true) {
|
|
1027
1107
|
const result = await adapter.fetchMessages(threadId, {
|
|
1028
1108
|
cursor,
|
|
@@ -1030,6 +1110,7 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1030
1110
|
});
|
|
1031
1111
|
const reversed = [...result.messages].reverse();
|
|
1032
1112
|
for (const message of reversed) {
|
|
1113
|
+
yieldedAny = true;
|
|
1033
1114
|
yield message;
|
|
1034
1115
|
}
|
|
1035
1116
|
if (!result.nextCursor || result.messages.length === 0) {
|
|
@@ -1037,15 +1118,23 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1037
1118
|
}
|
|
1038
1119
|
cursor = result.nextCursor;
|
|
1039
1120
|
}
|
|
1121
|
+
if (!yieldedAny && messageHistory) {
|
|
1122
|
+
const cached = await messageHistory.getMessages(threadId);
|
|
1123
|
+
for (let i = cached.length - 1; i >= 0; i--) {
|
|
1124
|
+
yield cached[i];
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1040
1127
|
}
|
|
1041
1128
|
};
|
|
1042
1129
|
}
|
|
1043
1130
|
get allMessages() {
|
|
1044
1131
|
const adapter = this.adapter;
|
|
1045
1132
|
const threadId = this.id;
|
|
1133
|
+
const messageHistory = this._messageHistory;
|
|
1046
1134
|
return {
|
|
1047
1135
|
async *[Symbol.asyncIterator]() {
|
|
1048
1136
|
let cursor;
|
|
1137
|
+
let yieldedAny = false;
|
|
1049
1138
|
while (true) {
|
|
1050
1139
|
const result = await adapter.fetchMessages(threadId, {
|
|
1051
1140
|
limit: 100,
|
|
@@ -1053,6 +1142,7 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1053
1142
|
direction: "forward"
|
|
1054
1143
|
});
|
|
1055
1144
|
for (const message of result.messages) {
|
|
1145
|
+
yieldedAny = true;
|
|
1056
1146
|
yield message;
|
|
1057
1147
|
}
|
|
1058
1148
|
if (!result.nextCursor || result.messages.length === 0) {
|
|
@@ -1060,6 +1150,12 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1060
1150
|
}
|
|
1061
1151
|
cursor = result.nextCursor;
|
|
1062
1152
|
}
|
|
1153
|
+
if (!yieldedAny && messageHistory) {
|
|
1154
|
+
const cached = await messageHistory.getMessages(threadId);
|
|
1155
|
+
for (const message of cached) {
|
|
1156
|
+
yield message;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1063
1159
|
}
|
|
1064
1160
|
};
|
|
1065
1161
|
}
|
|
@@ -1096,6 +1192,9 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1096
1192
|
postable,
|
|
1097
1193
|
rawMessage.threadId
|
|
1098
1194
|
);
|
|
1195
|
+
if (this._messageHistory) {
|
|
1196
|
+
await this._messageHistory.append(this.id, new Message(result));
|
|
1197
|
+
}
|
|
1099
1198
|
return result;
|
|
1100
1199
|
}
|
|
1101
1200
|
async postEphemeral(user, message, options) {
|
|
@@ -1183,11 +1282,15 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1183
1282
|
}
|
|
1184
1283
|
};
|
|
1185
1284
|
const raw = await this.adapter.stream(this.id, wrappedStream, options);
|
|
1186
|
-
|
|
1285
|
+
const sent = this.createSentMessage(
|
|
1187
1286
|
raw.id,
|
|
1188
1287
|
{ markdown: accumulated },
|
|
1189
1288
|
raw.threadId
|
|
1190
1289
|
);
|
|
1290
|
+
if (this._messageHistory) {
|
|
1291
|
+
await this._messageHistory.append(this.id, new Message(sent));
|
|
1292
|
+
}
|
|
1293
|
+
return sent;
|
|
1191
1294
|
}
|
|
1192
1295
|
const textOnlyStream = {
|
|
1193
1296
|
[Symbol.asyncIterator]: () => {
|
|
@@ -1299,15 +1402,28 @@ var ThreadImpl = class _ThreadImpl {
|
|
|
1299
1402
|
markdown: accumulated
|
|
1300
1403
|
});
|
|
1301
1404
|
}
|
|
1302
|
-
|
|
1405
|
+
const sent = this.createSentMessage(
|
|
1303
1406
|
msg.id,
|
|
1304
1407
|
{ markdown: accumulated },
|
|
1305
1408
|
threadIdForEdits
|
|
1306
1409
|
);
|
|
1410
|
+
if (this._messageHistory) {
|
|
1411
|
+
await this._messageHistory.append(this.id, new Message(sent));
|
|
1412
|
+
}
|
|
1413
|
+
return sent;
|
|
1307
1414
|
}
|
|
1308
1415
|
async refresh() {
|
|
1309
1416
|
const result = await this.adapter.fetchMessages(this.id, { limit: 50 });
|
|
1310
|
-
|
|
1417
|
+
if (result.messages.length > 0) {
|
|
1418
|
+
this._recentMessages = result.messages;
|
|
1419
|
+
} else if (this._messageHistory) {
|
|
1420
|
+
this._recentMessages = await this._messageHistory.getMessages(
|
|
1421
|
+
this.id,
|
|
1422
|
+
50
|
|
1423
|
+
);
|
|
1424
|
+
} else {
|
|
1425
|
+
this._recentMessages = [];
|
|
1426
|
+
}
|
|
1311
1427
|
}
|
|
1312
1428
|
mentionUser(userId) {
|
|
1313
1429
|
return `<@${userId}>`;
|
|
@@ -1564,7 +1680,9 @@ var Chat = class {
|
|
|
1564
1680
|
_fallbackStreamingPlaceholderText;
|
|
1565
1681
|
_dedupeTtlMs;
|
|
1566
1682
|
_onLockConflict;
|
|
1683
|
+
_messageHistory;
|
|
1567
1684
|
mentionHandlers = [];
|
|
1685
|
+
directMessageHandlers = [];
|
|
1568
1686
|
messagePatterns = [];
|
|
1569
1687
|
subscribedMessageHandlers = [];
|
|
1570
1688
|
reactionHandlers = [];
|
|
@@ -1593,6 +1711,10 @@ var Chat = class {
|
|
|
1593
1711
|
this._fallbackStreamingPlaceholderText = config.fallbackStreamingPlaceholderText !== void 0 ? config.fallbackStreamingPlaceholderText : "...";
|
|
1594
1712
|
this._dedupeTtlMs = config.dedupeTtlMs ?? DEDUPE_TTL_MS;
|
|
1595
1713
|
this._onLockConflict = config.onLockConflict;
|
|
1714
|
+
this._messageHistory = new MessageHistoryCache(
|
|
1715
|
+
this._stateAdapter,
|
|
1716
|
+
config.messageHistory
|
|
1717
|
+
);
|
|
1596
1718
|
if (typeof config.logger === "string") {
|
|
1597
1719
|
this.logger = new ConsoleLogger(config.logger);
|
|
1598
1720
|
} else {
|
|
@@ -1699,6 +1821,27 @@ var Chat = class {
|
|
|
1699
1821
|
this.mentionHandlers.push(handler);
|
|
1700
1822
|
this.logger.debug("Registered mention handler");
|
|
1701
1823
|
}
|
|
1824
|
+
/**
|
|
1825
|
+
* Register a handler for direct messages.
|
|
1826
|
+
*
|
|
1827
|
+
* Called when a message is received in a DM thread that is not subscribed.
|
|
1828
|
+
* If no `onDirectMessage` handlers are registered, DMs fall through to
|
|
1829
|
+
* `onNewMention` for backward compatibility.
|
|
1830
|
+
*
|
|
1831
|
+
* @param handler - Handler called for DM messages
|
|
1832
|
+
*
|
|
1833
|
+
* @example
|
|
1834
|
+
* ```typescript
|
|
1835
|
+
* chat.onDirectMessage(async (thread, message) => {
|
|
1836
|
+
* await thread.subscribe();
|
|
1837
|
+
* await thread.post("Thanks for the DM!");
|
|
1838
|
+
* });
|
|
1839
|
+
* ```
|
|
1840
|
+
*/
|
|
1841
|
+
onDirectMessage(handler) {
|
|
1842
|
+
this.directMessageHandlers.push(handler);
|
|
1843
|
+
this.logger.debug("Registered direct message handler");
|
|
1844
|
+
}
|
|
1702
1845
|
/**
|
|
1703
1846
|
* Register a handler for messages matching a regex pattern.
|
|
1704
1847
|
*
|
|
@@ -2525,6 +2668,14 @@ var Chat = class {
|
|
|
2525
2668
|
});
|
|
2526
2669
|
return;
|
|
2527
2670
|
}
|
|
2671
|
+
if (adapter.persistMessageHistory) {
|
|
2672
|
+
const channelId = adapter.channelIdFromThreadId(threadId);
|
|
2673
|
+
const appends = [this._messageHistory.append(threadId, message)];
|
|
2674
|
+
if (channelId !== threadId) {
|
|
2675
|
+
appends.push(this._messageHistory.append(channelId, message));
|
|
2676
|
+
}
|
|
2677
|
+
await Promise.all(appends);
|
|
2678
|
+
}
|
|
2528
2679
|
let lock = await this._stateAdapter.acquireLock(
|
|
2529
2680
|
threadId,
|
|
2530
2681
|
DEFAULT_LOCK_TTL_MS
|
|
@@ -2561,6 +2712,21 @@ var Chat = class {
|
|
|
2561
2712
|
message,
|
|
2562
2713
|
isSubscribed
|
|
2563
2714
|
);
|
|
2715
|
+
const isDM = adapter.isDM?.(threadId) ?? false;
|
|
2716
|
+
if (isDM && this.directMessageHandlers.length > 0) {
|
|
2717
|
+
this.logger.debug("Direct message received - calling handlers", {
|
|
2718
|
+
threadId,
|
|
2719
|
+
handlerCount: this.directMessageHandlers.length
|
|
2720
|
+
});
|
|
2721
|
+
const channel = thread.channel;
|
|
2722
|
+
for (const handler of this.directMessageHandlers) {
|
|
2723
|
+
await handler(thread, message, channel);
|
|
2724
|
+
}
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2727
|
+
if (isDM) {
|
|
2728
|
+
message.isMention = true;
|
|
2729
|
+
}
|
|
2564
2730
|
if (isSubscribed) {
|
|
2565
2731
|
this.logger.debug("Message in subscribed thread - calling handlers", {
|
|
2566
2732
|
threadId,
|
|
@@ -2623,7 +2789,8 @@ var Chat = class {
|
|
|
2623
2789
|
isDM,
|
|
2624
2790
|
currentMessage: initialMessage,
|
|
2625
2791
|
streamingUpdateIntervalMs: this._streamingUpdateIntervalMs,
|
|
2626
|
-
fallbackStreamingPlaceholderText: this._fallbackStreamingPlaceholderText
|
|
2792
|
+
fallbackStreamingPlaceholderText: this._fallbackStreamingPlaceholderText,
|
|
2793
|
+
messageHistory: adapter.persistMessageHistory ? this._messageHistory : void 0
|
|
2627
2794
|
});
|
|
2628
2795
|
}
|
|
2629
2796
|
/**
|
|
@@ -2922,6 +3089,8 @@ function convertEmojiPlaceholders(text2, platform, resolver = defaultEmojiResolv
|
|
|
2922
3089
|
return resolver.toGChat(emojiName);
|
|
2923
3090
|
case "linear":
|
|
2924
3091
|
return resolver.toGChat(emojiName);
|
|
3092
|
+
case "whatsapp":
|
|
3093
|
+
return resolver.toGChat(emojiName);
|
|
2925
3094
|
default:
|
|
2926
3095
|
return resolver.toGChat(emojiName);
|
|
2927
3096
|
}
|
|
@@ -3101,6 +3270,7 @@ export {
|
|
|
3101
3270
|
LinkButton2 as LinkButton,
|
|
3102
3271
|
LockError,
|
|
3103
3272
|
Message,
|
|
3273
|
+
MessageHistoryCache,
|
|
3104
3274
|
Modal2 as Modal,
|
|
3105
3275
|
NotImplementedError,
|
|
3106
3276
|
RadioSelect2 as RadioSelect,
|
|
@@ -3157,6 +3327,7 @@ export {
|
|
|
3157
3327
|
tableElementToAscii,
|
|
3158
3328
|
tableToAscii,
|
|
3159
3329
|
text,
|
|
3330
|
+
toAiMessages,
|
|
3160
3331
|
toCardElement2 as toCardElement,
|
|
3161
3332
|
toModalElement2 as toModalElement,
|
|
3162
3333
|
toPlainText,
|