@spinabot/brigade 1.1.0 → 1.2.1

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.
Files changed (139) hide show
  1. package/convex/channels.d.ts +5 -5
  2. package/convex/schema.d.ts +2 -2
  3. package/dist/agents/agent-loop.d.ts.map +1 -1
  4. package/dist/agents/agent-loop.js +27 -4
  5. package/dist/agents/agent-loop.js.map +1 -1
  6. package/dist/agents/channels/approval-callback-codec.d.ts +107 -0
  7. package/dist/agents/channels/approval-callback-codec.d.ts.map +1 -0
  8. package/dist/agents/channels/approval-callback-codec.js +173 -0
  9. package/dist/agents/channels/approval-callback-codec.js.map +1 -0
  10. package/dist/agents/channels/approval-router.d.ts +77 -20
  11. package/dist/agents/channels/approval-router.d.ts.map +1 -1
  12. package/dist/agents/channels/approval-router.js +163 -37
  13. package/dist/agents/channels/approval-router.js.map +1 -1
  14. package/dist/agents/channels/backoff.d.ts +55 -0
  15. package/dist/agents/channels/backoff.d.ts.map +1 -0
  16. package/dist/agents/channels/backoff.js +47 -0
  17. package/dist/agents/channels/backoff.js.map +1 -0
  18. package/dist/agents/channels/channel-secrets.d.ts +45 -0
  19. package/dist/agents/channels/channel-secrets.d.ts.map +1 -0
  20. package/dist/agents/channels/channel-secrets.js +69 -0
  21. package/dist/agents/channels/channel-secrets.js.map +1 -0
  22. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  23. package/dist/agents/channels/inbound-pipeline.js +67 -3
  24. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  25. package/dist/agents/channels/last-sent-message.d.ts +46 -0
  26. package/dist/agents/channels/last-sent-message.d.ts.map +1 -0
  27. package/dist/agents/channels/last-sent-message.js +55 -0
  28. package/dist/agents/channels/last-sent-message.js.map +1 -0
  29. package/dist/agents/channels/manager.d.ts +52 -0
  30. package/dist/agents/channels/manager.d.ts.map +1 -1
  31. package/dist/agents/channels/manager.js +141 -31
  32. package/dist/agents/channels/manager.js.map +1 -1
  33. package/dist/agents/channels/plugin-channel-manager-facade.d.ts +13 -2
  34. package/dist/agents/channels/plugin-channel-manager-facade.d.ts.map +1 -1
  35. package/dist/agents/channels/plugin-channel-manager-facade.js +21 -0
  36. package/dist/agents/channels/plugin-channel-manager-facade.js.map +1 -1
  37. package/dist/agents/channels/sdk.d.ts +426 -0
  38. package/dist/agents/channels/sdk.d.ts.map +1 -0
  39. package/dist/agents/channels/sdk.js +274 -0
  40. package/dist/agents/channels/sdk.js.map +1 -0
  41. package/dist/agents/channels/telegram/account-config.d.ts +92 -0
  42. package/dist/agents/channels/telegram/account-config.d.ts.map +1 -0
  43. package/dist/agents/channels/telegram/account-config.js +192 -0
  44. package/dist/agents/channels/telegram/account-config.js.map +1 -0
  45. package/dist/agents/channels/telegram/adapter.d.ts +79 -0
  46. package/dist/agents/channels/telegram/adapter.d.ts.map +1 -0
  47. package/dist/agents/channels/telegram/adapter.js +475 -0
  48. package/dist/agents/channels/telegram/adapter.js.map +1 -0
  49. package/dist/agents/channels/telegram/allowed-updates.d.ts +44 -0
  50. package/dist/agents/channels/telegram/allowed-updates.d.ts.map +1 -0
  51. package/dist/agents/channels/telegram/allowed-updates.js +52 -0
  52. package/dist/agents/channels/telegram/allowed-updates.js.map +1 -0
  53. package/dist/agents/channels/telegram/approval-authorize.d.ts +41 -0
  54. package/dist/agents/channels/telegram/approval-authorize.d.ts.map +1 -0
  55. package/dist/agents/channels/telegram/approval-authorize.js +69 -0
  56. package/dist/agents/channels/telegram/approval-authorize.js.map +1 -0
  57. package/dist/agents/channels/telegram/approval-native.d.ts +68 -0
  58. package/dist/agents/channels/telegram/approval-native.d.ts.map +1 -0
  59. package/dist/agents/channels/telegram/approval-native.js +94 -0
  60. package/dist/agents/channels/telegram/approval-native.js.map +1 -0
  61. package/dist/agents/channels/telegram/command-menu.d.ts +35 -0
  62. package/dist/agents/channels/telegram/command-menu.d.ts.map +1 -0
  63. package/dist/agents/channels/telegram/command-menu.js +59 -0
  64. package/dist/agents/channels/telegram/command-menu.js.map +1 -0
  65. package/dist/agents/channels/telegram/connection.d.ts +359 -0
  66. package/dist/agents/channels/telegram/connection.d.ts.map +1 -0
  67. package/dist/agents/channels/telegram/connection.js +865 -0
  68. package/dist/agents/channels/telegram/connection.js.map +1 -0
  69. package/dist/agents/channels/telegram/format.d.ts +48 -0
  70. package/dist/agents/channels/telegram/format.d.ts.map +1 -0
  71. package/dist/agents/channels/telegram/format.js +256 -0
  72. package/dist/agents/channels/telegram/format.js.map +1 -0
  73. package/dist/agents/channels/telegram/inbound-extras.d.ts +73 -0
  74. package/dist/agents/channels/telegram/inbound-extras.d.ts.map +1 -0
  75. package/dist/agents/channels/telegram/inbound-extras.js +231 -0
  76. package/dist/agents/channels/telegram/inbound-extras.js.map +1 -0
  77. package/dist/agents/channels/telegram/index.d.ts +14 -0
  78. package/dist/agents/channels/telegram/index.d.ts.map +1 -0
  79. package/dist/agents/channels/telegram/index.js +14 -0
  80. package/dist/agents/channels/telegram/index.js.map +1 -0
  81. package/dist/agents/channels/telegram/media.d.ts +68 -0
  82. package/dist/agents/channels/telegram/media.d.ts.map +1 -0
  83. package/dist/agents/channels/telegram/media.js +143 -0
  84. package/dist/agents/channels/telegram/media.js.map +1 -0
  85. package/dist/agents/channels/telegram/module.d.ts +15 -0
  86. package/dist/agents/channels/telegram/module.d.ts.map +1 -0
  87. package/dist/agents/channels/telegram/module.js +36 -0
  88. package/dist/agents/channels/telegram/module.js.map +1 -0
  89. package/dist/agents/channels/telegram/plugin.d.ts +76 -0
  90. package/dist/agents/channels/telegram/plugin.d.ts.map +1 -0
  91. package/dist/agents/channels/telegram/plugin.js +314 -0
  92. package/dist/agents/channels/telegram/plugin.js.map +1 -0
  93. package/dist/agents/channels/telegram/probe.d.ts +54 -0
  94. package/dist/agents/channels/telegram/probe.d.ts.map +1 -0
  95. package/dist/agents/channels/telegram/probe.js +95 -0
  96. package/dist/agents/channels/telegram/probe.js.map +1 -0
  97. package/dist/agents/channels/telegram/webhook.d.ts +55 -0
  98. package/dist/agents/channels/telegram/webhook.d.ts.map +1 -0
  99. package/dist/agents/channels/telegram/webhook.js +141 -0
  100. package/dist/agents/channels/telegram/webhook.js.map +1 -0
  101. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  102. package/dist/agents/extensions/modules/index.js +4 -0
  103. package/dist/agents/extensions/modules/index.js.map +1 -1
  104. package/dist/agents/extensions/types.d.ts +72 -2
  105. package/dist/agents/extensions/types.d.ts.map +1 -1
  106. package/dist/agents/extensions/types.js.map +1 -1
  107. package/dist/agents/tools/connect-channel-tool.d.ts +86 -0
  108. package/dist/agents/tools/connect-channel-tool.d.ts.map +1 -0
  109. package/dist/agents/tools/connect-channel-tool.js +398 -0
  110. package/dist/agents/tools/connect-channel-tool.js.map +1 -0
  111. package/dist/agents/tools/message-action-tool.d.ts +67 -0
  112. package/dist/agents/tools/message-action-tool.d.ts.map +1 -0
  113. package/dist/agents/tools/message-action-tool.js +216 -0
  114. package/dist/agents/tools/message-action-tool.js.map +1 -0
  115. package/dist/agents/tools/registry.d.ts.map +1 -1
  116. package/dist/agents/tools/registry.js +19 -0
  117. package/dist/agents/tools/registry.js.map +1 -1
  118. package/dist/buildstamp.json +1 -1
  119. package/dist/cli/commands/channels.d.ts.map +1 -1
  120. package/dist/cli/commands/channels.js +27 -2
  121. package/dist/cli/commands/channels.js.map +1 -1
  122. package/dist/core/server.d.ts.map +1 -1
  123. package/dist/core/server.js +77 -27
  124. package/dist/core/server.js.map +1 -1
  125. package/dist/cron/service/state.d.ts +10 -0
  126. package/dist/cron/service/state.d.ts.map +1 -1
  127. package/dist/cron/service/state.js.map +1 -1
  128. package/dist/cron/service/timer.d.ts.map +1 -1
  129. package/dist/cron/service/timer.js +43 -14
  130. package/dist/cron/service/timer.js.map +1 -1
  131. package/dist/cron/session-reaper.d.ts +27 -0
  132. package/dist/cron/session-reaper.d.ts.map +1 -1
  133. package/dist/cron/session-reaper.js +81 -0
  134. package/dist/cron/session-reaper.js.map +1 -1
  135. package/dist/system-prompt/assembler.d.ts +14 -0
  136. package/dist/system-prompt/assembler.d.ts.map +1 -1
  137. package/dist/system-prompt/assembler.js +36 -14
  138. package/dist/system-prompt/assembler.js.map +1 -1
  139. package/package.json +22 -6
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Telegram channel adapter.
3
+ *
4
+ * Implements the Brigade `ChannelAdapter` contract on top of the grammY
5
+ * long-polling connection. Unlike WhatsApp (QR pairing), Telegram is
6
+ * TOKEN-based: the operator pastes a Bot API token from @BotFather, so this
7
+ * adapter declares a `setup` wizard (single `botToken` credential) and has NO
8
+ * `link`/QR flow. Enablement is explicit — `channels.telegram.enabled: true`
9
+ * plus a resolvable token.
10
+ *
11
+ * Modeled directly on `whatsapp/adapter.ts`: same health-flag mirroring, same
12
+ * deferred-media passthrough on inbound, same chunk-then-send outbound shape
13
+ * (chunk markdown ≤4096, convert each chunk to Telegram HTML, send with
14
+ * `parse_mode: HTML`, and on a parse / empty-text error RETRY as plain text).
15
+ *
16
+ * Scope cut (v1): single account, and `callback_query` inline buttons are not
17
+ * handled (Brigade approvals are central text replies).
18
+ */
19
+ import { type ChannelAdapter, type ChannelCapabilities, type OutboundSendOptions } from "../sdk.js";
20
+ import { type ConnectTelegramArgs, type TelegramConnection, type TelegramPollSpec } from "./connection.js";
21
+ /** Adapter construction options — all optional for back-compat. */
22
+ export interface CreateTelegramAdapterOptions {
23
+ /** Per-account scope. Defaults to `"default"` (single-account v1). */
24
+ accountId?: string;
25
+ /**
26
+ * TEST SEAM: override how the connection is built. Production leaves this
27
+ * undefined and `connectTelegram` lazy-loads grammY. Tests inject a fake.
28
+ */
29
+ connectImpl?: (args: ConnectTelegramArgs) => Promise<TelegramConnection>;
30
+ /**
31
+ * The bot's `/` command menu to register on connect (Brigade's central
32
+ * commands, already mapped to `{ command, description }` via
33
+ * `buildTelegramCommandMenu`). Empty/omitted → no menu sync. The manager
34
+ * supplies this from `buildBundledCommands(adapter)`.
35
+ */
36
+ commandMenu?: Array<{
37
+ command: string;
38
+ description: string;
39
+ }>;
40
+ /**
41
+ * Widen the `allowed_updates` poller subscription beyond the default
42
+ * `message` + `callback_query`. Omitted → the minimal set.
43
+ */
44
+ allowedUpdates?: string[];
45
+ /**
46
+ * Enable forum-topic auto-labeling: when set, the FIRST message seen on a
47
+ * forum thread renames that topic from the message text. Off by default —
48
+ * the plugin path enables it from `channels.telegram.autoLabelTopics`.
49
+ */
50
+ autoLabelTopics?: boolean;
51
+ }
52
+ export declare function createTelegramAdapter(opts?: CreateTelegramAdapterOptions): ChannelAdapter;
53
+ /** Static Telegram capability flags (shared by the legacy adapter + plugin meta). */
54
+ export declare const TELEGRAM_CAPABILITIES: ChannelCapabilities;
55
+ /**
56
+ * The Telegram adapter shape with its poll extension. `createTelegramAdapter`
57
+ * returns a `ChannelAdapter`, but the concrete object ALSO carries `sendPoll`
58
+ * (not in the base contract). Callers that want polls cast through this type.
59
+ */
60
+ export interface TelegramAdapter extends ChannelAdapter {
61
+ sendPoll(conversationId: string, poll: TelegramPollSpec, opts?: OutboundSendOptions): Promise<{
62
+ messageId?: string;
63
+ }>;
64
+ /**
65
+ * Feed a raw Telegram `Update` (webhook mode). The gateway HTTP route calls
66
+ * this after verifying the secret-token header. No-op when not started or in
67
+ * polling mode. The argument is the parsed JSON body Telegram POSTed.
68
+ */
69
+ feedWebhookUpdate(update: unknown): void;
70
+ /** The transport mode this adapter's connection runs (`"polling"` | `"webhook"`). */
71
+ transportMode(): "polling" | "webhook" | "unstarted";
72
+ }
73
+ /**
74
+ * Derive a forum-topic name from a message's first line. Telegram caps topic
75
+ * names at 128 chars; we use the first line, collapsed + trimmed, clamped to a
76
+ * readable length. Returns "" when nothing usable remains.
77
+ */
78
+ export declare function deriveTopicName(text: string): string;
79
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/telegram/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AASH,OAAO,EACN,KAAK,cAAc,EAEnB,KAAK,mBAAmB,EAMxB,KAAK,mBAAmB,EAExB,MAAM,WAAW,CAAC;AAUnB,OAAO,EAAmB,KAAK,mBAAmB,EAA4B,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAUtJ,mEAAmE;AACnE,MAAM,WAAW,4BAA4B;IAC5C,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACzE;;;;;OAKG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,4BAAiC,GAAG,cAAc,CAkZ7F;AAED,qFAAqF;AACrF,eAAO,MAAM,qBAAqB,EAAE,mBAUnC,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACtD,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtH;;;;OAIG;IACH,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACzC,qFAAqF;IACrF,aAAa,IAAI,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;CACrD;AAgBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIpD"}
@@ -0,0 +1,475 @@
1
+ /**
2
+ * Telegram channel adapter.
3
+ *
4
+ * Implements the Brigade `ChannelAdapter` contract on top of the grammY
5
+ * long-polling connection. Unlike WhatsApp (QR pairing), Telegram is
6
+ * TOKEN-based: the operator pastes a Bot API token from @BotFather, so this
7
+ * adapter declares a `setup` wizard (single `botToken` credential) and has NO
8
+ * `link`/QR flow. Enablement is explicit — `channels.telegram.enabled: true`
9
+ * plus a resolvable token.
10
+ *
11
+ * Modeled directly on `whatsapp/adapter.ts`: same health-flag mirroring, same
12
+ * deferred-media passthrough on inbound, same chunk-then-send outbound shape
13
+ * (chunk markdown ≤4096, convert each chunk to Telegram HTML, send with
14
+ * `parse_mode: HTML`, and on a parse / empty-text error RETRY as plain text).
15
+ *
16
+ * Scope cut (v1): single account, and `callback_query` inline buttons are not
17
+ * handled (Brigade approvals are central text replies).
18
+ */
19
+ import { loadConfig } from "../../../core/config.js";
20
+ // Channel SDK barrel — the single import surface for the channel-authoring
21
+ // contract + shared helpers. Telegram is the proving ground: contract types
22
+ // (ChannelAdapter / ChannelHealth / ChannelStartContext / OutboundMedia /
23
+ // OutboundSendOptions) and `chunkText` now come from one place instead of
24
+ // scattered `../../extensions/types.js` + `../whatsapp/chunk.js` paths.
25
+ import { chunkText, } from "../sdk.js";
26
+ import { listTelegramAccountIds, resolveTelegramBotToken, telegramChannelEnabled, telegramWebhookConfig, TELEGRAM_CHANNEL_ID, TELEGRAM_DEFAULT_ACCOUNT_ID, } from "./account-config.js";
27
+ import { buildTelegramApprovalKeyboard, buildTelegramApprovalText } from "./approval-native.js";
28
+ import { connectTelegram } from "./connection.js";
29
+ import { markdownToTelegramHtml, telegramHtmlIsEmpty } from "./format.js";
30
+ import { resolveTelegramApprover } from "./approval-authorize.js";
31
+ /** Telegram's per-message text limit. */
32
+ const TELEGRAM_TEXT_LIMIT = 4096;
33
+ /** Errors Telegram returns when HTML failed to parse / produced an empty body. */
34
+ const PARSE_ERROR_RE = /can't parse entities|parse entities|find end of the entity|message text is empty/i;
35
+ export function createTelegramAdapter(opts = {}) {
36
+ const accountId = opts.accountId?.trim() || TELEGRAM_DEFAULT_ACCOUNT_ID;
37
+ const connectImpl = opts.connectImpl ?? connectTelegram;
38
+ let connection = null;
39
+ // Forum threads we've already auto-labeled this process, so the rename fires
40
+ // only on the FIRST message of a topic (keyed `${chatId}:${threadId}`).
41
+ const autoLabeledThreads = new Set();
42
+ // The ChannelStartContext doesn't carry the config, but the manager ALWAYS
43
+ // calls `isConfigured(cfg, env)` immediately before `start(ctx)` — so we
44
+ // capture the config + env it passed there and read the token from them in
45
+ // start(). This avoids a second config load and keeps the adapter pure.
46
+ let lastConfig = null;
47
+ let lastEnv = process.env;
48
+ // Health flags mirrored from the connection lifecycle so health() never has
49
+ // to round-trip Telegram on the hot path (cron timer / send pre-flight).
50
+ // - `connected` flips true on a successful getMe + poll start.
51
+ // - `tokenInvalid` is STICKY: a 401 means the token is dead and the only
52
+ // recovery is `brigade channels add --channel telegram` with a new token.
53
+ let connected = false;
54
+ let tokenInvalid = false;
55
+ const adapter = {
56
+ id: TELEGRAM_CHANNEL_ID,
57
+ label: "Telegram",
58
+ isConfigured(cfg, env) {
59
+ // Capture for start() — the manager calls this right before start(ctx).
60
+ lastConfig = cfg;
61
+ lastEnv = env ?? process.env;
62
+ if (!telegramChannelEnabled(cfg))
63
+ return false;
64
+ // Need a resolvable bot token (config `${VAR}` ref or TELEGRAM_BOT_TOKEN env).
65
+ if (!resolveTelegramBotToken(cfg, accountId, env ?? process.env))
66
+ return false;
67
+ // Multi-account follow-up: when the operator declares >1 account, the
68
+ // (future) plugin path owns lifecycle and the legacy single adapter
69
+ // steps aside. v1 only ever runs the default account.
70
+ const isLegacyAdapter = accountId === TELEGRAM_DEFAULT_ACCOUNT_ID;
71
+ if (isLegacyAdapter && listTelegramAccountIds(cfg).length > 1)
72
+ return false;
73
+ return true;
74
+ },
75
+ async start(ctx) {
76
+ // Resolve the token from the config the manager handed isConfigured().
77
+ // Fall back to a fresh load defensively (e.g. a direct start() in a test
78
+ // that skipped isConfigured).
79
+ const cfg = lastConfig ?? (await loadStartConfig());
80
+ const token = resolveTelegramBotToken(cfg, accountId, lastEnv);
81
+ if (!token) {
82
+ // Defensive — isConfigured already gates this, but never start a bot
83
+ // with an empty token (grammY would throw an opaque error).
84
+ ctx.log("Telegram not started — no bot token resolved (set channels.telegram.botToken or TELEGRAM_BOT_TOKEN).");
85
+ return;
86
+ }
87
+ // Resolve transport mode (polling default; webhook opt-in). Webhook mode
88
+ // registers the webhook on connect; the gateway HTTP route feeds updates
89
+ // via `feedWebhookUpdate` (wired by the module when webhook is active).
90
+ const transport = telegramWebhookConfig(cfg, lastEnv);
91
+ connection = await connectImpl({
92
+ token,
93
+ accountId,
94
+ ...(opts.commandMenu && opts.commandMenu.length > 0 ? { commandMenu: opts.commandMenu } : {}),
95
+ ...(opts.allowedUpdates && opts.allowedUpdates.length > 0 ? { allowedUpdates: opts.allowedUpdates } : {}),
96
+ ...(transport.mode === "webhook"
97
+ ? {
98
+ mode: "webhook",
99
+ webhook: {
100
+ ...(transport.url ? { url: transport.url } : {}),
101
+ ...(transport.secretToken ? { secretToken: transport.secretToken } : {}),
102
+ },
103
+ }
104
+ : {}),
105
+ log: ctx.log,
106
+ onConnected: () => {
107
+ connected = true;
108
+ tokenInvalid = false;
109
+ ctx.log("Telegram ready");
110
+ ctx.onConnected?.();
111
+ },
112
+ onTokenInvalid: () => {
113
+ connected = false;
114
+ tokenInvalid = true;
115
+ ctx.log("Telegram bot token was rejected. Run `brigade channels add --channel telegram` with a fresh @BotFather token.");
116
+ ctx.onLoggedOut?.();
117
+ },
118
+ onMessage: (msg) => {
119
+ // Forum-topic auto-labeling: rename a topic from its first message.
120
+ // Fire-and-forget + best-effort — never blocks inbound delivery.
121
+ if (opts.autoLabelTopics && msg.threadId && msg.chatType === "group" && msg.text.trim()) {
122
+ maybeAutoLabelThread(msg.conversationId, msg.threadId, msg.text);
123
+ }
124
+ void ctx.onInbound({
125
+ channel: TELEGRAM_CHANNEL_ID,
126
+ accountId,
127
+ conversationId: msg.conversationId,
128
+ messageId: msg.messageId,
129
+ messageTimestampMs: msg.messageTimestampMs,
130
+ from: msg.from,
131
+ fromName: msg.fromName,
132
+ text: msg.text,
133
+ chatType: msg.chatType,
134
+ isGroup: msg.chatType === "group",
135
+ threadId: msg.threadId,
136
+ mentions: msg.mentions,
137
+ replyTo: msg.replyTo,
138
+ // Deferred media thunk rides through untouched — the pipeline
139
+ // resolves it only after the access gate admits the sender.
140
+ resolveMedia: msg.resolveMedia,
141
+ raw: msg.raw,
142
+ });
143
+ },
144
+ // Inline-button press → emit an InboundMessage carrying `callbackQuery`
145
+ // so the central pipeline's approval-callback path resolves it. The
146
+ // connection has already acked the press via `answerCallbackQuery`.
147
+ onCallbackQuery: (msg) => {
148
+ if (!msg.callbackQuery)
149
+ return;
150
+ void ctx.onInbound({
151
+ channel: TELEGRAM_CHANNEL_ID,
152
+ accountId,
153
+ conversationId: msg.conversationId,
154
+ from: msg.from,
155
+ ...(msg.fromName !== undefined ? { fromName: msg.fromName } : {}),
156
+ text: "",
157
+ chatType: msg.chatType,
158
+ isGroup: msg.chatType === "group",
159
+ ...(msg.threadId !== undefined ? { threadId: msg.threadId } : {}),
160
+ callbackQuery: msg.callbackQuery,
161
+ raw: msg.raw,
162
+ });
163
+ },
164
+ });
165
+ },
166
+ async stop() {
167
+ await connection?.close();
168
+ connection = null;
169
+ connected = false;
170
+ },
171
+ /**
172
+ * Synchronous read of the cached connection state:
173
+ * - `{ ok: true }` once polling is live.
174
+ * - `{ ok: false, kind: "logged-out" }` after a 401 (sticky; re-token).
175
+ * - `{ ok: false, kind: "starting" }` between start() and first connect.
176
+ * - `{ ok: false, kind: "disconnected" }` for a transient drop mid-reconnect.
177
+ */
178
+ health() {
179
+ if (tokenInvalid || connection?.isTokenInvalid()) {
180
+ return {
181
+ ok: false,
182
+ kind: "logged-out",
183
+ reason: "Telegram bot token was rejected — Brigade can't send until a new token is set.",
184
+ remediation: "Run `brigade channels add --channel telegram` and paste a fresh @BotFather token.",
185
+ };
186
+ }
187
+ if (!connection) {
188
+ return { ok: false, kind: "starting", reason: "Telegram adapter is not started yet." };
189
+ }
190
+ if (!connected || !connection.isConnected()) {
191
+ return {
192
+ ok: false,
193
+ kind: "disconnected",
194
+ reason: "Telegram is reconnecting — sends will fail until polling resumes.",
195
+ };
196
+ }
197
+ return { ok: true };
198
+ },
199
+ async sendText(conversationId, text, opts) {
200
+ if (!connection)
201
+ throw new Error("Telegram channel is not started");
202
+ if (tokenInvalid || connection.isTokenInvalid()) {
203
+ throw new Error("Telegram token is invalid — run `brigade channels add --channel telegram` with a new token, then retry.");
204
+ }
205
+ const threadId = opts?.threadId;
206
+ // Chunk on the RAW markdown so fences/paragraphs aren't shredded, then
207
+ // convert each chunk to Telegram HTML and send. A chunk whose HTML is
208
+ // empty (syntax-only) or that Telegram rejects with a parse error is
209
+ // re-sent as plain text.
210
+ const chunks = chunkText(text, { limit: TELEGRAM_TEXT_LIMIT });
211
+ for (const chunk of chunks) {
212
+ const html = markdownToTelegramHtml(chunk);
213
+ if (telegramHtmlIsEmpty(html)) {
214
+ // Nothing renderable — send the raw chunk as plain text (if it has any).
215
+ if (chunk.trim().length > 0) {
216
+ await connection.sendText(conversationId, chunk, { threadId });
217
+ }
218
+ continue;
219
+ }
220
+ try {
221
+ await connection.sendText(conversationId, html, { html: true, threadId });
222
+ }
223
+ catch (err) {
224
+ const msg = err instanceof Error ? err.message : String(err);
225
+ if (PARSE_ERROR_RE.test(msg) && chunk.trim().length > 0) {
226
+ // HTML failed to parse — fall back to the plain chunk.
227
+ await connection.sendText(conversationId, chunk, { threadId });
228
+ }
229
+ else {
230
+ throw err;
231
+ }
232
+ }
233
+ }
234
+ },
235
+ // Telegram ids are numeric user/chat ids and @usernames, so the pairing
236
+ // challenge card uses the "Your username" line.
237
+ pairing: { idLabel: "username" },
238
+ // Token-based setup wizard — `brigade channels add --channel telegram`
239
+ // prompts for the bot token and writes `channels.telegram.botToken`.
240
+ setup: {
241
+ credentialKeys: [
242
+ {
243
+ key: "botToken",
244
+ prompt: "Telegram bot token (from @BotFather)",
245
+ secret: true,
246
+ envVar: "TELEGRAM_BOT_TOKEN",
247
+ docsUrl: "https://core.telegram.org/bots#botfather",
248
+ },
249
+ ],
250
+ validateInput(key, value) {
251
+ if (key !== "botToken")
252
+ return null;
253
+ const v = value.trim();
254
+ // @BotFather tokens look like `<digits>:<35-ish base64url chars>`.
255
+ if (/^\d{6,}:[A-Za-z0-9_-]{30,}$/.test(v))
256
+ return null;
257
+ // Allow a `${VAR}` ref through (resolved at runtime).
258
+ if (/^\$\{[A-Z_][A-Z0-9_]*\}$/.test(v))
259
+ return null;
260
+ return "That doesn't look like a bot token — expected `123456:ABC-DEF…` from @BotFather.";
261
+ },
262
+ },
263
+ async sendMedia(conversationId, media) {
264
+ if (!connection)
265
+ throw new Error("Telegram channel is not started");
266
+ await connection.sendMedia(conversationId, media);
267
+ },
268
+ // Outbound poll. Not part of the base `ChannelAdapter` contract — exposed as
269
+ // an extra method the plugin outbound + a typed accessor reach. Returns the
270
+ // poll message's id (string) so the agent can later act on it.
271
+ async sendPoll(conversationId, poll, opts) {
272
+ if (!connection)
273
+ throw new Error("Telegram channel is not started");
274
+ const normalized = normalizePollSpec(poll);
275
+ const sent = await connection.sendPoll(conversationId, normalized, {
276
+ ...(opts?.threadId !== undefined ? { threadId: opts.threadId } : {}),
277
+ });
278
+ return { messageId: String(sent.messageId) };
279
+ },
280
+ async react(conversationId, messageId, emoji) {
281
+ if (!connection)
282
+ return; // cosmetic — refuse silently when not started
283
+ await connection.react(conversationId, messageId, emoji);
284
+ },
285
+ async setComposing(conversationId, state) {
286
+ if (!connection)
287
+ return;
288
+ await connection.setComposing(conversationId, state);
289
+ },
290
+ // Static capability flags. The central `message_action` tool PRE-CHECKS the
291
+ // relevant flag here before calling `handleAction`, so an unsupported action
292
+ // fails cleanly without touching the adapter. Telegram supports edit
293
+ // (editMessageText), unsend (deleteMessage), reactions (setMessageReaction),
294
+ // reply (sendText with a thread), threads (forum topics), media, polls, and
295
+ // the native command menu.
296
+ capabilities: TELEGRAM_CAPABILITIES,
297
+ // Native inline-button approvals. When a channel-routed turn raises an
298
+ // approval, the central router calls `sendApprovalPrompt` to render the
299
+ // question as buttons (payloads from the central codec); the press comes
300
+ // back as `InboundMessage.callbackQuery` and is resolved centrally. A
301
+ // pathological approval id that can't fit the 64-byte button budget falls
302
+ // back to the text prompt (the router sends text when this throws/returns
303
+ // without a keyboard — here we throw so the router's catch path runs).
304
+ approvalCapability: {
305
+ async sendApprovalPrompt(params) {
306
+ if (!connection)
307
+ throw new Error("Telegram channel is not started");
308
+ const keyboard = buildTelegramApprovalKeyboard({ approvalId: params.approvalId });
309
+ if (!keyboard) {
310
+ // Too few byte-safe buttons — let the router fall back to text.
311
+ throw new Error("telegram approval prompt: approval id too long for inline buttons");
312
+ }
313
+ const text = buildTelegramApprovalText({
314
+ command: params.command,
315
+ approvalKind: params.approvalKind,
316
+ ...(params.toolName !== undefined ? { toolName: params.toolName } : {}),
317
+ });
318
+ // Send with the inline keyboard via the dedicated interactive path.
319
+ await connection.sendInteractive(params.conversationId, text, keyboard, {
320
+ ...(params.threadId !== undefined ? { threadId: params.threadId } : {}),
321
+ });
322
+ },
323
+ authorizeApprover(p) {
324
+ return resolveTelegramApprover({
325
+ cfg: p.cfg,
326
+ ...(p.senderId !== undefined ? { senderId: p.senderId } : {}),
327
+ ...(p.accountId !== undefined ? { accountId: p.accountId } : {}),
328
+ });
329
+ },
330
+ },
331
+ // Edit / delete / react / pin / unpin a message. The manager pre-checks the
332
+ // capability flag (above) before calling, so an action only reaches here
333
+ // when Telegram advertised support for it. Edit text is already sanitized +
334
+ // HTML-formatted centrally? No — `message_action` sanitizes <think> leaks
335
+ // but the HTML formatting is ours, so run `edit` text through the same
336
+ // markdown→HTML converter the reply path uses.
337
+ async handleAction(p) {
338
+ if (!connection)
339
+ return { ok: false, error: "Telegram channel is not started" };
340
+ if (tokenInvalid || connection.isTokenInvalid()) {
341
+ return { ok: false, error: "Telegram token is invalid — re-token before acting on messages." };
342
+ }
343
+ const a = p.action;
344
+ try {
345
+ switch (a.kind) {
346
+ case "edit": {
347
+ // Run the new text through the Telegram HTML formatter (same as
348
+ // the reply path); fall back to plain text on a parse error.
349
+ const html = markdownToTelegramHtml(a.text);
350
+ if (telegramHtmlIsEmpty(html)) {
351
+ await connection.editMessageText(p.conversationId, a.messageId, a.text);
352
+ }
353
+ else {
354
+ try {
355
+ await connection.editMessageText(p.conversationId, a.messageId, html, { html: true });
356
+ }
357
+ catch (err) {
358
+ const m = err instanceof Error ? err.message : String(err);
359
+ if (PARSE_ERROR_RE.test(m)) {
360
+ await connection.editMessageText(p.conversationId, a.messageId, a.text);
361
+ }
362
+ else {
363
+ throw err;
364
+ }
365
+ }
366
+ }
367
+ return { ok: true, messageId: a.messageId };
368
+ }
369
+ case "delete":
370
+ await connection.deleteMessage(p.conversationId, a.messageId);
371
+ return { ok: true, messageId: a.messageId };
372
+ case "react":
373
+ await connection.react(p.conversationId, a.messageId, a.emoji);
374
+ return { ok: true, messageId: a.messageId };
375
+ case "pin":
376
+ await connection.pinMessage(p.conversationId, a.messageId);
377
+ return { ok: true, messageId: a.messageId };
378
+ case "unpin":
379
+ await connection.unpinMessage(p.conversationId, a.messageId);
380
+ return { ok: true, messageId: a.messageId };
381
+ case "reply": {
382
+ // A reply is just a threaded send; surface the new id.
383
+ const sent = await connection.sendText(p.conversationId, a.text, {
384
+ ...(a.threadId !== undefined ? { threadId: a.threadId } : {}),
385
+ });
386
+ return { ok: true, messageId: String(sent.messageId) };
387
+ }
388
+ default:
389
+ return { ok: false, error: `unsupported action kind` };
390
+ }
391
+ }
392
+ catch (err) {
393
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
394
+ }
395
+ },
396
+ selfId() {
397
+ return connection?.selfId() ?? undefined;
398
+ },
399
+ connectedAt() {
400
+ return connection?.connectedAt() ?? null;
401
+ },
402
+ feedWebhookUpdate(update) {
403
+ // Defensive: only dispatch a plausibly-shaped update object.
404
+ if (!connection || !update || typeof update !== "object")
405
+ return;
406
+ connection.feedUpdate(update);
407
+ },
408
+ transportMode() {
409
+ return connection ? connection.mode() : "unstarted";
410
+ },
411
+ };
412
+ /**
413
+ * Best-effort forum-topic auto-label: on the FIRST message seen on a thread
414
+ * (this process), rename the topic from the message text. Fire-and-forget so
415
+ * it never delays inbound delivery; the connection swallows API errors.
416
+ */
417
+ function maybeAutoLabelThread(conversationId, threadId, text) {
418
+ const key = `${conversationId}:${threadId}`;
419
+ if (autoLabeledThreads.has(key))
420
+ return;
421
+ autoLabeledThreads.add(key);
422
+ const name = deriveTopicName(text);
423
+ if (!name)
424
+ return;
425
+ void connection?.editForumTopic(conversationId, threadId, name);
426
+ }
427
+ return adapter;
428
+ }
429
+ /** Static Telegram capability flags (shared by the legacy adapter + plugin meta). */
430
+ export const TELEGRAM_CAPABILITIES = {
431
+ chatTypes: ["direct", "group", "thread"],
432
+ reactions: true,
433
+ edit: true,
434
+ unsend: true,
435
+ reply: true,
436
+ threads: true,
437
+ media: true,
438
+ polls: true,
439
+ nativeCommands: true,
440
+ };
441
+ /** Telegram allows 2–10 poll options; clamp + require a non-empty question. */
442
+ function normalizePollSpec(poll) {
443
+ const question = (poll.question ?? "").trim();
444
+ if (!question)
445
+ throw new Error("Telegram poll: a non-empty question is required.");
446
+ const options = (poll.options ?? []).map((o) => String(o).trim()).filter(Boolean).slice(0, 10);
447
+ if (options.length < 2)
448
+ throw new Error("Telegram poll: at least 2 options are required.");
449
+ return {
450
+ question: question.length > 300 ? question.slice(0, 300) : question,
451
+ options,
452
+ ...(poll.isAnonymous !== undefined ? { isAnonymous: poll.isAnonymous } : {}),
453
+ ...(poll.allowsMultipleAnswers !== undefined ? { allowsMultipleAnswers: poll.allowsMultipleAnswers } : {}),
454
+ };
455
+ }
456
+ /**
457
+ * Derive a forum-topic name from a message's first line. Telegram caps topic
458
+ * names at 128 chars; we use the first line, collapsed + trimmed, clamped to a
459
+ * readable length. Returns "" when nothing usable remains.
460
+ */
461
+ export function deriveTopicName(text) {
462
+ const firstLine = (text.split(/\r?\n/, 1)[0] ?? "").replace(/\s+/g, " ").trim();
463
+ if (!firstLine)
464
+ return "";
465
+ return firstLine.length > 64 ? `${firstLine.slice(0, 63)}…` : firstLine;
466
+ }
467
+ /**
468
+ * Defensive config fallback for a direct `start()` that skipped `isConfigured`
469
+ * (the manager always calls isConfigured first, so this is the rare path). Sync
470
+ * + cached — `loadConfig` carries no heavy deps.
471
+ */
472
+ async function loadStartConfig() {
473
+ return loadConfig();
474
+ }
475
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../../src/agents/channels/telegram/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Telegram `allowed_updates` resolver.
3
+ *
4
+ * Telegram's `getUpdates` / `setWebhook` take an `allowed_updates` allow-list:
5
+ * only the named update kinds are delivered. Brigade subscribes the MINIMAL set
6
+ * its central pipeline actually consumes — keeping the firehose narrow means a
7
+ * chatty group never floods the poller with update kinds Brigade ignores
8
+ * (business messages, channel posts, inline queries, shipping/checkout, …, all
9
+ * of which the reference upstream subscribes but Brigade has no consumer for).
10
+ *
11
+ * The base set is always:
12
+ * - `message` — the inbound text/media path (the core surface).
13
+ * - `callback_query` — inline-button presses (interactive approvals). Without
14
+ * this in the list, a button tap is silently never delivered and the
15
+ * approval prompt hangs for its full timeout. Subscribed unconditionally so
16
+ * a button rendered by `sendApprovalPrompt` is always answerable.
17
+ *
18
+ * Conditionally added:
19
+ * - `message_reaction` — only when the channel opts into reaction inbound
20
+ * handling (`opts.reactions`). Brigade does not route inbound reactions to a
21
+ * turn today, so it is OFF by default; the flag exists so a future reaction-
22
+ * trigger feature can switch it on without touching the poller wiring.
23
+ * - `edited_message` — only when `opts.editedMessages` (off by default;
24
+ * Brigade treats an edit as a no-op rather than re-running the turn).
25
+ *
26
+ * Output is always a DEDUPED, STABLE-ORDER array of plain lowercase ASCII update
27
+ * names (no NUL / control bytes — these are fixed string literals).
28
+ */
29
+ /** One Telegram update kind Brigade may subscribe. */
30
+ export type TelegramAllowedUpdate = "message" | "callback_query" | "message_reaction" | "edited_message";
31
+ /** Options gating the conditional update kinds. */
32
+ export interface ResolveTelegramAllowedUpdatesOptions {
33
+ /** Subscribe `message_reaction` (inbound reaction events). Default false. */
34
+ reactions?: boolean;
35
+ /** Subscribe `edited_message` (inbound message edits). Default false. */
36
+ editedMessages?: boolean;
37
+ }
38
+ /**
39
+ * Resolve the `allowed_updates` list Brigade's Telegram poller/webhook should
40
+ * request. `message` + `callback_query` are always present; reactions / edited
41
+ * messages are added only when explicitly enabled. Deduped + stable order.
42
+ */
43
+ export declare function resolveTelegramAllowedUpdates(opts?: ResolveTelegramAllowedUpdatesOptions): TelegramAllowedUpdate[];
44
+ //# sourceMappingURL=allowed-updates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowed-updates.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/telegram/allowed-updates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,sDAAsD;AACtD,MAAM,MAAM,qBAAqB,GAC9B,SAAS,GACT,gBAAgB,GAChB,kBAAkB,GAClB,gBAAgB,CAAC;AAEpB,mDAAmD;AACnD,MAAM,WAAW,oCAAoC;IACpD,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC5C,IAAI,GAAE,oCAAyC,GAC7C,qBAAqB,EAAE,CAczB"}