feat(telegram): add Telegram platform support#17
feat(telegram): add Telegram platform support#17jettcc wants to merge 7 commits intoDoctor-wu:mainfrom
Conversation
📝 WalkthroughWalkthroughThis PR adds a new Telegram package and integrates Telegram across the monorepo: new package Changes
Sequence DiagramsequenceDiagram
participant User as Telegram User
participant Bot as Telegram Bot
participant Handler as Conversation Handler
participant Gate as Backend Gate
participant Backend as Agent Backend
participant Render as Telegram Renderer
participant Transport as Telegram Transport
User->>Bot: Send /ask prompt
Bot->>Handler: Message event
Handler->>Gate: beginTelegramConversationRun()
alt Backend Selection Required
Gate-->>Handler: blocked (backend-selection)
Handler->>Transport: Send backend selection keyboard
Transport-->>User: Inline keyboard (Claude/Codex)
User->>Bot: Select backend via callback
Bot->>Handler: Store pending run
else Backend Ready
Gate-->>Handler: ready (backend)
Handler->>Backend: runPlatformConversation(prompt, mode)
Backend->>Backend: Process events stream
Backend-->>Render: Stream events
Render->>Render: Buffer & format events
Render->>Transport: Edit/send chunked messages
Transport-->>User: Display streaming response
Backend-->>Render: Final output
Render->>Transport: Send summary with tools used
Transport-->>User: Final message
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 13
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/agent-inbox/src/config.ts`:
- Around line 195-209: normalizeTelegramImRecord currently loosens invalid
Telegram allowlist IDs (using Number.parseInt and filtering), which can accept
values like "123abc" or convert floats, and if all entries are dropped it
becomes an open allowlist; update normalizeTelegramImRecord to reject the whole
config when any ID is malformed by validating each raw id strictly (e.g.,
require a string/number that matches /^\d+$/ or yields a finite integer via
Number and Number.isInteger) and report the error through parseConfigRecord’s
error channel instead of silently normalizing to undefined; apply the same
strict validation and rejection logic to the duplicated parser in
apps/agent-inbox/src/setup.ts so both locations consistently fail closed on
malformed allowlist entries.
In `@packages/telegram/src/config.ts`:
- Around line 46-56: The parsing of TELEGRAM_ALLOWED_USER_IDS (rawAllowed →
allowedUserIds) currently drops invalid entries and results in undefined on bad
input; instead, if TELEGRAM_ALLOWED_USER_IDS is set but contains any
non-positive or non-numeric token, throw a configuration error. Change the
parsing logic around rawAllowed/allowedUserIds so that after splitting and
trimming you detect any token that does not parse to a finite positive integer
and throw an Error (or use the project's config error pattern) with a clear
message referencing TELEGRAM_ALLOWED_USER_IDS; only when all tokens are valid
produce telegramAllowedUserIds (as the parsed number array) in the returned
config.
- Around line 60-67: applyTelegramConfigEnvironment currently sets
TELEGRAM_BOT_TOKEN and TELEGRAM_ALLOWED_USER_IDS but omits the numeric Telegram
settings; update applyTelegramConfigEnvironment to also write the configured
telegramStreamUpdateIntervalMs and telegramMessageCharLimit back to process.env
(using setOptionalEnv or direct assignment) so that subsequent env-based reads
in readTelegramConfig pick up the configured values from the TelegramConfig
object.
- Line 5: The config file currently calls
dotenvConfig(resolve(import.meta.dirname, '../../../.env')) inside
packages/telegram/src/config.ts which hardcodes a dev-only path and loads dotenv
from a library; remove that dotenvConfig call and any import of dotenv from this
package, read configuration from process.env (e.g., export the existing config
getters/constants from config.ts that return process.env.TELEGRAM_TOKEN,
process.env.TELEGRAM_CHAT_ID, etc.), and document in the package README or
comments that the executable entry point must call dotenvConfig or otherwise
populate process.env before importing this package so consumers handle
environment loading.
In `@packages/telegram/src/index.ts`:
- Around line 112-115: The sendMessage calls use parse_mode: 'HTML' while
interpolating raw prompt and authorName (see bot.api.sendMessage usages), which
can break or inject HTML; escape HTML-special characters in authorName and
prompt before interpolation (e.g., implement or reuse an escapeHtml/escapeHTML
helper and apply it to both occurrences around the bot.api.sendMessage calls at
the places shown, including the forum-topic bootstrapping and backend-selection
messages) so the message payload contains safe HTML-escaped text while keeping
the surrounding <b> tags intact.
- Around line 411-427: The bot.on('message') handler for auto-forwarded
(is_automatic_forward) messages bypasses the configured allowlist
(telegramAllowedUserIds / isAllowed), so add an explicit allowlist check at the
top of that branch: call isAllowed(ctx.from?.id or ctx.chat.id as appropriate)
(or check telegramAllowedUserIds) before processing auto-forwards and return
next() if not allowed; ensure this check runs before registerCommentThread and
handleConversation so forwarded channel posts cannot be used unless the source
chat/user is permitted.
- Around line 369-405: The callback handler for backend selection (checking
BACKEND_CALLBACK_PREFIX and using conversationBackend, takePendingTelegramRun
and runTelegramConversation) lacks an authorization gate and allows any group
member to change another conversation's backend; add the same isAllowed check
used elsewhere (e.g., call isAllowed(ctx, conversationId) or equivalent) at the
start of the handler after parsing conversationId and before setting
conversationBackend or resuming pending runs, return early (and optionally
answerCallbackQuery with a denial message) when not allowed, so only authorized
users can change backend and resume pendingTelegramRun.
In `@packages/telegram/src/runtime.ts`:
- Around line 35-36: resolveTelegramConversationId currently only keys on chatId
+ threadId, causing all replies in a regular group (where threadId is undefined)
to collapse into a single conversation; update the function signature to accept
the reply-root message id (e.g., replyToMessageId or replyRootMessageId) and use
it when threadId is undefined so keys become `tg-{chatId}-{replyRootMessageId}`
for non-topic reply threads. Also update callers in
packages/telegram/src/index.ts that currently pass undefined for threadId to
forward the replyToMessageId from incoming messages into
resolveTelegramConversationId so each visible reply thread gets a distinct
conversation id.
In `@packages/telegram/src/stream.ts`:
- Around line 190-197: The environment banner interpolates raw values (model,
cwd, gitBranch, and cwdSuffix) and is sent with parseMode: 'HTML', so
HTML-escape these dynamic fields to prevent broken/unsafe HTML; add or reuse a
helper like escapeHtml/escapeHtmlEntities and apply it to model, cwd (and
cwdSuffix), and gitBranch (and optionally environment.backend) before building
the array in the return block in packages/telegram/src/stream.ts so the joined
string contains escaped &, <, >, " and ' characters.
- Around line 253-255: The environment banner is sent without the thread
reference so it appears in main chat; update the transport.sendMessage call in
stream.ts (the branch handling event.type === 'environment') to include the same
reply/thread id used for later chunks (e.g., add replyToMessageId:
options.replyToMessageId or the existing thread/message id variable your stream
uses) in the options object alongside parseMode: 'HTML' so the environment
summary (formatEnvironmentSummary) posts into the same reply/comment thread.
- Around line 64-65: convertMarkdownForTelegram emits fenced blocks as
"<pre><code>...</code></pre>" but chunkForTelegram only closes/reopens "<pre>"
causing unbalanced "<code>" tags and loss of leading indentation when a code
block spans chunks; update chunkForTelegram to detect when a split occurs inside
a "<pre><code>" region and ensure both "</code></pre>" are appended to the end
of the previous chunk and corresponding "<pre><code>" are prepended to the next
chunk (instead of only "<pre>"), and when re-opening a code block preserve
original leading whitespace (remove the trimStart behavior for content inside
code regions) so indentation is kept intact; locate logic that handles pre/code
splitting and trimming in chunkForTelegram and make these changes to maintain
balanced tags and indentation.
In `@packages/telegram/tsconfig.json`:
- Around line 2-15: Add "composite": true to the "compilerOptions" block of each
referenced package tsconfig so TypeScript project references work with tsc -b;
specifically update the compilerOptions in the tsconfig.json for core, discord,
feishu, telegram and agent-inbox to include "composite": true (keep existing
settings like "declaration" and "declarationMap"). Ensure you add it alongside
the other compilerOptions entries and commit the five tsconfig.json changes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d5aa24fb-7489-4dc1-afca-43e3ff56deb1
📒 Files selected for processing (16)
.env.exampleapps/agent-inbox/package.jsonapps/agent-inbox/src/__tests__/packaging.test.tsapps/agent-inbox/src/config.tsapps/agent-inbox/src/runtime.tsapps/agent-inbox/src/setup.tspackage.jsonpackages/core/src/relay-platform.tspackages/telegram/package.jsonpackages/telegram/src/config.tspackages/telegram/src/index.tspackages/telegram/src/runtime.tspackages/telegram/src/stream.tspackages/telegram/tsconfig.jsonpackages/telegram/tsdown.config.tstsconfig.json
💤 Files with no reviewable changes (1)
- apps/agent-inbox/src/tests/packaging.test.ts
apps/agent-inbox/src/config.ts
Outdated
| function normalizeTelegramImRecord(value: Record<string, unknown>): TelegramImRecord { | ||
| const config = isRecord(value.config) ? value.config : {}; | ||
| const rawIds = config.allowedUserIds; | ||
| const allowedUserIds = Array.isArray(rawIds) | ||
| ? rawIds.map(id => typeof id === 'number' ? id : Number.parseInt(String(id), 10)).filter(n => Number.isFinite(n) && n > 0) | ||
| : undefined; | ||
|
|
||
| return { | ||
| type: 'im', | ||
| id: 'telegram', | ||
| enabled: asBoolean(value.enabled, true), | ||
| note: asString(value.note), | ||
| config: { | ||
| botToken: asString(config.botToken), | ||
| allowedUserIds: allowedUserIds?.length ? allowedUserIds : undefined, |
There was a problem hiding this comment.
Reject malformed Telegram allowlist IDs instead of dropping them.
Number.parseInt() accepts prefixes like 123abc, raw numeric values like 1.5 also survive the current filter, and if every entry is malformed the allowedUserIds?.length ? … : undefined fallback turns the config into “allow everyone”. parseConfigRecord() already has an error channel, so this should fail closed instead of normalizing bad IDs away. The same loose parser is also duplicated in apps/agent-inbox/src/setup.ts.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/agent-inbox/src/config.ts` around lines 195 - 209,
normalizeTelegramImRecord currently loosens invalid Telegram allowlist IDs
(using Number.parseInt and filtering), which can accept values like "123abc" or
convert floats, and if all entries are dropped it becomes an open allowlist;
update normalizeTelegramImRecord to reject the whole config when any ID is
malformed by validating each raw id strictly (e.g., require a string/number that
matches /^\d+$/ or yields a finite integer via Number and Number.isInteger) and
report the error through parseConfigRecord’s error channel instead of silently
normalizing to undefined; apply the same strict validation and rejection logic
to the duplicated parser in apps/agent-inbox/src/setup.ts so both locations
consistently fail closed on malformed allowlist entries.
| import { resolve } from 'node:path'; | ||
| import { applyCoreConfigEnvironment, readCoreConfig, type CoreConfig } from '@agent-im-relay/core'; | ||
|
|
||
| dotenvConfig({ path: resolve(import.meta.dirname, '../../../.env') }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python - <<'PY'
from pathlib import Path
paths = {
"repo src": Path("packages/telegram/src"),
"repo dist": Path("packages/telegram/dist"),
"installed dist": Path("node_modules/@agent-im-relay/telegram/dist"),
}
for label, base in paths.items():
print(f"{label:14} -> {(base / '../../../.env').resolve()}")
PY
echo
echo "Package publishability:"
sed -n '1,80p' packages/telegram/package.jsonRepository: Doctor-wu/agent-im-relay
Length of output: 892
Load dotenv in the executable layer, not in library packages.
This hardcoded ../../../.env path only works in the monorepo development environment. After publishing and installing this package via npm, the path resolves to node_modules/.env instead of the project root, breaking secret loading. Packages should not bake environment configuration loading into their imports; that responsibility belongs to the executable entry point. Store config values in environment variables and expose them through exports, allowing the consuming application to handle dotenv setup once.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/telegram/src/config.ts` at line 5, The config file currently calls
dotenvConfig(resolve(import.meta.dirname, '../../../.env')) inside
packages/telegram/src/config.ts which hardcodes a dev-only path and loads dotenv
from a library; remove that dotenvConfig call and any import of dotenv from this
package, read configuration from process.env (e.g., export the existing config
getters/constants from config.ts that return process.env.TELEGRAM_TOKEN,
process.env.TELEGRAM_CHAT_ID, etc.), and document in the package README or
comments that the executable entry point must call dotenvConfig or otherwise
populate process.env before importing this package so consumers handle
environment loading.
| const rawAllowed = optionalEnv(env, 'TELEGRAM_ALLOWED_USER_IDS'); | ||
| const allowedUserIds = rawAllowed | ||
| ? rawAllowed.split(',').map(s => Number.parseInt(s.trim(), 10)).filter(n => Number.isFinite(n) && n > 0) | ||
| : undefined; | ||
|
|
||
| return { | ||
| ...readCoreConfig(env), | ||
| telegramBotToken: requireEnv(env, 'TELEGRAM_BOT_TOKEN'), | ||
| telegramStreamUpdateIntervalMs: numberEnv(env, 'STREAM_UPDATE_INTERVAL_MS', 1000), | ||
| telegramMessageCharLimit: numberEnv(env, 'TELEGRAM_MESSAGE_CHAR_LIMIT', 4000), | ||
| telegramAllowedUserIds: allowedUserIds?.length ? allowedUserIds : undefined, |
There was a problem hiding this comment.
Fail closed on invalid TELEGRAM_ALLOWED_USER_IDS.
The current filter silently drops bad entries. TELEGRAM_ALLOWED_USER_IDS=abc ends up as undefined, which removes the allowlist instead of rejecting the misconfiguration.
Suggested change
const rawAllowed = optionalEnv(env, 'TELEGRAM_ALLOWED_USER_IDS');
const allowedUserIds = rawAllowed
- ? rawAllowed.split(',').map(s => Number.parseInt(s.trim(), 10)).filter(n => Number.isFinite(n) && n > 0)
+ ? rawAllowed.split(',').map((segment) => {
+ const parsed = Number.parseInt(segment.trim(), 10);
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
+ throw new Error(`Invalid TELEGRAM_ALLOWED_USER_IDS entry: ${segment}`);
+ }
+ return parsed;
+ })
: undefined;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const rawAllowed = optionalEnv(env, 'TELEGRAM_ALLOWED_USER_IDS'); | |
| const allowedUserIds = rawAllowed | |
| ? rawAllowed.split(',').map(s => Number.parseInt(s.trim(), 10)).filter(n => Number.isFinite(n) && n > 0) | |
| : undefined; | |
| return { | |
| ...readCoreConfig(env), | |
| telegramBotToken: requireEnv(env, 'TELEGRAM_BOT_TOKEN'), | |
| telegramStreamUpdateIntervalMs: numberEnv(env, 'STREAM_UPDATE_INTERVAL_MS', 1000), | |
| telegramMessageCharLimit: numberEnv(env, 'TELEGRAM_MESSAGE_CHAR_LIMIT', 4000), | |
| telegramAllowedUserIds: allowedUserIds?.length ? allowedUserIds : undefined, | |
| const rawAllowed = optionalEnv(env, 'TELEGRAM_ALLOWED_USER_IDS'); | |
| const allowedUserIds = rawAllowed | |
| ? rawAllowed.split(',').map((segment) => { | |
| const parsed = Number.parseInt(segment.trim(), 10); | |
| if (!Number.isSafeInteger(parsed) || parsed <= 0) { | |
| throw new Error(`Invalid TELEGRAM_ALLOWED_USER_IDS entry: ${segment}`); | |
| } | |
| return parsed; | |
| }) | |
| : undefined; | |
| return { | |
| ...readCoreConfig(env), | |
| telegramBotToken: requireEnv(env, 'TELEGRAM_BOT_TOKEN'), | |
| telegramStreamUpdateIntervalMs: numberEnv(env, 'STREAM_UPDATE_INTERVAL_MS', 1000), | |
| telegramMessageCharLimit: numberEnv(env, 'TELEGRAM_MESSAGE_CHAR_LIMIT', 4000), | |
| telegramAllowedUserIds: allowedUserIds?.length ? allowedUserIds : undefined, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/telegram/src/config.ts` around lines 46 - 56, The parsing of
TELEGRAM_ALLOWED_USER_IDS (rawAllowed → allowedUserIds) currently drops invalid
entries and results in undefined on bad input; instead, if
TELEGRAM_ALLOWED_USER_IDS is set but contains any non-positive or non-numeric
token, throw a configuration error. Change the parsing logic around
rawAllowed/allowedUserIds so that after splitting and trimming you detect any
token that does not parse to a finite positive integer and throw an Error (or
use the project's config error pattern) with a clear message referencing
TELEGRAM_ALLOWED_USER_IDS; only when all tokens are valid produce
telegramAllowedUserIds (as the parsed number array) in the returned config.
| export function applyTelegramConfigEnvironment(config: TelegramConfig): void { | ||
| applyCoreConfigEnvironment(config); | ||
| process.env['TELEGRAM_BOT_TOKEN'] = config.telegramBotToken; | ||
| setOptionalEnv( | ||
| 'TELEGRAM_ALLOWED_USER_IDS', | ||
| config.telegramAllowedUserIds?.join(','), | ||
| ); | ||
| } |
There was a problem hiding this comment.
Apply the Telegram numeric settings back to process.env too.
readTelegramConfig() reads telegramStreamUpdateIntervalMs and telegramMessageCharLimit, but applyTelegramConfigEnvironment() drops both. Any later env-based read falls back to defaults instead of the configured values.
Suggested change
function setOptionalEnv(key: string, value: string | undefined): void {
if (value) {
process.env[key] = value;
return;
}
delete process.env[key];
}
+
+function setNumericEnv(key: string, value: number): void {
+ process.env[key] = String(value);
+}
export function applyTelegramConfigEnvironment(config: TelegramConfig): void {
applyCoreConfigEnvironment(config);
process.env['TELEGRAM_BOT_TOKEN'] = config.telegramBotToken;
+ setNumericEnv('STREAM_UPDATE_INTERVAL_MS', config.telegramStreamUpdateIntervalMs);
+ setNumericEnv('TELEGRAM_MESSAGE_CHAR_LIMIT', config.telegramMessageCharLimit);
setOptionalEnv(
'TELEGRAM_ALLOWED_USER_IDS',
config.telegramAllowedUserIds?.join(','),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/telegram/src/config.ts` around lines 60 - 67,
applyTelegramConfigEnvironment currently sets TELEGRAM_BOT_TOKEN and
TELEGRAM_ALLOWED_USER_IDS but omits the numeric Telegram settings; update
applyTelegramConfigEnvironment to also write the configured
telegramStreamUpdateIntervalMs and telegramMessageCharLimit back to process.env
(using setOptionalEnv or direct assignment) so that subsequent env-based reads
in readTelegramConfig pick up the configured values from the TelegramConfig
object.
| await bot.api.sendMessage( | ||
| chatId, | ||
| `<b>${authorName}:</b> ${prompt}`, | ||
| { parse_mode: 'HTML', message_thread_id: threadId }, |
There was a problem hiding this comment.
Escape user-controlled text before using parse_mode: 'HTML'.
Both messages interpolate raw prompt/authorName into HTML. Prompts like <div> or a && b can make the send fail, which breaks forum-topic bootstrapping and backend-selection prompts.
Also applies to: 158-165
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/telegram/src/index.ts` around lines 112 - 115, The sendMessage calls
use parse_mode: 'HTML' while interpolating raw prompt and authorName (see
bot.api.sendMessage usages), which can break or inject HTML; escape HTML-special
characters in authorName and prompt before interpolation (e.g., implement or
reuse an escapeHtml/escapeHTML helper and apply it to both occurrences around
the bot.api.sendMessage calls at the places shown, including the forum-topic
bootstrapping and backend-selection messages) so the message payload contains
safe HTML-escaped text while keeping the surrounding <b> tags intact.
| const codeContent = (match[2] ?? '').trimEnd(); | ||
| result.push(`<pre><code>${escapeHtml(codeContent)}</code></pre>`); |
There was a problem hiding this comment.
Keep fenced code blocks balanced when splitting messages.
convertMarkdownForTelegram() emits <pre><code>…</code></pre>, but chunkForTelegram() only closes and reopens <pre>. Once a code block crosses the limit, the first chunk is left with an unclosed <code>, and the continuation loses leading indentation because of trimStart().
Possible fix
- result.push(`<pre><code>${escapeHtml(codeContent)}</code></pre>`);
+ result.push(`<pre>${escapeHtml(codeContent)}</pre>`);
- remaining = '<pre>' + remaining.slice(splitIndex).trimStart();
+ remaining = '<pre>' + remaining.slice(splitIndex);Also applies to: 101-105
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/telegram/src/stream.ts` around lines 64 - 65,
convertMarkdownForTelegram emits fenced blocks as "<pre><code>...</code></pre>"
but chunkForTelegram only closes/reopens "<pre>" causing unbalanced "<code>"
tags and loss of leading indentation when a code block spans chunks; update
chunkForTelegram to detect when a split occurs inside a "<pre><code>" region and
ensure both "</code></pre>" are appended to the end of the previous chunk and
corresponding "<pre><code>" are prepended to the next chunk (instead of only
"<pre>"), and when re-opening a code block preserve original leading whitespace
(remove the trimStart behavior for content inside code regions) so indentation
is kept intact; locate logic that handles pre/code splitting and trimming in
chunkForTelegram and make these changes to maintain balanced tags and
indentation.
| return [ | ||
| '<b>Environment</b>', | ||
| `- Backend: ${capitalize(environment.backend)}`, | ||
| `- Model: ${model}`, | ||
| `- Working directory: ${cwd}${cwdSuffix}`, | ||
| `- Git branch: ${gitBranch}`, | ||
| `- Mode: ${environment.mode}`, | ||
| ].join('\n'); |
There was a problem hiding this comment.
Escape dynamic environment fields before sending HTML.
This string is sent with parseMode: 'HTML', but model, cwd, and gitBranch are interpolated raw. A path or branch containing &, <, or > can make the environment banner fail to send.
Possible fix
- `- Backend: ${capitalize(environment.backend)}`,
- `- Model: ${model}`,
- `- Working directory: ${cwd}${cwdSuffix}`,
- `- Git branch: ${gitBranch}`,
- `- Mode: ${environment.mode}`,
+ `- Backend: ${escapeHtml(capitalize(environment.backend))}`,
+ `- Model: ${escapeHtml(model)}`,
+ `- Working directory: ${escapeHtml(cwd)}${cwdSuffix}`,
+ `- Git branch: ${escapeHtml(gitBranch)}`,
+ `- Mode: ${escapeHtml(environment.mode)}`,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/telegram/src/stream.ts` around lines 190 - 197, The environment
banner interpolates raw values (model, cwd, gitBranch, and cwdSuffix) and is
sent with parseMode: 'HTML', so HTML-escape these dynamic fields to prevent
broken/unsafe HTML; add or reuse a helper like escapeHtml/escapeHtmlEntities and
apply it to model, cwd (and cwdSuffix), and gitBranch (and optionally
environment.backend) before building the array in the return block in
packages/telegram/src/stream.ts so the joined string contains escaped &, <, >, "
and ' characters.
| const flush = async (): Promise<void> => { | ||
| const strippedBody = stripArtifactManifest(buffer).trim(); | ||
| const body = strippedBody || '⏳ Thinking...'; | ||
| const converted = convertMarkdownForTelegram(body); | ||
| const chunks = chunkForTelegram(converted || '⏳', maxLength); |
There was a problem hiding this comment.
Keep the stream buffer in one format.
buffer mixes raw markdown from text events with preformatted HTML from tool/status/error events. The later convertMarkdownForTelegram() pass escapes those HTML fragments again, so tool summaries and errors will render with literal <b>/<i>/<code> tags and double-escaped content.
Also applies to: 263-282
| if (event.type === 'environment') { | ||
| if (options.showEnvironment) { | ||
| await transport.sendMessage(target, formatEnvironmentSummary(event.environment), { parseMode: 'HTML' }); |
There was a problem hiding this comment.
Keep the environment banner in the same reply/comment thread.
This send omits replyToMessageId, so the first message in a group or linked discussion lands in the main chat while later streamed chunks are threaded correctly.
Possible fix
- await transport.sendMessage(target, formatEnvironmentSummary(event.environment), { parseMode: 'HTML' });
+ await transport.sendMessage(target, formatEnvironmentSummary(event.environment), {
+ parseMode: 'HTML',
+ replyToMessageId: target.replyToMessageId,
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (event.type === 'environment') { | |
| if (options.showEnvironment) { | |
| await transport.sendMessage(target, formatEnvironmentSummary(event.environment), { parseMode: 'HTML' }); | |
| if (event.type === 'environment') { | |
| if (options.showEnvironment) { | |
| await transport.sendMessage(target, formatEnvironmentSummary(event.environment), { | |
| parseMode: 'HTML', | |
| replyToMessageId: target.replyToMessageId, | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/telegram/src/stream.ts` around lines 253 - 255, The environment
banner is sent without the thread reference so it appears in main chat; update
the transport.sendMessage call in stream.ts (the branch handling event.type ===
'environment') to include the same reply/thread id used for later chunks (e.g.,
add replyToMessageId: options.replyToMessageId or the existing thread/message id
variable your stream uses) in the options object alongside parseMode: 'HTML' so
the environment summary (formatEnvironmentSummary) posts into the same
reply/comment thread.
| "compilerOptions": { | ||
| "target": "ES2022", | ||
| "module": "NodeNext", | ||
| "moduleResolution": "NodeNext", | ||
| "lib": ["ES2022"], | ||
| "outDir": "dist", | ||
| "rootDir": "src", | ||
| "strict": true, | ||
| "esModuleInterop": true, | ||
| "skipLibCheck": true, | ||
| "declaration": true, | ||
| "declarationMap": true, | ||
| "sourceMap": true | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Root solution references:"
sed -n '1,60p' tsconfig.json
echo
echo "Telegram tsconfig:"
sed -n '1,120p' packages/telegram/tsconfig.json
echo
echo "Sibling tsconfig files mentioning composite/references:"
fd '^tsconfig\.json$' packages apps -x sh -c 'printf "\n== %s ==\n" "$1"; rg -n "\"composite\"|\"references\"" "$1" || true' sh {}Repository: Doctor-wu/agent-im-relay
Length of output: 974
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Inspecting all referenced packages for 'composite' field ==="
for pkg in packages/core packages/discord packages/feishu apps/agent-inbox packages/telegram; do
if [ -f "$pkg/tsconfig.json" ]; then
echo ""
echo "File: $pkg/tsconfig.json"
# Extract compilerOptions section
jq '.compilerOptions | keys' "$pkg/tsconfig.json" 2>/dev/null | grep -q "composite" && echo " ✓ Has 'composite'" || echo " ✗ Missing 'composite'"
# Show the full compilerOptions to verify
jq '.compilerOptions' "$pkg/tsconfig.json" 2>/dev/null | head -20
fi
doneRepository: Doctor-wu/agent-im-relay
Length of output: 1894
Add composite: true to all referenced packages' tsconfig.json files.
The root tsconfig.json references five packages, but all of them are missing "composite": true in their compilerOptions. This breaks tsc -b and editor project-reference workflows. Apply this fix to:
- packages/core/tsconfig.json
- packages/discord/tsconfig.json
- packages/feishu/tsconfig.json
- packages/telegram/tsconfig.json
- apps/agent-inbox/tsconfig.json
Suggested change for each file
"compilerOptions": {
+ "composite": true,
"target": "ES2022",
"module": "NodeNext",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "compilerOptions": { | |
| "target": "ES2022", | |
| "module": "NodeNext", | |
| "moduleResolution": "NodeNext", | |
| "lib": ["ES2022"], | |
| "outDir": "dist", | |
| "rootDir": "src", | |
| "strict": true, | |
| "esModuleInterop": true, | |
| "skipLibCheck": true, | |
| "declaration": true, | |
| "declarationMap": true, | |
| "sourceMap": true | |
| }, | |
| "compilerOptions": { | |
| "composite": true, | |
| "target": "ES2022", | |
| "module": "NodeNext", | |
| "moduleResolution": "NodeNext", | |
| "lib": ["ES2022"], | |
| "outDir": "dist", | |
| "rootDir": "src", | |
| "strict": true, | |
| "esModuleInterop": true, | |
| "skipLibCheck": true, | |
| "declaration": true, | |
| "declarationMap": true, | |
| "sourceMap": true | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/telegram/tsconfig.json` around lines 2 - 15, Add "composite": true
to the "compilerOptions" block of each referenced package tsconfig so TypeScript
project references work with tsc -b; specifically update the compilerOptions in
the tsconfig.json for core, discord, feishu, telegram and agent-inbox to include
"composite": true (keep existing settings like "declaration" and
"declarationMap"). Ensure you add it alongside the other compilerOptions entries
and commit the five tsconfig.json changes.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
README.md (1)
151-154: Scope the Privacy Mode step to group/channel setups.Line 152 reads like a universal requirement, but private-chat-only deployments do not need Privacy Mode disabled. Please qualify this as required for
@mention/ discussion-group flows so the docs do not recommend broader bot visibility than necessary.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 151 - 154, Update the Privacy Mode step to clarify it's only required for group/channel scenarios: modify the step that currently says "Disable Privacy Mode" to state that disabling Privacy Mode is necessary when the bot needs to receive all group messages (e.g., for `@mention` handling or discussion-group flows), but is not required for private-chat-only deployments; reference the related configuration names TELEGRAM_BOT_TOKEN and TELEGRAM_ALLOWED_USER_IDS so readers understand this setting applies to group/channel setups.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@README.md`:
- Around line 141-155: Update the README's earlier "Multiple IM platforms"
overview and the "Supported IM Platforms" table to include Telegram as a
first-class adapter: add Telegram (using grammY) to the list alongside Discord
and Feishu, mention its three conversation modes (private, group `@mention`,
channel+discussion group) and note the
TELEGRAM_BOT_TOKEN/TELEGRAM_ALLOWED_USER_IDS config and startup command (pnpm
dev:telegram) so the intro and the table are consistent with the existing
"Telegram Runtime" section.
---
Nitpick comments:
In `@README.md`:
- Around line 151-154: Update the Privacy Mode step to clarify it's only
required for group/channel scenarios: modify the step that currently says
"Disable Privacy Mode" to state that disabling Privacy Mode is necessary when
the bot needs to receive all group messages (e.g., for `@mention` handling or
discussion-group flows), but is not required for private-chat-only deployments;
reference the related configuration names TELEGRAM_BOT_TOKEN and
TELEGRAM_ALLOWED_USER_IDS so readers understand this setting applies to
group/channel setups.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4767777a-b155-4870-91c6-5c0d6f9e8627
📒 Files selected for processing (4)
README.mdapps/agent-inbox/package.jsonapps/agent-inbox/src/setup.tspackage.json
🚧 Files skipped from review as they are similar to previous changes (2)
- package.json
- apps/agent-inbox/src/setup.ts
| ## Telegram Runtime | ||
|
|
||
| The Telegram adapter uses [grammY](https://grammy.dev/) and supports three conversation modes: | ||
|
|
||
| - Private chat with the bot directly | ||
| - Group chat via `@mention` — bot replies in a reply thread per conversation | ||
| - Channel + Discussion Group — each channel post automatically triggers an agent session in its comment thread; replies in the thread continue the same session | ||
|
|
||
| Typical startup flow: | ||
|
|
||
| 1. Create a bot via [@BotFather](https://t.me/BotFather), copy the token. | ||
| 2. Disable Privacy Mode: `/mybots` → Bot Settings → Group Privacy → Turn off. | ||
| 3. For channel mode: link a Discussion Group to your channel (channel Edit → Discussion), then add the bot as admin to both the channel and the discussion group. | ||
| 4. Configure `TELEGRAM_BOT_TOKEN` and optionally `TELEGRAM_ALLOWED_USER_IDS`. | ||
| 5. Start `pnpm dev:telegram`. |
There was a problem hiding this comment.
Add Telegram to the earlier platform overview too.
This section documents Telegram as a first-class adapter, but the earlier “Multiple IM platforms” copy and the “Supported IM Platforms” table still only list Discord and Feishu. Right now the README is internally inconsistent, and Telegram looks unsupported unless readers scroll this far.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@README.md` around lines 141 - 155, Update the README's earlier "Multiple IM
platforms" overview and the "Supported IM Platforms" table to include Telegram
as a first-class adapter: add Telegram (using grammY) to the list alongside
Discord and Feishu, mention its three conversation modes (private, group
`@mention`, channel+discussion group) and note the
TELEGRAM_BOT_TOKEN/TELEGRAM_ALLOWED_USER_IDS config and startup command (pnpm
dev:telegram) so the intro and the table are consistent with the existing
"Telegram Runtime" section.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
README.md (1)
144-159:⚠️ Potential issue | 🟡 MinorDoc consistency gap remains: Telegram section added, but earlier platform summary/table still omit it.
After adding this Telegram runtime section, the earlier “Multiple IM platforms” copy and “Supported IM Platforms” table still present only Discord/Feishu, which is inconsistent for readers scanning top-down.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 144 - 159, The README now documents a Telegram Runtime section but the earlier "Multiple IM platforms" summary and the "Supported IM Platforms" table still list only Discord/Feishu, causing inconsistency; update those sections to include Telegram (and note its grammY-based runtime and the three conversation modes) so the top-level summary and the "Supported IM Platforms" table match the new "Telegram Runtime" details, referring to the "Telegram Runtime" heading and the "Multiple IM platforms"/"Supported IM Platforms" table entries when making the edits.
🧹 Nitpick comments (1)
apps/agent-inbox/src/runtime.ts (1)
121-123: Make Telegram startup explicit instead of implicit default.Line 121 currently acts as a catch-all fallback. If a new platform is added later without a dedicated branch, it would incorrectly start Telegram runtime.
Proposed hardening diff
- const loadTelegram = loaders.telegram ?? (() => importRuntimeModule<{ startTelegramRuntime: () => Promise<unknown> }>('@agent-im-relay/telegram')); - const telegram = await loadTelegram(); - await telegram.startTelegramRuntime(); + if (selectedIm.id === 'telegram') { + const loadTelegram = loaders.telegram ?? (() => importRuntimeModule<{ startTelegramRuntime: () => Promise<unknown> }>('@agent-im-relay/telegram')); + const telegram = await loadTelegram(); + await telegram.startTelegramRuntime(); + return; + } + + const _exhaustive: never = selectedIm.id; + throw new Error(`Unsupported IM platform: ${_exhaustive}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/agent-inbox/src/runtime.ts` around lines 121 - 123, The current fallback that assigns loadTelegram via loaders.telegram ?? (() => importRuntimeModule(...)) makes Telegram the implicit default; change this so Telegram is started only when explicitly requested: remove the fallback default, instead check for loaders.telegram and if present call await (await loaders.telegram()).startTelegramRuntime(); otherwise throw or handle a clear "no platform loader provided" error; reference the existing symbols loadTelegram, loaders.telegram, importRuntimeModule, and startTelegramRuntime to locate and update the logic so new platforms cannot accidentally trigger Telegram startup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@README.md`:
- Around line 144-159: The README now documents a Telegram Runtime section but
the earlier "Multiple IM platforms" summary and the "Supported IM Platforms"
table still list only Discord/Feishu, causing inconsistency; update those
sections to include Telegram (and note its grammY-based runtime and the three
conversation modes) so the top-level summary and the "Supported IM Platforms"
table match the new "Telegram Runtime" details, referring to the "Telegram
Runtime" heading and the "Multiple IM platforms"/"Supported IM Platforms" table
entries when making the edits.
---
Nitpick comments:
In `@apps/agent-inbox/src/runtime.ts`:
- Around line 121-123: The current fallback that assigns loadTelegram via
loaders.telegram ?? (() => importRuntimeModule(...)) makes Telegram the implicit
default; change this so Telegram is started only when explicitly requested:
remove the fallback default, instead check for loaders.telegram and if present
call await (await loaders.telegram()).startTelegramRuntime(); otherwise throw or
handle a clear "no platform loader provided" error; reference the existing
symbols loadTelegram, loaders.telegram, importRuntimeModule, and
startTelegramRuntime to locate and update the logic so new platforms cannot
accidentally trigger Telegram startup.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: dfa6d1f2-dd7c-4922-ac9f-6416af5c1e33
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
README.mdapps/agent-inbox/package.jsonapps/agent-inbox/src/config.tsapps/agent-inbox/src/runtime.tsapps/agent-inbox/src/setup.tspackage.jsonpackages/core/src/relay-platform.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/agent-inbox/package.json
- apps/agent-inbox/src/setup.ts
There was a problem hiding this comment.
♻️ Duplicate comments (2)
README.md (2)
18-18:⚠️ Potential issue | 🟡 MinorUpdate platform overview to include Telegram.
This line still only mentions "Discord and Feishu" as supported platforms, but Telegram is now a first-class adapter with full documentation below (lines 194-209). The README is internally inconsistent.
📝 Suggested update
-- **Multiple IM platforms** - Discord and Feishu are supported today, and the architecture is designed to extend cleanly to additional platforms. +- **Multiple IM platforms** - Discord, Feishu, and Telegram are supported today, and the architecture is designed to extend cleanly to additional platforms.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` at line 18, Update the README sentence that currently lists supported IM platforms ("Multiple IM platforms - Discord and Feishu...") to include Telegram as well (e.g., "Discord, Feishu, and Telegram") so the overview matches the detailed Telegram adapter documentation; ensure the phrasing around "first-class adapter" is reflected consistently with the Telegram docs section referenced by the README.
61-66:⚠️ Potential issue | 🟡 MinorAdd Telegram to the Supported IM Platforms table.
The table only lists Discord and Feishu, but Telegram is now fully supported with documentation at lines 194-209. Add a row describing Telegram's three conversation modes and key features.
📋 Suggested addition
| Platform | Status | Notes | |------|------|------| | **Discord** ⭐ Recommended | ✅ Supported | Slash commands + thread sessions, file upload/download support, streaming output | | **Feishu (Lark)** | ✅ Supported | Long-connection mode, DM-triggered session groups, interrupt cards on every message | +| **Telegram** | ✅ Supported | Private chat, group `@mention` with reply threads, channel+discussion group mode |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 61 - 66, Update the "Supported IM Platforms" table under the "Supported IM Platforms" section in README.md to add a new row for Telegram describing that it is supported and summarizing its three conversation modes (inline bot/DM, group chat mode, and channel/broadcast mode) and key features (message threading/conversation context, file upload/download support, and streaming output/real-time responses); ensure the Telegram row mirrors the existing table columns (Platform, Status, Notes) and uses similar formatting/emoji style as the Discord and Feishu rows, and pull detailed behavior from the Telegram documentation block near the existing Telegram docs to keep the Notes concise.
🧹 Nitpick comments (3)
apps/agent-inbox/src/runtime.ts (1)
121-124: Make Telegram startup explicit and keep an exhaustive guard.Using Telegram as the implicit fallback can hide unsupported/invalid
selectedIm.idvalues and can become error-prone when new platforms are added.♻️ Suggested refactor
- const loadTelegram = loaders.telegram ?? (() => importRuntimeModule<{ startTelegramRuntime: () => Promise<unknown> }>('@agent-im-relay/telegram')); - const telegram = await loadTelegram(); - await telegram.startTelegramRuntime(); + if (selectedIm.id === 'telegram') { + const loadTelegram = loaders.telegram ?? (() => importRuntimeModule<{ startTelegramRuntime: () => Promise<unknown> }>('@agent-im-relay/telegram')); + const telegram = await loadTelegram(); + await telegram.startTelegramRuntime(); + return; + } + + const exhaustiveCheck: never = selectedIm; + throw new Error(`Unsupported IM platform: ${String(exhaustiveCheck)}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/agent-inbox/src/runtime.ts` around lines 121 - 124, The current code uses an implicit fallback to Telegram via loadTelegram which can mask invalid selectedIm.id values; change this to an explicit startup path and an exhaustive guard: stop using the fallback default in loadTelegram, only import/start Telegram when the selected IM is explicitly Telegram (e.g., check selectedIm.id === 'telegram' or equivalent), and add an else branch that throws or logs a clear error for unsupported/unknown selectedIm.id values so new platforms won't be silently ignored; update the logic around loadTelegram and telegram.startTelegramRuntime to only run when the explicit guard passes.README.md (2)
138-140: Document Telegram permission card style if supported.This section describes permission card styles for Discord, Feishu, and Slack, but Telegram is not mentioned. If Telegram runtime supports safe-mode permission requests, document its card style here for completeness.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 138 - 140, Add documentation for Telegram in the same style as the existing entries for "Discord", "Feishu", and "Slack": describe whether Telegram supports a safe-mode permission card, state the header/title (e.g., "Permission Required"), outline the content layout (tool/reason text, optional fields), list available actions (e.g., "Approve" / "Deny" buttons or equivalent quick replies), and explain how the message/card is updated after a decision so it mirrors the Discord/Feishu/Slack entries.
131-131: Consider adding Telegram to the safe-mode platform list.This line lists platforms that support safe-mode permission cards (Discord, Feishu, Slack) but omits Telegram. If Telegram runtime supports the same permission workflow, it should be included here for consistency.
📝 Suggested update
-2. Agent Inbox renders an approval card in the active Discord thread, Feishu session chat, or Slack thread / DM. +2. Agent Inbox renders an approval card in the active Discord thread, Feishu session chat, Slack thread / DM, or Telegram chat / reply thread.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` at line 131, Update the sentence "Agent Inbox renders an approval card in the active Discord thread, Feishu session chat, or Slack thread / DM." to include Telegram (e.g., "...Discord thread, Feishu session chat, Slack thread / DM, or Telegram chat"). Ensure the phrasing matches surrounding list style and only add Telegram if the Telegram runtime supports the same safe-mode permission workflow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@README.md`:
- Line 18: Update the README sentence that currently lists supported IM
platforms ("Multiple IM platforms - Discord and Feishu...") to include Telegram
as well (e.g., "Discord, Feishu, and Telegram") so the overview matches the
detailed Telegram adapter documentation; ensure the phrasing around "first-class
adapter" is reflected consistently with the Telegram docs section referenced by
the README.
- Around line 61-66: Update the "Supported IM Platforms" table under the
"Supported IM Platforms" section in README.md to add a new row for Telegram
describing that it is supported and summarizing its three conversation modes
(inline bot/DM, group chat mode, and channel/broadcast mode) and key features
(message threading/conversation context, file upload/download support, and
streaming output/real-time responses); ensure the Telegram row mirrors the
existing table columns (Platform, Status, Notes) and uses similar
formatting/emoji style as the Discord and Feishu rows, and pull detailed
behavior from the Telegram documentation block near the existing Telegram docs
to keep the Notes concise.
---
Nitpick comments:
In `@apps/agent-inbox/src/runtime.ts`:
- Around line 121-124: The current code uses an implicit fallback to Telegram
via loadTelegram which can mask invalid selectedIm.id values; change this to an
explicit startup path and an exhaustive guard: stop using the fallback default
in loadTelegram, only import/start Telegram when the selected IM is explicitly
Telegram (e.g., check selectedIm.id === 'telegram' or equivalent), and add an
else branch that throws or logs a clear error for unsupported/unknown
selectedIm.id values so new platforms won't be silently ignored; update the
logic around loadTelegram and telegram.startTelegramRuntime to only run when the
explicit guard passes.
In `@README.md`:
- Around line 138-140: Add documentation for Telegram in the same style as the
existing entries for "Discord", "Feishu", and "Slack": describe whether Telegram
supports a safe-mode permission card, state the header/title (e.g., "Permission
Required"), outline the content layout (tool/reason text, optional fields), list
available actions (e.g., "Approve" / "Deny" buttons or equivalent quick
replies), and explain how the message/card is updated after a decision so it
mirrors the Discord/Feishu/Slack entries.
- Line 131: Update the sentence "Agent Inbox renders an approval card in the
active Discord thread, Feishu session chat, or Slack thread / DM." to include
Telegram (e.g., "...Discord thread, Feishu session chat, Slack thread / DM, or
Telegram chat"). Ensure the phrasing matches surrounding list style and only add
Telegram if the Telegram runtime supports the same safe-mode permission
workflow.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9073d4f8-d54f-478e-9301-dbcbfa4f7da7
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
README.mdapps/agent-inbox/package.jsonapps/agent-inbox/src/runtime.tsapps/agent-inbox/src/setup.tspackage.jsontsconfig.json
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/agent-inbox/src/setup.ts
- package.json
Summary
@agent-im-relay/telegramadapter built on grammY@mention(reply thread), and Channel + Discussion Group (auto-responds to channel posts in comment thread)agent-inboxCLI setup flow and README docsKey fix
grammy middleware chain requires
return next()instead of a barereturnwhen passing through — a barereturnin themessagehandler was silently swallowing all regular group messages including@mentions.Summary by CodeRabbit
New Features
Documentation
Chores