@diegoaltoworks/chatter 0.60.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 +56 -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 +152 -0
- package/dist/channels/matrix/api.d.ts.map +1 -0
- package/dist/channels/matrix/channel.d.ts +46 -0
- package/dist/channels/matrix/channel.d.ts.map +1 -0
- package/dist/channels/matrix/handler.d.ts +58 -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 +1128 -0
- package/dist/channels/matrix/index.mjs +1079 -0
- package/dist/channels/matrix/sync.d.ts +53 -0
- package/dist/channels/matrix/sync.d.ts.map +1 -0
- package/dist/channels/matrix/updates.d.ts +104 -0
- package/dist/channels/matrix/updates.d.ts.map +1 -0
- 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 +11 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `/sync` long-poll loop, isolated from both the HTTP client and the
|
|
3
|
+
* channel so its failure behaviour is testable without either — the same
|
|
4
|
+
* shape as `../telegram/poll.ts`'s `runLongPoll`, adapted to Matrix's
|
|
5
|
+
* `since`-token pagination instead of an acknowledged offset.
|
|
6
|
+
*
|
|
7
|
+
* The property that matters: a homeserver that is down, rate-limiting, or
|
|
8
|
+
* rejecting the token must never turn into a tight retry loop. Every
|
|
9
|
+
* failure backs off exponentially, and `M_LIMIT_EXCEEDED`'s own
|
|
10
|
+
* `retry_after_ms` wins over that backoff when the homeserver sends one.
|
|
11
|
+
*/
|
|
12
|
+
import { type Logger } from "../../core/logger";
|
|
13
|
+
import { type MatrixSyncResponse } from "./api";
|
|
14
|
+
/** Exponential backoff: 2s, 4s, 8s ... capped at a minute. `failures` is the count including the one just seen. */
|
|
15
|
+
export declare function syncBackoffMs(failures: number): number;
|
|
16
|
+
/**
|
|
17
|
+
* How long to wait after a failed sync. `M_LIMIT_EXCEEDED`'s
|
|
18
|
+
* `retry_after_ms` is an instruction, not a hint — honour it verbatim even
|
|
19
|
+
* when it exceeds the backoff cap, because syncing again sooner just
|
|
20
|
+
* extends the rate-limit window.
|
|
21
|
+
*/
|
|
22
|
+
export declare function retryDelayMs(error: unknown, failures: number): number;
|
|
23
|
+
export interface MatrixSyncLoopDeps {
|
|
24
|
+
/** One `/sync` call. Rejections are backed off; they never end the loop. */
|
|
25
|
+
sync(since: string | undefined): Promise<MatrixSyncResponse>;
|
|
26
|
+
/** Per-batch work. A throw is logged and skipped — one bad batch never stops the loop. */
|
|
27
|
+
handleSync(response: MatrixSyncResponse): Promise<void>;
|
|
28
|
+
/** Checked before every sync, and again after a failure, so `stop()` cuts the loop instead of sleeping out a backoff first. */
|
|
29
|
+
isStopped(): boolean;
|
|
30
|
+
/** Overridable for tests; a real channel passes a `setTimeout`-based sleep. */
|
|
31
|
+
sleep(ms: number): Promise<void>;
|
|
32
|
+
/** Where this loop's `since` token resumes from. Omitted = an initial full sync. */
|
|
33
|
+
initialSince?: string;
|
|
34
|
+
/** Called with each newly acknowledged `since` token, for a host that persists it. */
|
|
35
|
+
onSince?(since: string): void;
|
|
36
|
+
logger?: Logger;
|
|
37
|
+
/** Prefix for log lines, e.g. `Matrix[@bot:example.org]`. */
|
|
38
|
+
label?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Syncs until `isStopped()`, resolving with the last `since` token reached
|
|
42
|
+
* (what a restart would resume from).
|
|
43
|
+
*
|
|
44
|
+
* The token advances BEFORE the batch is handled, matching the Telegram
|
|
45
|
+
* poll loop's offset-first ordering: a handler that throws on one bad
|
|
46
|
+
* batch must not make the homeserver redeliver it forever, which would
|
|
47
|
+
* wedge the loop on a single poison event and starve every later one. It
|
|
48
|
+
* advances only for a batch this loop is actually going to handle, though:
|
|
49
|
+
* a stop that lands between the sync and the handler leaves the token where
|
|
50
|
+
* it was, so a restart resumes at the unhandled batch rather than past it.
|
|
51
|
+
*/
|
|
52
|
+
export declare function runMatrixSyncLoop(deps: MatrixSyncLoopDeps): Promise<string | undefined>;
|
|
53
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAKhE,mHAAmH;AACnH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrE;AAED,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7D,0FAA0F;IAC1F,UAAU,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,+HAA+H;IAC/H,SAAS,IAAI,OAAO,CAAC;IACrB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,oFAAoF;IACpF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoC7F"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matrix room event -> {@link ChannelMessage}: the transport's own half of
|
|
3
|
+
* the channel contract (see docs/build-a-channel.md), kept pure so mention,
|
|
4
|
+
* reply-to and DM detection are testable without a network or a running
|
|
5
|
+
* channel.
|
|
6
|
+
*
|
|
7
|
+
* Addressing parity with the other built-in channels is the point of this
|
|
8
|
+
* module. WhatsApp and Telegram both resolve "was the bot addressed?" from
|
|
9
|
+
* transport-native structures; Matrix resolves it from the stable
|
|
10
|
+
* `m.mentions` field (MSC3952, in the spec since v1.7) with a pill-in-HTML
|
|
11
|
+
* fallback for clients that only set that. The gate policy that consumes
|
|
12
|
+
* those booleans (`decideChannelAction`) is identical for every channel.
|
|
13
|
+
*/
|
|
14
|
+
import type { ChannelMessage } from "../gates";
|
|
15
|
+
import type { MatrixAccountDataEvent, MatrixEvent, MatrixInvitedRoom } from "./api";
|
|
16
|
+
/** The bot's own identity, as `whoami` reports it. */
|
|
17
|
+
export interface MatrixIdentity {
|
|
18
|
+
userId: string;
|
|
19
|
+
}
|
|
20
|
+
interface MatrixMentions {
|
|
21
|
+
user_ids?: string[];
|
|
22
|
+
room?: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface MatrixInReplyTo {
|
|
25
|
+
event_id?: string;
|
|
26
|
+
}
|
|
27
|
+
interface MatrixRelatesTo {
|
|
28
|
+
/** `m.replace` for an edit, `m.annotation` for a reaction, `m.thread` for a threaded message. Absent on a plain reply. */
|
|
29
|
+
rel_type?: string;
|
|
30
|
+
event_id?: string;
|
|
31
|
+
"m.in_reply_to"?: MatrixInReplyTo;
|
|
32
|
+
}
|
|
33
|
+
interface MatrixMessageContent {
|
|
34
|
+
msgtype?: string;
|
|
35
|
+
body?: string;
|
|
36
|
+
format?: string;
|
|
37
|
+
formatted_body?: string;
|
|
38
|
+
"m.mentions"?: MatrixMentions;
|
|
39
|
+
"m.relates_to"?: MatrixRelatesTo;
|
|
40
|
+
}
|
|
41
|
+
/** The message text, or "" for an event this channel doesn't render as text (a redaction, a non-text msgtype with no body). */
|
|
42
|
+
export declare function messageText(content: MatrixMessageContent): string;
|
|
43
|
+
export declare function mentionsBot(content: MatrixMessageContent, me: MatrixIdentity): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Was this message a reply to one the bot sent? `sentEventIds` is the
|
|
46
|
+
* session's own record of event ids it has sent (see `./channel`) — Matrix
|
|
47
|
+
* has no cheap "who sent event X" lookup without fetching that event, and a
|
|
48
|
+
* bot only ever needs to recognise its OWN messages, which it already knows
|
|
49
|
+
* without asking the server.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isReplyToBot(content: MatrixMessageContent, sentEventIds: ReadonlySet<string>): boolean;
|
|
52
|
+
/** How many of the session's own sent event ids {@link isReplyToBot} remembers — bounded so a long-running bot's memory doesn't grow with every message it ever sent. */
|
|
53
|
+
export declare const MAX_TRACKED_SENT_EVENTS = 500;
|
|
54
|
+
/** Records `eventId` as one of ours, evicting the oldest entry first once the set is at capacity (`Set` iterates in insertion order, so the first value is the oldest). */
|
|
55
|
+
export declare function recordSentEventId(sentEventIds: Set<string>, eventId: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* The `m.direct` account-data document: peer user id -> the rooms that are
|
|
58
|
+
* direct messages with that peer. Matrix has no per-room "this is a DM"
|
|
59
|
+
* flag, so this mapping is the only thing that tells one from a group.
|
|
60
|
+
*/
|
|
61
|
+
export type MatrixDirectMapping = Record<string, string[]>;
|
|
62
|
+
/** Raw `m.direct` content (whatever the homeserver stored) narrowed to peer -> room ids, dropping any entry that isn't a non-empty array of strings. */
|
|
63
|
+
export declare function toDirectMapping(content: Record<string, unknown> | undefined): MatrixDirectMapping;
|
|
64
|
+
/** Every room id in a mapping, across every peer. A room absent from it is treated as a group and needs addressing, the safer default. */
|
|
65
|
+
export declare function directMappingRooms(mapping: MatrixDirectMapping): Set<string>;
|
|
66
|
+
/** The `m.direct` mapping carried by a sync batch's account data, or `undefined` when this batch says nothing about it (an unrelated account-data change must not be read as "no DMs"). */
|
|
67
|
+
export declare function directMappingFromEvents(accountDataEvents: MatrixAccountDataEvent[]): MatrixDirectMapping | undefined;
|
|
68
|
+
/** Room ids the homeserver's `m.direct` account data lists as direct messages, across every peer. */
|
|
69
|
+
export declare function directRoomIds(accountDataEvents: MatrixAccountDataEvent[]): Set<string>;
|
|
70
|
+
/**
|
|
71
|
+
* `mapping` with `roomId` recorded against `peer`, or `undefined` when it is
|
|
72
|
+
* already there, which the caller uses to skip a pointless account-data
|
|
73
|
+
* write. Never mutates the input: `m.direct` is a whole-document PUT, so the
|
|
74
|
+
* merged copy is what gets sent.
|
|
75
|
+
*/
|
|
76
|
+
export declare function withDirectRoom(mapping: MatrixDirectMapping, peer: string, roomId: string): MatrixDirectMapping | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* The inviting user id when this invite is for a direct-message room, else
|
|
79
|
+
* `undefined`.
|
|
80
|
+
*
|
|
81
|
+
* A client opening a DM sets `is_direct: true` on the `m.room.member` invite
|
|
82
|
+
* it sends the bot, and records the room in ITS OWN `m.direct`, never in the
|
|
83
|
+
* bot's. The invite is therefore the only moment the bot is told a room is a
|
|
84
|
+
* DM; `./handler` seeds its DM set from this and writes the room into the
|
|
85
|
+
* bot's own `m.direct` so a later restart still knows.
|
|
86
|
+
*/
|
|
87
|
+
export declare function directInviteFrom(room: MatrixInvitedRoom, me: MatrixIdentity): string | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* The {@link ChannelMessage} for a timeline event, or `undefined` when
|
|
90
|
+
* there is nothing for a chat pipeline to look at: not an `m.room.message`
|
|
91
|
+
* (a reaction, a membership change, an encrypted event this channel can't
|
|
92
|
+
* decrypt), one with no `msgtype` at all (a redacted message), or an edit of
|
|
93
|
+
* a message that was already delivered (see below).
|
|
94
|
+
*/
|
|
95
|
+
export declare function toChannelMessage(roomId: string, event: MatrixEvent, me: MatrixIdentity, directRooms: ReadonlySet<string>, sentEventIds: ReadonlySet<string>): ChannelMessage | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* A stable identity key for `bucketsFor`/`personaResolver`/`answerFn`.
|
|
98
|
+
* Namespaced so a bare Matrix user id (which is itself already `@user:
|
|
99
|
+
* server.tld`, unlike Telegram's bare numeral) never collides with another
|
|
100
|
+
* channel's key when a host shares persona/spend state across channels.
|
|
101
|
+
*/
|
|
102
|
+
export declare function matrixSenderKey(userId: string): string;
|
|
103
|
+
export {};
|
|
104
|
+
//# sourceMappingURL=updates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/updates.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,15 +14,23 @@
|
|
|
14
14
|
* re-derive it. See docs/build-a-channel.md for a worked example.
|
|
15
15
|
*/
|
|
16
16
|
import type OpenAI from "openai";
|
|
17
|
-
import type { AnswerFn, TransformReply } from "../core/answer";
|
|
18
|
-
import type { BucketsFor } from "../core/buckets";
|
|
19
17
|
import type { Logger } from "../core/logger";
|
|
20
|
-
import { type RerankContext, type RewriteQuery } from "../core/pipeline";
|
|
21
18
|
import type { PromptLoader } from "../core/prompts";
|
|
22
|
-
import type {
|
|
19
|
+
import type { Retriever } from "../core/retrieval";
|
|
23
20
|
import type { HistoryCompactionOptions } from "../history/compaction";
|
|
24
21
|
import type { HistoryStore } from "../history/types";
|
|
22
|
+
import type { BrainHooks } from "../types";
|
|
25
23
|
import { type ChannelMessage } from "./gates";
|
|
24
|
+
/**
|
|
25
|
+
* Resolves the brain hooks (`answerFn`, `bucketsFor`, `rewriteQuery`,
|
|
26
|
+
* `rerankContext`, `fallbackFn`, `transformReply`) for one channel: each
|
|
27
|
+
* field from `config` wins when set, falling back to the matching field on
|
|
28
|
+
* `fallback` (typically `deps.config`, the server-level `ChatterConfig`).
|
|
29
|
+
* Every channel that layers its own hooks over the server's uses this
|
|
30
|
+
* instead of hand-rolling the same six `??` lines: see `../telegram`,
|
|
31
|
+
* `../matrix` and `../whatsapp/inbound`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveBrainHooks(config: BrainHooks, fallback?: BrainHooks): BrainHooks;
|
|
26
34
|
/** Where a pipeline turn's output goes. Distinct from `ChannelSender` (`./senders`) — a transport implementing this may thread/quote the chat answer without doing the same for a plain gate acknowledgement. */
|
|
27
35
|
export interface InboundReplySender {
|
|
28
36
|
/** Deliver the chat answer for `chatId`. */
|
|
@@ -32,23 +40,15 @@ export interface InboundReplySender {
|
|
|
32
40
|
}
|
|
33
41
|
export interface InboundPipelineDeps {
|
|
34
42
|
client: OpenAI;
|
|
35
|
-
store:
|
|
43
|
+
store: Retriever;
|
|
36
44
|
prompts: PromptLoader;
|
|
37
45
|
}
|
|
38
|
-
export interface InboundPipelineConfig {
|
|
46
|
+
export interface InboundPipelineConfig extends BrainHooks {
|
|
39
47
|
/**
|
|
40
48
|
* This channel's identity for `transformReply` — e.g. "whatsapp",
|
|
41
49
|
* "telegram". @default "channel"
|
|
42
50
|
*/
|
|
43
51
|
channel?: string;
|
|
44
|
-
answerFn?: AnswerFn;
|
|
45
|
-
bucketsFor?: BucketsFor;
|
|
46
|
-
/** Rewrites the retrieval query before it reaches the vector store — see `ChatterConfig.rewriteQuery`. */
|
|
47
|
-
rewriteQuery?: RewriteQuery;
|
|
48
|
-
/** Post-processes retrieved chunks before they're folded into the prompt — see `ChatterConfig.rerankContext`. */
|
|
49
|
-
rerankContext?: RerankContext;
|
|
50
|
-
/** Modifies or vetoes the produced reply before delivery — see `ChatterConfig.transformReply`. */
|
|
51
|
-
transformReply?: TransformReply;
|
|
52
52
|
model?: string;
|
|
53
53
|
/** Extra system-prompt section describing the delivery channel; passed through to `prepareChat`. */
|
|
54
54
|
channelHint?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/channels/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/channels/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared config surface for a long-poll style channel (Telegram, Matrix): the
|
|
3
|
+
* gates/persona/history/rate-limit knobs `createInboundPipeline` accepts, the
|
|
4
|
+
* brain hooks (via `BrainHooks`), and the sleep/now/logger overrides tests
|
|
5
|
+
* use. Each transport extends this with its own protocol specifics (poll
|
|
6
|
+
* timeout vs. sync timeout, bot token vs. homeserver credentials, ...): see
|
|
7
|
+
* `./telegram/channel.ts` and `./matrix/channel.ts`.
|
|
8
|
+
*/
|
|
9
|
+
import type { Logger } from "../core/logger";
|
|
10
|
+
import type { HistoryCompactionOptions } from "../history/compaction";
|
|
11
|
+
import type { HistoryStore } from "../history/types";
|
|
12
|
+
import type { BrainHooks } from "../types";
|
|
13
|
+
export interface PollingChannelConfig extends BrainHooks {
|
|
14
|
+
/** Channel and sender-registry name. Override to run more than one bot in one process. */
|
|
15
|
+
name?: string;
|
|
16
|
+
/** Group chats eligible for a reply. Empty (default) = every group/room. Has no effect on DMs, which always reply. */
|
|
17
|
+
allowedChats?: string[];
|
|
18
|
+
model?: string;
|
|
19
|
+
/** Extra system-prompt section describing the delivery channel; passed through to `prepareChat`. */
|
|
20
|
+
channelHint?: string;
|
|
21
|
+
/** A throw/rejection is treated as "no persona" for that turn. */
|
|
22
|
+
personaResolver?: (ctx: {
|
|
23
|
+
sender: string;
|
|
24
|
+
text: string;
|
|
25
|
+
}) => string | undefined | Promise<string | undefined>;
|
|
26
|
+
/** Off by default — the channel stays single-turn until a store is configured. */
|
|
27
|
+
history?: {
|
|
28
|
+
store: HistoryStore;
|
|
29
|
+
/** Most recent turns to load per reply. @default 20 */
|
|
30
|
+
limit?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Excludes a sender from history entirely — see
|
|
33
|
+
* `InboundPipelineConfig.history.historyEnabledFor` in `./channels`.
|
|
34
|
+
* @default every sender is enabled
|
|
35
|
+
*/
|
|
36
|
+
historyEnabledFor?: (sender: string) => boolean | Promise<boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* Summarize-then-truncate compaction — see
|
|
39
|
+
* `InboundPipelineConfig.history.compaction` in `./channels`.
|
|
40
|
+
* @default off
|
|
41
|
+
*/
|
|
42
|
+
compaction?: HistoryCompactionOptions;
|
|
43
|
+
};
|
|
44
|
+
muteRegex?: RegExp;
|
|
45
|
+
unmuteRegex?: RegExp;
|
|
46
|
+
/** Neutral, overridable acknowledgements — this module ships no bot personality; unset = silent mute/unmute. */
|
|
47
|
+
muteReply?: string;
|
|
48
|
+
unmuteReply?: string;
|
|
49
|
+
dmRateLimit?: {
|
|
50
|
+
max: number;
|
|
51
|
+
windowMs: number;
|
|
52
|
+
};
|
|
53
|
+
groupRateLimit?: {
|
|
54
|
+
max: number;
|
|
55
|
+
windowMs: number;
|
|
56
|
+
};
|
|
57
|
+
/** Overridable for tests and for hosts routing through a proxy; defaults to `globalThis.fetch`. */
|
|
58
|
+
fetch?: typeof fetch;
|
|
59
|
+
/** Overridable for tests; defaults to a `setTimeout`-based sleep. */
|
|
60
|
+
sleep?: (ms: number) => Promise<void>;
|
|
61
|
+
now?: () => number;
|
|
62
|
+
/** Logger for poll/gate diagnostics. Falls back to the host's `deps.logger`, then a console logger. */
|
|
63
|
+
logger?: Logger;
|
|
64
|
+
}
|
|
65
|
+
/** `setTimeout`-based sleep, `unref`'d where supported so a pending sleep never keeps the process alive on its own. */
|
|
66
|
+
export declare function defaultSleep(ms: number): Promise<void>;
|
|
67
|
+
//# sourceMappingURL=polling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../../src/channels/polling.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,WAAW,oBAAqB,SAAQ,UAAU;IACtD,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sHAAsH;IACtH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACvD,kFAAkF;IAClF,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,YAAY,CAAC;QACpB,uDAAuD;QACvD,KAAK,CAAC,EAAE,MAAM,CAAC;QACf;;;;WAIG;QACH,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QACnE;;;;WAIG;QACH,UAAU,CAAC,EAAE,wBAAwB,CAAC;KACvC,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gHAAgH;IAChH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,cAAc,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,mGAAmG;IACnG,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,qEAAqE;IACrE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,uGAAuG;IACvG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uHAAuH;AACvH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKtD"}
|
|
@@ -20,30 +20,14 @@
|
|
|
20
20
|
* Telegram's privacy mode means it only receives messages that address it —
|
|
21
21
|
* which is the same policy `decideChannelAction` applies anyway.
|
|
22
22
|
*/
|
|
23
|
-
import type { AnswerFn, TransformReply } from "../../core/answer";
|
|
24
|
-
import type { BucketsFor } from "../../core/buckets";
|
|
25
|
-
import { type Logger } from "../../core/logger";
|
|
26
|
-
import type { RerankContext, RewriteQuery } from "../../core/pipeline";
|
|
27
|
-
import type { HistoryCompactionOptions } from "../../history/compaction";
|
|
28
|
-
import type { HistoryStore } from "../../history/types";
|
|
29
23
|
import type { Channel } from "../index";
|
|
24
|
+
import { type PollingChannelConfig } from "../polling";
|
|
30
25
|
import { type TelegramApi } from "./api";
|
|
31
|
-
export interface TelegramChannelConfig {
|
|
26
|
+
export interface TelegramChannelConfig extends PollingChannelConfig {
|
|
32
27
|
/** From @BotFather. A credential — pass it from the environment, never commit it. */
|
|
33
28
|
botToken: string;
|
|
34
29
|
/** Channel and sender-registry name. Override to run more than one bot in one process. @default "telegram" */
|
|
35
30
|
name?: string;
|
|
36
|
-
/** Group chats eligible for a reply. Empty (default) = every group. Has no effect on DMs, which always reply. */
|
|
37
|
-
allowedChats?: string[];
|
|
38
|
-
answerFn?: AnswerFn;
|
|
39
|
-
bucketsFor?: BucketsFor;
|
|
40
|
-
/** Rewrites the retrieval query before it reaches the vector store — see `ChatterConfig.rewriteQuery`. Falls back to the server's own. */
|
|
41
|
-
rewriteQuery?: RewriteQuery;
|
|
42
|
-
/** Post-processes retrieved chunks before they're folded into the prompt — see `ChatterConfig.rerankContext`. Falls back to the server's own. */
|
|
43
|
-
rerankContext?: RerankContext;
|
|
44
|
-
/** Modifies or vetoes the produced reply before delivery — see `ChatterConfig.transformReply`. Falls back to the server's own. */
|
|
45
|
-
transformReply?: TransformReply;
|
|
46
|
-
model?: string;
|
|
47
31
|
/** Extra system-prompt section describing the delivery channel; passed through to `prepareChat`. @default "Channel: Telegram." */
|
|
48
32
|
channelHint?: string;
|
|
49
33
|
/** A throw/rejection is treated as "no persona" for that turn. `sender` is the namespaced `tg:<id>` key. */
|
|
@@ -51,54 +35,16 @@ export interface TelegramChannelConfig {
|
|
|
51
35
|
sender: string;
|
|
52
36
|
text: string;
|
|
53
37
|
}) => string | undefined | Promise<string | undefined>;
|
|
54
|
-
/** Off by default — the channel stays single-turn until a store is configured. */
|
|
55
|
-
history?: {
|
|
56
|
-
store: HistoryStore;
|
|
57
|
-
/** Most recent turns to load per reply. @default 20 */
|
|
58
|
-
limit?: number;
|
|
59
|
-
/**
|
|
60
|
-
* Excludes a sender from history entirely — see
|
|
61
|
-
* `InboundPipelineConfig.history.historyEnabledFor` in `./channels`.
|
|
62
|
-
* @default every sender is enabled
|
|
63
|
-
*/
|
|
64
|
-
historyEnabledFor?: (sender: string) => boolean | Promise<boolean>;
|
|
65
|
-
/**
|
|
66
|
-
* Summarize-then-truncate compaction — see
|
|
67
|
-
* `InboundPipelineConfig.history.compaction` in `./channels`.
|
|
68
|
-
* @default off
|
|
69
|
-
*/
|
|
70
|
-
compaction?: HistoryCompactionOptions;
|
|
71
|
-
};
|
|
72
|
-
muteRegex?: RegExp;
|
|
73
|
-
unmuteRegex?: RegExp;
|
|
74
|
-
/** Neutral, overridable acknowledgements — this module ships no bot personality; unset = silent mute/unmute. */
|
|
75
|
-
muteReply?: string;
|
|
76
|
-
unmuteReply?: string;
|
|
77
|
-
dmRateLimit?: {
|
|
78
|
-
max: number;
|
|
79
|
-
windowMs: number;
|
|
80
|
-
};
|
|
81
|
-
groupRateLimit?: {
|
|
82
|
-
max: number;
|
|
83
|
-
windowMs: number;
|
|
84
|
-
};
|
|
85
38
|
/** @default 30 */
|
|
86
39
|
pollTimeoutSeconds?: number;
|
|
87
40
|
/** Resume point for `getUpdates`. Omitted = whatever Telegram still has queued (see docs/telegram.md). */
|
|
88
41
|
initialOffset?: number;
|
|
89
42
|
/** Called with each acknowledged offset, for a host that wants to persist it across restarts. */
|
|
90
43
|
onOffset?: (offset: number) => void;
|
|
91
|
-
/** Overridable for tests and for hosts routing through a proxy; defaults to `globalThis.fetch`. */
|
|
92
|
-
fetch?: typeof fetch;
|
|
93
44
|
/** Self-hosted Bot API server origin. */
|
|
94
45
|
apiBaseUrl?: string;
|
|
95
46
|
/** Overridable for tests, which fake the Bot API instead of calling it; defaults to a `fetch` client over {@link TelegramChannelConfig.botToken}. */
|
|
96
47
|
api?: TelegramApi;
|
|
97
|
-
/** Overridable for tests; defaults to a `setTimeout`-based sleep. */
|
|
98
|
-
sleep?: (ms: number) => Promise<void>;
|
|
99
|
-
now?: () => number;
|
|
100
|
-
/** Logger for poll/gate diagnostics. Falls back to the host's `deps.logger`, then a console logger. */
|
|
101
|
-
logger?: Logger;
|
|
102
48
|
}
|
|
103
49
|
export declare function createTelegramChannel(config: TelegramChannelConfig): Channel;
|
|
104
50
|
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC;AAQ5D,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,8GAA8G;IAC9G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kIAAkI;IAClI,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4GAA4G;IAC5G,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACvD,kBAAkB;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0GAA0G;IAC1G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qJAAqJ;IACrJ,GAAG,CAAC,EAAE,WAAW,CAAC;CACnB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAmG5E"}
|
|
@@ -294,7 +294,8 @@ async function answerOnce({
|
|
|
294
294
|
async function applyTransformReply(transformReply, input, logger) {
|
|
295
295
|
if (!transformReply) return input.text;
|
|
296
296
|
try {
|
|
297
|
-
|
|
297
|
+
const result = await transformReply(input);
|
|
298
|
+
return typeof result === "string" ? result : null;
|
|
298
299
|
} catch (error) {
|
|
299
300
|
logger?.error(
|
|
300
301
|
`transformReply threw for channel "${input.channel}"; sending the original reply`,
|
|
@@ -356,6 +357,7 @@ async function prepareChat({
|
|
|
356
357
|
sender,
|
|
357
358
|
rewriteQuery,
|
|
358
359
|
rerankContext,
|
|
360
|
+
fallbackFn,
|
|
359
361
|
logger
|
|
360
362
|
}) {
|
|
361
363
|
const lastUserMsg = lastUserMessage(messages);
|
|
@@ -372,21 +374,39 @@ async function prepareChat({
|
|
|
372
374
|
logger?.error("rewriteQuery threw; falling back to the original query", error);
|
|
373
375
|
}
|
|
374
376
|
}
|
|
375
|
-
|
|
377
|
+
const resolvedBuckets = buckets ?? defaultBuckets(mode);
|
|
378
|
+
const retrievedChunks = await store.query(query, topK, resolvedBuckets);
|
|
379
|
+
let ctx = retrievedChunks;
|
|
376
380
|
if (rerankContext) {
|
|
377
381
|
try {
|
|
378
|
-
const reranked = await rerankContext({ query, chunks: ctx });
|
|
382
|
+
const reranked = await rerankContext({ query, chunks: [...ctx] });
|
|
379
383
|
if (Array.isArray(reranked) && reranked.every((c) => typeof c === "string")) ctx = reranked;
|
|
380
384
|
} catch (error) {
|
|
381
385
|
logger?.error("rerankContext threw; falling back to the original chunks", error);
|
|
382
386
|
}
|
|
383
387
|
}
|
|
388
|
+
let fallback;
|
|
389
|
+
if (ctx.length === 0 && fallbackFn) {
|
|
390
|
+
try {
|
|
391
|
+
const guidance = await fallbackFn({
|
|
392
|
+
query,
|
|
393
|
+
mode,
|
|
394
|
+
buckets: resolvedBuckets,
|
|
395
|
+
sender,
|
|
396
|
+
retrievedChunks
|
|
397
|
+
});
|
|
398
|
+
if (typeof guidance === "string" && guidance.trim()) fallback = guidance.trim();
|
|
399
|
+
} catch (error) {
|
|
400
|
+
logger?.error("fallbackFn threw; proceeding without fallback guidance", error);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
384
403
|
const persona = personaLayer?.trim() || (mode === "private" ? prompts.privatePersona : prompts.publicPersona);
|
|
385
404
|
const hint = channelHint?.trim();
|
|
386
405
|
const system = [
|
|
387
406
|
prompts.baseSystemRules,
|
|
388
407
|
persona,
|
|
389
408
|
...hint ? [hint] : [],
|
|
409
|
+
...fallback ? [fallback] : [],
|
|
390
410
|
`${label}:
|
|
391
411
|
${ctx.join("\n\n")}`
|
|
392
412
|
].join("\n\n");
|
|
@@ -394,7 +414,7 @@ ${ctx.join("\n\n")}`
|
|
|
394
414
|
}
|
|
395
415
|
|
|
396
416
|
// src/history/compaction.ts
|
|
397
|
-
var
|
|
417
|
+
var COMPACTION_TIMEOUT_MS = 8e3;
|
|
398
418
|
var LOAD_ALL = Number.MAX_SAFE_INTEGER;
|
|
399
419
|
var SUMMARY_PREFIX = "Summary of earlier conversation: ";
|
|
400
420
|
function defaultSummarize(client, model) {
|
|
@@ -422,7 +442,7 @@ function createHistoryCompactor(deps, options) {
|
|
|
422
442
|
throw new Error(`Invalid history compaction keep: ${keep}`);
|
|
423
443
|
}
|
|
424
444
|
const summarize = options.summarize ?? defaultSummarize(deps.client, options.model);
|
|
425
|
-
const timeoutMs = options.timeoutMs ??
|
|
445
|
+
const timeoutMs = options.timeoutMs ?? COMPACTION_TIMEOUT_MS;
|
|
426
446
|
return {
|
|
427
447
|
async maybeCompact(store, conversationId) {
|
|
428
448
|
const turns = await store.load(conversationId, LOAD_ALL);
|
|
@@ -513,6 +533,16 @@ function underReplyRateLimit(msg, limiters) {
|
|
|
513
533
|
}
|
|
514
534
|
|
|
515
535
|
// src/channels/pipeline.ts
|
|
536
|
+
function resolveBrainHooks(config, fallback) {
|
|
537
|
+
return {
|
|
538
|
+
answerFn: config.answerFn ?? fallback?.answerFn,
|
|
539
|
+
bucketsFor: config.bucketsFor ?? fallback?.bucketsFor,
|
|
540
|
+
rewriteQuery: config.rewriteQuery ?? fallback?.rewriteQuery,
|
|
541
|
+
rerankContext: config.rerankContext ?? fallback?.rerankContext,
|
|
542
|
+
fallbackFn: config.fallbackFn ?? fallback?.fallbackFn,
|
|
543
|
+
transformReply: config.transformReply ?? fallback?.transformReply
|
|
544
|
+
};
|
|
545
|
+
}
|
|
516
546
|
var DEFAULT_HISTORY_LIMIT = 20;
|
|
517
547
|
var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
|
|
518
548
|
var DEFAULT_DM_RATE_LIMIT = { max: 20, windowMs: 60 * 60 * 1e3 };
|
|
@@ -597,6 +627,7 @@ function createInboundPipeline(deps, config) {
|
|
|
597
627
|
sender,
|
|
598
628
|
rewriteQuery: config.rewriteQuery,
|
|
599
629
|
rerankContext: config.rerankContext,
|
|
630
|
+
fallbackFn: config.fallbackFn,
|
|
600
631
|
logger: config.logger
|
|
601
632
|
});
|
|
602
633
|
const { content: produced } = await answerOnce({
|
|
@@ -633,6 +664,14 @@ function createInboundPipeline(deps, config) {
|
|
|
633
664
|
};
|
|
634
665
|
}
|
|
635
666
|
|
|
667
|
+
// src/channels/polling.ts
|
|
668
|
+
function defaultSleep(ms) {
|
|
669
|
+
return new Promise((resolve) => {
|
|
670
|
+
const timer = setTimeout(resolve, ms);
|
|
671
|
+
if (typeof timer === "object" && "unref" in timer) timer.unref();
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
|
|
636
675
|
// src/channels/telegram/updates.ts
|
|
637
676
|
function messageText(message) {
|
|
638
677
|
return message.text ?? message.caption ?? "";
|
|
@@ -711,11 +750,16 @@ function createTelegramSender(api) {
|
|
|
711
750
|
};
|
|
712
751
|
}
|
|
713
752
|
|
|
753
|
+
// src/channels/backoff.ts
|
|
754
|
+
function exponentialBackoffMs(baseMs, maxMs, n) {
|
|
755
|
+
return Math.min(baseMs * 2 ** Math.max(0, Math.min(n, 20)), maxMs);
|
|
756
|
+
}
|
|
757
|
+
|
|
714
758
|
// src/channels/telegram/poll.ts
|
|
715
759
|
var BASE_DELAY_MS = 1e3;
|
|
716
760
|
var MAX_DELAY_MS = 6e4;
|
|
717
761
|
function pollBackoffMs(failures) {
|
|
718
|
-
return
|
|
762
|
+
return exponentialBackoffMs(BASE_DELAY_MS, MAX_DELAY_MS, failures);
|
|
719
763
|
}
|
|
720
764
|
function retryDelayMs(error, failures) {
|
|
721
765
|
const retryAfterMs = error instanceof TelegramApiError ? error.retryAfterMs : void 0;
|
|
@@ -740,9 +784,9 @@ async function runLongPoll(deps) {
|
|
|
740
784
|
}
|
|
741
785
|
failures = 0;
|
|
742
786
|
for (const update of updates) {
|
|
787
|
+
if (deps.isStopped()) break;
|
|
743
788
|
offset = nextOffset(update);
|
|
744
789
|
deps.onOffset?.(offset);
|
|
745
|
-
if (deps.isStopped()) break;
|
|
746
790
|
try {
|
|
747
791
|
await deps.handleUpdate(update);
|
|
748
792
|
} catch (error) {
|
|
@@ -755,12 +799,6 @@ async function runLongPoll(deps) {
|
|
|
755
799
|
|
|
756
800
|
// src/channels/telegram/channel.ts
|
|
757
801
|
var DEFAULT_POLL_TIMEOUT_SECONDS = 30;
|
|
758
|
-
function defaultSleep(ms) {
|
|
759
|
-
return new Promise((resolve) => {
|
|
760
|
-
const timer = setTimeout(resolve, ms);
|
|
761
|
-
if (typeof timer === "object" && "unref" in timer) timer.unref();
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
802
|
function createTelegramChannel(config) {
|
|
765
803
|
const channelName = config.name ?? "telegram";
|
|
766
804
|
const allowedChats = config.allowedChats ?? [];
|
|
@@ -788,11 +826,7 @@ function createTelegramChannel(config) {
|
|
|
788
826
|
{ client: deps.client, store: deps.store, prompts: deps.prompts },
|
|
789
827
|
{
|
|
790
828
|
channel: channelName,
|
|
791
|
-
|
|
792
|
-
bucketsFor: config.bucketsFor ?? deps.config.bucketsFor,
|
|
793
|
-
rewriteQuery: config.rewriteQuery ?? deps.config.rewriteQuery,
|
|
794
|
-
rerankContext: config.rerankContext ?? deps.config.rerankContext,
|
|
795
|
-
transformReply: config.transformReply ?? deps.config.transformReply,
|
|
829
|
+
...resolveBrainHooks(config, deps.config),
|
|
796
830
|
model: config.model,
|
|
797
831
|
channelHint: config.channelHint ?? "Channel: Telegram.",
|
|
798
832
|
personaResolver: config.personaResolver,
|
|
@@ -971,11 +1005,7 @@ function createTelegramWebhookRoute(config) {
|
|
|
971
1005
|
{ client: deps.client, store: deps.store, prompts: deps.prompts },
|
|
972
1006
|
{
|
|
973
1007
|
channel: channelName,
|
|
974
|
-
|
|
975
|
-
bucketsFor: config.bucketsFor ?? deps.config.bucketsFor,
|
|
976
|
-
rewriteQuery: config.rewriteQuery ?? deps.config.rewriteQuery,
|
|
977
|
-
rerankContext: config.rerankContext ?? deps.config.rerankContext,
|
|
978
|
-
transformReply: config.transformReply ?? deps.config.transformReply,
|
|
1008
|
+
...resolveBrainHooks(config, deps.config),
|
|
979
1009
|
model: config.model,
|
|
980
1010
|
channelHint: config.channelHint ?? "Channel: Telegram.",
|
|
981
1011
|
personaResolver: config.personaResolver,
|