@diegoaltoworks/chatter 0.59.0 → 0.61.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 +2 -1
- package/dist/channels/index.js +81 -0
- package/dist/channels/index.mjs +81 -0
- package/dist/channels/matrix/api.d.ts +133 -0
- package/dist/channels/matrix/api.d.ts.map +1 -0
- package/dist/channels/matrix/channel.d.ts +98 -0
- package/dist/channels/matrix/channel.d.ts.map +1 -0
- package/dist/channels/matrix/handler.d.ts +51 -0
- package/dist/channels/matrix/handler.d.ts.map +1 -0
- package/dist/channels/matrix/index.d.ts +37 -0
- package/dist/channels/matrix/index.d.ts.map +1 -0
- package/dist/channels/matrix/index.js +972 -0
- package/dist/channels/matrix/index.mjs +929 -0
- package/dist/channels/matrix/sync.d.ts +50 -0
- package/dist/channels/matrix/sync.d.ts.map +1 -0
- package/dist/channels/matrix/updates.d.ts +75 -0
- package/dist/channels/matrix/updates.d.ts.map +1 -0
- package/dist/channels/pipeline.d.ts +8 -0
- package/dist/channels/pipeline.d.ts.map +1 -1
- package/dist/channels/telegram/channel.d.ts +7 -0
- package/dist/channels/telegram/channel.d.ts.map +1 -1
- package/dist/channels/telegram/index.js +81 -0
- package/dist/channels/telegram/index.mjs +81 -0
- package/dist/channels/telegram/webhook.d.ts +7 -0
- package/dist/channels/telegram/webhook.d.ts.map +1 -1
- package/dist/channels/whatsapp/inbound.d.ts +7 -0
- package/dist/channels/whatsapp/inbound.d.ts.map +1 -1
- package/dist/channels/whatsapp/index.js +81 -0
- package/dist/channels/whatsapp/index.mjs +81 -0
- package/dist/history/compaction.d.ts +61 -0
- package/dist/history/compaction.d.ts.map +1 -0
- package/dist/history/index.d.ts +7 -0
- package/dist/history/index.d.ts.map +1 -1
- package/dist/history/index.js +143 -0
- package/dist/history/index.mjs +141 -0
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
- ⚡ **High Performance**: Built on Hono with streaming support
|
|
27
27
|
- 🛡️ **Security First**: Rate limiting, CORS, referrer checking, and input guardrails
|
|
28
28
|
- 💸 **Usage Metering**: Per-caller and global daily caps for paid features, multi-instance safe, via `@diegoaltoworks/chatter/usage` ([guide](./docs/usage.md))
|
|
29
|
-
- 💬 **Channels**: Built-in WhatsApp and
|
|
29
|
+
- 💬 **Channels**: Built-in WhatsApp, Telegram and Matrix transports plus a Channel SPI for plugging in any other one — allowlist/mute gates, reply rate-limiting, and a shared inbound pipeline every channel reuses ([WhatsApp](./docs/channels.md), [Telegram](./docs/telegram.md), [Matrix](./docs/matrix.md), [build your own](./docs/build-a-channel.md))
|
|
30
30
|
- 🧩 **Flows**: Multi-turn, schema-driven slot-filling for structured conversations, with hybrid keyword + LLM intent matching ([guide](./docs/flows.md))
|
|
31
31
|
- 🖼️ **Images**: On-demand generation and editing with cache-before-spend ordering and optional Cloudinary upload ([guide](./docs/images.md))
|
|
32
32
|
- 🎭 **Personas**: Windowed, per-contact prompt layers and named greetings from a JSON registry ([guide](./docs/personas.md))
|
|
@@ -103,6 +103,7 @@ Complete guides for setup, deployment, and integration — see
|
|
|
103
103
|
- **[WhatsApp Channel](./docs/channels.md)** - Link a WhatsApp number as a transport
|
|
104
104
|
- **[Building a Channel](./docs/build-a-channel.md)** - Plug in a new transport
|
|
105
105
|
- **[Telegram Channel](./docs/telegram.md)** - Run a bot on the official Bot API, no extra dependency
|
|
106
|
+
- **[Matrix Channel](./docs/matrix.md)** - Run a bot on the client-server API, no extra dependency (unencrypted rooms only)
|
|
106
107
|
- **[Flows](./docs/flows.md)** - Multi-turn, schema-driven slot-filling flows
|
|
107
108
|
- **[Images](./docs/images.md)** - Generate and cache images on demand
|
|
108
109
|
- **[Conversation History](./docs/history.md)** - Structural, host-replaceable multi-turn context
|
package/dist/channels/index.js
CHANGED
|
@@ -262,6 +262,75 @@ ${ctx.join("\n\n")}`
|
|
|
262
262
|
return { system, messages, context: ctx };
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
// src/history/compaction.ts
|
|
266
|
+
var DEFAULT_TIMEOUT_MS = 8e3;
|
|
267
|
+
var LOAD_ALL = Number.MAX_SAFE_INTEGER;
|
|
268
|
+
var SUMMARY_PREFIX = "Summary of earlier conversation: ";
|
|
269
|
+
function defaultSummarize(client, model) {
|
|
270
|
+
return async ({ turns }) => {
|
|
271
|
+
const transcript = turns.map((turn) => `${turn.role}: ${turn.content}`).join("\n");
|
|
272
|
+
const { content } = await answerOnce({
|
|
273
|
+
client,
|
|
274
|
+
system: "Summarize the conversation turns below into a short paragraph a reader would need to continue the conversation. Preserve names, facts, and decisions; drop pleasantries. Reply with the summary only, no preamble.",
|
|
275
|
+
messages: [{ role: "user", content: transcript }],
|
|
276
|
+
// No `answerFn`: compaction is an internal chatter operation, not a
|
|
277
|
+
// chat surface, so it must not conscript a caller's brain hook, which
|
|
278
|
+
// is shaped to answer the user, not to summarize on the engine's behalf.
|
|
279
|
+
mode: "public",
|
|
280
|
+
model
|
|
281
|
+
});
|
|
282
|
+
return content;
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function createHistoryCompactor(deps, options) {
|
|
286
|
+
const { threshold, keep, logger } = options;
|
|
287
|
+
if (!Number.isInteger(threshold) || threshold < 1) {
|
|
288
|
+
throw new Error(`Invalid history compaction threshold: ${threshold}`);
|
|
289
|
+
}
|
|
290
|
+
if (!Number.isInteger(keep) || keep < 0 || keep >= threshold) {
|
|
291
|
+
throw new Error(`Invalid history compaction keep: ${keep}`);
|
|
292
|
+
}
|
|
293
|
+
const summarize = options.summarize ?? defaultSummarize(deps.client, options.model);
|
|
294
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
295
|
+
return {
|
|
296
|
+
async maybeCompact(store, conversationId) {
|
|
297
|
+
const turns = await store.load(conversationId, LOAD_ALL);
|
|
298
|
+
if (turns.length < threshold) return;
|
|
299
|
+
const older = turns.slice(0, turns.length - keep);
|
|
300
|
+
let summary;
|
|
301
|
+
let timer;
|
|
302
|
+
try {
|
|
303
|
+
summary = await Promise.race([
|
|
304
|
+
summarize({ conversationId, turns: older }),
|
|
305
|
+
new Promise((_, reject) => {
|
|
306
|
+
timer = setTimeout(() => reject(new Error("history compaction timed out")), timeoutMs);
|
|
307
|
+
})
|
|
308
|
+
]);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
logger?.error(
|
|
311
|
+
`history compaction summarize failed for "${conversationId}"; history left untouched`,
|
|
312
|
+
error
|
|
313
|
+
);
|
|
314
|
+
return;
|
|
315
|
+
} finally {
|
|
316
|
+
clearTimeout(timer);
|
|
317
|
+
}
|
|
318
|
+
const trimmed = summary.trim();
|
|
319
|
+
if (!trimmed) return;
|
|
320
|
+
const fresh = await store.load(conversationId, LOAD_ALL);
|
|
321
|
+
const recent = fresh.slice(older.length);
|
|
322
|
+
await store.clear(conversationId);
|
|
323
|
+
await store.append(conversationId, {
|
|
324
|
+
role: "assistant",
|
|
325
|
+
content: `${SUMMARY_PREFIX}${trimmed}`
|
|
326
|
+
});
|
|
327
|
+
for (const turn of recent) {
|
|
328
|
+
await store.append(conversationId, turn);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
265
334
|
// src/channels/pipeline.ts
|
|
266
335
|
var DEFAULT_HISTORY_LIMIT = 20;
|
|
267
336
|
var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
|
|
@@ -292,6 +361,10 @@ function createInboundPipeline(deps, config) {
|
|
|
292
361
|
const underGroupRateLimit = createSlidingWindowRateLimiter(group.max, group.windowMs, now);
|
|
293
362
|
const underDmRateLimit = createSlidingWindowRateLimiter(dm.max, dm.windowMs, now);
|
|
294
363
|
const mode = "public";
|
|
364
|
+
const compactor = config.history?.compaction ? createHistoryCompactor(
|
|
365
|
+
{ client: deps.client },
|
|
366
|
+
{ model: config.model, ...config.history.compaction }
|
|
367
|
+
) : void 0;
|
|
295
368
|
return async function handleInboundMessage(msg, turn) {
|
|
296
369
|
const allowedChats = config.allowedChats ?? [];
|
|
297
370
|
const action = decideChannelAction(msg, {
|
|
@@ -367,6 +440,14 @@ function createInboundPipeline(deps, config) {
|
|
|
367
440
|
await config.history?.store.append(conversationId, { role: "assistant", content });
|
|
368
441
|
}
|
|
369
442
|
await turn.reply.sendAnswer(msg.chatId, content);
|
|
443
|
+
const history = config.history;
|
|
444
|
+
if (compactor && historyEnabled && history) {
|
|
445
|
+
try {
|
|
446
|
+
await compactor.maybeCompact(history.store, conversationId);
|
|
447
|
+
} catch (error) {
|
|
448
|
+
config.logger?.error(`history compaction failed for "${conversationId}"`, error);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
370
451
|
return { action: "reply", content };
|
|
371
452
|
};
|
|
372
453
|
}
|
package/dist/channels/index.mjs
CHANGED
|
@@ -229,6 +229,75 @@ ${ctx.join("\n\n")}`
|
|
|
229
229
|
return { system, messages, context: ctx };
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
// src/history/compaction.ts
|
|
233
|
+
var DEFAULT_TIMEOUT_MS = 8e3;
|
|
234
|
+
var LOAD_ALL = Number.MAX_SAFE_INTEGER;
|
|
235
|
+
var SUMMARY_PREFIX = "Summary of earlier conversation: ";
|
|
236
|
+
function defaultSummarize(client, model) {
|
|
237
|
+
return async ({ turns }) => {
|
|
238
|
+
const transcript = turns.map((turn) => `${turn.role}: ${turn.content}`).join("\n");
|
|
239
|
+
const { content } = await answerOnce({
|
|
240
|
+
client,
|
|
241
|
+
system: "Summarize the conversation turns below into a short paragraph a reader would need to continue the conversation. Preserve names, facts, and decisions; drop pleasantries. Reply with the summary only, no preamble.",
|
|
242
|
+
messages: [{ role: "user", content: transcript }],
|
|
243
|
+
// No `answerFn`: compaction is an internal chatter operation, not a
|
|
244
|
+
// chat surface, so it must not conscript a caller's brain hook, which
|
|
245
|
+
// is shaped to answer the user, not to summarize on the engine's behalf.
|
|
246
|
+
mode: "public",
|
|
247
|
+
model
|
|
248
|
+
});
|
|
249
|
+
return content;
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function createHistoryCompactor(deps, options) {
|
|
253
|
+
const { threshold, keep, logger } = options;
|
|
254
|
+
if (!Number.isInteger(threshold) || threshold < 1) {
|
|
255
|
+
throw new Error(`Invalid history compaction threshold: ${threshold}`);
|
|
256
|
+
}
|
|
257
|
+
if (!Number.isInteger(keep) || keep < 0 || keep >= threshold) {
|
|
258
|
+
throw new Error(`Invalid history compaction keep: ${keep}`);
|
|
259
|
+
}
|
|
260
|
+
const summarize = options.summarize ?? defaultSummarize(deps.client, options.model);
|
|
261
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
262
|
+
return {
|
|
263
|
+
async maybeCompact(store, conversationId) {
|
|
264
|
+
const turns = await store.load(conversationId, LOAD_ALL);
|
|
265
|
+
if (turns.length < threshold) return;
|
|
266
|
+
const older = turns.slice(0, turns.length - keep);
|
|
267
|
+
let summary;
|
|
268
|
+
let timer;
|
|
269
|
+
try {
|
|
270
|
+
summary = await Promise.race([
|
|
271
|
+
summarize({ conversationId, turns: older }),
|
|
272
|
+
new Promise((_, reject) => {
|
|
273
|
+
timer = setTimeout(() => reject(new Error("history compaction timed out")), timeoutMs);
|
|
274
|
+
})
|
|
275
|
+
]);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
logger?.error(
|
|
278
|
+
`history compaction summarize failed for "${conversationId}"; history left untouched`,
|
|
279
|
+
error
|
|
280
|
+
);
|
|
281
|
+
return;
|
|
282
|
+
} finally {
|
|
283
|
+
clearTimeout(timer);
|
|
284
|
+
}
|
|
285
|
+
const trimmed = summary.trim();
|
|
286
|
+
if (!trimmed) return;
|
|
287
|
+
const fresh = await store.load(conversationId, LOAD_ALL);
|
|
288
|
+
const recent = fresh.slice(older.length);
|
|
289
|
+
await store.clear(conversationId);
|
|
290
|
+
await store.append(conversationId, {
|
|
291
|
+
role: "assistant",
|
|
292
|
+
content: `${SUMMARY_PREFIX}${trimmed}`
|
|
293
|
+
});
|
|
294
|
+
for (const turn of recent) {
|
|
295
|
+
await store.append(conversationId, turn);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
232
301
|
// src/channels/pipeline.ts
|
|
233
302
|
var DEFAULT_HISTORY_LIMIT = 20;
|
|
234
303
|
var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
|
|
@@ -259,6 +328,10 @@ function createInboundPipeline(deps, config) {
|
|
|
259
328
|
const underGroupRateLimit = createSlidingWindowRateLimiter(group.max, group.windowMs, now);
|
|
260
329
|
const underDmRateLimit = createSlidingWindowRateLimiter(dm.max, dm.windowMs, now);
|
|
261
330
|
const mode = "public";
|
|
331
|
+
const compactor = config.history?.compaction ? createHistoryCompactor(
|
|
332
|
+
{ client: deps.client },
|
|
333
|
+
{ model: config.model, ...config.history.compaction }
|
|
334
|
+
) : void 0;
|
|
262
335
|
return async function handleInboundMessage(msg, turn) {
|
|
263
336
|
const allowedChats = config.allowedChats ?? [];
|
|
264
337
|
const action = decideChannelAction(msg, {
|
|
@@ -334,6 +407,14 @@ function createInboundPipeline(deps, config) {
|
|
|
334
407
|
await config.history?.store.append(conversationId, { role: "assistant", content });
|
|
335
408
|
}
|
|
336
409
|
await turn.reply.sendAnswer(msg.chatId, content);
|
|
410
|
+
const history = config.history;
|
|
411
|
+
if (compactor && historyEnabled && history) {
|
|
412
|
+
try {
|
|
413
|
+
await compactor.maybeCompact(history.store, conversationId);
|
|
414
|
+
} catch (error) {
|
|
415
|
+
config.logger?.error(`history compaction failed for "${conversationId}"`, error);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
337
418
|
return { action: "reply", content };
|
|
338
419
|
};
|
|
339
420
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matrix Client-Server API client — the whole transport layer of the Matrix
|
|
3
|
+
* channel, over plain `fetch`. No SDK, no optional peer dependency: the
|
|
4
|
+
* client-server API is JSON over HTTPS (plus one raw-bytes upload endpoint),
|
|
5
|
+
* so `./matrix` costs a consumer nothing beyond the package itself.
|
|
6
|
+
*
|
|
7
|
+
* Everything here is about the wire: envelopes, error mapping, sync polling,
|
|
8
|
+
* sending, media upload. Interpretation of a room event (mentions, DMs,
|
|
9
|
+
* reply-to) lives in `./updates` and `./channel`.
|
|
10
|
+
*
|
|
11
|
+
* The access token is a credential carried in an `Authorization: Bearer`
|
|
12
|
+
* header, never a query string, so it never lands in a URL an error message
|
|
13
|
+
* might echo back — but a homeserver's own error body could still quote it
|
|
14
|
+
* back verbatim (a malformed-token 401, say), so it is redacted the same
|
|
15
|
+
* defensive way the Telegram client redacts its token — see
|
|
16
|
+
* {@link redactToken}.
|
|
17
|
+
*/
|
|
18
|
+
export interface MatrixEvent {
|
|
19
|
+
type: string;
|
|
20
|
+
event_id: string;
|
|
21
|
+
sender: string;
|
|
22
|
+
origin_server_ts: number;
|
|
23
|
+
content: Record<string, unknown>;
|
|
24
|
+
unsigned?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export interface MatrixRoomTimeline {
|
|
27
|
+
events: MatrixEvent[];
|
|
28
|
+
/**
|
|
29
|
+
* True when the server omitted earlier events for size — a bot only ever
|
|
30
|
+
* reads forward from its own `since` token, so a limited timeline just
|
|
31
|
+
* means "more happened than fit in this batch", not a gap it needs to
|
|
32
|
+
* backfill; every event actually included here is still handled normally.
|
|
33
|
+
*/
|
|
34
|
+
limited?: boolean;
|
|
35
|
+
prev_batch?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface MatrixJoinedRoom {
|
|
38
|
+
timeline: MatrixRoomTimeline;
|
|
39
|
+
}
|
|
40
|
+
export interface MatrixInvitedRoom {
|
|
41
|
+
invite_state?: {
|
|
42
|
+
events: Array<{
|
|
43
|
+
type: string;
|
|
44
|
+
sender?: string;
|
|
45
|
+
content?: unknown;
|
|
46
|
+
}>;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export interface MatrixAccountDataEvent {
|
|
50
|
+
type: string;
|
|
51
|
+
content: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
export interface MatrixSyncResponse {
|
|
54
|
+
next_batch: string;
|
|
55
|
+
rooms?: {
|
|
56
|
+
join?: Record<string, MatrixJoinedRoom>;
|
|
57
|
+
invite?: Record<string, MatrixInvitedRoom>;
|
|
58
|
+
};
|
|
59
|
+
account_data?: {
|
|
60
|
+
events?: MatrixAccountDataEvent[];
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** A client-server API call that returned a non-2xx, or never completed. `retryAfterMs` carries `M_LIMIT_EXCEEDED`'s own wait instruction when the homeserver sent one. */
|
|
64
|
+
export declare class MatrixApiError extends Error {
|
|
65
|
+
readonly errcode?: string;
|
|
66
|
+
readonly status?: number;
|
|
67
|
+
readonly retryAfterMs?: number;
|
|
68
|
+
constructor(message: string, options?: {
|
|
69
|
+
errcode?: string;
|
|
70
|
+
status?: number;
|
|
71
|
+
retryAfterMs?: number;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Replaces every occurrence of `token` with `***`. An empty token is left
|
|
76
|
+
* alone: replacing "" would corrupt the message rather than protect
|
|
77
|
+
* anything.
|
|
78
|
+
*/
|
|
79
|
+
export declare function redactToken(text: string, token: string): string;
|
|
80
|
+
export type MatrixMediaKind = "image" | "file" | "video" | "audio";
|
|
81
|
+
/** What `ChannelSender.sendMedia` accepts for this channel. A bare string is shorthand for an already-uploaded `mxc://` URI or an https URL to fetch and re-upload. */
|
|
82
|
+
export interface MatrixMediaPayload {
|
|
83
|
+
/** @default "image" */
|
|
84
|
+
kind?: MatrixMediaKind;
|
|
85
|
+
/** An `mxc://` content URI (sent as-is) or an https URL (fetched, then uploaded). */
|
|
86
|
+
url: string;
|
|
87
|
+
caption?: string;
|
|
88
|
+
/** @default derived from the URL's last path segment, or the media kind */
|
|
89
|
+
filename?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface MatrixApiConfig {
|
|
92
|
+
/** Homeserver client-server API origin, e.g. `https://matrix.example.org`. */
|
|
93
|
+
homeserverUrl: string;
|
|
94
|
+
/** A logged-in bot user's access token. A credential — pass it from the environment, never commit it. */
|
|
95
|
+
accessToken: string;
|
|
96
|
+
/** Overridable for tests and for hosts routing through a proxy; defaults to `globalThis.fetch`. */
|
|
97
|
+
fetch?: typeof fetch;
|
|
98
|
+
}
|
|
99
|
+
export interface MatrixApi {
|
|
100
|
+
/** Raw call, for an endpoint this interface does not wrap. Rejects with {@link MatrixApiError} on any non-2xx response. */
|
|
101
|
+
call<T>(method: string, path: string, options?: {
|
|
102
|
+
body?: unknown;
|
|
103
|
+
query?: Record<string, string | number | undefined>;
|
|
104
|
+
signal?: AbortSignal;
|
|
105
|
+
}): Promise<T>;
|
|
106
|
+
whoami(): Promise<{
|
|
107
|
+
userId: string;
|
|
108
|
+
}>;
|
|
109
|
+
sync(options: {
|
|
110
|
+
since?: string;
|
|
111
|
+
timeoutMs: number;
|
|
112
|
+
signal?: AbortSignal;
|
|
113
|
+
}): Promise<MatrixSyncResponse>;
|
|
114
|
+
/** A user's global account data of `type` (e.g. `m.direct`), or `undefined` if it was never set (`M_NOT_FOUND`). */
|
|
115
|
+
getAccountData<T>(userId: string, type: string): Promise<T | undefined>;
|
|
116
|
+
/** Sends an `m.room.message` (or any event type, via `eventType`) and returns its event id. */
|
|
117
|
+
sendEvent(roomId: string, content: Record<string, unknown>, options?: {
|
|
118
|
+
eventType?: string;
|
|
119
|
+
}): Promise<{
|
|
120
|
+
eventId: string;
|
|
121
|
+
}>;
|
|
122
|
+
/** Uploads raw bytes to the media repository and returns its `mxc://` content URI. */
|
|
123
|
+
uploadMedia(bytes: Uint8Array, contentType: string, filename?: string): Promise<{
|
|
124
|
+
contentUri: string;
|
|
125
|
+
}>;
|
|
126
|
+
/** Fetches `url`, uploads the bytes, and sends the resulting `m.room.message` — the whole `MatrixMediaPayload` -> delivered-event path. */
|
|
127
|
+
sendMedia(roomId: string, payload: unknown): Promise<{
|
|
128
|
+
eventId: string;
|
|
129
|
+
}>;
|
|
130
|
+
joinRoom(roomIdOrAlias: string): Promise<void>;
|
|
131
|
+
}
|
|
132
|
+
export declare function createMatrixApi(config: MatrixApiConfig): MatrixApi;
|
|
133
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matrix client-server transport: a {@link Channel} that long-polls
|
|
3
|
+
* `/sync`, maps each room event into a `ChannelMessage`, and answers
|
|
4
|
+
* through the shared `createInboundPipeline` — the same gates, persona,
|
|
5
|
+
* buckets, history and `answerFn` seams every other channel uses.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately the plain client-server HTTP API over `fetch`, not an SDK:
|
|
8
|
+
* no optional peer dependency, same as `../telegram`. That also means
|
|
9
|
+
* **no end-to-end encryption support** — an encrypted room's events arrive
|
|
10
|
+
* as opaque `m.room.encrypted` ciphertext this channel cannot decrypt, so
|
|
11
|
+
* it silently cannot see anything sent there. Use this channel only in
|
|
12
|
+
* unencrypted rooms; see docs/matrix.md for the full explanation and why
|
|
13
|
+
* that rules out most default-E2EE personal homeservers for DMs.
|
|
14
|
+
*/
|
|
15
|
+
import type { AnswerFn, TransformReply } from "../../core/answer";
|
|
16
|
+
import type { BucketsFor } from "../../core/buckets";
|
|
17
|
+
import { type Logger } from "../../core/logger";
|
|
18
|
+
import type { RerankContext, RewriteQuery } from "../../core/pipeline";
|
|
19
|
+
import type { HistoryCompactionOptions } from "../../history/compaction";
|
|
20
|
+
import type { HistoryStore } from "../../history/types";
|
|
21
|
+
import type { Channel } from "../index";
|
|
22
|
+
import { type MatrixApi } from "./api";
|
|
23
|
+
export interface MatrixChannelConfig {
|
|
24
|
+
/** Homeserver client-server API origin, e.g. `https://matrix.example.org`. */
|
|
25
|
+
homeserverUrl: string;
|
|
26
|
+
/** A logged-in bot user's access token. A credential — pass it from the environment, never commit it. */
|
|
27
|
+
accessToken: string;
|
|
28
|
+
/** Channel and sender-registry name. Override to run more than one bot in one process. @default "matrix" */
|
|
29
|
+
name?: string;
|
|
30
|
+
/** Group rooms eligible for a reply. Empty (default) = every room. Has no effect on DMs, which always reply. */
|
|
31
|
+
allowedChats?: string[];
|
|
32
|
+
answerFn?: AnswerFn;
|
|
33
|
+
bucketsFor?: BucketsFor;
|
|
34
|
+
/** Rewrites the retrieval query before it reaches the vector store — see `ChatterConfig.rewriteQuery`. Falls back to the server's own. */
|
|
35
|
+
rewriteQuery?: RewriteQuery;
|
|
36
|
+
/** Post-processes retrieved chunks before they're folded into the prompt — see `ChatterConfig.rerankContext`. Falls back to the server's own. */
|
|
37
|
+
rerankContext?: RerankContext;
|
|
38
|
+
/** Modifies or vetoes the produced reply before delivery — see `ChatterConfig.transformReply`. Falls back to the server's own. */
|
|
39
|
+
transformReply?: TransformReply;
|
|
40
|
+
model?: string;
|
|
41
|
+
/** Extra system-prompt section describing the delivery channel; passed through to `prepareChat`. @default "Channel: Matrix." */
|
|
42
|
+
channelHint?: string;
|
|
43
|
+
/** A throw/rejection is treated as "no persona" for that turn. `sender` is the namespaced `mx:<user id>` key. */
|
|
44
|
+
personaResolver?: (ctx: {
|
|
45
|
+
sender: string;
|
|
46
|
+
text: string;
|
|
47
|
+
}) => string | undefined | Promise<string | undefined>;
|
|
48
|
+
/** Off by default — the channel stays single-turn until a store is configured. */
|
|
49
|
+
history?: {
|
|
50
|
+
store: HistoryStore;
|
|
51
|
+
/** Most recent turns to load per reply. @default 20 */
|
|
52
|
+
limit?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Excludes a sender from history entirely — see
|
|
55
|
+
* `InboundPipelineConfig.history.historyEnabledFor` in `./channels`.
|
|
56
|
+
* @default every sender is enabled
|
|
57
|
+
*/
|
|
58
|
+
historyEnabledFor?: (sender: string) => boolean | Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Summarize-then-truncate compaction — see
|
|
61
|
+
* `InboundPipelineConfig.history.compaction` in `./channels`.
|
|
62
|
+
* @default off
|
|
63
|
+
*/
|
|
64
|
+
compaction?: HistoryCompactionOptions;
|
|
65
|
+
};
|
|
66
|
+
muteRegex?: RegExp;
|
|
67
|
+
unmuteRegex?: RegExp;
|
|
68
|
+
/** Neutral, overridable acknowledgements — this module ships no bot personality; unset = silent mute/unmute. */
|
|
69
|
+
muteReply?: string;
|
|
70
|
+
unmuteReply?: string;
|
|
71
|
+
dmRateLimit?: {
|
|
72
|
+
max: number;
|
|
73
|
+
windowMs: number;
|
|
74
|
+
};
|
|
75
|
+
groupRateLimit?: {
|
|
76
|
+
max: number;
|
|
77
|
+
windowMs: number;
|
|
78
|
+
};
|
|
79
|
+
/** Auto-accept room invites, so the bot can actually receive messages in a room a user just invited it to. @default true */
|
|
80
|
+
autoJoin?: boolean;
|
|
81
|
+
/** @default 30000 */
|
|
82
|
+
syncTimeoutMs?: number;
|
|
83
|
+
/** Resume point for `/sync`. Omitted = an initial full sync (see docs/matrix.md on `since`-token persistence). */
|
|
84
|
+
initialSince?: string;
|
|
85
|
+
/** Called with each acknowledged `since` token, for a host that wants to persist it across restarts. */
|
|
86
|
+
onSince?: (since: string) => void;
|
|
87
|
+
/** Overridable for tests and for hosts routing through a proxy; defaults to `globalThis.fetch`. */
|
|
88
|
+
fetch?: typeof fetch;
|
|
89
|
+
/** Overridable for tests, which fake the client-server API instead of calling it; defaults to a `fetch` client over {@link MatrixChannelConfig.homeserverUrl}/{@link MatrixChannelConfig.accessToken}. */
|
|
90
|
+
api?: MatrixApi;
|
|
91
|
+
/** Overridable for tests; defaults to a `setTimeout`-based sleep. */
|
|
92
|
+
sleep?: (ms: number) => Promise<void>;
|
|
93
|
+
now?: () => number;
|
|
94
|
+
/** Logger for sync/gate diagnostics. Falls back to the host's `deps.logger`, then a console logger. */
|
|
95
|
+
logger?: Logger;
|
|
96
|
+
}
|
|
97
|
+
export declare function createMatrixChannel(config: MatrixChannelConfig): Channel;
|
|
98
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-sync-batch handling logic for the Matrix channel: room-invite
|
|
3
|
+
* auto-join, `m.direct` account-data tracking, event -> `ChannelMessage`
|
|
4
|
+
* mapping, and pipeline dispatch — the Matrix analogue of
|
|
5
|
+
* `../telegram/handler.ts`, adapted to a `/sync` response covering several
|
|
6
|
+
* rooms and events at once instead of one Telegram update.
|
|
7
|
+
*/
|
|
8
|
+
import type { Logger } from "../../core/logger";
|
|
9
|
+
import type { InboundPipeline } from "../pipeline";
|
|
10
|
+
import type { ChannelSender } from "../senders";
|
|
11
|
+
import type { MatrixApi, MatrixSyncResponse } from "./api";
|
|
12
|
+
import { type MatrixIdentity } from "./updates";
|
|
13
|
+
export interface MatrixSyncHandlerDeps {
|
|
14
|
+
api: MatrixApi;
|
|
15
|
+
me: MatrixIdentity;
|
|
16
|
+
pipeline: InboundPipeline;
|
|
17
|
+
/** Group rooms eligible for a reply. Empty = every room. */
|
|
18
|
+
allowedChats: string[];
|
|
19
|
+
/**
|
|
20
|
+
* This session's own sent event ids, for reply-to-bot detection (see
|
|
21
|
+
* `./updates`'s `isReplyToBot`) — shared with, and appended to by, the
|
|
22
|
+
* `ChannelSender` this channel registers, so a reply sent outside a
|
|
23
|
+
* pipeline turn (a scheduler, a flow) is still recognised.
|
|
24
|
+
*/
|
|
25
|
+
sentEventIds: Set<string>;
|
|
26
|
+
/** Auto-accept room invites so the bot can actually receive messages there. @default true */
|
|
27
|
+
autoJoin?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* The DM room set as of `start()` (see `./channel`'s upfront
|
|
30
|
+
* `getAccountData("m.direct")` fetch) — seeded here because an initial
|
|
31
|
+
* `/sync` response's `account_data` isn't guaranteed to repeat `m.direct`
|
|
32
|
+
* and a resumed sync (with `initialSince`) never carries it again unless
|
|
33
|
+
* it changes, so without this a restart would treat every known DM as an
|
|
34
|
+
* addressing-required group until the user's `m.direct` next changes.
|
|
35
|
+
*/
|
|
36
|
+
initialDirectRooms?: ReadonlySet<string>;
|
|
37
|
+
logger: Logger;
|
|
38
|
+
/** Log-line prefix, e.g. `Matrix[@bot:example.org]`. */
|
|
39
|
+
label: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* One `/sync` response -> zero or more pipeline turns, one per
|
|
43
|
+
* `m.room.message` event across every joined room in the batch. Builds its
|
|
44
|
+
* own allowlist-log dedup set, so each transport instance gets its own
|
|
45
|
+
* "skipped room" throttling rather than sharing (or fighting over) state
|
|
46
|
+
* with another.
|
|
47
|
+
*/
|
|
48
|
+
export declare function createMatrixSyncHandler(deps: MatrixSyncHandlerDeps): (response: MatrixSyncResponse) => Promise<void>;
|
|
49
|
+
/** The `ChannelSender` every Matrix transport registers — text, media and reactions over the same `MatrixApi`. */
|
|
50
|
+
export declare function createMatrixSender(api: MatrixApi, sentEventIds: Set<string>): ChannelSender;
|
|
51
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAEL,KAAK,cAAc,EAIpB,MAAM,WAAW,CAAC;AAmBnB,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,SAAS,CAAC;IACf,EAAE,EAAE,cAAc,CAAC;IACnB,QAAQ,EAAE,eAAe,CAAC;IAC1B,4DAA4D;IAC5D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;;;;;OAKG;IACH,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAgEjD;AAED,kHAAkH;AAClH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,aAAa,CAkB3F"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matrix client-server transport — a {@link Channel} with NO optional peer
|
|
3
|
+
* dependency: the client-server API is JSON over HTTPS (plus one raw-bytes
|
|
4
|
+
* upload endpoint), reached with plain `fetch`, so this subpath costs a
|
|
5
|
+
* consumer nothing beyond the package itself.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createMatrixChannel } from "@diegoaltoworks/chatter/matrix";
|
|
9
|
+
*
|
|
10
|
+
* await createServer({
|
|
11
|
+
* ...,
|
|
12
|
+
* channels: [
|
|
13
|
+
* createMatrixChannel({
|
|
14
|
+
* homeserverUrl: process.env.MATRIX_HOMESERVER_URL as string,
|
|
15
|
+
* accessToken: process.env.MATRIX_ACCESS_TOKEN as string,
|
|
16
|
+
* }),
|
|
17
|
+
* ],
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* **End-to-end encryption is not supported.** This channel only sees
|
|
22
|
+
* unencrypted rooms — see docs/matrix.md for the full explanation before
|
|
23
|
+
* relying on this for DMs, which most clients encrypt by default.
|
|
24
|
+
*
|
|
25
|
+
* Everything past turning a room event into a `ChannelMessage` runs through
|
|
26
|
+
* `./channels`' `createInboundPipeline`, shared with every other channel —
|
|
27
|
+
* see docs/matrix.md for configuration and docs/build-a-channel.md for the
|
|
28
|
+
* SPI this implements.
|
|
29
|
+
*
|
|
30
|
+
* @packageDocumentation
|
|
31
|
+
*/
|
|
32
|
+
export { createMatrixApi, type MatrixAccountDataEvent, type MatrixApi, type MatrixApiConfig, MatrixApiError, type MatrixEvent, type MatrixInvitedRoom, type MatrixJoinedRoom, type MatrixMediaKind, type MatrixMediaPayload, type MatrixRoomTimeline, type MatrixSyncResponse, redactToken, } from "./api";
|
|
33
|
+
export { createMatrixChannel, type MatrixChannelConfig } from "./channel";
|
|
34
|
+
export { createMatrixSender, createMatrixSyncHandler, type MatrixSyncHandlerDeps, } from "./handler";
|
|
35
|
+
export { retryDelayMs, runMatrixSyncLoop, syncBackoffMs } from "./sync";
|
|
36
|
+
export { directRoomIds, isReplyToBot, MAX_TRACKED_SENT_EVENTS, type MatrixIdentity, matrixSenderKey, mentionsBot, messageText, recordSentEventId, toChannelMessage, } from "./updates";
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,WAAW,GACZ,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC1E,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACxE,OAAO,EACL,aAAa,EACb,YAAY,EACZ,uBAAuB,EACvB,KAAK,cAAc,EACnB,eAAe,EACf,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,WAAW,CAAC"}
|