Skip to content

Commit 5291f51

Browse files
committed
0.3.0: _
1 parent d5db073 commit 5291f51

47 files changed

Lines changed: 8551 additions & 4302 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/validate.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Validate
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
validate:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Check out repository
12+
uses: actions/checkout@v4
13+
- name: Set up Node.js
14+
uses: actions/setup-node@v4
15+
with:
16+
node-version: 24
17+
cache: npm
18+
- name: Install dependencies
19+
run: npm ci
20+
- name: Run validation
21+
run: npm run validate

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
node_modules/
2-
package-lock.json

AGENTS.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,13 @@
5757
- Keep comments and user-facing docs in English unless the surrounding file already follows another convention
5858
- Each project `.ts` file should start with a short multi-line responsibility header comment that explains the file boundary to future maintainers
5959
- Name extracted `/lib` modules and mirrored `/tests` suites by bare domain when the repository already supplies the Telegram scope; prefer `api.ts`, `queue.ts`, `updates.ts`, and `queue.test.ts` over redundant `telegram-*` filename prefixes
60-
- Prefer targeted edits, keeping `index.ts` as the orchestration layer and moving reusable logic into flat `/lib` domain modules when a subsystem becomes large enough to earn extraction; current extracted domains include queueing/runtime decisions, preview streaming, replies, polling, updates, attachments, registration and lifecycle-hook binding, Telegram API/config support, Telegram Bot API transport types, command parsing/action routing, turn-building, media extraction/media-group coalescing, setup, rendering, status rendering, menu/model-resolution/UI support, and model-switch support
60+
- Prefer targeted edits, keeping `index.ts` as the orchestration layer and moving reusable logic into flat `/lib` domain modules when a subsystem becomes large enough to earn extraction; current extracted domains include queueing/runtime/session sequencing/agent lifecycle handling/queue mutation/prompt-enqueue/model-switch decisions, preview streaming/lifecycle, replies/rendered-message delivery runtime, polling start/stop/loop orchestration, updates/pairing/reaction handling, attachments/file-stat checks, registration and lifecycle-hook binding, Telegram API/config/runtime-error wrapping/temp-directory support, Telegram Bot API/bridge state transport types, shared constants/file-size limits, command parsing/action routing/runtime ports/metadata/stop-compact-status-model-debug-help side effects, turn-building, media extraction/file-download assembly/media-group coalescing, setup prompt/validation flow, rendering block/chunk/preview-snapshot boundaries, status rendering/diagnostics, and menu/model-resolution/state-store/command-opening/callback-runtime-routing/input-cache/state-building/UI support
6161
- Keep preview appearance logic in the rendering domain and preview transport/lifecycle logic in the preview domain so richer streaming strategies can evolve without entangling Telegram delivery state with Markdown formatting rules
62+
- Keep direct `node:*` file-operation dependencies out of `index.ts` when an owning domain exists; the entrypoint should compose ports while domains own local filesystem details such as temp-dir preparation, attachment stats, and turn image reads
63+
- In `index.ts`, prefer namespace imports for local bridge domains so orchestration reads as domain-scoped calls such as `Constants.*`, `Queue.*`, and `Rendering.*` instead of long flat import lists
64+
- Keep the local `index.ts` plus `/lib/*.ts` import graph acyclic; `tests/dependencies.test.ts` guards this boundary as domains keep evolving
65+
- Keep `lib/constants.ts` free of local domain imports; bridge-wide constants may move there, domain-specific constants should stay in their owning domain, and `index.ts` should not grow new shared magic constants
66+
- Keep remaining `index.ts` code focused on cross-domain adapter wiring that needs live extension state, pi callbacks, Telegram API ports, or status updates; do not extract one-off closures solely to reduce line count
6267

6368
## 7. Operational Conventions
6469

BACKLOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
## Open Backlog
44

5-
- No open backlog items right now
5+
No open backlog items.

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
## Current
44

5+
- `[Safety]` Added default 50 MiB inbound Telegram download and outbound attachment limits with environment overrides, enforced outbound attachment checks at queue and send time, and wrote `telegram.json` with private `0600` permissions. Impact: large Telegram files fail predictably before stressing the bridge, and persisted bot tokens are less exposed on shared systems.
6+
- `[Replies]` Send Telegram prompt responses, rich previews, final replies, errors, attachment notices, and uploads as explicit Telegram replies to the source prompt when possible, using `reply_parameters` with `allow_sending_without_reply` and applying reply metadata only to the first chunk of split long responses. Impact: queued Telegram answers are visually tied to the prompt that produced them while preserving fallback delivery if Telegram cannot attach the reply.
7+
- `[Packaging]` Added an explicit npm package allowlist and stopped ignoring the tracked lockfile. Impact: published tarballs now exclude tests and internal backlog/changelog/context files while keeping release contents predictable.
8+
- `[Validation]` Added TypeScript typecheck tooling, `audit`/`pack:check`/`validate` scripts, dependency audit fixes, a GitHub Actions workflow that runs install plus local validation, split extension-runtime regressions out of the large queue helper suite, expanded rendering fixture/invariant coverage for realistic model outputs, removed entrypoint test-utils coupling from setup/rendering/queue helper suites, added dependency-boundary coverage for circular local imports and the shared constants module's local-import-free boundary, and fake-timer coverage for preview-throttle plus media-group debounce runtime paths. Impact: release validation now catches type errors, known vulnerable dependency ranges, test regressions, circular domain-import drift, constants-boundary drift, and package-content drift before publishing 0.3.x builds while queue-helper tests are easier to navigate, timer-sensitive runtime regressions no longer depend on wall-clock timing, and Telegram HTML rendering is covered against realistic model-output shapes.
9+
- `[Observability]` Expanded `/telegram-status` with last update id, active turn source ids, pending dispatch, compaction state, active tool count, pending model-switch state, recent runtime/API error context, total queue depth, and queue-lane counts, added Telegram `/debug` to show the redacted recent runtime/API event ring, and centralized structured runtime-event recording with redacted message/details fields. Impact: operators can diagnose queue/lifecycle stalls and recent bridge failures without reading runtime state directly.
10+
- `[Refactor]` Moved bridge status-bar/status-line construction and recent runtime-event ring-buffer helpers into the status domain with direct regression coverage, moved CLI scoped-model pattern parsing into the menu domain, moved assistant-message text extraction into the replies domain, moved queued-edit mutation into the turns domain, moved Telegram setup prompt/validation/persistence flow into the setup domain, moved polling start/stop state orchestration into the polling domain, moved assistant preview message lifecycle branching into the preview domain, moved Telegram-aware system-prompt suffix construction into the registration domain, moved inbound Telegram file download assembly into the media domain, moved Telegram user-pairing side effects into the updates domain, moved Telegram API runtime error-wrapping into the API domain, moved command runtime port orchestration into the commands domain, moved rendered-message reply and interactive-message delivery runtime into the replies domain, moved Node-backed temp-directory preparation, attachment stat checks, and turn image-file reads into their owning API/attachment/turn domains, moved session start/shutdown sequencing plus agent-start/tool/agent-end lifecycle handling, prompt enqueue/history planning/runtime, queue mutation runtime, and control/model-switch continuation item construction into the queue domain, moved local bridge state types into `lib/types.ts`, centralized runtime constants and the shared Telegram file-size limit in `lib/constants.ts`, grouped local domain imports in `index.ts` behind namespace imports, moved Bot API command definitions and stop/compact/status/model/debug/help command side-effect branching into the commands domain, moved model-menu store pruning/refresh, command open-flow branching, callback entry/runtime routing, plus input-cache/state-building resolution behavior into the menu domain, and moved authorized reaction priority/removal handling into the updates domain, separated reusable Markdown block, inline-token/style, text-piece, stable-preview scanning/rendering, and final chunk-accumulation helpers inside the rendering domain, kept HTML escaping plus raw HTML tag-preserving chunking in the rendering domain after consolidating premature standalone helpers, removed stale shared type exports after verifying they had no consumers, tightened update runtime generics so `index.ts` no longer casts authorized update callback payloads, centralized AgentMessage structural access in the replies domain, DRY'd repeated config load/persist adapter wiring in `index.ts`, destructured composition-root runtime factory outputs and small adapter result objects in `index.ts`, and documented the remaining `index.ts` event wiring as cross-domain adapter code instead of extraction-ready domain behavior. Impact: `index.ts` owns less diagnostics, menu-configuration parsing, status-bar branching, setup flow branching, polling start/stop state mutation, inbound file assembly, pairing side-effect branching, API runtime error wrapping, command runtime port wiring, rendered-message reply/interactive delivery branching, direct `node:*` file-operation imports, repeated config persistence wiring, authorized-update callback casts, repeated assistant-message structural casts, runtime factory method alias boilerplate, generic result-object unpacking, session start/shutdown sequencing, assistant preview lifecycle branching, reply-finalization extraction, queued-turn mutation, lifecycle prompt-shaping, stale shared type exports, type/constant definitions, flat local-domain import lists, command metadata, stop/compact/status/model/debug/help command branching, model-menu command opening, model-menu callback runtime routing, model-menu cache/state-building mutation, reaction side-effect branching, and prompt-enqueue planning and queue-item construction logic while rendering internals remain in the cohesive rendering module with clearer block-rendering and chunking boundaries.
11+
- `[Refactor]` Folded the small model-switch helper module into the queue domain and removed duplicate guard logic. Impact: in-flight model-switch behavior now lives with the queue/lifecycle rules it depends on, reducing domain sprawl during 0.3.0 preparation.
12+
13+
## 0.2.x
14+
515
- `[Turns]` Preserved existing attachment-path blocks and aborted-turn history context when a still-queued Telegram message is edited. Impact: caption edits no longer make queued prompts lose their downloaded file references or prior-message context.
616
- `[Polling]` Persisted Telegram long-poll offsets only after each update is handled successfully. Impact: a handler failure no longer marks an unprocessed Telegram update as consumed, reducing the chance of silently dropping inbound messages.
717
- `[Telegram API]` Added HTTP-status-aware Bot API response parsing, malformed-success handling, retry/backoff for 429 and 5xx Bot API responses, streaming Telegram downloads with size-limit checks, file-backed multipart upload blobs, partial-download cleanup on limit failures, startup cleanup for stale Telegram temp files, and UUID-based sanitized temp filenames. Impact: Telegram transport failures now report clearer status/description details, transient Telegram throttling/server failures get retried automatically, oversized inbound files are rejected before or during download, outbound multipart sends avoid preloading files into memory, partial and stale temp files are removed, and downloaded files are less prone to timestamp collisions or unsafe local names.

