Skip to content

feat(telegram): add Telegram platform support#17

Open
jettcc wants to merge 7 commits intoDoctor-wu:mainfrom
jettcc:feature-telegram
Open

feat(telegram): add Telegram platform support#17
jettcc wants to merge 7 commits intoDoctor-wu:mainfrom
jettcc:feature-telegram

Conversation

@jettcc
Copy link
Copy Markdown
Contributor

@jettcc jettcc commented Mar 10, 2026

Summary

  • Add @agent-im-relay/telegram adapter built on grammY
  • Support three conversation modes: private chat, group @mention (reply thread), and Channel + Discussion Group (auto-responds to channel posts in comment thread)
  • Wire up agent-inbox CLI setup flow and README docs

Key fix

grammy middleware chain requires return next() instead of a bare return when passing through — a bare return in the message handler was silently swallowing all regular group messages including @mentions.

Summary by CodeRabbit

  • New Features

    • Full Telegram integration: bot commands (/ask, /code, /interrupt, /done, /status), forum/thread support, channel forwarding, backend selection UI, and streaming conversation outputs to Telegram.
  • Documentation

    • README updated with Telegram adapter details, startup and development instructions.
  • Chores

    • Added Telegram package and dev scripts (dev:telegram, build orchestration updates) and project config updates to include Telegram.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

This PR adds a new Telegram package and integrates Telegram across the monorepo: new package @agent-im-relay/telegram (config, runtime, stream, bot), core platform detection for Telegram, and wiring Telegram support into the agent-inbox app, scripts, tsconfig, and README.

Changes

Cohort / File(s) Summary
Telegram package
packages/telegram/package.json, packages/telegram/src/index.ts, packages/telegram/src/config.ts, packages/telegram/src/runtime.ts, packages/telegram/src/stream.ts, packages/telegram/tsconfig.json, packages/telegram/tsdown.config.ts
New ESM package implementing Telegram integration: bot creation and runtime lifecycle, config parsing/application, streaming helpers, conversation/runtime gating, forum/thread handling, command set, and exports for starting the Telegram runtime.
Agent-inbox integration
apps/agent-inbox/package.json, apps/agent-inbox/src/config.ts, apps/agent-inbox/src/runtime.ts, apps/agent-inbox/src/setup.ts
Added Telegram types (TelegramImConfig/TelegramImRecord/TelegramAvailableIm), extended AvailableIm union, added telegram loader to RuntimeLoaders, applied Telegram env handling and startup path, included Telegram in setup platform lists, and added build/dev script wiring.
Core platform extension
packages/core/src/relay-platform.ts
Added 'telegram' to exported relayPlatforms and updated inferRelayPlatformFromConversationId to return 'telegram' for conversationIds starting with "tg-".
Repository config & docs
tsconfig.json, package.json, README.md
Added path mapping for @agent-im-relay/telegram, added dev:telegram npm script, updated top-level build scripts, and documented Telegram usage/badges/startup in README.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Hopping through code with a tiny telegram tune,

I stitched a bot by the light of the moon.
Streams that chunk and runtimes that start,
Threads and backends that play their part.
Hooray — new hops for the relay's heart! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(telegram): add Telegram platform support' clearly and concisely summarizes the main change—adding Telegram as a new platform in the agent-im-relay system.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between ba77f4c and acbdd1a.

📒 Files selected for processing (16)
  • .env.example
  • apps/agent-inbox/package.json
  • apps/agent-inbox/src/__tests__/packaging.test.ts
  • apps/agent-inbox/src/config.ts
  • apps/agent-inbox/src/runtime.ts
  • apps/agent-inbox/src/setup.ts
  • package.json
  • packages/core/src/relay-platform.ts
  • packages/telegram/package.json
  • packages/telegram/src/config.ts
  • packages/telegram/src/index.ts
  • packages/telegram/src/runtime.ts
  • packages/telegram/src/stream.ts
  • packages/telegram/tsconfig.json
  • packages/telegram/tsdown.config.ts
  • tsconfig.json
💤 Files with no reviewable changes (1)
  • apps/agent-inbox/src/tests/packaging.test.ts

Comment on lines +195 to +209
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,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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') });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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.json

Repository: 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.

Comment on lines +46 to +56
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,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

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)
: 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.

Comment on lines +60 to +67
export function applyTelegramConfigEnvironment(config: TelegramConfig): void {
applyCoreConfigEnvironment(config);
process.env['TELEGRAM_BOT_TOKEN'] = config.telegramBotToken;
setOptionalEnv(
'TELEGRAM_ALLOWED_USER_IDS',
config.telegramAllowedUserIds?.join(','),
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +112 to +115
await bot.api.sendMessage(
chatId,
`<b>${authorName}:</b> ${prompt}`,
{ parse_mode: 'HTML', message_thread_id: threadId },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +64 to +65
const codeContent = (match[2] ?? '').trimEnd();
result.push(`<pre><code>${escapeHtml(codeContent)}</code></pre>`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +190 to +197
return [
'<b>Environment</b>',
`- Backend: ${capitalize(environment.backend)}`,
`- Model: ${model}`,
`- Working directory: ${cwd}${cwdSuffix}`,
`- Git branch: ${gitBranch}`,
`- Mode: ${environment.mode}`,
].join('\n');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +222 to +226
const flush = async (): Promise<void> => {
const strippedBody = stripArtifactManifest(buffer).trim();
const body = strippedBody || '⏳ Thinking...';
const converted = convertMarkdownForTelegram(body);
const chunks = chunkForTelegram(converted || '⏳', maxLength);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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

Comment on lines +253 to +255
if (event.type === 'environment') {
if (options.showEnvironment) {
await transport.sendMessage(target, formatEnvironmentSummary(event.environment), { parseMode: 'HTML' });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Suggested change
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.

Comment on lines +2 to +15
"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
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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
done

Repository: 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.

Suggested change
"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.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between acbdd1a and 0e3aa6e.

📒 Files selected for processing (4)
  • README.md
  • apps/agent-inbox/package.json
  • apps/agent-inbox/src/setup.ts
  • package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • apps/agent-inbox/src/setup.ts

Comment on lines +141 to +155
## 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`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
README.md (1)

144-159: ⚠️ Potential issue | 🟡 Minor

Doc 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

📥 Commits

Reviewing files that changed from the base of the PR and between 0e3aa6e and c9753bb.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • README.md
  • apps/agent-inbox/package.json
  • apps/agent-inbox/src/config.ts
  • apps/agent-inbox/src/runtime.ts
  • apps/agent-inbox/src/setup.ts
  • package.json
  • packages/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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
README.md (2)

18-18: ⚠️ Potential issue | 🟡 Minor

Update 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 | 🟡 Minor

Add 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.id values 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

📥 Commits

Reviewing files that changed from the base of the PR and between c9753bb and cf8e9bc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • README.md
  • apps/agent-inbox/package.json
  • apps/agent-inbox/src/runtime.ts
  • apps/agent-inbox/src/setup.ts
  • package.json
  • tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/agent-inbox/src/setup.ts
  • package.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant