Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ Key design goals:

## Screenshot


### Install

```bash
Expand Down Expand Up @@ -281,6 +280,9 @@ GitHub skill:
Telegram adaptation notes:

- Plain text messages behave like a normal Codex conversation turn
- Photo, document, video, audio, voice, animation, sticker, and video-note messages are also routed to Codex as structured attachment prompts
- Media captions are treated as the user request; attachment metadata and Telegram file links are included when available
- On SDK runs, files created or updated in the current Codex turn can be sent back to the Telegram user as document attachments
- `/exec` runs a one-off Codex task and does not overwrite the saved project conversation slot
- `/auto` runs a one-off Codex task with `approvalPolicy=never` on the SDK backend, or `codex exec --full-auto` on the CLI backend
- `/new` is implemented by the bot and resets the current chat session
Expand All @@ -304,6 +306,7 @@ Telegram adaptation notes:
Codex output is streamed with throttled `editMessageText` updates.

- Throttle: controlled by `STREAM_THROTTLE_MS` (default `1200`)
- While Codex is still working, the bot keeps Telegram's `typing` indicator alive so the chat shows that a reply is in progress
- Long output: auto-chunked to Telegram-safe message sizes
- MarkdownV2: escaped to avoid parse failures
- Reasoning tags: `<think>...</think>` extracted and rendered as:
Expand Down
17 changes: 9 additions & 8 deletions scripts/telegramSmoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,31 @@ const expectedUsername = String(process.env.TELEGRAM_EXPECTED_USERNAME || "")
.replace(/^@/, "");
const smokeChatId = String(process.env.TELEGRAM_SMOKE_CHAT_ID || "").trim();

if (!token) {
console.error("Missing BOT_TOKEN.");
function fail(message: string): never {
process.stderr.write(`${message}\n`);
process.exit(1);
}

if (!token) {
fail("Missing BOT_TOKEN.");
}

const getMeResponse = await fetch(`https://api.telegram.org/bot${token}/getMe`);
const getMePayload =
(await getMeResponse.json()) as TelegramApiResponse<TelegramBotUser>;

if (!getMeResponse.ok || !getMePayload?.ok) {
console.error(
fail(
`Telegram getMe failed: ${getMePayload?.description || getMeResponse.status}`
);
process.exit(1);
}

const botUser = getMePayload.result;
console.log(`Bot username: @${botUser.username}`);
console.log(`Bot id: ${botUser.id}`);

if (expectedUsername && botUser.username !== expectedUsername) {
console.error(`Expected @${expectedUsername}, got @${botUser.username}`);
process.exit(1);
fail(`Expected @${expectedUsername}, got @${botUser.username}`);
}

if (smokeChatId) {
Expand All @@ -73,10 +75,9 @@ if (smokeChatId) {
(await sendResponse.json()) as TelegramApiResponse<TelegramSendMessageResult>;

if (!sendResponse.ok || !sendPayload?.ok) {
console.error(
fail(
`Telegram sendMessage failed: ${sendPayload?.description || sendResponse.status}`
);
process.exit(1);
}

console.log(`Smoke message sent to chat ${smokeChatId}.`);
Expand Down
Loading