README.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This repository is an actively maintained fork of [`badlogic/pi-telegram`](https
1818
- **In-flight Model Switching**: Change the active model mid-generation. The agent gracefully pauses, applies the new model, and restarts its response without losing context.
1919
- **Smart Message Queue**: Messages sent while the agent is busy are queued and previewed in the pi status bar, and queued turns can be reprioritized or removed with Telegram reactions.
2020
- **Mobile-Optimized Rendering**: Tables and lists are formatted for narrow screens. Markdown is correctly parsed and split to fit Telegram's limits without breaking HTML structures or code blocks, block spacing stays faithful to the original Markdown with readable heading separation, supported absolute links stay clickable, and unsupported link forms degrade safely.
21-
- **File Handling & Attachments**: Send images and files to the agent, or ask it to generate and return artifacts. Outbound files are delivered automatically via the `telegram_attach` tool.
21+
- **File Handling & Attachments**: Send images and files to the agent, or ask it to generate and return artifacts. Inbound downloads and outbound attachments are size-limited by default, and outbound files are delivered automatically via the `telegram_attach` tool.
2222
- **Streaming Responses**: Closed Markdown blocks stream back as rich Telegram HTML while pi is generating, and the still-growing tail stays readable until the final fully rendered reply lands.
2323

2424
## Install
@@ -52,7 +52,7 @@ Start pi, then run:
5252
/telegram-setup
5353
```
5454

55-
Paste your bot token when prompted. If a bot token is already saved in `~/.pi/agent/telegram.json`, `/telegram-setup` shows that stored value by default. Otherwise it prefills from the first configured environment variable in `TELEGRAM_BOT_TOKEN`, `TELEGRAM_BOT_KEY`, `TELEGRAM_TOKEN`, or `TELEGRAM_KEY`.
55+
Paste your bot token when prompted. If a bot token is already saved in `~/.pi/agent/telegram.json`, `/telegram-setup` shows that stored value by default. Otherwise it prefills from the first configured environment variable in `TELEGRAM_BOT_TOKEN`, `TELEGRAM_BOT_KEY`, `TELEGRAM_TOKEN`, or `TELEGRAM_KEY`. The saved config file is written with private `0600` permissions.
5656

5757
Link the bridge to your current pi session:
5858

@@ -77,10 +77,11 @@ Once paired, simply chat with your bot in Telegram. All text, images, and files
7777

7878
- **`/status`**: View session stats, cost, and use inline buttons to change models.
7979
- **`/model`**: Open the interactive model selector.
80+
- **`/debug`**: Show the recent redacted bridge runtime/API event ring.
8081
- **`/compact`**: Start session compaction (only works when the session is idle).
8182
- **`/stop`**: Abort the active run.
8283
- **`/telegram-disconnect`** (in pi): Stop polling in the current session.
83-
- **`/telegram-status`** (in pi): Check bridge status.
84+
- **`/telegram-status`** (in pi): Check bridge status, including polling state, queue lanes, active turn, pending dispatch, compaction, active tool count, last Telegram update id, and latest runtime/API error context.
8485

8586
### Queue, Reactions, and Media
8687

@@ -89,18 +90,18 @@ Once paired, simply chat with your bot in Telegram. All text, images, and files
8990
- `👎` removes a waiting turn from the queue. Telegram Bot API does not expose ordinary DM message-deletion events through the polling path used here, so queue removal is bound to the dislike reaction.
9091
- For media groups, a reaction on any message in the group applies to the whole queued turn.
9192
- If you edit a Telegram message while it is still waiting in the queue, the queued turn is updated instead of creating a duplicate prompt. Edits after a turn has already started may not affect the active run.
92-
- Inbound images, albums, and files are saved to `~/.pi/agent/tmp/telegram`, local file paths are included in the prompt, and inbound images are forwarded to pi as image inputs.
93+
- Inbound images, albums, and files are saved to `~/.pi/agent/tmp/telegram`, local file paths are included in the prompt, and inbound images are forwarded to pi as image inputs. Inbound downloads default to a 50 MiB limit and can be adjusted with `PI_TELEGRAM_INBOUND_FILE_MAX_BYTES` or `TELEGRAM_MAX_FILE_SIZE_BYTES`.
9394
- Queue reactions depend on Telegram delivering `message_reaction` updates for your bot and chat type.
9495

9596
### Requesting Files
9697

97-
If you ask pi for a file or generated artifact (e.g., _"generate a shell script and attach it"_), pi will call the `telegram_attach` tool, and the extension will send the file alongside its next Telegram reply.
98+
If you ask pi for a file or generated artifact (e.g., _"generate a shell script and attach it"_), pi will call the `telegram_attach` tool, and the extension will send the file alongside its next Telegram reply. Outbound attachments default to a 50 MiB limit and can be adjusted with `PI_TELEGRAM_OUTBOUND_ATTACHMENT_MAX_BYTES` or `TELEGRAM_MAX_ATTACHMENT_SIZE_BYTES`.
9899

99100
## Streaming
100101

101102
The extension streams assistant previews back to Telegram while pi is generating.
102103

103-
Rich previews are sent through editable messages because Telegram drafts are text-only. Closed top-level Markdown blocks can appear with formatting before the answer finishes, while the still-growing tail remains conservative and readable until the preview is replaced with the fully rendered Telegram HTML reply.
104+
Rich previews are sent through editable messages because Telegram drafts are text-only. Closed top-level Markdown blocks can appear with formatting before the answer finishes, while the still-growing tail remains conservative and readable until the preview is replaced with the fully rendered Telegram HTML reply. Editable preview messages are also attached as replies to the source Telegram prompt when possible.
104105

105106
## Status bar
106107

@@ -113,8 +114,8 @@ The pi status bar shows queued Telegram turns as compact previews, for example:
113114
## Notes
114115

115116
- Only one pi session should be connected to the bot at a time
116-
- Replies are sent as normal Telegram messages, not quote-replies
117-
- Long replies are split below Telegram's 4096 character limit without intentionally breaking Telegram HTML formatting
117+
- Replies to Telegram prompts are sent as Telegram replies to the source message when possible; if the source message is unavailable, delivery falls back to a normal message
118+
- Long replies are split below Telegram's 4096 character limit without intentionally breaking Telegram HTML formatting; only the first split message is attached as a Telegram reply to the source prompt
118119
- Outbound files are sent via `telegram_attach`
119120
- Temporary inbound Telegram files are cleaned up on later session starts
120121

0 commit comments

Comments
 (0)