@llblab/pi-telegram 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +90 -0
- package/BACKLOG.md +5 -0
- package/CHANGELOG.md +17 -0
- package/README.md +202 -0
- package/docs/README.md +9 -0
- package/docs/architecture.md +148 -0
- package/index.ts +1968 -0
- package/lib/api.ts +222 -0
- package/lib/attachments.ts +98 -0
- package/lib/media.ts +234 -0
- package/lib/menu.ts +951 -0
- package/lib/model-switch.ts +62 -0
- package/lib/polling.ts +122 -0
- package/lib/queue.ts +534 -0
- package/lib/registration.ts +163 -0
- package/lib/rendering.ts +697 -0
- package/lib/replies.ts +313 -0
- package/lib/setup.ts +41 -0
- package/lib/status.ts +109 -0
- package/lib/turns.ts +144 -0
- package/lib/updates.ts +397 -0
- package/package.json +40 -0
- package/screenshot.png +0 -0
- package/tests/api.test.ts +89 -0
- package/tests/attachments.test.ts +132 -0
- package/tests/config.test.ts +80 -0
- package/tests/media.test.ts +77 -0
- package/tests/menu.test.ts +645 -0
- package/tests/polling.test.ts +129 -0
- package/tests/queue.test.ts +2982 -0
- package/tests/registration.test.ts +268 -0
- package/tests/rendering.test.ts +308 -0
- package/tests/replies.test.ts +362 -0
- package/tests/turns.test.ts +132 -0
- package/tests/updates.test.ts +366 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Project Context
|
|
2
|
+
|
|
3
|
+
## 0. Meta-Protocol Principles
|
|
4
|
+
|
|
5
|
+
- `Constraint-Driven Evolution`: Add structure when the bridge gains real operator or runtime constraints
|
|
6
|
+
- `Single Source of Truth`: Keep durable rules in `AGENTS.md`, open work in `BACKLOG.md`, completed delivery in `CHANGELOG.md`, and deeper technical detail in `/docs`
|
|
7
|
+
- `Boundary Clarity`: Separate Telegram transport concerns, pi integration concerns, rendering behavior, and release/documentation state
|
|
8
|
+
- `Progressive Enhancement + Graceful Degradation`: Prefer behavior that upgrades automatically when richer runtime context exists, but always preserves a useful fallback path when it does not
|
|
9
|
+
- `Runtime Safety`: Prefer queue and rendering behavior that fails predictably over clever behavior that can desynchronize the Telegram bridge from pi session state
|
|
10
|
+
|
|
11
|
+
## 1. Concept
|
|
12
|
+
|
|
13
|
+
`pi-telegram` is a pi extension that turns a Telegram DM into a session-local frontend for pi, including text/file forwarding, streaming previews, queued follow-ups, model controls, and outbound attachment delivery.
|
|
14
|
+
|
|
15
|
+
## 2. Identity & Naming Contract
|
|
16
|
+
|
|
17
|
+
- `Telegram turn`: One unit of Telegram input processed by pi; this may represent one message or a coalesced media group
|
|
18
|
+
- `Queued Telegram turn`: A Telegram turn accepted by the bridge but not yet active in pi
|
|
19
|
+
- `Active Telegram turn`: The Telegram turn currently bound to the running pi agent loop
|
|
20
|
+
- `Preview`: The transient streamed response shown through Telegram drafts or editable messages before the final reply lands
|
|
21
|
+
- `Scoped models`: The subset of models exposed to Telegram model selection when pi settings or CLI flags limit the available list
|
|
22
|
+
|
|
23
|
+
## 3. Project Topology
|
|
24
|
+
|
|
25
|
+
- `/index.ts`: Main extension entrypoint and runtime composition layer for the bridge
|
|
26
|
+
- `/lib/*.ts`: Flat domain modules for reusable runtime logic. Favor domain files such as queueing/runtime, replies, polling, updates, attachments, registration/hooks, Telegram API/config, turns, media, setup, rendering, menu/status/model-resolution support, and other cohesive bridge subsystems; use `shared` only when a type or constant truly spans multiple domains
|
|
27
|
+
- `/tests/*.test.ts`: Domain-mirrored regression suites that follow the same flat naming as `/lib`
|
|
28
|
+
- `/docs/README.md`: Documentation index for technical project docs
|
|
29
|
+
- `/docs/architecture.md`: Runtime and subsystem overview for the bridge
|
|
30
|
+
- `/README.md`: User-facing project entry point, install guide, and fork summary
|
|
31
|
+
- `/AGENTS.md`: Durable engineering and runtime conventions
|
|
32
|
+
- `/BACKLOG.md`: Canonical open work
|
|
33
|
+
- `/CHANGELOG.md`: Completed delivery history
|
|
34
|
+
|
|
35
|
+
## 4. Core Entities
|
|
36
|
+
|
|
37
|
+
- `TelegramConfig`: Persisted bot/session pairing state
|
|
38
|
+
- `PendingTelegramTurn` / `ActiveTelegramTurn`: Queue and active-turn state for Telegram-originated work
|
|
39
|
+
- `TelegramPreviewState`: Streaming preview state for drafts or editable Telegram messages
|
|
40
|
+
- `TelegramModelMenuState`: Inline menu state for status/model/thinking controls
|
|
41
|
+
- `QueuedAttachment`: Outbound files staged for delivery through `telegram_attach`
|
|
42
|
+
|
|
43
|
+
## 5. Architectural Decisions
|
|
44
|
+
|
|
45
|
+
- `index.ts` stays the single extension entrypoint, while reusable runtime logic should be split into flat domain files under `/lib`; prefer domain-oriented grouping over atomizing every helper into its own file, and use `shared` sparingly for genuinely cross-domain types or constants
|
|
46
|
+
- The bridge is session-local and intentionally pairs with a single allowed Telegram user per config
|
|
47
|
+
- Telegram queue state is tracked locally and must stay aligned with pi agent lifecycle hooks; queued items now have explicit kinds and lanes so prompt turns and synthetic control actions can share one ordering model, while dispatch still respects active turns, pending dispatch, compaction, and pi pending-message state
|
|
48
|
+
- Prompt items should remain in the queue until `agent_start` consumes the dispatched turn; removing them earlier breaks active-turn binding, preview delivery, and end-of-turn follow-up behavior
|
|
49
|
+
- In-flight `/model` switching is supported only for Telegram-owned active turns and is implemented as set-model plus synthetic continuation turn plus abort; if a tool call is active, the abort is delayed until that tool finishes instead of interrupting the tool mid-flight
|
|
50
|
+
- Telegram replies render through Telegram HTML, not raw Markdown; real code blocks must stay literal and escaped
|
|
51
|
+
- `telegram_attach` is the canonical outbound file-delivery path for Telegram-originated requests
|
|
52
|
+
|
|
53
|
+
## 6. Engineering Conventions
|
|
54
|
+
|
|
55
|
+
- Treat queue handling, compaction interaction, and lifecycle-hook state transitions as regression-prone areas; validate them after changing dispatch logic
|
|
56
|
+
- Treat Markdown rendering as Telegram-specific output work, not generic Markdown rendering; preserve literal code content, avoid HTML chunk splits that break tags, prefer width-efficient monospace table and list formatting for narrow clients, and flatten nested Markdown quotes into indented single-blockquote output because Telegram does not render nested blockquotes reliably
|
|
57
|
+
- Keep comments and user-facing docs in English unless the surrounding file already follows another convention
|
|
58
|
+
- Each project `.ts` file should start with a short multi-line responsibility header comment that explains the file boundary to future maintainers
|
|
59
|
+
- 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, replies, polling, updates, attachments, registration and lifecycle-hook binding, Telegram API/config support, turn-building, media extraction, setup, rendering, status rendering, menu/model-resolution/UI support, and model-switch support
|
|
61
|
+
|
|
62
|
+
## 7. Operational Conventions
|
|
63
|
+
|
|
64
|
+
- When Telegram-visible behavior changes, sync `README.md` and the relevant `/docs` entry in the same pass
|
|
65
|
+
- When durable runtime constraints or repeat bug patterns emerge, record them here instead of burying them in changelog prose
|
|
66
|
+
- When fork identity changes, keep `README.md`, package metadata, and docs aligned so the published package does not point back at stale upstream coordinates
|
|
67
|
+
- Work only inside this repository during development tasks; updating the installed Pi extension checkout is a separate manual operator step, not part of normal in-repo implementation work
|
|
68
|
+
|
|
69
|
+
## 8. Integration Protocols
|
|
70
|
+
|
|
71
|
+
- Telegram API methods currently used include polling, message editing, draft streaming, callback queries, reactions, file download, and media upload endpoints
|
|
72
|
+
- pi integration depends on lifecycle hooks such as `before_agent_start`, `agent_start`, `message_start`, `message_update`, and `agent_end`
|
|
73
|
+
- `ctx.ui.input()` provides placeholder text rather than an editable prefilled value; when a real default must appear already filled in, prefer `ctx.ui.editor()`
|
|
74
|
+
- For `/telegram-setup`, prefer the locally saved bot token over environment variables on repeat setup runs; env vars are the bootstrap path when no local token exists
|
|
75
|
+
- Status/model/thinking controls are driven through Telegram inline keyboards and callback queries
|
|
76
|
+
- Inbound files may become pi image inputs; outbound files must flow through `telegram_attach`
|
|
77
|
+
|
|
78
|
+
## 9. Pre-Task Preparation Protocol
|
|
79
|
+
|
|
80
|
+
- Read `README.md` for current user-facing behavior and fork positioning
|
|
81
|
+
- Read `BACKLOG.md` before changing runtime behavior or documentation so open work stays truthful
|
|
82
|
+
- Read `/docs/architecture.md` before restructuring queue, preview, rendering, or command-handling logic
|
|
83
|
+
- Inspect the relevant `index.ts` section before editing because most bridge behavior is stateful and cross-linked
|
|
84
|
+
|
|
85
|
+
## 10. Task Completion Protocol
|
|
86
|
+
|
|
87
|
+
- Run the smallest meaningful validation for the touched area; `npm test` is the default regression suite once rendering or queue logic changes
|
|
88
|
+
- For rendering changes, ensure regressions still cover nested lists, code blocks, underscore-heavy text, and long-message chunking
|
|
89
|
+
- For queue/dispatch changes, validate abort, compaction, pending-dispatch, and pi pending-message guard behavior
|
|
90
|
+
- Sync `README.md`, `CHANGELOG.md`, `BACKLOG.md`, and `/docs` whenever user-visible behavior or real open-work state changes
|
package/BACKLOG.md
ADDED
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Current
|
|
4
|
+
|
|
5
|
+
- `[Docs]` Added short responsibility header comments to every project `.ts` file. Impact: file boundaries are easier to understand while navigating the growing `/lib` split.
|
|
6
|
+
- `[Naming]` Renamed extracted domain modules and mirrored regression suites to use repo-scoped bare domain filenames such as `api.ts`, `queue.ts`, and `queue.test.ts` instead of repeating `telegram-*` in every path. Impact: the internal topology is easier to scan and stays aligned with the repository-level Telegram scope.
|
|
7
|
+
- `[Controls]` Expanded Telegram session controls with a richer `/status` view, inline model selection, and thinking-level controls. Impact: more bridge configuration can be managed directly from Telegram.
|
|
8
|
+
- `[Queue]` Upgraded Telegram turn queueing with previews, reaction-driven prioritization/removal, media-group handling, aborted-turn history preservation, and safer dispatch gating. Impact: follow-up handling is more transparent and less prone to lifecycle races.
|
|
9
|
+
- `[Rendering]` Added Telegram-oriented Markdown rendering and hardened reply streaming/chunking behavior, including narrower monospace Markdown table output without outer side borders, monospace list markers for unordered and ordered lists, and flattened nested quote indentation inside a single Telegram blockquote. Impact: formatted replies render more reliably while preserving literal code blocks and using width more efficiently on narrow Telegram clients.
|
|
10
|
+
- `[Runtime]` Hardened attachment delivery, polling/runtime behavior, Telegram session integration, preview-finalization and reply-transport routing into the replies domain, lazy Telegram API client routing into the Telegram API domain, turn-building extraction into its own domain, menu/model-resolution plus menu-state, pure menu-page derivation, pure menu render-payload builders, menu-message runtime, callback parsing, callback entry handling, callback mutation helpers, full model-callback planning and execution, and interface-polished callback effect ports into the menu domain, direct execute-from-update routing into the updates domain, model-switch restart glue extraction into the model-switch domain, and tool/command/lifecycle-hook registration extraction into a dedicated registration domain. Impact: the bridge is more robust as a daily Telegram frontend for pi.
|
|
11
|
+
- `[Metadata]` Updated package repository metadata to point at the `llblab/pi-telegram` fork and renamed the npm package to `@llblab/pi-telegram` with public scoped publish settings. Impact: published package links no longer send users to stale upstream coordinates and the package can be published under the fork-owned npm scope.
|
|
12
|
+
- `[Validation]` Added lightweight regression tests for Telegram Markdown rendering, queue/runtime/agent-loop/session/control/dispatch, replies, polling, updates, attachments, registration, turns, menu, and Telegram API/media/config helpers, including quote/list, table, link/code, mixed-link/code chunking, mixed-block chunk transitions, long multi-block, long-quote, long inline-formatting chunk boundaries, list-code-quote-prose chunk transitions, narrower monospace table rendering without outer side borders, monospace unordered and ordered list markers, flattened nested quote indentation inside one Telegram blockquote, inbound poll/pair/dispatch runtime cases, preview finalization, aborted-turn history carry-over, queued-status/model-after-agent-end sequencing, compaction gating, media-group debounce dispatch, direct menu callback planning and execution, pure menu-page derivation, pure menu render-payload builders, reaction-driven reprioritization/removal, immediate in-flight model-switch continuation, delayed abort-after-tool-completion, lazy Telegram API client routing, turn-building, and scoped-model resolution. Impact: key renderer and queue invariants now have repeatable automated coverage across the known high-risk bridge paths.
|
|
13
|
+
- `[Model Switching]` Enabled `/model` during an active Telegram-owned run by applying the new model and continuing on the new model automatically, delaying the abort until the current tool finishes when needed. Impact: Telegram can now approximate pi's manual stop-switch-continue workflow with fewer mid-tool aborts.
|
|
14
|
+
- `[Queue Core]` Introduced queued item kinds and explicit queue-lane ordering semantics so prompt turns and synthetic control actions share one ordering model, then regrouped the extracted helpers into flatter domain-oriented `/lib` modules such as queue, replies, polling, updates, attachments, turns, menu, Telegram API, and registration while keeping `index.ts` as the entrypoint. Prompt items now stay queued until `agent_start` consumes the dispatched turn, which restores correct active-turn binding for previews and final delivery. Impact: the bridge now has a clearer foundation for scheduling async extension operations alongside Telegram prompts without losing a single obvious runtime entry file.
|
|
15
|
+
- `[Registration]` Moved extension tool, command, and lifecycle-hook binding into the registration domain and added registration-focused regression coverage. Impact: extension wiring is easier to reason about and test without dragging full runtime state into every registration change.
|
|
16
|
+
- `[Control Queue]` Moved `/status` and `/model` command handling onto high-priority control queue items. Impact: control actions can wait safely behind the current run while still jumping ahead of normal queued prompts.
|
|
17
|
+
- `[Setup]` `/telegram-setup` now shows the stored bot token first, otherwise prefills from common Telegram bot environment variables before falling back to the placeholder, using an actual prefilled editor when a real default exists. Impact: repeat setup respects local saved state while first-run and secret-managed setup stay fast.
|
package/README.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# pi-telegram
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Telegram DM bridge for pi.
|
|
6
|
+
|
|
7
|
+
This repository is a fork of the original [`badlogic/pi-telegram`](https://github.com/badlogic/pi-telegram).
|
|
8
|
+
It started from upstream commit [`cb34008460b6c1ca036d92322f69d87f626be0fc`](https://github.com/badlogic/pi-telegram/commit/cb34008460b6c1ca036d92322f69d87f626be0fc) and has since diverged substantially.
|
|
9
|
+
|
|
10
|
+
## Start Here
|
|
11
|
+
|
|
12
|
+
- [Project Context](./AGENTS.md)
|
|
13
|
+
- [Open Backlog](./BACKLOG.md)
|
|
14
|
+
- [Changelog](./CHANGELOG.md)
|
|
15
|
+
- [Documentation](./docs/README.md)
|
|
16
|
+
|
|
17
|
+
## What Changed In This Fork
|
|
18
|
+
|
|
19
|
+
Compared to upstream commit `cb34008`, this fork significantly extends and hardens the extension.
|
|
20
|
+
|
|
21
|
+
- Better Telegram control UI, including an improved `/status` view with inline buttons for model and thinking selection
|
|
22
|
+
- Interactive model selection improvements, including scoped model lists, thinking-level control for reasoning-capable models, and in-flight restart on a newly selected model for active Telegram-owned runs
|
|
23
|
+
- Queueing and interaction upgrades, including queue previews, reaction-based prioritization/removal, media-group handling, high-priority control actions, and safer dispatch behavior
|
|
24
|
+
- Markdown and reply rendering improvements, with richer formatting support, narrow-client-friendly table/list rendering, quote compatibility fixes, and multiple fixes for incorrect Telegram rendering and chunking edge cases
|
|
25
|
+
- Streaming, attachment, and delivery workflow hardening, including more robust preview updates and file handling
|
|
26
|
+
- General runtime polish, bug fixes, and refactors across pairing, command handling, and Telegram session behavior
|
|
27
|
+
- Cleaner internal domain layout, with flat `/lib/*.ts` modules and mirrored `/tests/*.test.ts` suites that use repo-scoped domain names instead of redundant `telegram-*` filename prefixes
|
|
28
|
+
|
|
29
|
+
In short: this fork is no longer just a repackaged copy of upstream; it is a feature-expanded and bug-fixed Telegram frontend for pi.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
From npm once published:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pi install @llblab/pi-telegram
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
From git:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pi install git:github.com/llblab/pi-telegram
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or for a single run:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pi -e @llblab/pi-telegram
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configure
|
|
52
|
+
|
|
53
|
+
### Telegram
|
|
54
|
+
|
|
55
|
+
1. Open [@BotFather](https://t.me/BotFather)
|
|
56
|
+
2. Run `/newbot`
|
|
57
|
+
3. Pick a name and username
|
|
58
|
+
4. Copy the bot token
|
|
59
|
+
|
|
60
|
+
### pi
|
|
61
|
+
|
|
62
|
+
Start pi, then run:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
/telegram-setup
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Paste the bot token when prompted.
|
|
69
|
+
If a bot token is already saved in `~/.pi/agent/telegram.json`, `/telegram-setup` shows that stored value by default. Otherwise it pre-fills from the first configured environment variable in `TELEGRAM_BOT_TOKEN`, `TELEGRAM_BOT_KEY`, `TELEGRAM_TOKEN`, or `TELEGRAM_KEY`.
|
|
70
|
+
|
|
71
|
+
The extension stores config in:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
~/.pi/agent/telegram.json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Connect a pi session
|
|
78
|
+
|
|
79
|
+
The Telegram bridge is session-local. Connect it only in the pi session that should own the bot:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
/telegram-connect
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
To stop polling in the current session:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
/telegram-disconnect
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Check status:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
/telegram-status
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Pair your Telegram account
|
|
98
|
+
|
|
99
|
+
After token setup and `/telegram-connect`:
|
|
100
|
+
|
|
101
|
+
1. Open the DM with your bot in Telegram
|
|
102
|
+
2. Send `/start`
|
|
103
|
+
|
|
104
|
+
The first DM user becomes the allowed Telegram user for the bridge. The extension only accepts messages from that user.
|
|
105
|
+
|
|
106
|
+
## Usage
|
|
107
|
+
|
|
108
|
+
Chat with your bot in Telegram DMs.
|
|
109
|
+
|
|
110
|
+
Additional fork-specific controls:
|
|
111
|
+
|
|
112
|
+
- `/status` now has a richer view with inline buttons for model and thinking controls, and joins the high-priority control queue when pi is busy
|
|
113
|
+
- `/model` opens the interactive model selector, joins the high-priority control queue when pi is busy, and can restart the active Telegram-owned run on the newly selected model, waiting for the current tool call to finish when needed
|
|
114
|
+
- `/compact` starts session compaction when pi and the Telegram queue are idle
|
|
115
|
+
- Queue reactions: `👍` prioritizes a waiting turn, `👎` removes it
|
|
116
|
+
|
|
117
|
+
### Send text
|
|
118
|
+
|
|
119
|
+
Send any message in the bot DM. It is forwarded into pi with a `[telegram]` prefix.
|
|
120
|
+
|
|
121
|
+
### Send images and files
|
|
122
|
+
|
|
123
|
+
Send images, albums, or files in the DM.
|
|
124
|
+
|
|
125
|
+
The extension:
|
|
126
|
+
|
|
127
|
+
- downloads them to `~/.pi/agent/tmp/telegram`
|
|
128
|
+
- includes local file paths in the prompt
|
|
129
|
+
- forwards inbound images as image inputs to pi
|
|
130
|
+
|
|
131
|
+
### Ask for files back
|
|
132
|
+
|
|
133
|
+
If you ask pi for a file or generated artifact, pi should call the `telegram_attach` tool. The extension then sends those files with the next Telegram reply.
|
|
134
|
+
|
|
135
|
+
Examples:
|
|
136
|
+
|
|
137
|
+
- `summarize this image`
|
|
138
|
+
- `read this README and summarize it`
|
|
139
|
+
- `write me a markdown file with the plan and send it back`
|
|
140
|
+
- `generate a shell script and attach it`
|
|
141
|
+
|
|
142
|
+
### Stop a run
|
|
143
|
+
|
|
144
|
+
In Telegram, send:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
stop
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
or:
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
/stop
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
That aborts the active pi turn.
|
|
157
|
+
|
|
158
|
+
### Queue follow-ups
|
|
159
|
+
|
|
160
|
+
If you send more Telegram messages while pi is busy, they are queued and processed in order.
|
|
161
|
+
|
|
162
|
+
The pi status bar shows queued Telegram turns as compact previews, for example:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
+3: [summarize this image…, write a shell script…, 📎 2 attachments]
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Each preview is limited to at most 5 words or 40 characters.
|
|
169
|
+
|
|
170
|
+
### Reprioritize or discard queued messages
|
|
171
|
+
|
|
172
|
+
While a message is still waiting in the queue:
|
|
173
|
+
|
|
174
|
+
- React with 👍 to move it into the priority block
|
|
175
|
+
- React with 👎 to remove it from the queue
|
|
176
|
+
|
|
177
|
+
Priority is stable:
|
|
178
|
+
|
|
179
|
+
- The first liked queued message stays ahead of later liked messages
|
|
180
|
+
- Removing 👍 sends the message back to its normal queue position
|
|
181
|
+
- Adding 👍 again gives it a fresh priority position
|
|
182
|
+
|
|
183
|
+
For media groups, a reaction on any message in the group applies to the whole queued turn.
|
|
184
|
+
|
|
185
|
+
Message reactions depend on Telegram delivering `message_reaction` updates for your bot and chat type.
|
|
186
|
+
|
|
187
|
+
## Streaming
|
|
188
|
+
|
|
189
|
+
The extension streams assistant text previews back to Telegram while pi is generating.
|
|
190
|
+
|
|
191
|
+
It tries Telegram draft streaming first with `sendMessageDraft`. If that is not supported for your bot, it falls back to `sendMessage` plus `editMessageText`.
|
|
192
|
+
|
|
193
|
+
## Notes
|
|
194
|
+
|
|
195
|
+
- Only one pi session should be connected to the bot at a time
|
|
196
|
+
- Replies are sent as normal Telegram messages, not quote-replies
|
|
197
|
+
- Long replies are split below Telegram's 4096 character limit
|
|
198
|
+
- Outbound files are sent via `telegram_attach`
|
|
199
|
+
|
|
200
|
+
## License
|
|
201
|
+
|
|
202
|
+
MIT
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Documentation Index
|
|
2
|
+
|
|
3
|
+
Living index of project documentation in `/docs`.
|
|
4
|
+
|
|
5
|
+
## Documents
|
|
6
|
+
|
|
7
|
+
| Document | Description |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| [architecture.md](./architecture.md) | Overview of the Telegram bridge runtime, queueing model, rendering pipeline, and interactive controls |
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Telegram Bridge Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`pi-telegram` is a session-local pi extension that binds one Telegram DM to one running pi session. The bridge owns four main responsibilities:
|
|
6
|
+
|
|
7
|
+
- Poll Telegram updates and enforce single-user pairing
|
|
8
|
+
- Translate Telegram messages and media into pi inputs
|
|
9
|
+
- Stream and deliver pi responses back to Telegram
|
|
10
|
+
- Manage Telegram-specific controls such as queue reactions, `/status`, `/model`, and `/compact`
|
|
11
|
+
|
|
12
|
+
## Runtime Structure
|
|
13
|
+
|
|
14
|
+
`index.ts` remains the extension entrypoint and composition layer. Reusable runtime logic is split into flat domain files under `/lib` rather than into a deep local module tree.
|
|
15
|
+
|
|
16
|
+
Domain grouping rule: prefer cohesive domain files over atomizing every helper into its own file. A `shared` domain is allowed only for types or constants that genuinely span multiple bridge domains.
|
|
17
|
+
|
|
18
|
+
Naming rule: because the repository already scopes this codebase to Telegram, extracted module and test filenames use bare domain names such as `api.ts`, `queue.ts`, `updates.ts`, and `queue.test.ts` rather than repeating `telegram-*` in every filename.
|
|
19
|
+
|
|
20
|
+
Current runtime areas include:
|
|
21
|
+
|
|
22
|
+
- Telegram API types and local bridge state in `index.ts`
|
|
23
|
+
- Queueing and queue-runtime helpers in `/lib/queue.ts`
|
|
24
|
+
- Reply, preview, preview-finalization, reply-transport, and rendered-message delivery helpers in `/lib/replies.ts`
|
|
25
|
+
- Polling request, stop-condition, and long-poll loop helpers in `/lib/polling.ts`
|
|
26
|
+
- Telegram API/config helpers and lazy bot-token client wrappers in `/lib/api.ts`
|
|
27
|
+
- Telegram turn-building helpers in `/lib/turns.ts`
|
|
28
|
+
- Telegram media/text extraction helpers in `/lib/media.ts`
|
|
29
|
+
- Telegram updates extraction, authorization, flow, execution-planning, direct execute-from-update routing, and runtime helpers in `/lib/updates.ts`
|
|
30
|
+
- Telegram attachment queueing and delivery helpers in `/lib/attachments.ts`
|
|
31
|
+
- Telegram tool, command, and lifecycle-hook registration helpers in `/lib/registration.ts`
|
|
32
|
+
- Setup/token prompt helpers in `/lib/setup.ts`
|
|
33
|
+
- Markdown and Telegram message rendering helpers in `/lib/rendering.ts`
|
|
34
|
+
- Status rendering helpers in `/lib/status.ts`
|
|
35
|
+
- Menu/model-resolution, menu-state construction, pure menu-page derivation, pure menu render-payload builders, menu-message runtime, callback parsing, callback entry handling, callback mutation helpers, full model-callback planning and execution, interface-polished callback effect ports, status-thinking callback handling, and UI helpers in `/lib/menu.ts`
|
|
36
|
+
- Model-switch guard, continuation, and restart helpers in `/lib/model-switch.ts`
|
|
37
|
+
- Telegram API-bound reply transport wiring and broader event-side orchestration in `index.ts`
|
|
38
|
+
- Additional domains can be extracted into `/lib/*.ts` as the bridge grows, while keeping `index.ts` as the single entrypoint
|
|
39
|
+
- Mirrored domain regression coverage lives in `/tests/*.test.ts` using the same bare domain naming scheme
|
|
40
|
+
|
|
41
|
+
## Configuration UX
|
|
42
|
+
|
|
43
|
+
`/telegram-setup` uses a progressive-enhancement flow for the bot token prompt:
|
|
44
|
+
|
|
45
|
+
1. Show the locally saved token from `~/.pi/agent/telegram.json` when one already exists
|
|
46
|
+
2. Otherwise use the first configured environment variable from the supported Telegram token list
|
|
47
|
+
3. Fall back to the example placeholder when no real value exists
|
|
48
|
+
|
|
49
|
+
Because `ctx.ui.input()` only exposes placeholder text, the bridge uses `ctx.ui.editor()` whenever a real default value must appear already filled in.
|
|
50
|
+
|
|
51
|
+
## Message And Queue Flow
|
|
52
|
+
|
|
53
|
+
### Inbound Path
|
|
54
|
+
|
|
55
|
+
1. Telegram updates are polled through `getUpdates`
|
|
56
|
+
2. The bridge filters to the paired private user
|
|
57
|
+
3. Media groups are coalesced into a single Telegram turn when needed
|
|
58
|
+
4. Files are downloaded into `~/.pi/agent/tmp/telegram`
|
|
59
|
+
5. A `PendingTelegramTurn` is created and queued locally
|
|
60
|
+
6. The queue dispatcher sends the turn into pi only when dispatch is safe
|
|
61
|
+
|
|
62
|
+
### Queue Safety Model
|
|
63
|
+
|
|
64
|
+
The bridge keeps its own Telegram queue and does not rely only on pi's internal pending-message state.
|
|
65
|
+
|
|
66
|
+
Queued items now use two explicit dimensions:
|
|
67
|
+
|
|
68
|
+
- `kind`: prompt vs control
|
|
69
|
+
- `queueLane`: control vs priority vs default
|
|
70
|
+
|
|
71
|
+
This lets synthetic control actions and Telegram prompts share one stable ordering model while still rendering distinctly in status output.
|
|
72
|
+
|
|
73
|
+
A dispatched prompt remains in the queue until `agent_start` consumes it. That keeps the active Telegram turn bound correctly for previews, attachments, abort handling, and final reply delivery.
|
|
74
|
+
|
|
75
|
+
Dispatch is gated by:
|
|
76
|
+
|
|
77
|
+
- No active Telegram turn
|
|
78
|
+
- No pending Telegram dispatch already sent to pi
|
|
79
|
+
- No compaction in progress
|
|
80
|
+
- `ctx.isIdle()` being true
|
|
81
|
+
- `ctx.hasPendingMessages()` being false
|
|
82
|
+
|
|
83
|
+
This prevents queue races around rapid follow-ups, `/compact`, and mixed local plus Telegram activity.
|
|
84
|
+
|
|
85
|
+
### Abort Behavior
|
|
86
|
+
|
|
87
|
+
When `/stop` aborts an active Telegram turn, queued follow-up Telegram messages can be preserved as prior-user history for the next turn. This keeps later Telegram input from being silently dropped after an interrupted run.
|
|
88
|
+
|
|
89
|
+
## Rendering Model
|
|
90
|
+
|
|
91
|
+
Telegram replies are rendered as Telegram HTML rather than raw Markdown.
|
|
92
|
+
|
|
93
|
+
Key rules:
|
|
94
|
+
|
|
95
|
+
- Rich text should render cleanly in Telegram chats
|
|
96
|
+
- Real code blocks must remain literal and escaped
|
|
97
|
+
- Markdown tables should keep their internal separators but drop the outer left and right borders when rendered as monospace blocks so narrow Telegram clients keep more usable width
|
|
98
|
+
- Unordered Markdown lists should render with a monospace `-` marker and ordered Markdown lists should render with monospace numeric markers so list indentation stays more predictable on narrow Telegram clients
|
|
99
|
+
- Nested Markdown quotes should flatten into one Telegram blockquote with added non-breaking-space indentation because Telegram does not render nested blockquotes reliably
|
|
100
|
+
- Long replies must be split below Telegram's 4096-character limit
|
|
101
|
+
- Chunking should avoid breaking HTML structure where possible
|
|
102
|
+
- Preview rendering is intentionally simpler than final rich rendering
|
|
103
|
+
|
|
104
|
+
The renderer is a Telegram-specific formatter, not a general Markdown engine, so rendering changes should be treated as regression-prone.
|
|
105
|
+
|
|
106
|
+
## Streaming And Delivery
|
|
107
|
+
|
|
108
|
+
During generation, the bridge streams previews back to Telegram.
|
|
109
|
+
|
|
110
|
+
Preferred order:
|
|
111
|
+
|
|
112
|
+
1. Try `sendMessageDraft`
|
|
113
|
+
2. Fall back to `sendMessage` plus `editMessageText`
|
|
114
|
+
3. Replace the preview with the final rendered reply when generation ends
|
|
115
|
+
|
|
116
|
+
Outbound files are sent only after the active Telegram turn completes and must be staged through the `telegram_attach` tool.
|
|
117
|
+
|
|
118
|
+
## Interactive Controls
|
|
119
|
+
|
|
120
|
+
The bridge exposes Telegram-side session controls in addition to regular chat forwarding.
|
|
121
|
+
|
|
122
|
+
Current operator controls include:
|
|
123
|
+
|
|
124
|
+
- `/status` for model, usage, cost, and context visibility, queued as a high-priority control item when needed
|
|
125
|
+
- Inline status buttons for model and thinking adjustments
|
|
126
|
+
- `/model` for interactive model selection, queued as a high-priority control item when needed and supporting in-flight restart of the active Telegram-owned run on a newly selected model
|
|
127
|
+
- `/compact` for Telegram-triggered pi session compaction when the bridge is idle
|
|
128
|
+
- Queue reactions using `👍` and `👎`
|
|
129
|
+
|
|
130
|
+
## In-Flight Model Switching
|
|
131
|
+
|
|
132
|
+
When `/model` is used during an active Telegram-owned run, the bridge can emulate the interactive pi workflow of stopping, switching model, and continuing.
|
|
133
|
+
|
|
134
|
+
The current implementation does this by:
|
|
135
|
+
|
|
136
|
+
1. Applying the newly selected model immediately
|
|
137
|
+
2. Queuing or staging a synthetic Telegram continuation turn
|
|
138
|
+
3. Aborting the active Telegram turn immediately, or delaying the abort until the current tool finishes when a tool call is in flight
|
|
139
|
+
4. Dispatching the continuation turn after the abort completes
|
|
140
|
+
|
|
141
|
+
This behavior is intentionally limited to runs currently owned by the Telegram bridge. If pi is busy with non-Telegram work, the bridge still refuses the switch instead of hijacking unrelated session activity.
|
|
142
|
+
|
|
143
|
+
## Related
|
|
144
|
+
|
|
145
|
+
- [README.md](../README.md)
|
|
146
|
+
- [Project Context](../AGENTS.md)
|
|
147
|
+
- [Project Backlog](../BACKLOG.md)
|
|
148
|
+
- [Changelog](../CHANGELOG.md)
|