@llblab/pi-telegram 0.2.9 → 0.3.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/README.md +40 -26
- package/docs/architecture.md +62 -35
- package/index.ts +388 -1936
- package/lib/api.ts +647 -76
- package/lib/attachments.ts +128 -16
- package/lib/commands.ts +721 -0
- package/lib/config.ts +157 -0
- package/lib/media.ts +211 -36
- package/lib/menu.ts +920 -338
- package/lib/model.ts +647 -0
- package/lib/pi.ts +80 -0
- package/lib/polling.ts +264 -18
- package/lib/preview.ts +451 -29
- package/lib/queue.ts +1134 -110
- package/lib/registration.ts +127 -28
- package/lib/rendering.ts +575 -281
- package/lib/replies.ts +198 -8
- package/lib/runtime.ts +475 -0
- package/lib/setup.ts +129 -1
- package/lib/status.ts +428 -13
- package/lib/turns.ts +207 -17
- package/lib/updates.ts +392 -99
- package/package.json +18 -3
- package/AGENTS.md +0 -91
- package/BACKLOG.md +0 -5
- package/CHANGELOG.md +0 -23
- package/lib/model-switch.ts +0 -62
- package/tests/api.test.ts +0 -89
- package/tests/attachments.test.ts +0 -132
- package/tests/config.test.ts +0 -80
- package/tests/media.test.ts +0 -77
- package/tests/menu.test.ts +0 -676
- package/tests/polling.test.ts +0 -129
- package/tests/preview.test.ts +0 -441
- package/tests/queue.test.ts +0 -3245
- package/tests/registration.test.ts +0 -268
- package/tests/rendering.test.ts +0 -475
- package/tests/replies.test.ts +0 -142
- package/tests/turns.test.ts +0 -132
- package/tests/updates.test.ts +0 -357
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
Better Telegram DM bridge for pi.
|
|
6
|
-
|
|
7
5
|
This repository is an actively maintained fork of [`badlogic/pi-telegram`](https://github.com/badlogic/pi-telegram). It started from upstream commit [`cb34008460b6c1ca036d92322f69d87f626be0fc`](https://github.com/badlogic/pi-telegram/commit/cb34008460b6c1ca036d92322f69d87f626be0fc) and has since diverged substantially.
|
|
8
6
|
|
|
9
7
|
## Start Here
|
|
@@ -19,8 +17,8 @@ This repository is an actively maintained fork of [`badlogic/pi-telegram`](https
|
|
|
19
17
|
- **Interactive UI**: Manage your session directly from Telegram. Inline buttons allow you to switch models and adjust reasoning (thinking) levels on the fly.
|
|
20
18
|
- **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.
|
|
21
19
|
- **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.
|
|
22
|
-
- **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.
|
|
23
|
-
- **File Handling & Attachments**: Send images and files to the agent, or ask it to generate and return artifacts.
|
|
20
|
+
- **Mobile-Optimized Rendering**: Tables and lists are formatted for narrow screens, table padding accounts for emoji grapheme and wide Unicode display width, and Telegram-originated runs prompt the assistant to prefer narrow table columns for phone readability. 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. Inbound downloads and outbound attachments are size-limited by default, and outbound files are delivered automatically via the `telegram_attach` tool.
|
|
24
22
|
- **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.
|
|
25
23
|
|
|
26
24
|
## Install
|
|
@@ -46,7 +44,7 @@ pi install git:github.com/llblab/pi-telegram
|
|
|
46
44
|
3. Pick a name and username
|
|
47
45
|
4. Copy the bot token
|
|
48
46
|
|
|
49
|
-
### 2.
|
|
47
|
+
### 2. Configure the extension in pi
|
|
50
48
|
|
|
51
49
|
Start pi, then run:
|
|
52
50
|
|
|
@@ -54,17 +52,17 @@ Start pi, then run:
|
|
|
54
52
|
/telegram-setup
|
|
55
53
|
```
|
|
56
54
|
|
|
57
|
-
Paste your bot token when prompted. If a bot token is already saved in `~/.pi/agent/telegram.json`,
|
|
55
|
+
Paste your bot token when prompted. If a bot token is already saved in `~/.pi/agent/telegram.json`, the setup prompt 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.
|
|
58
56
|
|
|
59
|
-
|
|
57
|
+
### 3. Connect this pi session
|
|
60
58
|
|
|
61
59
|
```bash
|
|
62
60
|
/telegram-connect
|
|
63
61
|
```
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
The bridge is session-local. Only one pi session should be connected to the bot at a time.
|
|
66
64
|
|
|
67
|
-
###
|
|
65
|
+
### 4. Pair your account from Telegram
|
|
68
66
|
|
|
69
67
|
1. Open the DM with your bot in Telegram
|
|
70
68
|
2. Send `/start`
|
|
@@ -75,45 +73,61 @@ The first user to message the bot becomes the exclusive owner of the bridge. The
|
|
|
75
73
|
|
|
76
74
|
Once paired, simply chat with your bot in Telegram. All text, images, and files are forwarded to pi.
|
|
77
75
|
|
|
78
|
-
### Commands & Controls
|
|
76
|
+
### Telegram Commands & Controls
|
|
77
|
+
|
|
78
|
+
Use these inside the Telegram DM with your bot:
|
|
79
79
|
|
|
80
|
+
- **`/start`**: Pair the first Telegram user when needed, register the bot command menu, and show help.
|
|
81
|
+
- **`/help`**: Show the Telegram help text.
|
|
80
82
|
- **`/status`**: View session stats, cost, and use inline buttons to change models.
|
|
81
83
|
- **`/model`**: Open the interactive model selector.
|
|
82
84
|
- **`/compact`**: Start session compaction (only works when the session is idle).
|
|
83
85
|
- **`/stop`**: Abort the active run.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
|
|
87
|
+
Telegram command admission is explicit: `/compact`, `/stop`, `/help`, and `/start` execute immediately; `/status` and `/model` enter the high-priority control lane so they can run before normal queued prompts when pi becomes safe to dispatch.
|
|
88
|
+
|
|
89
|
+
### Pi Commands
|
|
90
|
+
|
|
91
|
+
Run these inside pi, not Telegram:
|
|
92
|
+
|
|
93
|
+
- **`/telegram-setup`**: Configure or update the Telegram bot token.
|
|
94
|
+
- **`/telegram-status`**: Check bridge status, connection, polling, execution, queue, and recent redacted runtime/API failure events.
|
|
95
|
+
- **`/telegram-connect`**: Start polling Telegram updates in the current pi session.
|
|
96
|
+
- **`/telegram-disconnect`**: Stop polling in the current pi session.
|
|
86
97
|
|
|
87
98
|
### Queue, Reactions, and Media
|
|
88
99
|
|
|
89
|
-
- If you send more Telegram messages while pi is busy, they
|
|
90
|
-
- `👍` moves a waiting
|
|
100
|
+
- If you send more Telegram messages while pi is busy, they enter the default prompt queue and are processed in order.
|
|
101
|
+
- `👍` moves a waiting prompt into the priority prompt queue, behind control actions but ahead of default prompts. Removing `👍` sends it back to its normal queue position, and adding `👍` again gives it a fresh priority position.
|
|
91
102
|
- `👎` 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.
|
|
92
103
|
- For media groups, a reaction on any message in the group applies to the whole queued turn.
|
|
93
|
-
-
|
|
104
|
+
- 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.
|
|
105
|
+
- 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`.
|
|
94
106
|
- Queue reactions depend on Telegram delivering `message_reaction` updates for your bot and chat type.
|
|
95
107
|
|
|
96
108
|
### Requesting Files
|
|
97
109
|
|
|
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.
|
|
99
|
-
|
|
100
|
-
Examples:
|
|
101
|
-
|
|
102
|
-
- `summarize this image`
|
|
103
|
-
- `generate a shell script and attach it`
|
|
110
|
+
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`.
|
|
104
111
|
|
|
105
112
|
## Streaming
|
|
106
113
|
|
|
107
114
|
The extension streams assistant previews back to Telegram while pi is generating.
|
|
108
115
|
|
|
109
|
-
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.
|
|
116
|
+
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.
|
|
117
|
+
|
|
118
|
+
## Status bar
|
|
119
|
+
|
|
120
|
+
The pi status bar shows queued Telegram turns as compact previews, for example:
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
+3: [⬆ write a shell script…, summarize this image…, 📎 2 attachments]
|
|
124
|
+
```
|
|
110
125
|
|
|
111
126
|
## Notes
|
|
112
127
|
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
- Outbound files are sent via `telegram_attach`
|
|
128
|
+
- 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
|
|
129
|
+
- 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
|
|
130
|
+
- Temporary inbound Telegram files are cleaned up on later session starts
|
|
117
131
|
|
|
118
132
|
## License
|
|
119
133
|
|
package/docs/architecture.md
CHANGED
|
@@ -7,38 +7,49 @@
|
|
|
7
7
|
- Poll Telegram updates and enforce single-user pairing
|
|
8
8
|
- Translate Telegram messages and media into pi inputs
|
|
9
9
|
- Stream and deliver pi responses back to Telegram
|
|
10
|
-
- Manage Telegram-specific controls such as queue reactions, `/status`, `/model`, and `/
|
|
10
|
+
- Manage Telegram-specific controls such as queue reactions, `/status`, `/model`, `/compact`, and `/stop`
|
|
11
11
|
|
|
12
12
|
## Runtime Structure
|
|
13
13
|
|
|
14
|
-
`index.ts` remains the extension entrypoint and composition
|
|
14
|
+
`index.ts` remains the extension entrypoint and composition root. Reusable runtime logic is split into flat domain files under `/lib` rather than into a deep local module tree.
|
|
15
|
+
|
|
16
|
+
Architecture shorthand: this repository uses a `Flat Domain DAG`: cohesive bridge domains live as flat `/lib/*.ts` modules, local imports must form a directed acyclic graph, shared buckets are avoided, and `index.ts` wires live pi/Telegram ports plus session state.
|
|
15
17
|
|
|
16
18
|
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
19
|
|
|
20
|
+
Interface consistency rule: when two modules mean the same runtime entity, they should converge on the owning domain's exported contract. Local structural `*Like` or view contracts are appropriate only when a domain intentionally needs a narrow projection to avoid unnecessary coupling; they should not become duplicate source-of-truth shapes for the same entity.
|
|
21
|
+
|
|
18
22
|
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
23
|
|
|
20
24
|
Current runtime areas include:
|
|
21
25
|
|
|
22
|
-
- Telegram API types
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
+
- Telegram Bot API concrete transport shapes live with Telegram API helpers in `/lib/api.ts`, while persisted bot/session pairing state lives in `/lib/config.ts`; domain-owned runtime state types stay with their owners, such as queued/active turn state in `/lib/queue.ts` and preview state in `/lib/preview.ts`, while domain helpers prefer local structural `*Like` contracts instead of importing concrete wire DTOs
|
|
27
|
+
- Direct pi SDK imports are centralized in `/lib/pi.ts`, which exposes concrete pi SDK type exports, bound extension API runtime ports, and narrow bridge-facing helpers such as settings-manager creation plus context model/idle/pending-message/compaction adapters; `index.ts` uses this adapter namespace instead of importing `@mariozechner/pi-coding-agent` directly
|
|
28
|
+
- Session-local runtime primitives such as queue/control/priority ordering counters, lifecycle/dispatch flags, setup guard state, abort-handler storage/binding, typing-loop timer lifecycle, typing-loop starter binding, prompt-dispatch lifecycle/runtime adapters, and agent-end reset sequencing in `/lib/runtime.ts`; the runtime domain's essence is mutable cross-domain session coordination rather than business behavior. It exposes a grouped bridge runtime facade with named queue/lifecycle/setup/abort/typing ports that bind those primitives to one session state while remaining a cohesive state/runtime boundary, and `index.ts` still wires live Telegram API calls and status updates into those helpers. Preview-specific state, draft-support detection, and draft-id allocation live in `/lib/preview.ts`.
|
|
29
|
+
- Constants live in their owning domains instead of a shared constants module: API paths/inbound limits and inbound file-size env parsing in `/lib/api.ts`, outbound attachment limits and outbound attachment-size env parsing in `/lib/attachments.ts`, media-group debounce in `/lib/media.ts`, menu cache/state bounds in `/lib/menu.ts`, preview throttle/draft bounds in `/lib/preview.ts`, typing cadence in `/lib/runtime.ts`, diagnostic ring limits in `/lib/status.ts`, Telegram prompt prefix in `/lib/turns.ts`, and system-prompt guidance in `/lib/registration.ts`.
|
|
30
|
+
- Queueing, narrow Telegram prompt content contracts, queue-store contracts/state helpers, active-turn state helpers, dispatch-readiness adapters, queue append/mutation runtime/controller adapters, control enqueue controllers, queue dispatch readiness/controller/runtime adapters, prompt enqueue/history planning/runtime/controllers, queue-runtime, session state appliers plus lifecycle/runtime sequencing, session start/shutdown sequencing plus hook binding, agent-start/agent-end lifecycle handling plus hook/runtime binding, and tool lifecycle handling plus tool-execution hook/runtime binding in `/lib/queue.ts`
|
|
31
|
+
- Model identity/thinking-level contracts, scoped model-pattern parsing/resolution/sorting, current-model store/update/runtime helpers, in-flight model-switch state helpers, restart eligibility, delayed abort decisions, Telegram-prefix defaulted continuation prompt construction, continuation queue adapters, and model-switch controller/runtime binding over queue-owned turns in `/lib/model.ts`
|
|
32
|
+
- Preview transport-selection, assistant-message preview lifecycle hook binding/handling, preview-finalization, preview controller state/reset helpers, preview Bot API message/rendered-chunk transport adapters, preview-controller/assistant-preview runtime binding, reply-metadata defaulting through the replies-domain helper, and preview-runtime helpers in `/lib/preview.ts`
|
|
33
|
+
- Reply-transport, rendered-message delivery runtime/binding, structural assistant-message extraction, reply-parameter construction over API-owned transport shapes, and plain/Markdown final-reply helpers in `/lib/replies.ts`
|
|
26
34
|
- Preview appearance and snapshot derivation stay in `/lib/rendering.ts`, while `/lib/preview.ts` owns transport and lifecycle decisions, so richer preview strategies can evolve without entangling Markdown formatting with Telegram delivery state
|
|
27
|
-
- Polling request, stop-condition,
|
|
28
|
-
- Telegram
|
|
29
|
-
- Telegram
|
|
30
|
-
- Telegram media
|
|
31
|
-
- Telegram
|
|
32
|
-
- Telegram
|
|
33
|
-
- Telegram
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
35
|
+
- Polling request, start/stop controller state orchestration, polling activity readers, stop-condition, structural config contract, long-poll loop helpers, and poll-loop/controller runtime wiring over Telegram transport ports in `/lib/polling.ts`
|
|
36
|
+
- Telegram persisted config shape, config-path defaults, config file read/write helpers, mutable config-store accessors, single-user authorization, and first-user pairing side effects/runtime adapters in `/lib/config.ts`
|
|
37
|
+
- Telegram API helpers, concrete Bot API transport shapes including reply parameters and send/edit message bodies, typed/default Bot API runtime helpers, bot identity fetch transport, chat-action sender adapters/runtime-bound typing action, lazy bot-token client wrappers, API runtime error-recording wrappers, temp paths, inbound file-size limits, and runtime-bound temp-directory preparation/default cleanup in `/lib/api.ts`
|
|
38
|
+
- Telegram turn-building helpers, runtime turn-builder wiring over media download ports and media-owned downloaded-file metadata contracts, queued-prompt edit runtime binding, and Node-backed image-file reads for pi image inputs in `/lib/turns.ts`
|
|
39
|
+
- Telegram media/text extraction, file-info normalization, downloaded-message-file metadata contracts, inbound file download assembly, media-group debounce helpers, media-group controller state, and media-group-aware authorized-message dispatch adapter wiring in `/lib/media.ts`
|
|
40
|
+
- Telegram slash-command parsing, command-message target helpers/adapters, command control-enqueue adapters/runtime binding, command-action routing, command-handler/target-runtime and command-or-prompt dispatch binding, command runtime port orchestration, shared command-runtime reply/status/control adapter closures, stop/compact/status/model/help command side-effect branching, bound Bot API command registration, and Bot API command metadata helpers in `/lib/commands.ts`
|
|
41
|
+
- Telegram updates extraction, paired update-runtime binding, flow, execution-planning, authorized reaction priority/removal handling, direct execute-from-update routing, update runtime adapters over queue/media/menu ports, and runtime helpers in `/lib/updates.ts`
|
|
42
|
+
- Telegram attachment queueing, narrow structural attachment turn targets, queued-attachment sender runtime binding, delivery helpers, Node-backed file stat checks, outbound photo-vs-document classification, and outbound attachment limits/env parsing in `/lib/attachments.ts`
|
|
43
|
+
- Telegram tool, command, before-agent prompt, and lifecycle-hook registration helpers in `/lib/registration.ts`
|
|
44
|
+
- Setup/token prompt, environment fallback, guarded setup runtime adapter wiring, structural setup config contract, token validation, config persistence orchestration, and setup notification helpers in `/lib/setup.ts`
|
|
45
|
+
- Markdown block scanning/rendering, inline-token/style rendering, text-piece rendering, stable-preview block scanning, final rendered-block chunk balancing, preview-snapshot derivation, HTML escaping, raw HTML tag-preserving chunking, and Telegram message rendering helpers in `/lib/rendering.ts`
|
|
46
|
+
- Status-bar rendering/runtime adapters, bridge status state adapters, status-message rendering and status-HTML binding, structural queue-lane status view contracts, structured redacted runtime-event recording, recent-event recorder state, recent-event line formatting, and grouped pi-side diagnostics helpers in `/lib/status.ts`
|
|
47
|
+
- Menu settings/model-registry access through structural ports, menu-state construction, menu runtime state/cache controller, menu-state storage pruning/refresh helpers, command open-flow branching, action runtime/state-builder adapters, menu callback handler adapters, stored callback entry/runtime routing, model-menu input-cache/state-building resolution, pure menu-page derivation, pure menu render-payload builders, menu-message runtime, callback parsing, 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`
|
|
48
|
+
- Telegram API-bound transport adapters and broader event-side orchestration in `index.ts`; direct Node file-operation imports stay in the owning domains rather than the entrypoint
|
|
49
|
+
- Remaining `index.ts` wiring is intentionally cross-domain adapter code that closes over live extension state, pi callbacks, Telegram API ports, and status updates; keep repeated wiring DRY through small local adapter helpers or owning-domain contracts when that reduces duplication without obscuring live state, and extract more only when a boundary can move cohesive behavior into an owning domain instead of relocating one-off closures
|
|
40
50
|
- Additional domains can be extracted into `/lib/*.ts` as the bridge grows, while keeping `index.ts` as the single entrypoint
|
|
41
|
-
-
|
|
51
|
+
- `index.ts` uses namespace imports for local bridge domains so orchestration reads as domain-scoped calls such as `Queue.*`, `Turns.*`, and `Rendering.*` instead of long flat import lists
|
|
52
|
+
- Mirrored domain regression coverage lives in `/tests/*.test.ts` using the same bare domain naming scheme, and architecture-invariant coverage in `/tests/invariants.test.ts` checks that the local `index.ts` plus `/lib/*.ts` import graph stays acyclic, shared bucket domains such as `lib/constants.ts` or `lib/types.ts` are not reintroduced, empty interface-extension shells stay collapsed into clearer type aliases, direct pi SDK imports stay centralized, `index.ts` source code stays free of direct Node runtime imports, local helper declarations, local arrow adapters, direct `process.env`, and direct `pi.*` receiver access, `/lib/runtime.ts` stays free of local domain imports, structural leaf domains stay free of local nominal imports, the menu domain stays on structural ports without re-exporting model, API transport stays decoupled from persisted config defaults, structural update/media domains stay decoupled from concrete API transport shapes, and attachment delivery stays decoupled from queue/inbound media/API helpers
|
|
42
53
|
|
|
43
54
|
## Configuration UX
|
|
44
55
|
|
|
@@ -48,18 +59,20 @@ Current runtime areas include:
|
|
|
48
59
|
2. Otherwise use the first configured environment variable from the supported Telegram token list
|
|
49
60
|
3. Fall back to the example placeholder when no real value exists
|
|
50
61
|
|
|
51
|
-
Because `ctx.ui.input()` only exposes placeholder text, the bridge uses `ctx.ui.editor()` whenever a real default value must appear already filled in.
|
|
62
|
+
Because `ctx.ui.input()` only exposes placeholder text, the bridge uses `ctx.ui.editor()` whenever a real default value must appear already filled in. The persisted `telegram.json` config is written with private `0600` permissions because it contains the bot token.
|
|
52
63
|
|
|
53
64
|
## Message And Queue Flow
|
|
54
65
|
|
|
55
66
|
### Inbound Path
|
|
56
67
|
|
|
57
68
|
1. Telegram updates are polled through `getUpdates`
|
|
58
|
-
2.
|
|
59
|
-
3.
|
|
60
|
-
4.
|
|
61
|
-
5.
|
|
62
|
-
6.
|
|
69
|
+
2. Each update offset is persisted only after the update handler succeeds; repeated handler failures are bounded so one poisoned update cannot stall polling forever
|
|
70
|
+
3. The bridge filters to the paired private user
|
|
71
|
+
4. Media groups are coalesced into a single Telegram turn when needed
|
|
72
|
+
5. Files are streamed into `~/.pi/agent/tmp/telegram` with a default 50 MiB size limit, partial-download cleanup on failures, and stale temp cleanup on session start; operators can tune the limit with `PI_TELEGRAM_INBOUND_FILE_MAX_BYTES` or `TELEGRAM_MAX_FILE_SIZE_BYTES`
|
|
73
|
+
6. A `PendingTelegramTurn` is created and queued locally
|
|
74
|
+
7. Telegram `edited_message` updates are routed separately and update a matching queued turn when the original message has not been dispatched yet
|
|
75
|
+
8. The queue dispatcher sends the turn into pi only when dispatch is safe
|
|
63
76
|
|
|
64
77
|
### Queue Safety Model
|
|
65
78
|
|
|
@@ -70,7 +83,16 @@ Queued items now use two explicit dimensions:
|
|
|
70
83
|
- `kind`: prompt vs control
|
|
71
84
|
- `queueLane`: control vs priority vs default
|
|
72
85
|
|
|
73
|
-
|
|
86
|
+
Admission contract:
|
|
87
|
+
|
|
88
|
+
| Admission | Examples | Queue shape | Dispatch rank |
|
|
89
|
+
| --------------------- | ---------------------------------------------------- | -------------------------------------------------------------------- | ------------- |
|
|
90
|
+
| Immediate execution | `/compact`, `/stop`, `/help`, `/start` | Does not enter the Telegram queue | N/A |
|
|
91
|
+
| Control queue | `/status`, `/model`, model-switch continuation turns | `queueLane: control`; accepts control items and continuation prompts | 0 |
|
|
92
|
+
| Priority prompt queue | A waiting prompt promoted by `👍` | `kind: prompt`, `queueLane: priority` | 1 |
|
|
93
|
+
| Default prompt queue | Normal Telegram text/media turns | `kind: prompt`, `queueLane: default` | 2 |
|
|
94
|
+
|
|
95
|
+
The command action itself carries its execution mode, and the queue domain exposes lane contracts for admission mode, dispatch rank, and allowed item kinds. Queue append and planning paths validate lane admission so a malformed control/default or other invalid lane pairing fails predictably instead of silently changing priority. This lets synthetic control actions and Telegram prompts share one stable ordering model while still rendering distinctly in status output. In the pi status bar queue preview, priority prompts are marked with `⬆` while control items keep their own control-specific summary markers such as `⚡`.
|
|
74
96
|
|
|
75
97
|
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.
|
|
76
98
|
|
|
@@ -82,7 +104,7 @@ Dispatch is gated by:
|
|
|
82
104
|
- `ctx.isIdle()` being true
|
|
83
105
|
- `ctx.hasPendingMessages()` being false
|
|
84
106
|
|
|
85
|
-
This prevents queue races around rapid follow-ups, `/compact`, and mixed local plus Telegram activity.
|
|
107
|
+
This prevents queue races around rapid follow-ups, `/compact`, and mixed local plus Telegram activity. The dispatch controller also serializes asynchronous control items, so a queued `/status` or `/model` action must settle before the next queued action can dispatch.
|
|
86
108
|
|
|
87
109
|
### Abort Behavior
|
|
88
110
|
|
|
@@ -96,14 +118,14 @@ Key rules:
|
|
|
96
118
|
|
|
97
119
|
- Rich text should render cleanly in Telegram chats
|
|
98
120
|
- Real code blocks must remain literal and escaped
|
|
99
|
-
- Supported absolute HTTP(S) and mailto links should stay clickable, while unsupported link forms such as unresolved references, footnotes, or relative links without a known base should degrade safely instead of producing broken Telegram anchors
|
|
100
|
-
- 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
|
|
121
|
+
- Supported absolute HTTP(S) and mailto links should stay clickable, with generated HTML attributes escaped separately from text content, while unsupported link forms such as unresolved references, footnotes, or relative links without a known base should degrade safely instead of producing broken Telegram anchors
|
|
122
|
+
- 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; table padding should count grapheme/display width for multi-codepoint emoji, combining marks, and wide Unicode where possible, and the Telegram before-agent prompt suffix also asks the assistant to prefer narrow table columns because many chats are read on phone-width screens
|
|
101
123
|
- 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
|
|
102
124
|
- Real Markdown task-list items should render with checkbox markers, while standalone `[x]` and `[ ]` prose should stay literal instead of being reinterpreted as checklists
|
|
103
125
|
- Nested Markdown quotes should flatten into one Telegram blockquote with added non-breaking-space indentation because Telegram does not render nested blockquotes reliably
|
|
104
126
|
- Original blank-line spacing between Markdown blocks should stay intact in both preview and final rendering instead of being collapsed to one generic block separator, while headings should still keep readable separation from following blocks such as code fences even when source Markdown omits a blank line
|
|
105
|
-
- Long replies must be split below Telegram's 4096-character limit
|
|
106
|
-
-
|
|
127
|
+
- Long replies, including raw HTML-mode replies used by interactive/status flows, must be split below Telegram's 4096-character limit
|
|
128
|
+
- Raw HTML chunking lives with the rendering helpers in `/lib/rendering.ts` and should preserve/reopen active tags across chunk boundaries where possible
|
|
107
129
|
- Preview rendering uses stable top-level Markdown blocks for rich Telegram HTML and appends the still-growing tail conservatively as readable plain text so the preview stays valid even when the answer is incomplete
|
|
108
130
|
|
|
109
131
|
The renderer is a Telegram-specific formatter, not a general Markdown engine, so rendering changes should be treated as regression-prone.
|
|
@@ -116,11 +138,14 @@ Preferred order:
|
|
|
116
138
|
|
|
117
139
|
1. Re-render the current Markdown buffer into a preview snapshot that renders closed top-level blocks as rich Telegram HTML and keeps the unstable tail conservative and readable
|
|
118
140
|
2. Send or update that preview through `sendMessage` plus `editMessageText`, because `sendMessageDraft` is text-only for rich previews
|
|
119
|
-
3.
|
|
141
|
+
3. Serialize overlapping preview flushes so older Telegram edit calls cannot race newer streamed snapshots
|
|
142
|
+
4. Replace the preview with the final rendered reply when generation ends
|
|
120
143
|
|
|
121
144
|
Draft streaming can remain as a plain-text fallback path, but rich Telegram previews are driven through editable messages and stable-block snapshot selection.
|
|
122
145
|
|
|
123
|
-
|
|
146
|
+
Telegram prompt responses use explicit delivery context to attach outbound text, rich previews, errors, attachment notices, and uploads as Telegram replies to the source prompt when possible. Reply metadata is opt-in per delivery path, uses `reply_parameters` with `allow_sending_without_reply: true`, and is applied only to the first chunk of split long responses; continuation chunks are sent as normal adjacent messages. Media-group turns reply to the turn's representative `replyToMessageId`, not to every source message in the group.
|
|
147
|
+
|
|
148
|
+
Outbound files are sent only after the active Telegram turn completes, must be staged through the `telegram_attach` tool, are staged atomically per tool call, are checked against a default 50 MiB limit configurable through `PI_TELEGRAM_OUTBOUND_ATTACHMENT_MAX_BYTES` or `TELEGRAM_MAX_ATTACHMENT_SIZE_BYTES`, and use file-backed multipart blobs so large sends do not require preloading whole files into memory.
|
|
124
149
|
|
|
125
150
|
## Interactive Controls
|
|
126
151
|
|
|
@@ -129,9 +154,11 @@ The bridge exposes Telegram-side session controls in addition to regular chat fo
|
|
|
129
154
|
Current operator controls include:
|
|
130
155
|
|
|
131
156
|
- `/status` for model, usage, cost, and context visibility, queued as a high-priority control item when needed
|
|
132
|
-
- Inline status buttons for model and thinking adjustments, applying idle selections immediately while still respecting busy-run restart rules
|
|
157
|
+
- Inline status buttons for model and thinking adjustments, applying idle selections immediately while still respecting busy-run restart rules; model-menu inputs are cached briefly and stored inline-menu states are pruned by TTL/LRU so old keyboards expire predictably
|
|
133
158
|
- `/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
|
|
134
159
|
- `/compact` for Telegram-triggered pi session compaction when the bridge is idle
|
|
160
|
+
- `/stop` for aborting the active Telegram-owned run
|
|
161
|
+
- `/telegram-status` for pi-side diagnostics as grouped line-by-line sections separated by blank lines: connection, polling, execution, queue, and the recent redacted runtime/API event ring. These sections include polling state, last update id, active turn source ids, pending dispatch, compaction state, active tool count, pending model-switch state, total queue depth, and queue-lane counts. The event ring records transport/API, polling/update, prompt-dispatch, control-action, typing, compaction, setup, session-lifecycle, and attachment queue/delivery failures; benign unchanged edit responses and unsupported empty draft-clear attempts are filtered out so expected preview transport noise does not obscure real failures
|
|
135
162
|
- Queue reactions using `👍` and `👎`, with `👎` acting as the canonical queue-removal path because ordinary Telegram DM message deletions are not exposed through the Bot API polling path this bridge uses
|
|
136
163
|
|
|
137
164
|
## In-Flight Model Switching
|