@llblab/pi-telegram 0.11.1 → 0.12.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 +17 -12
- package/BACKLOG.md +0 -10
- package/CHANGELOG.md +33 -2
- package/README.md +42 -25
- package/api/inbound.ts +14 -0
- package/api/keyboard.ts +10 -0
- package/api/outbound.ts +11 -0
- package/api/sections.ts +17 -0
- package/api/updates.ts +11 -0
- package/api/voice.ts +24 -0
- package/docs/README.md +7 -5
- package/docs/architecture.md +176 -135
- package/docs/callback-namespaces.md +3 -3
- package/docs/command-templates.md +81 -24
- package/docs/{inbound-handlers.md → inbound.md} +13 -10
- package/docs/locks.md +3 -3
- package/docs/{outbound-handlers.md → outbound.md} +13 -10
- package/docs/public-api.md +266 -0
- package/docs/{extension-sections.md → sections.md} +31 -27
- package/docs/ui-style.md +165 -0
- package/docs/{external-handlers.md → updates.md} +33 -31
- package/docs/voice.md +17 -14
- package/index.ts +86 -261
- package/lib/bindings.ts +301 -0
- package/lib/command-templates.ts +163 -32
- package/lib/commands.ts +114 -1
- package/lib/config.ts +45 -4
- package/lib/{inbound-handlers.ts → inbound.ts} +5 -4
- package/lib/lifecycle.ts +122 -1
- package/lib/menu-model.ts +3 -3
- package/lib/menu-queue.ts +1 -1
- package/lib/menu-settings.ts +63 -32
- package/lib/menu-status.ts +1 -1
- package/lib/menu.ts +1 -1
- package/lib/{outbound-handlers.ts → outbound.ts} +21 -11
- package/lib/pi.ts +4 -0
- package/lib/polling.ts +4 -3
- package/lib/preview.ts +1 -1
- package/lib/routing.ts +45 -13
- package/lib/{extension-sections.ts → sections.ts} +37 -8
- package/lib/time-injection.ts +1 -1
- package/lib/updates.ts +121 -1
- package/lib/voice.ts +33 -14
- package/package.json +11 -1
- package/lib/external-handlers.ts +0 -166
package/AGENTS.md
CHANGED
|
@@ -24,10 +24,12 @@
|
|
|
24
24
|
## 3. Project Topology
|
|
25
25
|
|
|
26
26
|
- `/index.ts`: Main extension entrypoint and runtime composition layer for the bridge
|
|
27
|
-
- `/
|
|
28
|
-
- `/
|
|
27
|
+
- `/api/*.ts`: Public package entrypoint membranes. Export only stable companion-extension symbols documented in `/docs/public-api.md`; keep runtime helpers in `/lib` package-private.
|
|
28
|
+
- `/lib/*.ts`: Flat domain modules for reusable runtime logic. Favor domain files such as queueing/runtime, replies, polling, updates, outbound-attachments, commands, lifecycle hooks, prompts, prompt-templates, pi SDK adapter/bindings, Telegram API, config, turns, media, setup, rendering, app menu, menu-model, menu-thinking, menu-queue, status/model-resolution support, and other cohesive bridge subsystems; use `shared` only when a type or constant truly spans multiple domains
|
|
29
|
+
- `/tests/*.test.ts`: Domain-mirrored regression suites that follow the same flat naming as `/lib` plus public package-boundary regressions for `/api`
|
|
29
30
|
- `/docs/README.md`: Documentation index for technical project docs
|
|
30
31
|
- `/docs/architecture.md`: Runtime and subsystem overview for the bridge
|
|
32
|
+
- `/docs/public-api.md`: Stable public API map for commands, config, assistant markup, extension APIs, package entrypoints, and compatibility boundaries
|
|
31
33
|
- `/README.md`: User-facing project entry point. Keep its rhythm as install → connect → use → core features → docs, with vivid examples that explain the runtime adapter/operator-console model without duplicating full docs.
|
|
32
34
|
- `/AGENTS.md`: Durable engineering and runtime conventions
|
|
33
35
|
- `/BACKLOG.md`: Canonical open work
|
|
@@ -73,7 +75,7 @@
|
|
|
73
75
|
- Telegram delivery strips top-level HTML comments from preview/final text; column-zero top-level `<!-- telegram_voice ... -->` and `<!-- telegram_button ... -->` blocks are special outbound comments handled after `agent_end` without requiring agent-side transport tool calls, while comments inside code, quotes, lists, or indented examples stay literal
|
|
74
76
|
- `telegram_voice` and `telegram_button` are not π tools; keep prompts/docs explicit that agents should author markup while voice synthesis provider extensions own TTS/OGG conversion, and pi-telegram owns button routing plus Telegram delivery
|
|
75
77
|
- Voice reply policy and prompt context are owned by pi-telegram's `telegram.json` `voice.replyMode`: missing/invalid config behaves as `manual` but does not add a `[voice]` prompt-context block; only an explicit valid `voice.replyMode` renders context. Render a single voice field as `[voice] reply mode: manual|mirror|always`, and render multiple fields as a `[voice]` list; place voice context after `[outputs]` when handler output exists, otherwise after `[attachments]`; provider prompt contributions are optional provider-specific additions, not the default policy channel
|
|
76
|
-
- Optional `telegram.json` `time` may add `[time] YYYY-MM-DD HH:mm:ss <timezone>` to Telegram-originated prompts for wall-clock context. It is
|
|
78
|
+
- Optional `telegram.json` `time` may add `[time] YYYY-MM-DD HH:mm:ss <timezone>` to Telegram-originated prompts for wall-clock context. It is hidden by default, uses `time.injectionMode` values `hidden|always|interval`, stores `time.interval` in milliseconds, uses the system timezone, and should render last after `[attachments]`, `[outputs]`, and `[voice]` sections. The Settings row `🕒 Time injection: hidden|always|interval` controls `time.injectionMode` only.
|
|
77
79
|
- Voice reply mode Settings UI standard: the top-level Settings row is `👄 Voice reply: hidden|manual|mirror|always`; `hidden` is the true default and means no valid `voice.replyMode` is persisted, behavior is manual, and no voice policy is added to prompt context; explicit `manual` behaves the same operationally but renders reply-mode context. The submenu title is `👄 Voice reply mode:`; choice buttons use lowercase labels with a model-style active dot (`🟢 hidden`, `🟢 mirror`) rather than per-mode emoji; the explanatory submenu body uses compact HTML-code bullets such as `<code>-</code> <code>hidden</code> (default): ...`. Preserve this wording/icons unless the operator explicitly asks to redesign it
|
|
78
80
|
- Outbound voice delivery is one fallback pipeline: configured `outboundHandlers` with `type: "voice"` run first in `telegram.json` order, then programmatic voice handlers, then registered voice synthesis providers as zero-config progressive fallbacks; provider extensions must not override operator-configured handlers
|
|
79
81
|
- `telegram_voice` text is arbitrary TTS-target text: use body form for multiline text, `<!-- telegram_voice text="Short summary" -->` for explicit one-line text, or `<!-- telegram_voice: Short summary -->` for one-line text with no attributes
|
|
@@ -106,11 +108,11 @@
|
|
|
106
108
|
The canonical detailed ownership map lives in [`docs/architecture.md`](./docs/architecture.md). Keep this section as a compact agent-facing index, not a second copy of the full map.
|
|
107
109
|
|
|
108
110
|
- Scheduling and lifecycle: `queue`, `runtime`, `lifecycle`, `locks`
|
|
109
|
-
- Telegram transport and inbound flow: `api`, `polling`, `updates`, `routing`, `media`, `turns`, `inbound
|
|
110
|
-
- Response surfaces: `preview`, `replies`, `rendering`, `keyboard`, `outbound-attachments`, `outbound
|
|
111
|
+
- Telegram transport and inbound flow: `api`, `polling`, `updates`, `routing`, `media`, `turns`, `inbound`, `config`, `setup`
|
|
112
|
+
- Response surfaces: `preview`, `replies`, `rendering`, `keyboard`, `outbound-attachments`, `outbound`, `voice`, `status`
|
|
111
113
|
- Controls and application menu UI: `commands`, `menu`, `menu-model`, `menu-thinking`, `menu-status`, `menu-queue`, `model`, `prompts`
|
|
112
|
-
- Extension platform: `
|
|
113
|
-
- Pi SDK boundary: `pi` owns direct pi imports and bound extension API ports
|
|
114
|
+
- Extension platform: `sections` owns section registry, token mapping, callback dispatch, context building, and its globalThis bridge; `voice` owns the voice-provider registry and its globalThis bridge
|
|
115
|
+
- Pi SDK boundary: `pi` owns direct pi imports and bound extension API ports; `bindings` owns pi-facing command/tool/lifecycle registration wiring extracted from the entrypoint
|
|
114
116
|
|
|
115
117
|
## 6.4 Entrypoint And Import Boundaries
|
|
116
118
|
|
|
@@ -130,6 +132,7 @@ The canonical detailed ownership map lives in [`docs/architecture.md`](./docs/ar
|
|
|
130
132
|
- When fork identity changes, keep `README.md`, package metadata, and docs aligned so the published package does not point back at stale upstream coordinates
|
|
131
133
|
- README positioning should emphasize `/start` as the primary Telegram operator menu and keep reaction shortcuts secondary. Reactions are useful queue affordances, but menu controls are the core CLI-to-Telegram bridge.
|
|
132
134
|
- Document configuration knobs without UI in the root README when they affect bootstrap, networking, transport limits, or prompt context; currently this includes token env bootstrap, Node env proxy mode, inbound/outbound size limits, and `time`.
|
|
135
|
+
- Keep extension-local standards self-contained: shared patterns such as command templates may evolve independently in multiple extensions, but pi-telegram docs/changelog should describe the standard without naming sibling extension implementations as dependencies or authorities.
|
|
133
136
|
- 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
|
|
134
137
|
|
|
135
138
|
## 8. Integration Protocols
|
|
@@ -141,11 +144,13 @@ The canonical detailed ownership map lives in [`docs/architecture.md`](./docs/ar
|
|
|
141
144
|
- Command help plus prompt-template commands and status/model/thinking/queue controls are driven through `/start`'s Telegram inline application menu and callback queries; the Queue button shows the queued-item count, model-menu scope/pagination controls stay at the top under Main menu, the model pagination indicator opens a compact page picker, and thinking-menu text stays a compact heading because the current level is marked by button state; `/status`, `/model`, `/thinking`, and `/queue` are hidden compatibility shortcuts
|
|
142
145
|
- Shared inline-keyboard structure belongs to `keyboard`; application-control button labels, callback data, and callback behavior stay in `menu`/`menu-model`/`menu-thinking`/`menu-status`/`menu-queue` while core queue mechanics stay in `queue`
|
|
143
146
|
- Telegram `/settings` options should open nested detail submenus by default: checkbox options show a description plus Back, `on`, and `off`; list options show Back plus selectable values. One-shot actions such as syncing may run directly without a submenu when there is no meaningful choice or description step.
|
|
147
|
+
- Inline UI labels and dialogs follow [`docs/ui-style.md`](./docs/ui-style.md): action buttons use emoji plus capitalized action text, state & navigation buttons show state and lead to a submenu, first-level submenus start with `⬆️ Main menu` while deeper submenus start with `⬆️ Back`, boolean toggles use Capitalized horizontal `On`/`Off` with green active `On`, yellow active `Off`, and black inactive dots, tabs use capitalized labels with purple default-state and yellow elevated-state active dots and black inactive dots, vertical option lists mark only the current value green, and confirmation dialogs use a single bold text-only question with emoji on buttons only.
|
|
144
148
|
- Inbound text/media may be transformed through configured `inboundHandlers` before queueing; legacy `attachmentHandlers` are deprecated compatibility aliases appended after `inboundHandlers`; outbound files must flow through `telegram_attach`
|
|
145
149
|
- 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
|
|
146
|
-
- Public
|
|
150
|
+
- Public API boundaries live in [`docs/public-api.md`](./docs/public-api.md): companion extensions must use public API domain subpaths such as `@llblab/pi-telegram/sections`, `/voice`, `/inbound`, `/outbound`, and `/updates`; `0.12.0` intentionally removes the published `@llblab/pi-telegram/lib/*.ts` compatibility wildcard
|
|
151
|
+
- Public handler API matrix: low-level buses use `registerTelegramUpdateHandler(handler)`, `registerTelegramInboundHandler(kind, handler)`, and `registerTelegramOutboundHandler(kind, handler)` without ids; high-level surfaces use stable identity (`registerTelegramSection({ id, ... })`, `registerTelegramVoiceTranscriptionProvider(provider, { id })`, and `registerTelegramVoiceSynthesisProvider(provider, { id })`). Inbound handlers and command-backed outbound handlers use command templates as the standard config contract; built-in outbound buttons use inline keyboards plus callback routing because no polling command execution is needed
|
|
147
152
|
- 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
|
|
148
|
-
- 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;
|
|
153
|
+
- Unknown callback data not owned by pi-telegram prefixes (`compact:`, `tgbtn:`, `menu:`, `model:`, `thinking:`, `status:`, `queue:`, `section:`, `settings:`) may be forwarded as `[callback] <data>` after built-in handlers decline it; update-handler extensions should follow `docs/callback-namespaces.md` and must not poll the same bot independently
|
|
149
154
|
- 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
|
|
150
155
|
- 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
|
|
151
156
|
|
|
@@ -154,15 +159,15 @@ The canonical detailed ownership map lives in [`docs/architecture.md`](./docs/ar
|
|
|
154
159
|
- `Section identity`: use the same identity-key rules as the Extension Locks Standard (`package.json/name` → canonical id); no separate `owner` field
|
|
155
160
|
- `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?)`
|
|
156
161
|
- `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`
|
|
157
|
-
- `Context ports`: sections receive `TelegramSectionContext` / `TelegramSectionCallbackContext` with `answerCallback`, `edit`, `open`, `enqueuePrompt`, and `callbackData`. No filesystem access, no raw bot clients, no second
|
|
162
|
+
- `Context ports`: sections receive `TelegramSectionContext` / `TelegramSectionCallbackContext` with `answerCallback`, `edit`, `open`, `enqueuePrompt`, and `callbackData`. No filesystem access, no raw bot clients, no second polling loop
|
|
158
163
|
- `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
|
|
159
164
|
- `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"`
|
|
160
|
-
- `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
|
|
165
|
+
- `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 polling
|
|
161
166
|
- `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
|
|
162
167
|
- `Shutdown`: call `pi.on("shutdown", () => unregister())` in the extension's default export
|
|
163
168
|
- `Section separators`: extension-injected main-menu rows appear before the **⚙️ Settings** row. Extension settings rows appear before built-in Proactive push controls
|
|
164
169
|
- `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
|
|
165
|
-
- `Section domain ownership`: `lib/
|
|
170
|
+
- `Section domain ownership`: `lib/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
|
|
166
171
|
- `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`
|
|
167
172
|
|
|
168
173
|
## 9. Pre-Task Preparation Protocol
|
package/BACKLOG.md
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
1
|
# Project Backlog
|
|
2
2
|
|
|
3
3
|
## Open Work
|
|
4
|
-
|
|
5
|
-
- [ ] Adapt `pi-xai-voice` to the finalized voice-provider contract.
|
|
6
|
-
- Priority: High after `0.11.0` lands.
|
|
7
|
-
- Idea: Update provider imports to `@llblab/pi-telegram/lib/voice.ts`, persist `voice.replyMode` to the same `telegram.json` location pi-telegram reads, return `transcriptText` only when the provider's transcript toggle is enabled, and rely on provider-owned OGG/Opus conversion.
|
|
8
|
-
- Exit: `pi-xai-voice` works against `pi-telegram@0.11.x` without direct `globalThis` access or fork-local import resolution.
|
|
9
|
-
|
|
10
|
-
- [ ] Explore always-available outbound Telegram tools for queued artifacts and controls.
|
|
11
|
-
- Priority: Low.
|
|
12
|
-
- 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.
|
|
13
|
-
- Exit: Design note defines active-turn versus ambient delivery semantics, safety constraints, failure modes, and whether the current `telegram_attach` contract should stay turn-scoped or gain an ambient companion.
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Nothing yet.
|
|
6
|
+
|
|
7
|
+
## 0.12.0: Public API Membranes, Telegram UX Safety, And Extension Interop
|
|
8
|
+
|
|
9
|
+
- `[Typing Status]` Auto-compaction now starts and stops the native Telegram `typing` keepalive like manual `/compact`, including timeout and shutdown cleanup. Active Telegram turns also re-arm typing on assistant message start/update events so transient provider/model errors cannot permanently leave a continuing run without Telegram activity feedback.
|
|
10
|
+
- `[Compaction Safety]` Telegram `/compact` now opens an inline confirmation dialog before manual compaction starts, protecting the operator from accidental taps near `/start`. The dialog follows the dedicated UI style guide: a bold text-only question with emoji only on the explicit `Yes, compact` and `No` buttons. Confirming edits the dialog directly to `Compaction started.` instead of showing a separate `Compaction confirmed.` step.
|
|
11
|
+
- `[Docs]` Added `docs/ui-style.md` as the focused style guide for inline buttons, toggles, tabs, option lists, cards, and dialogs.
|
|
12
|
+
- `[Docs]` Restructured `docs/architecture.md` into a clearer architectural map with runtime topology, domain ownership, core flows, extension surfaces, and operational behavior while pushing detailed UI/callback rules toward focused standards.
|
|
13
|
+
- `[Breaking API]` Bumped package version to `0.12.0` and renamed the public implementation domains to `lib/sections.ts`, `lib/updates.ts`, `lib/inbound.ts`, and `lib/outbound.ts`. Package exports now expose only the stable public API domains (`/sections`, `/updates`, `/inbound`, `/outbound`, `/voice`, `/keyboard`) and no longer expose the compatibility `./lib/*.ts` wildcard.
|
|
14
|
+
- `[Architecture]` Folded the public update-handler interop surface into `updates` and renamed the internal long-poll loop module back to `polling`, giving the pair concise one-word domains: `updates` for update contracts/classification/handler registry and `polling` for the `getUpdates` runtime. Entrypoint extraction now lives in `bindings`, a concrete pi-facing command/tool/lifecycle wiring boundary rather than a new product domain.
|
|
15
|
+
- `[Tests]` Added an architecture invariant and package self-import regressions that pin the `0.12.0` package exports to stable `/api` membranes with exact runtime export shapes and prevent accidental restoration of the removed `./lib/*.ts` wildcard.
|
|
16
|
+
- `[Docs]` Added `docs/public-api.md` as the public API map for commands, config, assistant markup, extension APIs, callback ownership, and public/internal stability boundaries.
|
|
17
|
+
- `[API]` Hardened Telegram Extension Sections by rejecting duplicate section ids and validating `ctx.callbackData()` against Telegram's 64-byte callback-data limit.
|
|
18
|
+
- `[API]` Added `registerTelegramUpdateHandler()` as the matrix-aligned low-level update bus name.
|
|
19
|
+
- `[API]` Documented the public low/high-level registration matrix: low-level buses (`updates`, `inbound`, `outbound`) intentionally have no ids, while high-level sections and voice providers use stable ids in new integrations.
|
|
20
|
+
- `[Settings UI]` Refined control conventions: boolean toggles use Capitalized horizontal `On`/`Off` with green active `On`, yellow active `Off`, and black inactive markers; state/navigation rows use Capitalized status values; horizontal tabs use capitalized labels with purple default-state and yellow elevated-state active markers; vertical option lists keep only the current value marked green; submenu navigation distinguishes `⬆️ Main menu` from deeper `⬆️ Back` rows; confirmation actions use explicit `Yes, ...` labels such as `🗜 Yes, compact`; added State & Navigation Buttons section to the style guide for buttons that show state and lead to a submenu.
|
|
21
|
+
- `[Config]` Time Injection Hidden mode now removes `time.injectionMode` from `telegram.json` instead of persisting `"hidden"`, matching Voice Reply Hidden semantics: missing key = default hidden state.
|
|
22
|
+
|
|
23
|
+
## 0.11.2: Queue Continuation, Compaction Safety, And Settings Polish
|
|
24
|
+
|
|
25
|
+
- `[Time Context]` Renamed the disabled time injection mode from `off` to `hidden` in Settings and config defaults, matching voice reply mode semantics where no prompt-context line is injected. Legacy `off` callbacks/config values are still treated as hidden.
|
|
26
|
+
- `[Settings UI]` Settings detail headings now show the current value immediately after the bold label in monospace style, making each submenu title double as the active setting summary.
|
|
27
|
+
- `[Entrypoint]` Removed root-level API re-exports from `index.ts`; public extension APIs remain available from their owning `lib/*` modules while the root file stays a default-only composition root.
|
|
28
|
+
- `[Continue Queue]` `/continue` now enqueues a standalone priority prompt without preserving already queued prompts as history. Impact: queued prompts stay iterative queue items instead of being folded into one combined `continue` prompt.
|
|
29
|
+
- `[Auto Compaction]` Observes native `session_before_compact` / `session_compact` events and blocks queued Telegram prompt dispatch while compaction is running, then resumes the queue after compaction settles. Impact: queued Telegram turns no longer race Pi auto-compaction and trigger `Cannot read properties of undefined (reading 'signal')` after compaction.
|
|
30
|
+
- `[Command Templates]` Updated the command-template helper library and regressions with typed placeholders, array-index placeholder resolution, repeat fanout from array length, unbounded default timeout semantics, and trusted-command warnings.
|
|
31
|
+
- `[Docs]` Updated the command-template standard with typed args, array placeholders, failure propagation, recover cleanup, and trust-boundary guidance.
|
|
32
|
+
- `[Docs]` Decomposed oversized architecture documentation blocks into focused sections for runtime ownership, queue validation, application menu shape, outbound actions, and interactive controls. Impact: the architecture entry point is easier to scan without changing runtime behavior.
|
|
33
|
+
- `[README]` Split queue reaction shortcuts into priority and removal lists, added `pi-xai-voice` as a companion extension, and kept the time-injection row label compact while preserving the full detail-heading label. Impact: operator-facing docs match the current Telegram menu language.
|
|
34
|
+
- `[Context]` Recorded the convention that extension-local standards should stay self-contained and avoid naming sibling extension implementations as authorities. Impact: shared standards can evolve independently without creating false extension dependencies.
|
|
35
|
+
|
|
5
36
|
## 0.11.1: Time Context And Settings Polish
|
|
6
37
|
|
|
7
38
|
- `[Time Context]` Added optional `telegram.json` `time` prompt context for Telegram-originated turns. `time.injectionMode` values are `off`, `always`, and per-chat `interval`; `time.interval` is stored in milliseconds and timezone comes from the system. The `[time]` line renders last after attachments, handler outputs, and voice context, and Settings exposes a `🕒 Time` mode selector.
|
|
@@ -138,7 +169,7 @@
|
|
|
138
169
|
## 0.9.4: Temp Dir And Command Template Hotfix
|
|
139
170
|
|
|
140
171
|
- `[Telegram Temp Dir]` Default Telegram API temp files now respect `PI_CODING_AGENT_DIR`, falling back to `~/.pi/agent` when the env var is unset. Impact: sandboxed or relocated agent dirs no longer force Telegram downloads through the default home-directory path.
|
|
141
|
-
- `[Command Templates]`
|
|
172
|
+
- `[Command Templates]` Updated the local Command Template Standard: command-template nodes now document `mode`, `label`, `delay`, `repeat`, parallel fanout semantics, zero-based repeat placeholders, padding, and limited arithmetic expressions such as `{_(index+1)}`. Impact: inbound/outbound Telegram handler docs and helpers share the current portable automation contract without depending on another extension's documentation.
|
|
142
173
|
- `[Queue Menu]` Empty queue refresh clicks now rotate through compact alternate empty-state headings while preserving the default first-open `⌛ Queue is empty.` state, and the Refresh button now stays directly under Back for both empty and populated queue lists. Impact: manual queue polling feels alive and the primary refresh control stays in a stable location without changing queue semantics.
|
|
143
174
|
- `[Package]` Bumped package metadata to `0.9.4` and kept the lockfile in sync.
|
|
144
175
|
|
|
@@ -190,7 +221,7 @@
|
|
|
190
221
|
- `[Configuration Docs]` Documented the configuration philosophy that rich visual/TUI setup stays minimal for now while agents can read README/docs and update `telegram.json` for advanced workflows. Impact: configuration guidance matches the extension's agent-assisted operator model without adding premature TUI surfaces.
|
|
191
222
|
- `[Outbound Docs]` Tightened voice-handler critical-step wording around transform → TTS → conversion pipelines and handler-level fallbacks. Impact: docs now match translated voice pipelines without implying provider-specific TTS fallbacks.
|
|
192
223
|
- `[Package]` Bumped package metadata to `0.8.1` and kept the lockfile in sync.
|
|
193
|
-
- `[Command Template Docs]`
|
|
224
|
+
- `[Command Template Docs]` Updated `docs/command-templates.md` to the current portable standard. Impact: the documented standard now includes retry, fail-open composition, critical-step abort semantics, and the 30s default timeout without requiring cross-extension references.
|
|
194
225
|
- `[Lock Docs]` Synchronized `docs/locks.md` bit-for-bit with the extension-neutral Locks Standard shared by `pi-wakeup`. Impact: singleton ownership documentation no longer carries project-specific examples that prevent exact reuse across extensions.
|
|
195
226
|
|
|
196
227
|
## 0.8.0: Handler Bus
|
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ What it feels like:
|
|
|
85
85
|
Use these inside the Telegram DM with your bot. The main entrypoint is `/start`: it opens the operator menu and exposes many of the important agent controls that normally live in the CLI, adapted for Telegram.
|
|
86
86
|
|
|
87
87
|
- **`/start`**: Pair the first Telegram user when needed, register bot commands, and open the inline application menu with command help, prompt-template commands, status rows, model controls, thinking controls, settings, and queue controls.
|
|
88
|
-
- **`/compact`**:
|
|
88
|
+
- **`/compact`**: Ask for inline confirmation, then start session compaction when the session is idle; Telegram shows the native typing indicator while manual or automatic compaction is running.
|
|
89
89
|
- **`/next`**: Dispatch the next queued turn, aborting π first if needed.
|
|
90
90
|
- **`/continue`**: Enqueue a priority `continue` prompt.
|
|
91
91
|
- **`/abort`**: Abort the active run without touching the queue.
|
|
@@ -120,7 +120,10 @@ The inline application menu is the primary operator surface. It exposes status,
|
|
|
120
120
|
|
|
121
121
|
Messages sent while π is busy enter the prompt queue and are processed in order. Control actions and model-switch continuation turns use higher-priority lanes so operational commands can resume before normal prompts.
|
|
122
122
|
|
|
123
|
-
The menu is the primary way to inspect and mutate the queue. Reactions are an extra shortcut when Telegram delivers `message_reaction` updates for the chat
|
|
123
|
+
The menu is the primary way to inspect and mutate the queue. Reactions are an extra shortcut when Telegram delivers `message_reaction` updates for the chat. The same rules apply to text, voice, files, images, and media groups:
|
|
124
|
+
|
|
125
|
+
- Priority shortcuts: `👍`, `⚡️`, `❤️`, `🕊`, and `🔥` promote waiting work.
|
|
126
|
+
- Removal shortcuts: `👎`, `👻`, `💔`, `💩`, and `🗑` remove waiting work from the queue.
|
|
124
127
|
|
|
125
128
|
### Streaming and Telegram HTML rendering
|
|
126
129
|
|
|
@@ -196,24 +199,30 @@ If `telegram.json` explicitly sets a valid `voice.replyMode`, prompts include co
|
|
|
196
199
|
|
|
197
200
|
In `mirror` and `always` modes, the bridge transparently intercepts agent text responses and routes them through the outbound voice pipeline. Configured `outboundHandlers` with `type: "voice"` run first in their configured order; zero-config registered synthesis providers run after them as progressive fallbacks. If several synthesis providers are installed, they are tried in registration order and the first one that returns a valid `.ogg`/`.opus` artifact handles the reply; `undefined`, errors, or invalid output fall through to the next provider. If every voice generator fails, the bridge falls back to sending the text reply instead.
|
|
198
201
|
|
|
199
|
-
Voice synthesis provider extensions (e.g. `pi-xai-voice`) register a TTS backend at runtime:
|
|
202
|
+
Voice synthesis provider extensions (e.g. `pi-xai-voice`) register a TTS backend at runtime through public API domain subpaths:
|
|
200
203
|
|
|
201
204
|
```typescript
|
|
202
|
-
import { registerTelegramVoiceSynthesisProvider } from "@llblab/pi-telegram/
|
|
203
|
-
import { recordTelegramRuntimeEvent } from "@llblab/pi-telegram/
|
|
205
|
+
import { registerTelegramVoiceSynthesisProvider } from "@llblab/pi-telegram/voice";
|
|
206
|
+
import { recordTelegramRuntimeEvent } from "@llblab/pi-telegram/outbound";
|
|
204
207
|
|
|
205
208
|
// Return path only (backward compatible)
|
|
206
|
-
const dispose = registerTelegramVoiceSynthesisProvider(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
const dispose = registerTelegramVoiceSynthesisProvider(
|
|
210
|
+
async (text, { lang, rate }) => {
|
|
211
|
+
const path = await myTTS(text, { language: lang });
|
|
212
|
+
return path; // must be .ogg or .opus
|
|
213
|
+
},
|
|
214
|
+
{ id: "pi-xai-voice/tts" },
|
|
215
|
+
);
|
|
210
216
|
|
|
211
217
|
// Return path + transcript caption
|
|
212
|
-
const dispose2 = registerTelegramVoiceSynthesisProvider(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
218
|
+
const dispose2 = registerTelegramVoiceSynthesisProvider(
|
|
219
|
+
async (text, { lang, rate }) => {
|
|
220
|
+
const rewritten = rewriteWithSpeechTags(text); // internal TTS optimization
|
|
221
|
+
const path = await myTTS(rewritten, { language: lang });
|
|
222
|
+
return { audioPath: path, transcriptText: text };
|
|
223
|
+
},
|
|
224
|
+
{ id: "pi-xai-voice/tts-with-transcript" },
|
|
225
|
+
);
|
|
217
226
|
|
|
218
227
|
// Surface diagnostics in /telegram-status
|
|
219
228
|
recordTelegramRuntimeEvent("xai-voice", new Error("TTS complete"), {
|
|
@@ -222,17 +231,17 @@ recordTelegramRuntimeEvent("xai-voice", new Error("TTS complete"), {
|
|
|
222
231
|
});
|
|
223
232
|
```
|
|
224
233
|
|
|
225
|
-
Multiple synthesis providers can be registered;
|
|
234
|
+
Multiple synthesis providers can be registered; stable provider registrations pass a durable `id`, while omitted ids remain a compatibility path for older providers. The bridge tries configured `type: "voice"` handlers first, then programmatic handlers, then registered synthesis providers in registration order until one succeeds. Providers and handlers receive the text to synthesize and optional `lang`/`rate` hints from `<!-- telegram_voice -->` markup or the automatic interception path. Voice delivery must produce `.ogg` or `.opus` files.
|
|
226
235
|
|
|
227
236
|
### Extension interop
|
|
228
237
|
|
|
229
|
-
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
|
|
238
|
+
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 handler on the shared update registry.
|
|
230
239
|
|
|
231
240
|
### Extension Sections
|
|
232
241
|
|
|
233
|
-
Ordinary pi extensions can register structured UI sections that appear in the main Telegram menu and Settings submenu without owning a second
|
|
242
|
+
Ordinary pi extensions can register structured UI sections that appear in the main Telegram menu and Settings submenu without owning a second polling loop. 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.
|
|
234
243
|
|
|
235
|
-
Import `registerTelegramSection()` from `@llblab/pi-telegram/
|
|
244
|
+
Import `registerTelegramSection()` from `@llblab/pi-telegram/sections` 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/sections.md) for the full contract.
|
|
236
245
|
|
|
237
246
|
### Proactive push
|
|
238
247
|
|
|
@@ -240,7 +249,7 @@ Import `registerTelegramSection()` from `@llblab/pi-telegram/lib/extension-secti
|
|
|
240
249
|
|
|
241
250
|
### Time context
|
|
242
251
|
|
|
243
|
-
`telegram.json` can opt into a compact `[time]` line in Telegram-originated prompts so π has a wall-clock reference for requests such as "today", "now", or scheduling. It is
|
|
252
|
+
`telegram.json` can opt into a compact `[time]` line in Telegram-originated prompts so π has a wall-clock reference for requests such as "today", "now", or scheduling. It is hidden by default and uses the system timezone; the mode can also be changed from Settings → `🕒 Time injection`.
|
|
244
253
|
|
|
245
254
|
```json
|
|
246
255
|
{
|
|
@@ -251,7 +260,7 @@ Import `registerTelegramSection()` from `@llblab/pi-telegram/lib/extension-secti
|
|
|
251
260
|
}
|
|
252
261
|
```
|
|
253
262
|
|
|
254
|
-
Modes are `
|
|
263
|
+
Modes are `hidden`, `always`, and `interval`. `hidden` means no time line is added to prompt context. `interval` is measured in milliseconds and rate-limits the time line per chat in memory, so back-to-back messages do not repeatedly spend context on the same timestamp. When present, `[time]` is the final prompt-context section after attachments, handler outputs, and voice policy.
|
|
255
264
|
|
|
256
265
|
## Docs
|
|
257
266
|
|
|
@@ -260,14 +269,16 @@ Modes are `off`, `always`, and `interval`. `interval` is measured in millisecond
|
|
|
260
269
|
- [Changelog](./CHANGELOG.md): completed delivery history.
|
|
261
270
|
- [Documentation Index](./docs/README.md): technical docs hub.
|
|
262
271
|
- [Architecture](./docs/architecture.md): runtime and subsystem overview.
|
|
263
|
-
- [
|
|
264
|
-
- [
|
|
265
|
-
- [
|
|
272
|
+
- [Public API](./docs/public-api.md): stable commands, config, package entrypoints, assistant markup, and extension APIs.
|
|
273
|
+
- [Inbound Handlers](./docs/inbound.md): Telegram → π preprocessing.
|
|
274
|
+
- [Outbound Handlers](./docs/outbound.md): final text, voice, and artifact pipelines.
|
|
266
275
|
- [Command Templates](./docs/command-templates.md): portable command-template contract.
|
|
267
276
|
- [Callback Namespaces](./docs/callback-namespaces.md): callback interop for layered extensions.
|
|
268
|
-
- [
|
|
269
|
-
- [Extension Sections](./docs/
|
|
277
|
+
- [Updates](./docs/updates.md): shared update interception.
|
|
278
|
+
- [Extension Sections](./docs/sections.md): Telegram extension sections platform for loading extensions that register UI surfaces.
|
|
279
|
+
- [Voice Integration](./docs/voice.md): voice reply policies, transparent interception, and provider extension API.
|
|
270
280
|
- [Locks](./docs/locks.md): singleton polling ownership.
|
|
281
|
+
- [UI Style](./docs/ui-style.md): inline button, toggle, tab, option-list, card, and dialog style guide.
|
|
271
282
|
|
|
272
283
|
## Notes
|
|
273
284
|
|
|
@@ -285,6 +296,12 @@ Third-party extensions that integrate with `pi-telegram`:
|
|
|
285
296
|
pi install npm:pi-telegram-tool-status
|
|
286
297
|
```
|
|
287
298
|
|
|
299
|
+
- [`pi-xai-voice`](https://github.com/luxus/pi-xai-voice) — Companion extension that adds xAI-powered TTS for voice reply policies and `telegram_voice` markup.
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
pi install npm:pi-xai-voice
|
|
303
|
+
```
|
|
304
|
+
|
|
288
305
|
## License
|
|
289
306
|
|
|
290
307
|
MIT
|
package/api/inbound.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram inbound API
|
|
3
|
+
* Zones: package boundary, companion extension interop
|
|
4
|
+
* Exposes the stable programmatic inbound handler surface while keeping handler runtime internals package-private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
registerTelegramInboundHandler,
|
|
9
|
+
type TelegramInboundHandlerFile,
|
|
10
|
+
type TelegramInboundHandlerOutput,
|
|
11
|
+
type TelegramInboundProgrammaticHandler,
|
|
12
|
+
type TelegramInboundProgrammaticHandlerInput,
|
|
13
|
+
type TelegramInboundProgrammaticHandlerResult,
|
|
14
|
+
} from "../lib/inbound.ts";
|
package/api/keyboard.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram keyboard API
|
|
3
|
+
* Zones: package boundary, companion extension interop
|
|
4
|
+
* Exposes shared inline-keyboard structural types without runtime exports
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type {
|
|
8
|
+
TelegramInlineKeyboardButton,
|
|
9
|
+
TelegramInlineKeyboardMarkup,
|
|
10
|
+
} from "../lib/keyboard.ts";
|
package/api/outbound.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram outbound API
|
|
3
|
+
* Zones: package boundary, companion extension interop
|
|
4
|
+
* Exposes stable outbound handler and diagnostics surfaces while keeping delivery internals package-private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
recordTelegramRuntimeEvent,
|
|
9
|
+
registerTelegramOutboundHandler,
|
|
10
|
+
type TelegramOutboundProgrammaticHandler,
|
|
11
|
+
} from "../lib/outbound.ts";
|
package/api/sections.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram sections API
|
|
3
|
+
* Zones: package boundary, companion extension interop
|
|
4
|
+
* Exposes the stable managed Telegram menu-section surface while keeping registry internals package-private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
getTelegramSectionDiagnostics,
|
|
9
|
+
registerTelegramSection,
|
|
10
|
+
type TelegramSectionCallbackContext,
|
|
11
|
+
type TelegramSectionCallbackResult,
|
|
12
|
+
type TelegramSectionContext,
|
|
13
|
+
type TelegramSectionDiagnostic,
|
|
14
|
+
type TelegramSectionRegistration,
|
|
15
|
+
type TelegramSectionSettingsRegistration,
|
|
16
|
+
type TelegramSectionView,
|
|
17
|
+
} from "../lib/sections.ts";
|
package/api/updates.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram updates API
|
|
3
|
+
* Zones: package boundary, companion extension interop
|
|
4
|
+
* Exposes the stable raw-update handler surface while keeping update routing internals package-private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
registerTelegramUpdateHandler,
|
|
9
|
+
type TelegramUpdateHandler,
|
|
10
|
+
type TelegramUpdateHandlerVerdict,
|
|
11
|
+
} from "../lib/updates.ts";
|
package/api/voice.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram voice API
|
|
3
|
+
* Zones: package boundary, companion extension interop
|
|
4
|
+
* Exposes the stable STT/TTS provider surface and voice policy helpers
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
TELEGRAM_VOICE_REPLY_MODES,
|
|
9
|
+
computeVoicePromptContribution,
|
|
10
|
+
computeVoiceTurnFlags,
|
|
11
|
+
getTelegramVoiceReplyMode,
|
|
12
|
+
getTelegramVoiceSendTranscript,
|
|
13
|
+
isVoiceTurn,
|
|
14
|
+
registerTelegramVoiceSynthesisProvider,
|
|
15
|
+
registerTelegramVoiceTranscriptionProvider,
|
|
16
|
+
shouldSuppressPreviewForVoice,
|
|
17
|
+
type TelegramVoiceReplyMode,
|
|
18
|
+
type TelegramVoiceSynthesisProvider,
|
|
19
|
+
type TelegramVoiceSynthesisProviderResult,
|
|
20
|
+
type TelegramVoiceTranscriptionFile,
|
|
21
|
+
type TelegramVoiceTranscriptionProvider,
|
|
22
|
+
type TelegramVoiceTranscriptionProviderResult,
|
|
23
|
+
type TelegramVoiceTurnView,
|
|
24
|
+
} from "../lib/voice.ts";
|
package/docs/README.md
CHANGED
|
@@ -5,11 +5,13 @@ Living index of project documentation in `/docs`.
|
|
|
5
5
|
## Documents
|
|
6
6
|
|
|
7
7
|
- [architecture.md](./architecture.md) — Overview of the Telegram bridge runtime, queueing model, rendering pipeline, and interactive controls
|
|
8
|
+
- [public-api.md](./public-api.md) — Stable public API map: package entrypoints, commands, config, assistant markup, extension APIs, and compatibility boundaries
|
|
8
9
|
- [command-templates.md](./command-templates.md) — Portable command-template standard core
|
|
9
|
-
- [inbound
|
|
10
|
-
- [outbound
|
|
10
|
+
- [inbound.md](./inbound.md) — Local `pi-telegram` inbound text/media handler bus, programmatic inbound handlers, registered STT provider fallbacks, legacy `attachmentHandlers` compatibility, placeholders, and fallbacks
|
|
11
|
+
- [outbound.md](./outbound.md) — Local `pi-telegram` outbound-handler config, text/voice/button behavior, voice synthesis provider fallback priority, artifact outputs, and callback routing
|
|
12
|
+
- [callback-namespaces.md](./callback-namespaces.md) — Shared Telegram `callback_data` namespace standard for layered extensions
|
|
13
|
+
- [updates.md](./updates.md) — Update classification and runtime handler registry that lets layered extensions observe and consume Telegram updates without owning their own polling connection
|
|
14
|
+
- [sections.md](./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
|
|
11
15
|
- [voice.md](./voice.md) — Voice integration guide: detection, reply policy, STT/TTS provider registration, provider-owned conversion, and transparent interception
|
|
12
16
|
- [locks.md](./locks.md) — Shared `locks.json` standard for singleton extension ownership
|
|
13
|
-
- [
|
|
14
|
-
- [external-handlers.md](./external-handlers.md) — Runtime interceptor registry that lets layered extensions observe and consume Telegram updates without owning their own polling connection
|
|
15
|
-
- [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
|
|
17
|
+
- [ui-style.md](./ui-style.md) — Inline UI style guide for buttons, toggles, tabs, option lists, cards, and dialogs
|