Telegram
권장 시작 지점. 3분 설정, 스트리밍 지원 게이트웨이, 가장 많이 검증된 공급자.
🟢 런타임 준비 완료. 이 게이트웨이는 스트리밍 편집 기능을 갖추고 출시되었습니다(아직 프로덕션 호출자가 연결되지 않은 상태입니다. 아래를 참조하세요). 대부분의 Minara 운영자가 처음 시작하는 공급자이며, 외부 바이너리나 비즈니스 계정 승인 없이 봇 토큰과 채팅 id만 있으면 됩니다.
제공 기능
- 스트리밍 편집(게이트웨이 준비 완료).
TelegramGateway는 플레이스홀더를 게시한 뒤 텍스트가 도착할 때마다 750ms 간격으로 편집합니다.apps/agent/src/messaging/stream-helpers.ts의createStreamSink를 통해 구동하세요.send_message도구 자체는 단발성입니다. - 리치 텍스트(기본 켜짐). Markdown 응답이 Telegram 서식(굵게, 제목, 표, 작업 목록, 코드 블록)으로 렌더링됩니다. 일반 텍스트로 보내려면
TELEGRAM_RICH_TEXT=false로 설정하세요. - 첨부 파일. 이미지(
sendPhoto), 파일(sendDocument), 음성 메모(sendVoice, OGG/Opus 필수), 오디오(sendAudio)를 지원합니다. 소스는 Agent가 샌드박스 내에서 생성한 파일이어야 합니다(자세한 내용은 개요 페이지를 참조하세요). - 그룹 및 1:1 채팅. 두 경우 모두 동일한 흐름을 사용합니다. 그룹 채팅 id는 음수입니다.
- 메시지당 4,096자 제한.
send_message는 도구 경계에서 더 긴 텍스트를 거부하며, 스트림 싱크는 스트리밍 도중… (truncated)표시와 함께 텍스트를 자릅니다.
설정
1. 봇 생성
- Telegram을 열고 @BotFather를 찾습니다.
/newbot을 전송하고 안내에 따라 이름과 사용자명을 입력합니다.- BotFather가 제공하는 토큰을 저장합니다(예:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11).
2. 채팅 id 확인
- 새 봇과 채팅을 시작하고 메시지를 전송합니다. 채팅이 먼저 연락을 시작하지 않으면 Telegram이 봇의 메시지를 차단합니다.
- 브라우저에서
https://api.telegram.org/bot<TOKEN>/getUpdates를 열고 응답에서"chat":{"id":...}를 찾습니다.
그룹의 경우, 봇을 그룹에 추가하고 그룹에서 메시지를 전송한 뒤 getUpdates를 확인합니다. 그룹 id는 음수입니다(예: -1001234567890).
3. Minara 설정
간편한 방법. 채팅에서 Agent에게 요청합니다.
"set up Telegram notifications"
Minara가 토큰과 채팅 id를 묻고, ~/.minara/credentials.json(messaging 슬롯)에 기록한 뒤 테스트 핑을 실행합니다.
수동 방법:
minara auth messaging add telegram또는 프로젝트 루트의 .env 파일에 환경 변수를 직접 설정합니다.
TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
TELEGRAM_CHAT_ID=-10012345678904. 테스트
minara auth messaging test telegram1~2초 내에 핑 메시지가 수신되어야 합니다.
스트리밍 동작
Telegram의 editMessageText 엔드포인트는 속도 제한에 걸리지 않고 메시지당 최대 약 30회 편집을 허용합니다. TelegramGateway는 플레이스홀더를 게시하고 새 텍스트가 도착할 때마다 편집하는 startStream() 세션을 제공합니다. createStreamSink는 해당 편집을 750ms 간격으로 조절합니다. 이는 실시간처럼 느껴질 만큼 빠르면서도 채팅별 제한을 충분히 여유 있게 유지합니다. 누적 텍스트가 4,096자를 초과하면 스트리밍 도중 … (truncated) 표시와 함께 잘립니다.
조절 간격 및 길이 재정의는 createStreamSink(gw, msg, { intervalMs, maxLength })의 호출자 측 옵션이며, send_message의 인수가 아닙니다. 도구 경로 자체는 단발성입니다. LLM은 완전히 구성된 메시지를 전송하며, 스트리밍은 워크플로/Autopilot 코드에 존재합니다(아직 프로덕션에 연결되지 않았습니다).
리치 텍스트
응답은 기본적으로 Telegram 리치 텍스트로 렌더링됩니다. Agent가 Markdown을 생성하면 게이트웨이가 전송 전에 이를 Telegram이 지원하는 HTML 하위 집합으로 변환합니다.
- 제목은 굵게 표시되고, 목록은 글머리 기호를 유지하며, 작업 목록은 ☐ / ☑로, 표는 고정폭 정렬로, 코드 블록은 언어 라벨을 유지합니다.
- Telegram이 HTML을 거부하면(드묾) 게이트웨이가 같은 내용을 MarkdownV2로 재시도한 뒤 일반 텍스트로 폴백합니다. 서식 오류로 메시지가 사라지지 않습니다.
- 스트리밍 중에는 각 편집이 닫힌 서식만 표시하므로, 확정되기 전에
**bold같은 미완성 서식이 깜빡이지 않습니다.
끄면 Agent의 텍스트를 그대로 보냅니다.
TELEGRAM_RICH_TEXT=false"끄기"로 인식하는 값은 0, false, no, off이며, 설정하지 않으면 켜진 상태입니다. 이 설정은 시작 시 한 번만 읽으므로 변경 후 게이트웨이를 재시작하세요. 웹 UI의 설정 → 메시징 동작 → Telegram 리치 텍스트에서도 전환할 수 있습니다.
첨부 파일
첨부 파일은 Agent가 샌드박스 내에서 이미 생성한 파일을 참조합니다(image_generate, audio_generate, write_file, 코드 실행 등을 통해 생성). LLM은 샌드박스 상대 경로를 전달합니다.
send_message({
provider: "telegram",
text: "BTC/USD daily, key levels marked",
attachments: [
{ kind: "image", sandbox_path: "images/btc-2026-04-19.png" },
],
})종류별 라우팅:
| kind | Telegram 엔드포인트 | 비고 |
|---|---|---|
image | sendPhoto | 캡션 지원 |
file | sendDocument | 임의 파일 형식 |
voice | sendVoice | OGG/Opus 필수, OGG가 아닌 형식은 거부됨 |
audio | sendAudio | mp3 / m4a / flac, 음악 스타일 플레이어 UI |
여러 첨부 파일은 순차 메시지로 전송됩니다. 첫 번째 메시지는 msg.text가 충분히 짧으면(1,024자 이하) 캡션으로 포함됩니다. 그렇지 않으면 텍스트가 별도의 선행 메시지로 전송되고 첨부 파일이 그 아래에 연결됩니다. 자세한 내용은 apps/agent/src/messaging/telegram.ts를 참조하세요.
채널 재정의
긴급 알림은 다른 채팅으로 라우팅하면서 일반 알림은 기본값을 유지할 수 있습니다.
send_message({
provider: "telegram",
channel: "-1009876543210",
text: "Critical: position liquidation imminent",
})문제 해결
"테스트 메시지가 수신되지 않음"
- 봇에게 먼저 메시지를 보냈습니까? 채팅이 먼저 연락을 시작하지 않으면 Telegram이 메시지를 차단합니다.
TELEGRAM_CHAT_ID의 부호를 확인하세요. 그룹 채팅은 음수입니다.- 봇이 그룹에 여전히 있는지 확인하세요. BotFather에서 해당 봇을 선택한 뒤
Bot Settings→Group Privacy를 확인합니다.
"스트리밍이 느리거나 끊김"
- 예상된 동작입니다.
TelegramGateway내부의 기본 조절 간격은 750ms입니다. 호출자 코드에서createStreamSink(gw, msg, { intervalMs: 500 })으로 재정의할 수 있습니다. 이는 호출자 측 옵션이며send_message도구 인수가 아닙니다. - 매우 긴 응답은 4,096자에서 잘립니다. 워크플로를 여러 메시지로 분할하는 것을 고려하세요.
"Chat not found (400)"
- 봇이 그룹에서 제거되었거나 채팅 id가 잘못된 경우입니다.
- 대상 채팅에서 새 메시지를 전송한 뒤
getUpdates단계를 다시 실행하세요.