@llblab/pi-telegram 0.9.9 → 0.10.1
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 +19 -2
- package/BACKLOG.md +0 -2
- package/CHANGELOG.md +24 -1
- package/README.md +8 -3
- package/docs/README.md +1 -1
- package/docs/callback-namespaces.md +1 -1
- package/docs/extension-sections.md +304 -163
- package/index.ts +25 -12
- package/lib/commands.ts +0 -36
- package/lib/extension-sections.ts +627 -0
- package/lib/menu-model.ts +1 -1
- package/lib/menu-settings.ts +68 -33
- package/lib/menu-status.ts +18 -0
- package/lib/menu.ts +130 -1
- package/lib/replies.ts +1 -2
- package/lib/routing.ts +63 -16
- package/package.json +2 -2
package/AGENTS.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
## 1. Concept
|
|
13
13
|
|
|
14
|
-
`pi-telegram` is a Telegram
|
|
14
|
+
`pi-telegram` is a Telegram runtime adapter for π: a session-local operator console that turns a private Telegram DM into a runtime surface for prompt intake, streaming previews, queue management, model/thinking/settings controls, inbound/outbound handler pipelines, voice/buttons, artifacts, and extension callback interop. Treat it as a Telegram membrane around π, not a narrow message pipe.
|
|
15
15
|
|
|
16
16
|
## 2. Identity & Naming Contract
|
|
17
17
|
|
|
@@ -104,6 +104,7 @@ The canonical detailed ownership map lives in [`docs/architecture.md`](./docs/ar
|
|
|
104
104
|
- Telegram transport and inbound flow: `api`, `polling`, `updates`, `routing`, `media`, `turns`, `inbound-handlers`, `config`, `setup`
|
|
105
105
|
- Response surfaces: `preview`, `replies`, `rendering`, `keyboard`, `outbound-attachments`, `outbound-handlers`, `status`
|
|
106
106
|
- Controls and application menu UI: `commands`, `menu`, `menu-model`, `menu-thinking`, `menu-status`, `menu-queue`, `model`, `prompts`
|
|
107
|
+
- Extension platform: `extension-sections` owns section registry, token mapping, callback dispatch, context building, and globalThis bridge
|
|
107
108
|
- Pi SDK boundary: `pi` owns direct pi imports and bound extension API ports
|
|
108
109
|
|
|
109
110
|
## 6.4 Entrypoint And Import Boundaries
|
|
@@ -139,10 +140,26 @@ The canonical detailed ownership map lives in [`docs/architecture.md`](./docs/ar
|
|
|
139
140
|
- Long Telegram text split recovery belongs to `text-groups`: keep it conservative, short-debounced, same chat/user/message-id contiguous, and gated by near-limit human text so normal rapid follow-ups and slash commands stay separate
|
|
140
141
|
- Inbound handlers and command-backed outbound handlers use command templates as the standard integration contract; built-in outbound buttons use inline keyboards plus callback routing because no external command execution is needed
|
|
141
142
|
- Telegram prompt-template commands are discovered from π slash commands with `source: "prompt"`; π template names are mapped to Bot API-compatible aliases (`fix-tests` → `/fix_tests`), aliases that conflict with built-in bridge commands or hidden shortcuts are not displayed, prompt-template aliases stay out of the Telegram bot command menu, and the bridge expands template files before queueing because extension-originated `sendUserMessage()` bypasses π's interactive template expansion
|
|
142
|
-
- Unknown callback data not owned by pi-telegram prefixes (`tgbtn:`, `menu:`, `model:`, `thinking:`, `status:`, `queue:`) may be forwarded as `[callback] <data>` after built-in handlers decline it; external extensions should follow `docs/callback-namespaces.md` and must not poll the same bot independently
|
|
143
|
+
- Unknown callback data not owned by pi-telegram prefixes (`tgbtn:`, `menu:`, `model:`, `thinking:`, `status:`, `queue:`, `section:`, `settings:`) may be forwarded as `[callback] <data>` after built-in handlers decline it; external extensions should follow `docs/callback-namespaces.md` and must not poll the same bot independently
|
|
143
144
|
- Command templates stay compact and shell-free: no `command` field, no shell execution, inline defaults are allowed as `{name=default}`, `template` may be a string or an ordered composition array, only `args`/`defaults` inherit into leaves, top-level `timeout` wraps composed sequences, stdout pipes to the next step's stdin by default, and multi-step work should use `template: [...]` rather than provider-specific fields; `pipe` is only a legacy local alias
|
|
144
145
|
- Command-template documentation examples should use portable executable placeholders such as `/path/to/stt` and `/path/to/tts`, not host-local skill paths or machine-specific install locations
|
|
145
146
|
|
|
147
|
+
## 9. Extension Sections Conventions
|
|
148
|
+
|
|
149
|
+
- `Section identity`: use the same identity-key rules as the Extension Locks Standard (`package.json/name` → canonical id); no separate `owner` field
|
|
150
|
+
- `Token mapping`: Telegram's 64-byte `callback_data` limit forces compact numeric tokens (`section:0:action:payload`). Section authors never hand-roll `section:` strings — use `ctx.callbackData(action, payload?)`
|
|
151
|
+
- `Navigation hierarchy`: Back buttons are auto-prepended by `ctx.edit()` / `ctx.open()`. Root views use `⬆️ Main menu` → `menu:back`. Nested views from `handleCallback` use `⬆️ Back` → `section:<token>:open`. Settings views use `⬆️ Back` → `settings:list`
|
|
152
|
+
- `Context ports`: sections receive `TelegramSectionContext` / `TelegramSectionCallbackContext` with `answerCallback`, `edit`, `open`, `enqueuePrompt`, and `callbackData`. No filesystem access, no raw bot clients, no second poller
|
|
153
|
+
- `Settings indicators`: use `settings.getLabel()` for dynamic status rows in the Settings submenu (e.g., `🟢`/`⚫️` based on internal state). Called on every Settings list render
|
|
154
|
+
- `Handler fallback`: `section.handleCallback` runs first; if it returns `"pass"` and `settings.handleCallback` exists, the settings handler runs with a fresh context carrying `backCallback="settings:list"`
|
|
155
|
+
- `Stale tokens`: unknown or unregistered tokens answer the callback with a short popup. Section errors are caught and surfaced as popup text — no unhandled exceptions leak to the poller
|
|
156
|
+
- `Load order`: `pi-telegram` must load first (sets `globalThis.__piTelegramSectionRegistry__`). Consumer extensions load second. The typed import is the preferred path; the `globalThis` bridge exists for load-order tolerance
|
|
157
|
+
- `Shutdown`: call `pi.on("shutdown", () => unregister())` in the extension's default export
|
|
158
|
+
- `Section separators`: extension-injected main-menu rows appear before the **⚙️ Settings** row. Extension settings rows appear before built-in Proactive push controls
|
|
159
|
+
- `Model button format`: use `provider/ModelId` format (e.g., `anthropic/claude-sonnet-4-5`) across model menu buttons and status row. The compact `provider/id` form is canonical
|
|
160
|
+
- `Section domain ownership`: `lib/extension-sections.ts` owns the registry, token mapping, callback dispatch, and context building. `lib/menu.ts` dispatches `section:` callbacks before built-in handling. `lib/menu-status.ts` injects section rows. `lib/menu-settings.ts` injects settings rows and passes `sectionRegistry` through callback deps
|
|
161
|
+
- `Callback routing order`: button actions → queue menu → settings menu → section callbacks → built-in menu handling → `[callback]` fallback. Settings menu callbacks always pass `sectionRegistry` to `updateTelegramSettingsMenuMessage` and `handleTelegramSettingsMenuCallbackAction`
|
|
162
|
+
|
|
146
163
|
## 9. Pre-Task Preparation Protocol
|
|
147
164
|
|
|
148
165
|
- Read `README.md` for current user-facing behavior and fork positioning
|
package/BACKLOG.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## Open Work
|
|
4
4
|
|
|
5
|
-
- [ ] Implement Telegram Extension Sections Platform for the 0.10.0 line.
|
|
6
|
-
- Exit: Runtime registry, main-menu integration, `section:` callback routing, safe section context ports, diagnostics, docs, and at least one small demo/fixture prove ordinary pi extensions can add Telegram menu sections without owning a second poller.
|
|
7
5
|
- [ ] Explore always-available outbound Telegram tools for queued artifacts and controls.
|
|
8
6
|
- Priority: Low.
|
|
9
7
|
- Idea: Provide tools such as `telegram_attach_file` and `telegram_attach_button` that can be called outside an active Telegram turn, using the paired chat/session as the delivery target when safe.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.1: Navigation Abstraction Hotfix
|
|
4
|
+
|
|
5
|
+
- `[ctx.open()]` Removed automatic Back-row prepend from `ctx.open()`. `ctx.open()` sends a new message into the chat — a Back button makes no sense outside the menu. `ctx.edit()` still auto-prepends the correct navigation row for in-menu views.
|
|
6
|
+
- `[Platform Docs]` Extended `docs/extension-sections.md` with a dedicated section on sending interactive messages into chat via `ctx.open()`: confirmation dialogs, approve/deny gates, and extension-driven button flows that live outside the menu hierarchy.
|
|
7
|
+
|
|
8
|
+
## 0.10.0: Extension Sections Platform
|
|
9
|
+
|
|
10
|
+
- `[Extension Sections]` Implemented the Telegram Extension Sections platform: extensions can register structured UI sections that appear in the main Telegram application menu and Settings submenu without owning a second bot poller.
|
|
11
|
+
- `[Registry]` Added `lib/extension-sections.ts` with a section registry (`createTelegramExtensionSectionRegistry`), token-based callback routing (`section:<token>:<action>:<payload>`), main-menu row injection, settings submenu row injection, `registerTelegramSection()` globalThis bridge for ordinary pi extensions, and diagnostics.
|
|
12
|
+
- `[API]` Exported `registerTelegramSection(section)` / `getTelegramSectionDiagnostics()` from `@llblab/pi-telegram/lib/extension-sections.ts`. Extensions receive narrow typed context ports (`TelegramSectionContext` / `TelegramSectionCallbackContext`) with `answerCallback`, `edit`, `open`, and `enqueuePrompt`.
|
|
13
|
+
- `[Main Menu]` Section rows are injected before the built-in **Settings** row in the status/application menu. Sections render their own inline-keyboard views with an automatic `⬆️ Main menu` back button.
|
|
14
|
+
- `[Settings Submenu]` Extension settings rows appear before built-in settings controls. Each section can expose an optional `settings` block with its own `open` and `handleCallback`.
|
|
15
|
+
- `[Callback Routing]` `section:` is now a pi-telegram-owned callback prefix. Section callbacks are dispatched before built-in menu handling. Stale tokens receive a graceful "no longer available" answer. Unknown section callbacks fall through to the existing callback namespace fallback.
|
|
16
|
+
- `[Menu Integration]` Updated `menu-status.ts` to accept a `sectionRegistry` and inject section rows before Settings. Updated `menu-settings.ts` to accept a `sectionRegistry` and inject extension settings rows before built-in controls. Updated `menu.ts` to parse and dispatch `section:` callbacks through the registry.
|
|
17
|
+
- `[Demo]` Added `@llblab/pi-telegram-extension-demo` — a companion pi extension demonstrating section registration, a read-only Explorer UI with prompt enqueue, and a settings toggle. The demo lives in `extensions/pi-telegram-extension-demo/`.
|
|
18
|
+
- `[Model Labels]` Model button labels now use compact `provider/ModelId` format (e.g., `anthropic/claude-sonnet-4-5`) instead of `ModelId [provider]`. Models are sorted by provider for predictable grouping. The status row and detail view already used this canonical format.
|
|
19
|
+
- `[Navigation]` Section `ctx.edit()` and `ctx.open()` automatically prepend the correct Back button: `⬆️ Main menu` → `menu:back` at root level, `⬆️ Back` → `section:<token>:open` from section callbacks, `⬆️ Back` → `settings:list` from settings callbacks. Back buttons are deduplicated when already present.
|
|
20
|
+
- `[Settings Status]` Settings rows now support a dynamic `getLabel()` function for live status indicators (e.g., `🟢`/`⚫️` based on internal state). Called on every Settings list render, no polling needed.
|
|
21
|
+
- `[Context]` Added `callbackData(action, payload?)` to section context types — section authors never hand-roll `section:` callback strings. Tokens are filled in automatically.
|
|
22
|
+
- `[CLI]` Removed `/telegram-settings` from pi CLI commands. Telegram settings remain available through the Telegram `/settings` inline menu. Keeps the pi TUI simple.
|
|
23
|
+
- `[Demo]` Renamed `@llblab/pi-telegram-demo` → `@llblab/pi-telegram-extension-demo` with a standalone `package.json` depending on `@llblab/pi-telegram` ^0.10.0, a comprehensive `README.md`, and a GitHub repository reference. Proves third-party devs can extend the pi-telegram interface as an ordinary npm package.
|
|
24
|
+
- `[Tests]` Added 26 regression tests in `tests/extension-sections.test.ts` covering registry lifecycle, main-menu and settings row ordering, callback parsing, section open/callback/settings-open dispatch, stale token handling, handler fallback, and back-button dedup.
|
|
25
|
+
|
|
3
26
|
## 0.9.9: Guest Mode HTML Rendering
|
|
4
27
|
|
|
5
28
|
- `[Guest Mode]` Guest replies now render through the same `renderTelegramMessage` pipeline as direct messages: Markdown → HTML → `answerGuestQuery` with `parse_mode: "HTML"`. Bold, italic, code, links, lists, and tables render identically in guest and DM replies.
|
|
@@ -28,7 +51,7 @@
|
|
|
28
51
|
|
|
29
52
|
## 0.9.6: Runtime Adapter Positioning
|
|
30
53
|
|
|
31
|
-
- `[Package]` Bumped package metadata to `0.9.6` and repositioned the package description from "Better Telegram DM bridge extension for π" to "Telegram
|
|
54
|
+
- `[Package]` Bumped package metadata to `0.9.6` and repositioned the package description from "Better Telegram DM bridge extension for π" to "Telegram runtime adapter for π". Impact: package metadata now reflects the runtime adapter/operator-console role rather than a narrow pipe metaphor.
|
|
32
55
|
- `[Telegram API]` Introduced `TELEGRAM_API_BASE` for the Bot API endpoint and documented native HTTP/HTTPS proxy operation through `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, and explicit `NODE_USE_ENV_PROXY=1` / `--use-env-proxy` enablement. Impact: users behind corporate proxies, local HTTP tunnels, or restricted networks get a zero-runtime-dependency proxy path without replacing native `fetch`; SOCKS5 remains outside the zero-dependency core.
|
|
33
56
|
- `[Dependencies]` Refreshed the lockfile transitive dependency set so `npm audit` clears current `fast-uri` and `fast-xml-builder` advisories inherited through development peer installs. Impact: the full `npm run validate` pipeline passes without changing runtime dependencies.
|
|
34
57
|
- `[README]` Restructured the user entrypoint around install → connect → use → core features → docs, then consolidated examples, terminology, proxy setup, `PI_CODING_AGENT_DIR`, and other environment-only configuration around the runtime-adapter/operator-console model. Impact: first-time users get a clearer path from installation to operation, while vivid examples and non-UI runtime knobs stay discoverable.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
**Telegram
|
|
5
|
+
**Telegram runtime adapter for π.**
|
|
6
6
|
|
|
7
7
|
`pi-telegram` turns a private Telegram DM into a session-local operator console for π. It admits work, preserves context, streams readable replies, keeps busy sessions usable through queues, lets other extensions share one bot, and turns assistant-authored intent into native Telegram artifacts.
|
|
8
8
|
|
|
@@ -101,7 +101,6 @@ Run these inside π, not Telegram:
|
|
|
101
101
|
|
|
102
102
|
- **`/telegram-setup`**: Configure or update the Telegram bot token.
|
|
103
103
|
- **`/telegram-connect`**: Start polling Telegram updates in the current π session and acquire the singleton lock.
|
|
104
|
-
- **`/telegram-settings`**: Open local settings and toggle proactive push using the same `telegram.json` flag as the Telegram `/settings` menu.
|
|
105
104
|
- **`/telegram-disconnect`**: Stop polling in the current π session and release the singleton lock.
|
|
106
105
|
- **`/telegram-status`**: Inspect adapter status, connection, polling, execution, queue, and recent redacted runtime/API failure events.
|
|
107
106
|
|
|
@@ -206,6 +205,12 @@ The agent writes intent; the adapter owns transport. Text remains readable, voic
|
|
|
206
205
|
|
|
207
206
|
Unknown inline-button callbacks are forwarded to π as `[callback] <data>` when they do not belong to pi-telegram, so other extensions can namespace and handle Telegram buttons without polling the bot themselves. Layered extensions that need synchronous update handling can register a runtime interceptor on the shared update registry.
|
|
208
207
|
|
|
208
|
+
### Extension Sections
|
|
209
|
+
|
|
210
|
+
Ordinary pi extensions can register structured UI sections that appear in the main Telegram menu and Settings submenu without owning a second poller. Each section gets a narrow typed context with `edit`, `open`, `enqueuePrompt`, `answerCallback`, and `callbackData()` — enough to build interactive Telegram-native surfaces while `pi-telegram` owns transport, callback routing, navigation hierarchy, and diagnostics.
|
|
211
|
+
|
|
212
|
+
Import from `@llblab/pi-telegram`, call `registerTelegramSection()`, and return a disposer on shutdown. Sections can send interactive messages directly into the chat via `ctx.open()` — confirmation dialogs, approve/deny gates, and multi-step forms live outside the menu hierarchy while callbacks route through the same typed handler. See [`@llblab/pi-telegram-extension-demo`](https://github.com/llblab/pi-telegram-extension-demo) for a working reference and the [Extension Sections Standard](./docs/extension-sections.md) for the full contract.
|
|
213
|
+
|
|
209
214
|
### Proactive push
|
|
210
215
|
|
|
211
216
|
`telegram.json` can set `proactivePush: true` to send successful local non-Telegram final replies to the paired Telegram chat when no Telegram turn is active. Local prompt text is not mirrored because the bot does not own terminal user messages. The mode is off by default and can be toggled from settings.
|
|
@@ -222,7 +227,7 @@ Unknown inline-button callbacks are forwarded to π as `[callback] <data>` when
|
|
|
222
227
|
- [Command Templates](./docs/command-templates.md): portable command-template contract.
|
|
223
228
|
- [Callback Namespaces](./docs/callback-namespaces.md): callback interop for layered extensions.
|
|
224
229
|
- [External Handlers](./docs/external-handlers.md): shared update interception.
|
|
225
|
-
- [Extension Sections
|
|
230
|
+
- [Extension Sections](./docs/extension-sections.md): Telegram extension sections platform for loading extensions that register UI surfaces.
|
|
226
231
|
- [Locks](./docs/locks.md): singleton polling ownership.
|
|
227
232
|
|
|
228
233
|
## Notes
|
package/docs/README.md
CHANGED
|
@@ -11,4 +11,4 @@ Living index of project documentation in `/docs`.
|
|
|
11
11
|
- [locks.md](./locks.md) — Shared `locks.json` standard for singleton extension ownership
|
|
12
12
|
- [callback-namespaces.md](./callback-namespaces.md) — Shared Telegram `callback_data` namespace standard for layered extensions
|
|
13
13
|
- [external-handlers.md](./external-handlers.md) — Runtime interceptor registry that lets layered extensions observe and consume Telegram updates without owning their own polling connection
|
|
14
|
-
- [extension-sections.md](./extension-sections.md) —
|
|
14
|
+
- [extension-sections.md](./extension-sections.md) — Telegram Extension Sections Standard: registration contract, context ports, callback routing, navigation hierarchy, and demo reference for pi extensions that want Telegram UI surfaces
|
|
@@ -20,7 +20,7 @@ myext:page:2
|
|
|
20
20
|
|
|
21
21
|
- Use a stable extension-owned namespace, preferably the package or extension name without scope punctuation.
|
|
22
22
|
- Keep the namespace lowercase ASCII: `a-z`, `0-9`, `_`, `-`.
|
|
23
|
-
- Do not use `pi-telegram` owned prefixes: `tgbtn:`, `menu:`, `model:`, `thinking:`, `status:`, `queue:`, `section:`. Current app navigation uses `menu:`; `status:` remains reserved for legacy/owned status callbacks but is not emitted by current UI. `section:` is
|
|
23
|
+
- Do not use `pi-telegram` owned prefixes: `tgbtn:`, `menu:`, `model:`, `thinking:`, `status:`, `queue:`, `settings:`, `section:`. Current app navigation uses `menu:`; `status:` remains reserved for legacy/owned status callbacks but is not emitted by current UI. `section:` is owned by the Extension Sections platform (0.10.0+), documented in [Extension Sections](./extension-sections.md). `settings:` is owned for the built-in Settings submenu.
|
|
24
24
|
- Keep the full `callback_data` within Telegram's 64-byte limit.
|
|
25
25
|
- Put only opaque ids or small enum values in payloads; do not store secrets, full prompts, or large state.
|
|
26
26
|
- Treat callbacks as untrusted input. Validate namespace, action, and payload before executing side effects.
|