@diegoaltoworks/chatter 0.60.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 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 Telegram 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), [build your own](./docs/build-a-channel.md))
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
@@ -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"}