@diegoaltoworks/chatter 0.61.0 → 0.62.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/README.md +55 -17
- package/dist/auth/secretStrength.d.ts +1 -1
- package/dist/auth/secretStrength.d.ts.map +1 -1
- package/dist/bin/create-apikey.js +45 -28
- package/dist/bin/wa-pair.js +113 -46
- package/dist/channels/backoff.d.ts +10 -0
- package/dist/channels/backoff.d.ts.map +1 -0
- package/dist/channels/gates.d.ts +15 -8
- package/dist/channels/gates.d.ts.map +1 -1
- package/dist/channels/index.d.ts +1 -1
- package/dist/channels/index.d.ts.map +1 -1
- package/dist/channels/index.js +38 -5
- package/dist/channels/index.mjs +37 -5
- package/dist/channels/matrix/api.d.ts +25 -6
- package/dist/channels/matrix/api.d.ts.map +1 -1
- package/dist/channels/matrix/channel.d.ts +4 -56
- package/dist/channels/matrix/channel.d.ts.map +1 -1
- package/dist/channels/matrix/handler.d.ts +16 -9
- package/dist/channels/matrix/handler.d.ts.map +1 -1
- package/dist/channels/matrix/index.d.ts +2 -2
- package/dist/channels/matrix/index.d.ts.map +1 -1
- package/dist/channels/matrix/index.js +196 -40
- package/dist/channels/matrix/index.mjs +189 -39
- package/dist/channels/matrix/sync.d.ts +4 -1
- package/dist/channels/matrix/sync.d.ts.map +1 -1
- package/dist/channels/matrix/updates.d.ts +39 -10
- package/dist/channels/matrix/updates.d.ts.map +1 -1
- package/dist/channels/pipeline.d.ts +14 -14
- package/dist/channels/pipeline.d.ts.map +1 -1
- package/dist/channels/polling.d.ts +67 -0
- package/dist/channels/polling.d.ts.map +1 -0
- package/dist/channels/telegram/channel.d.ts +2 -56
- package/dist/channels/telegram/channel.d.ts.map +1 -1
- package/dist/channels/telegram/index.js +53 -23
- package/dist/channels/telegram/index.mjs +53 -23
- package/dist/channels/telegram/poll.d.ts +5 -1
- package/dist/channels/telegram/poll.d.ts.map +1 -1
- package/dist/channels/telegram/webhook.d.ts +2 -10
- package/dist/channels/telegram/webhook.d.ts.map +1 -1
- package/dist/channels/whatsapp/authState.d.ts +40 -9
- package/dist/channels/whatsapp/authState.d.ts.map +1 -1
- package/dist/channels/whatsapp/channel.d.ts +25 -4
- package/dist/channels/whatsapp/channel.d.ts.map +1 -1
- package/dist/channels/whatsapp/inbound.d.ts +23 -25
- package/dist/channels/whatsapp/inbound.d.ts.map +1 -1
- package/dist/channels/whatsapp/index.d.ts +3 -3
- package/dist/channels/whatsapp/index.d.ts.map +1 -1
- package/dist/channels/whatsapp/index.js +123 -41
- package/dist/channels/whatsapp/index.mjs +120 -41
- package/dist/channels/whatsapp/pairing.d.ts.map +1 -1
- package/dist/client/src/Chat.d.ts.map +1 -1
- package/dist/client/src/ChatButton.d.ts.map +1 -1
- package/dist/client/src/browser.d.ts.map +1 -1
- package/dist/core/answer.d.ts +8 -0
- package/dist/core/answer.d.ts.map +1 -1
- package/dist/core/buildLock.d.ts +52 -0
- package/dist/core/buildLock.d.ts.map +1 -0
- package/dist/core/pipeline.d.ts +42 -5
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/prompts.d.ts +2 -0
- package/dist/core/prompts.d.ts.map +1 -1
- package/dist/core/retrieval.d.ts +100 -25
- package/dist/core/retrieval.d.ts.map +1 -1
- package/dist/core/session.d.ts +8 -0
- package/dist/core/session.d.ts.map +1 -1
- package/dist/flows/index.d.ts +1 -1
- package/dist/flows/index.d.ts.map +1 -1
- package/dist/flows/index.js +8 -6
- package/dist/flows/index.mjs +7 -6
- package/dist/flows/intent.d.ts +1 -1
- package/dist/flows/intent.d.ts.map +1 -1
- package/dist/flows/loader.d.ts +1 -2
- package/dist/flows/loader.d.ts.map +1 -1
- package/dist/flows/params.d.ts +1 -1
- package/dist/flows/params.d.ts.map +1 -1
- package/dist/flows/session.d.ts +4 -2
- package/dist/flows/session.d.ts.map +1 -1
- package/dist/flows/types.d.ts +2 -3
- package/dist/flows/types.d.ts.map +1 -1
- package/dist/history/index.d.ts +1 -1
- package/dist/history/index.d.ts.map +1 -1
- package/dist/history/index.js +6 -3
- package/dist/history/index.mjs +5 -3
- package/dist/history/tursoStore.d.ts +6 -4
- package/dist/history/tursoStore.d.ts.map +1 -1
- package/dist/images/index.js +2 -2
- package/dist/images/index.mjs +2 -2
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +596 -295
- package/dist/index.mjs +595 -295
- package/dist/mcp-server/index.d.ts +5 -5
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/logger.d.ts +12 -2
- package/dist/mcp-server/logger.d.ts.map +1 -1
- package/dist/mcp-server/rate-limiter.d.ts +10 -3
- package/dist/mcp-server/rate-limiter.d.ts.map +1 -1
- package/dist/mcp-server/types.d.ts +20 -5
- package/dist/mcp-server/types.d.ts.map +1 -1
- package/dist/mcp-server.js +479 -244
- package/dist/mcp-server.mjs +485 -244
- package/dist/middleware/apiKey.d.ts +10 -0
- package/dist/middleware/apiKey.d.ts.map +1 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/cors.d.ts.map +1 -1
- package/dist/middleware/ratelimit.d.ts.map +1 -1
- package/dist/middleware/referrer.d.ts.map +1 -1
- package/dist/middleware/session.d.ts +1 -1
- package/dist/middleware/session.d.ts.map +1 -1
- package/dist/routes/demo.d.ts.map +1 -1
- package/dist/routes/openai.d.ts.map +1 -1
- package/dist/routes/private.d.ts.map +1 -1
- package/dist/routes/public.d.ts.map +1 -1
- package/dist/scheduler/index.js +1 -1
- package/dist/scheduler/index.mjs +1 -1
- package/dist/scheduler/scheduler.d.ts +9 -1
- package/dist/scheduler/scheduler.d.ts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +491 -268
- package/dist/server.mjs +497 -268
- package/dist/shortener.d.ts +5 -4
- package/dist/shortener.d.ts.map +1 -1
- package/dist/types.d.ts +129 -75
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -1
|
@@ -20,12 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/channels/matrix/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
DEFAULT_MAX_MEDIA_BYTES: () => DEFAULT_MAX_MEDIA_BYTES,
|
|
23
24
|
MAX_TRACKED_SENT_EVENTS: () => MAX_TRACKED_SENT_EVENTS,
|
|
24
25
|
MatrixApiError: () => MatrixApiError,
|
|
25
26
|
createMatrixApi: () => createMatrixApi,
|
|
26
27
|
createMatrixChannel: () => createMatrixChannel,
|
|
27
28
|
createMatrixSender: () => createMatrixSender,
|
|
28
29
|
createMatrixSyncHandler: () => createMatrixSyncHandler,
|
|
30
|
+
directInviteFrom: () => directInviteFrom,
|
|
31
|
+
directMappingFromEvents: () => directMappingFromEvents,
|
|
32
|
+
directMappingRooms: () => directMappingRooms,
|
|
29
33
|
directRoomIds: () => directRoomIds,
|
|
30
34
|
isReplyToBot: () => isReplyToBot,
|
|
31
35
|
matrixSenderKey: () => matrixSenderKey,
|
|
@@ -36,7 +40,9 @@ __export(index_exports, {
|
|
|
36
40
|
retryDelayMs: () => retryDelayMs,
|
|
37
41
|
runMatrixSyncLoop: () => runMatrixSyncLoop,
|
|
38
42
|
syncBackoffMs: () => syncBackoffMs,
|
|
39
|
-
toChannelMessage: () => toChannelMessage
|
|
43
|
+
toChannelMessage: () => toChannelMessage,
|
|
44
|
+
toDirectMapping: () => toDirectMapping,
|
|
45
|
+
withDirectRoom: () => withDirectRoom
|
|
40
46
|
});
|
|
41
47
|
module.exports = __toCommonJS(index_exports);
|
|
42
48
|
|
|
@@ -57,6 +63,7 @@ function redactToken(text, token) {
|
|
|
57
63
|
if (!token) return text;
|
|
58
64
|
return text.split(token).join("***");
|
|
59
65
|
}
|
|
66
|
+
var DEFAULT_MAX_MEDIA_BYTES = 25 * 1024 * 1024;
|
|
60
67
|
var MEDIA_MSGTYPE = {
|
|
61
68
|
image: "m.image",
|
|
62
69
|
file: "m.file",
|
|
@@ -86,6 +93,55 @@ function toMediaRequest(payload) {
|
|
|
86
93
|
}
|
|
87
94
|
return { kind, url: media.url, caption: media.caption, filename: media.filename };
|
|
88
95
|
}
|
|
96
|
+
function assertHttpsMediaUrl(url) {
|
|
97
|
+
let parsed;
|
|
98
|
+
try {
|
|
99
|
+
parsed = new URL(url);
|
|
100
|
+
} catch {
|
|
101
|
+
throw new TypeError(
|
|
102
|
+
`Matrix sendMedia url must be an mxc:// URI or an https URL - could not parse "${url}"`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (parsed.protocol !== "https:") {
|
|
106
|
+
throw new TypeError(
|
|
107
|
+
`Matrix sendMedia url must be an mxc:// URI or an https URL - got "${parsed.protocol}"`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function readCappedBytes(response, maxBytes) {
|
|
112
|
+
const declared = Number(response.headers.get("content-length"));
|
|
113
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
114
|
+
throw new Error(`media source declares ${declared} bytes, over the ${maxBytes} byte cap`);
|
|
115
|
+
}
|
|
116
|
+
const reader = response.body?.getReader();
|
|
117
|
+
if (!reader) {
|
|
118
|
+
const bytes2 = new Uint8Array(await response.arrayBuffer());
|
|
119
|
+
if (bytes2.byteLength > maxBytes) {
|
|
120
|
+
throw new Error(`media source is ${bytes2.byteLength} bytes, over the ${maxBytes} byte cap`);
|
|
121
|
+
}
|
|
122
|
+
return bytes2;
|
|
123
|
+
}
|
|
124
|
+
const chunks = [];
|
|
125
|
+
let total = 0;
|
|
126
|
+
while (true) {
|
|
127
|
+
const { done, value } = await reader.read();
|
|
128
|
+
if (done) break;
|
|
129
|
+
if (!value) continue;
|
|
130
|
+
total += value.byteLength;
|
|
131
|
+
if (total > maxBytes) {
|
|
132
|
+
await reader.cancel();
|
|
133
|
+
throw new Error(`media source exceeds the ${maxBytes} byte cap`);
|
|
134
|
+
}
|
|
135
|
+
chunks.push(value);
|
|
136
|
+
}
|
|
137
|
+
const bytes = new Uint8Array(total);
|
|
138
|
+
let offset = 0;
|
|
139
|
+
for (const chunk of chunks) {
|
|
140
|
+
bytes.set(chunk, offset);
|
|
141
|
+
offset += chunk.byteLength;
|
|
142
|
+
}
|
|
143
|
+
return bytes;
|
|
144
|
+
}
|
|
89
145
|
function createMatrixApi(config) {
|
|
90
146
|
const token = config.accessToken;
|
|
91
147
|
if (!token.trim()) throw new Error("Matrix accessToken is required (e.g. MATRIX_ACCESS_TOKEN)");
|
|
@@ -93,6 +149,7 @@ function createMatrixApi(config) {
|
|
|
93
149
|
if (!homeserverUrl)
|
|
94
150
|
throw new Error("Matrix homeserverUrl is required (e.g. https://matrix.example.org)");
|
|
95
151
|
const doFetch = config.fetch ?? globalThis.fetch;
|
|
152
|
+
const maxMediaBytes = config.maxMediaBytes ?? DEFAULT_MAX_MEDIA_BYTES;
|
|
96
153
|
async function call(method, path, options) {
|
|
97
154
|
const search = new URLSearchParams();
|
|
98
155
|
for (const [key, value] of Object.entries(options?.query ?? {})) {
|
|
@@ -186,13 +243,14 @@ function createMatrixApi(config) {
|
|
|
186
243
|
const media = toMediaRequest(payload);
|
|
187
244
|
let contentUri = media.url;
|
|
188
245
|
if (!contentUri.startsWith("mxc://")) {
|
|
246
|
+
assertHttpsMediaUrl(media.url);
|
|
189
247
|
let bytes;
|
|
190
248
|
let contentType = "application/octet-stream";
|
|
191
249
|
try {
|
|
192
250
|
const fetched = await doFetch(media.url);
|
|
193
251
|
if (!fetched.ok) throw new Error(`fetching media source returned HTTP ${fetched.status}`);
|
|
194
252
|
contentType = fetched.headers.get("content-type") ?? contentType;
|
|
195
|
-
bytes =
|
|
253
|
+
bytes = await readCappedBytes(fetched, maxMediaBytes);
|
|
196
254
|
} catch (error) {
|
|
197
255
|
throw new MatrixApiError(`could not fetch media source for upload: ${errorText(error)}`);
|
|
198
256
|
}
|
|
@@ -244,6 +302,13 @@ function createMatrixApi(config) {
|
|
|
244
302
|
if (error instanceof MatrixApiError && error.errcode === "M_NOT_FOUND") return void 0;
|
|
245
303
|
throw error;
|
|
246
304
|
}
|
|
305
|
+
},
|
|
306
|
+
async setAccountData(userId, type, content) {
|
|
307
|
+
await call(
|
|
308
|
+
"PUT",
|
|
309
|
+
`/_matrix/client/v3/user/${encodeURIComponent(userId)}/account_data/${encodeURIComponent(type)}`,
|
|
310
|
+
{ body: content }
|
|
311
|
+
);
|
|
247
312
|
}
|
|
248
313
|
};
|
|
249
314
|
}
|
|
@@ -336,7 +401,8 @@ async function answerOnce({
|
|
|
336
401
|
async function applyTransformReply(transformReply, input, logger) {
|
|
337
402
|
if (!transformReply) return input.text;
|
|
338
403
|
try {
|
|
339
|
-
|
|
404
|
+
const result = await transformReply(input);
|
|
405
|
+
return typeof result === "string" ? result : null;
|
|
340
406
|
} catch (error) {
|
|
341
407
|
logger?.error(
|
|
342
408
|
`transformReply threw for channel "${input.channel}"; sending the original reply`,
|
|
@@ -398,6 +464,7 @@ async function prepareChat({
|
|
|
398
464
|
sender,
|
|
399
465
|
rewriteQuery,
|
|
400
466
|
rerankContext,
|
|
467
|
+
fallbackFn,
|
|
401
468
|
logger
|
|
402
469
|
}) {
|
|
403
470
|
const lastUserMsg = lastUserMessage(messages);
|
|
@@ -414,21 +481,39 @@ async function prepareChat({
|
|
|
414
481
|
logger?.error("rewriteQuery threw; falling back to the original query", error);
|
|
415
482
|
}
|
|
416
483
|
}
|
|
417
|
-
|
|
484
|
+
const resolvedBuckets = buckets ?? defaultBuckets(mode);
|
|
485
|
+
const retrievedChunks = await store.query(query, topK, resolvedBuckets);
|
|
486
|
+
let ctx = retrievedChunks;
|
|
418
487
|
if (rerankContext) {
|
|
419
488
|
try {
|
|
420
|
-
const reranked = await rerankContext({ query, chunks: ctx });
|
|
489
|
+
const reranked = await rerankContext({ query, chunks: [...ctx] });
|
|
421
490
|
if (Array.isArray(reranked) && reranked.every((c) => typeof c === "string")) ctx = reranked;
|
|
422
491
|
} catch (error) {
|
|
423
492
|
logger?.error("rerankContext threw; falling back to the original chunks", error);
|
|
424
493
|
}
|
|
425
494
|
}
|
|
495
|
+
let fallback;
|
|
496
|
+
if (ctx.length === 0 && fallbackFn) {
|
|
497
|
+
try {
|
|
498
|
+
const guidance = await fallbackFn({
|
|
499
|
+
query,
|
|
500
|
+
mode,
|
|
501
|
+
buckets: resolvedBuckets,
|
|
502
|
+
sender,
|
|
503
|
+
retrievedChunks
|
|
504
|
+
});
|
|
505
|
+
if (typeof guidance === "string" && guidance.trim()) fallback = guidance.trim();
|
|
506
|
+
} catch (error) {
|
|
507
|
+
logger?.error("fallbackFn threw; proceeding without fallback guidance", error);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
426
510
|
const persona = personaLayer?.trim() || (mode === "private" ? prompts.privatePersona : prompts.publicPersona);
|
|
427
511
|
const hint = channelHint?.trim();
|
|
428
512
|
const system = [
|
|
429
513
|
prompts.baseSystemRules,
|
|
430
514
|
persona,
|
|
431
515
|
...hint ? [hint] : [],
|
|
516
|
+
...fallback ? [fallback] : [],
|
|
432
517
|
`${label}:
|
|
433
518
|
${ctx.join("\n\n")}`
|
|
434
519
|
].join("\n\n");
|
|
@@ -436,7 +521,7 @@ ${ctx.join("\n\n")}`
|
|
|
436
521
|
}
|
|
437
522
|
|
|
438
523
|
// src/history/compaction.ts
|
|
439
|
-
var
|
|
524
|
+
var COMPACTION_TIMEOUT_MS = 8e3;
|
|
440
525
|
var LOAD_ALL = Number.MAX_SAFE_INTEGER;
|
|
441
526
|
var SUMMARY_PREFIX = "Summary of earlier conversation: ";
|
|
442
527
|
function defaultSummarize(client, model) {
|
|
@@ -464,7 +549,7 @@ function createHistoryCompactor(deps, options) {
|
|
|
464
549
|
throw new Error(`Invalid history compaction keep: ${keep}`);
|
|
465
550
|
}
|
|
466
551
|
const summarize = options.summarize ?? defaultSummarize(deps.client, options.model);
|
|
467
|
-
const timeoutMs = options.timeoutMs ??
|
|
552
|
+
const timeoutMs = options.timeoutMs ?? COMPACTION_TIMEOUT_MS;
|
|
468
553
|
return {
|
|
469
554
|
async maybeCompact(store, conversationId) {
|
|
470
555
|
const turns = await store.load(conversationId, LOAD_ALL);
|
|
@@ -555,6 +640,16 @@ function underReplyRateLimit(msg, limiters) {
|
|
|
555
640
|
}
|
|
556
641
|
|
|
557
642
|
// src/channels/pipeline.ts
|
|
643
|
+
function resolveBrainHooks(config, fallback) {
|
|
644
|
+
return {
|
|
645
|
+
answerFn: config.answerFn ?? fallback?.answerFn,
|
|
646
|
+
bucketsFor: config.bucketsFor ?? fallback?.bucketsFor,
|
|
647
|
+
rewriteQuery: config.rewriteQuery ?? fallback?.rewriteQuery,
|
|
648
|
+
rerankContext: config.rerankContext ?? fallback?.rerankContext,
|
|
649
|
+
fallbackFn: config.fallbackFn ?? fallback?.fallbackFn,
|
|
650
|
+
transformReply: config.transformReply ?? fallback?.transformReply
|
|
651
|
+
};
|
|
652
|
+
}
|
|
558
653
|
var DEFAULT_HISTORY_LIMIT = 20;
|
|
559
654
|
var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
|
|
560
655
|
var DEFAULT_DM_RATE_LIMIT = { max: 20, windowMs: 60 * 60 * 1e3 };
|
|
@@ -639,6 +734,7 @@ function createInboundPipeline(deps, config) {
|
|
|
639
734
|
sender,
|
|
640
735
|
rewriteQuery: config.rewriteQuery,
|
|
641
736
|
rerankContext: config.rerankContext,
|
|
737
|
+
fallbackFn: config.fallbackFn,
|
|
642
738
|
logger: config.logger
|
|
643
739
|
});
|
|
644
740
|
const { content: produced } = await answerOnce({
|
|
@@ -675,6 +771,14 @@ function createInboundPipeline(deps, config) {
|
|
|
675
771
|
};
|
|
676
772
|
}
|
|
677
773
|
|
|
774
|
+
// src/channels/polling.ts
|
|
775
|
+
function defaultSleep(ms) {
|
|
776
|
+
return new Promise((resolve) => {
|
|
777
|
+
const timer = setTimeout(resolve, ms);
|
|
778
|
+
if (typeof timer === "object" && "unref" in timer) timer.unref();
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
|
|
678
782
|
// src/channels/matrix/updates.ts
|
|
679
783
|
function messageText(content) {
|
|
680
784
|
return content.body ?? "";
|
|
@@ -710,23 +814,44 @@ function recordSentEventId(sentEventIds, eventId) {
|
|
|
710
814
|
if (oldest !== void 0) sentEventIds.delete(oldest);
|
|
711
815
|
}
|
|
712
816
|
}
|
|
713
|
-
function
|
|
817
|
+
function toDirectMapping(content) {
|
|
818
|
+
const mapping = {};
|
|
819
|
+
for (const [peer, value] of Object.entries(content ?? {})) {
|
|
820
|
+
if (!Array.isArray(value)) continue;
|
|
821
|
+
const rooms = value.filter((roomId) => typeof roomId === "string");
|
|
822
|
+
if (rooms.length > 0) mapping[peer] = rooms;
|
|
823
|
+
}
|
|
824
|
+
return mapping;
|
|
825
|
+
}
|
|
826
|
+
function directMappingRooms(mapping) {
|
|
827
|
+
return new Set(Object.values(mapping).flat());
|
|
828
|
+
}
|
|
829
|
+
function directMappingFromEvents(accountDataEvents) {
|
|
714
830
|
const direct = accountDataEvents.find((event) => event.type === "m.direct");
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
831
|
+
return direct ? toDirectMapping(direct.content) : void 0;
|
|
832
|
+
}
|
|
833
|
+
function directRoomIds(accountDataEvents) {
|
|
834
|
+
return directMappingRooms(directMappingFromEvents(accountDataEvents) ?? {});
|
|
835
|
+
}
|
|
836
|
+
function withDirectRoom(mapping, peer, roomId) {
|
|
837
|
+
const existing = mapping[peer] ?? [];
|
|
838
|
+
if (existing.includes(roomId)) return void 0;
|
|
839
|
+
return { ...mapping, [peer]: [...existing, roomId] };
|
|
840
|
+
}
|
|
841
|
+
function directInviteFrom(room, me) {
|
|
842
|
+
for (const event of room.invite_state?.events ?? []) {
|
|
843
|
+
if (event.type !== "m.room.member" || event.state_key !== me.userId) continue;
|
|
844
|
+
const content = event.content ?? {};
|
|
845
|
+
if (content.membership !== "invite") continue;
|
|
846
|
+
if (content.is_direct === true) return event.sender;
|
|
723
847
|
}
|
|
724
|
-
return
|
|
848
|
+
return void 0;
|
|
725
849
|
}
|
|
726
850
|
function toChannelMessage(roomId, event, me, directRooms, sentEventIds) {
|
|
727
851
|
if (event.type !== "m.room.message") return void 0;
|
|
728
852
|
const content = event.content;
|
|
729
853
|
if (!content.msgtype) return void 0;
|
|
854
|
+
if (content["m.relates_to"]?.rel_type === "m.replace") return void 0;
|
|
730
855
|
return {
|
|
731
856
|
chatId: roomId,
|
|
732
857
|
senderId: event.sender,
|
|
@@ -755,19 +880,44 @@ function createMatrixSyncHandler(deps) {
|
|
|
755
880
|
const { api, me, pipeline, allowedChats, sentEventIds, logger, label } = deps;
|
|
756
881
|
const autoJoin = deps.autoJoin ?? true;
|
|
757
882
|
const loggedUnallowedChats = /* @__PURE__ */ new Set();
|
|
758
|
-
|
|
883
|
+
const loggedDeclinedInvites = /* @__PURE__ */ new Set();
|
|
884
|
+
let directMapping = { ...deps.initialDirect ?? {} };
|
|
885
|
+
let directRooms = directMappingRooms(directMapping);
|
|
886
|
+
async function rememberDirectRoom(peer, roomId) {
|
|
887
|
+
directRooms.add(roomId);
|
|
888
|
+
const merged = withDirectRoom(directMapping, peer, roomId);
|
|
889
|
+
if (!merged) return;
|
|
890
|
+
directMapping = merged;
|
|
891
|
+
try {
|
|
892
|
+
await api.setAccountData(me.userId, "m.direct", directMapping);
|
|
893
|
+
} catch (error) {
|
|
894
|
+
logger.warn(`${label}: could not record ${roomId} in m.direct:`, error);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
759
897
|
return async function handleSync(response) {
|
|
760
|
-
|
|
761
|
-
|
|
898
|
+
const syncedDirect = directMappingFromEvents(response.account_data?.events ?? []);
|
|
899
|
+
if (syncedDirect) {
|
|
900
|
+
directMapping = syncedDirect;
|
|
901
|
+
directRooms = directMappingRooms(directMapping);
|
|
762
902
|
}
|
|
763
903
|
if (autoJoin) {
|
|
764
|
-
for (const roomId of Object.
|
|
904
|
+
for (const [roomId, room] of Object.entries(response.rooms?.invite ?? {})) {
|
|
905
|
+
if (allowedChats.length > 0 && !allowedChats.includes(roomId)) {
|
|
906
|
+
if (!loggedDeclinedInvites.has(roomId)) {
|
|
907
|
+
loggedDeclinedInvites.add(roomId);
|
|
908
|
+
logger.warn(`${label}: left invite to ${roomId} pending - not in allowedChats`);
|
|
909
|
+
}
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
const directInviter = directInviteFrom(room, me);
|
|
765
913
|
try {
|
|
766
914
|
await api.joinRoom(roomId);
|
|
767
915
|
logger.info(`${label}: joined ${roomId} (accepted invite)`);
|
|
768
916
|
} catch (error) {
|
|
769
917
|
logger.warn(`${label}: failed to join ${roomId}:`, error);
|
|
918
|
+
continue;
|
|
770
919
|
}
|
|
920
|
+
if (directInviter) await rememberDirectRoom(directInviter, roomId);
|
|
771
921
|
}
|
|
772
922
|
}
|
|
773
923
|
for (const [roomId, room] of Object.entries(response.rooms?.join ?? {})) {
|
|
@@ -816,11 +966,16 @@ function createMatrixSender(api, sentEventIds) {
|
|
|
816
966
|
};
|
|
817
967
|
}
|
|
818
968
|
|
|
969
|
+
// src/channels/backoff.ts
|
|
970
|
+
function exponentialBackoffMs(baseMs, maxMs, n) {
|
|
971
|
+
return Math.min(baseMs * 2 ** Math.max(0, Math.min(n, 20)), maxMs);
|
|
972
|
+
}
|
|
973
|
+
|
|
819
974
|
// src/channels/matrix/sync.ts
|
|
820
975
|
var BASE_DELAY_MS = 1e3;
|
|
821
976
|
var MAX_DELAY_MS = 6e4;
|
|
822
977
|
function syncBackoffMs(failures) {
|
|
823
|
-
return
|
|
978
|
+
return exponentialBackoffMs(BASE_DELAY_MS, MAX_DELAY_MS, failures);
|
|
824
979
|
}
|
|
825
980
|
function retryDelayMs(error, failures) {
|
|
826
981
|
const retryAfterMs = error instanceof MatrixApiError ? error.retryAfterMs : void 0;
|
|
@@ -844,9 +999,9 @@ async function runMatrixSyncLoop(deps) {
|
|
|
844
999
|
continue;
|
|
845
1000
|
}
|
|
846
1001
|
failures = 0;
|
|
1002
|
+
if (deps.isStopped()) break;
|
|
847
1003
|
since = response.next_batch;
|
|
848
1004
|
deps.onSince?.(since);
|
|
849
|
-
if (deps.isStopped()) break;
|
|
850
1005
|
try {
|
|
851
1006
|
await deps.handleSync(response);
|
|
852
1007
|
} catch (error) {
|
|
@@ -858,12 +1013,6 @@ async function runMatrixSyncLoop(deps) {
|
|
|
858
1013
|
|
|
859
1014
|
// src/channels/matrix/channel.ts
|
|
860
1015
|
var DEFAULT_SYNC_TIMEOUT_MS = 3e4;
|
|
861
|
-
function defaultSleep(ms) {
|
|
862
|
-
return new Promise((resolve) => {
|
|
863
|
-
const timer = setTimeout(resolve, ms);
|
|
864
|
-
if (typeof timer === "object" && "unref" in timer) timer.unref();
|
|
865
|
-
});
|
|
866
|
-
}
|
|
867
1016
|
function createMatrixChannel(config) {
|
|
868
1017
|
const channelName = config.name ?? "matrix";
|
|
869
1018
|
const allowedChats = config.allowedChats ?? [];
|
|
@@ -871,6 +1020,7 @@ function createMatrixChannel(config) {
|
|
|
871
1020
|
const syncTimeoutMs = config.syncTimeoutMs ?? DEFAULT_SYNC_TIMEOUT_MS;
|
|
872
1021
|
let stopped = false;
|
|
873
1022
|
let registered = false;
|
|
1023
|
+
let abort;
|
|
874
1024
|
let senders;
|
|
875
1025
|
const sentEventIds = /* @__PURE__ */ new Set();
|
|
876
1026
|
return {
|
|
@@ -880,14 +1030,15 @@ function createMatrixChannel(config) {
|
|
|
880
1030
|
const api = config.api ?? createMatrixApi({
|
|
881
1031
|
homeserverUrl: config.homeserverUrl,
|
|
882
1032
|
accessToken: config.accessToken,
|
|
883
|
-
fetch: config.fetch
|
|
1033
|
+
fetch: config.fetch,
|
|
1034
|
+
maxMediaBytes: config.maxMediaBytes
|
|
884
1035
|
});
|
|
885
1036
|
const me = await api.whoami();
|
|
886
1037
|
const label = `Matrix[${me.userId}]`;
|
|
887
|
-
let
|
|
1038
|
+
let initialDirect;
|
|
888
1039
|
try {
|
|
889
1040
|
const direct = await api.getAccountData(me.userId, "m.direct");
|
|
890
|
-
if (direct)
|
|
1041
|
+
if (direct) initialDirect = toDirectMapping(direct);
|
|
891
1042
|
} catch (error) {
|
|
892
1043
|
log.warn(`${label}: could not load m.direct account data at start:`, error);
|
|
893
1044
|
}
|
|
@@ -898,11 +1049,7 @@ function createMatrixChannel(config) {
|
|
|
898
1049
|
{ client: deps.client, store: deps.store, prompts: deps.prompts },
|
|
899
1050
|
{
|
|
900
1051
|
channel: channelName,
|
|
901
|
-
|
|
902
|
-
bucketsFor: config.bucketsFor ?? deps.config.bucketsFor,
|
|
903
|
-
rewriteQuery: config.rewriteQuery ?? deps.config.rewriteQuery,
|
|
904
|
-
rerankContext: config.rerankContext ?? deps.config.rerankContext,
|
|
905
|
-
transformReply: config.transformReply ?? deps.config.transformReply,
|
|
1052
|
+
...resolveBrainHooks(config, deps.config),
|
|
906
1053
|
model: config.model,
|
|
907
1054
|
channelHint: config.channelHint ?? "Channel: Matrix.",
|
|
908
1055
|
personaResolver: config.personaResolver,
|
|
@@ -925,12 +1072,14 @@ function createMatrixChannel(config) {
|
|
|
925
1072
|
allowedChats,
|
|
926
1073
|
sentEventIds,
|
|
927
1074
|
autoJoin: config.autoJoin,
|
|
928
|
-
|
|
1075
|
+
initialDirect,
|
|
929
1076
|
logger: log,
|
|
930
1077
|
label
|
|
931
1078
|
});
|
|
1079
|
+
abort = new AbortController();
|
|
1080
|
+
const signal = abort.signal;
|
|
932
1081
|
void runMatrixSyncLoop({
|
|
933
|
-
sync: (since) => api.sync({ since, timeoutMs: syncTimeoutMs }),
|
|
1082
|
+
sync: (since) => api.sync({ since, timeoutMs: syncTimeoutMs, signal }),
|
|
934
1083
|
handleSync,
|
|
935
1084
|
isStopped: () => stopped,
|
|
936
1085
|
sleep,
|
|
@@ -943,6 +1092,7 @@ function createMatrixChannel(config) {
|
|
|
943
1092
|
},
|
|
944
1093
|
stop() {
|
|
945
1094
|
stopped = true;
|
|
1095
|
+
abort?.abort();
|
|
946
1096
|
if (registered) {
|
|
947
1097
|
senders?.unregister(channelName);
|
|
948
1098
|
registered = false;
|
|
@@ -952,12 +1102,16 @@ function createMatrixChannel(config) {
|
|
|
952
1102
|
}
|
|
953
1103
|
// Annotate the CommonJS export names for ESM import in node:
|
|
954
1104
|
0 && (module.exports = {
|
|
1105
|
+
DEFAULT_MAX_MEDIA_BYTES,
|
|
955
1106
|
MAX_TRACKED_SENT_EVENTS,
|
|
956
1107
|
MatrixApiError,
|
|
957
1108
|
createMatrixApi,
|
|
958
1109
|
createMatrixChannel,
|
|
959
1110
|
createMatrixSender,
|
|
960
1111
|
createMatrixSyncHandler,
|
|
1112
|
+
directInviteFrom,
|
|
1113
|
+
directMappingFromEvents,
|
|
1114
|
+
directMappingRooms,
|
|
961
1115
|
directRoomIds,
|
|
962
1116
|
isReplyToBot,
|
|
963
1117
|
matrixSenderKey,
|
|
@@ -968,5 +1122,7 @@ function createMatrixChannel(config) {
|
|
|
968
1122
|
retryDelayMs,
|
|
969
1123
|
runMatrixSyncLoop,
|
|
970
1124
|
syncBackoffMs,
|
|
971
|
-
toChannelMessage
|
|
1125
|
+
toChannelMessage,
|
|
1126
|
+
toDirectMapping,
|
|
1127
|
+
withDirectRoom
|
|
972
1128
|
});
|