@llblab/pi-telegram 0.24.11 → 0.25.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 CHANGED
@@ -89,6 +89,7 @@ The core product loop is mobile continuation: start or supervise work in the ter
89
89
  - Instance thread names are provisioner-authored identity metadata, not model-authored output. Fresh Threaded Mode threads select one of five curated compact 4-6 letter Latin names for the assigned slot letter using provisioning timestamp entropy, then create the Telegram thread with that thread name immediately. The title is the thread name itself, not `{slot} {threadName}` or `{slot} — {threadName}`. Do not register or reintroduce an agent-facing thread rename tool; removing the extra rename prompt/tool turn is an intentional simplicity constraint. Thread names must mirror into terminal status, live diagnostics, and `[telegram|thread:name]` through one target-aware current-instance identity resolver. Registered follower/leader metadata takes precedence over a stale shared record for the same target, with the record used only as fallback; do not hide a valid baked/custom thread name behind old slot-prefix validation. A follower that later becomes leader keeps its existing name; leadership changes are transport role changes, not identity resets.
90
90
  - Telegram private-chat Threaded Mode treats `All` as an aggregate/control surface, not a durable `General` thread or process launcher, and leader activation proactively creates or reuses its private-DM thread. When the owner writes in an unknown thread, the leader reclaims and routes the first one only if it lacks an active binding; later unknown threads remain intact and receive an in-thread chooser to reroute the captured prompt or restore a stale binding. Destructive cleanup requires explicit confirmation through `thread-reconciler`; another Pi instance still requires a manually started process followed by `/telegram-connect`. Without Threaded Mode, process the message through classic routing.
91
91
  - Telegram extension work should not hold Pi's core agent lifecycle hostage once Pi has produced the semantic result. For Telegram-originated turns, final Telegram delivery, attachment upload, and transport cleanup are extension-owned side effects; schedule them off the critical `agent_end` path when ordering can still be preserved, record failures as runtime events, and keep dispatch of the next Telegram turn behind the delivery task when needed to avoid interleaving previews/finals. Treat a low-level error `agent_end` as retryable while its Telegram turn remains active; only a later successful `agent_end` or Pi's `agent_settled` boundary may finalize and release that turn. Public activity handlers run through isolated asynchronous per-handler queues; lifecycle hooks enqueue normalized events and never await consumer work. Proactive push defaults enabled and requires explicit `assistant.proactivePush: false` to opt out. While enabled, core delivery projects each completed Pi-visible assistant text block from local/autonomous work once and in order; bind admitted blocks to the exact target, profile/token transport stamp, direct leader epoch or follower registration generation, and session generation. Token deltas, hidden reasoning, tool traffic, stale authority, and Telegram-owned turns never enter that projection.
92
+ - The only core reasoning/tool visibility path is the operator-enabled `assistant.activity: "verbose"` projection. It remains separate from proactive public prose and assistant Markdown: provider-exposed reasoning uses draft-only Rich `Thinking`, while completed executed tools use durable ordinary HTML messages with standard expandable blockquotes and never use Rich Messages. Keep it quiet by default, exact-target/transport-generation fenced, start-order preserving, boundary-aware, memory/transport bounded, and non-blocking; final delivery waits for admitted technical activity only inside the extension-owned background task, and session replacement abandons queued old-generation work without waiting on old transport. Read legacy `assistant.activityVerbosity` only when `assistant.activity` is absent and remove it on the next Settings write. Never persist reasoning, invent unavailable provider-private reasoning, or replay a possibly committed technical message.
92
93
  - Telegram runtime state should be treated as event-driven reconciliation of extension assumptions against observable Telegram signals, not as a full Telegram bot read-model and not as a reason to query Telegram on every action. Keep a local assumption model for bot identity/capabilities, pairing assumptions, thread support, known thread lifecycle, bound instance targets, reservations, and transport health. Invalidate and reconcile the relevant slice on meaningful events: startup/reload, lifecycle service messages, stale-send/API errors, setup/pairing changes, follower register/prune, explicit status/debug requests, and bounded low-frequency leader health ticks. `lib/sync.ts` owns sync slices, observation intake, invalidation triggers, status/debug freshness, and reconciliation scheduling; it must not promise complete bot-state mirroring because Bot API lacks a complete topic listing surface. `lib/thread-reconciler.ts` owns pure Threaded Mode lifecycle planning and should become the only policy authority for destructive thread cleanup decisions. `threads` owns current Telegram UI thread/tab binding primitives and thread-name helpers mapped to Bot API topic transport, `status` renders projections, and `index.ts` only wires ports. `tmp/telegram/logs.jsonl` is a session-local redacted runtime evidence stream for race debugging and resets on extension start / runtime scope changes; it is diagnostics only, not routing/provisioning authority. `state.json` should be an observable/debug snapshot aligned with `/telegram-status` (extension runtime, bot capabilities including `bot.lastSlot`, runtime role, live roster projection, reservations, diagnostics), not routing/provisioning authority. Because every process on one Telegram profile shares this file, only the active transport lock owner may persist it; followers read current state and gain write authority only after promotion. Status-only writes must refresh disk-backed bindings before serialization so a stale loaded snapshot cannot erase newer leader state. Live bus/runtime state is authoritative; file reservations and fresh capability observations may be startup hints/collision guards only; stale snapshots must re-probe before suppressing bus/topic behavior. Do not persist stale/offline/failed thread target history as source of truth.
93
94
  - Thread bindings are bidirectional. From the Pi-instance side, an instance knows and preserves its target, slot, thread name, lifecycle state, and direct-delivery defaults. From the Telegram-client/bot side, the bridge observes thread creation/close/reopen/stale-send signals and reconciles them into instance binding state. Lifecycle transitions that affect operator understanding should be Telegram-visible when a live transport remains: every successful follower registration/re-registration gets a compact connected notice in the assigned thread, while heartbeat pruning stays silent because it is only liveness suspicion. These notices should use the instance thread name when known and fall back to the slot letter only while the thread is still unnamed. New unknown or command-created temporary threads receive the complete forward plus replace/restore control set and remain preserved until the user chooses one. Successful forward deletes the chooser and temporary thread; successful replace/restore always deletes the chooser, rebinds the temporary thread, and deletes only the replaced old thread. Any destructive cleanup must go through `thread-reconciler`. Unknown `forum_topic_created` service events are observations, not destructive cleanup proof.
94
95
  - The multi-instance bus uses private bot DMs with Telegram private-chat Threaded Mode enabled for the bot. No supergroup, group, or forum configuration is needed; the thread chat is always the private chat with the paired owner. Threaded capability checks must use bot/private-chat evidence such as `getMe.has_topics_enabled`, incoming `message_thread_id`, and topic operation success/failure; do not use group chat metadata as the control-plane truth for Telegram private-chat Threaded Mode.
@@ -241,7 +242,7 @@ The canonical detailed ownership map lives in [`docs/architecture.md`](./docs/ar
241
242
  - `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
242
243
  - `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
243
244
  - `Shutdown`: call `pi.on("shutdown", () => unregister())` in the extension's default export
244
- - `Section separators`: extension-injected main-menu rows appear before the **⚙️ Settings** row. Extension settings rows appear before built-in Proactive push controls
245
+ - `Section separators`: extension-injected main-menu rows appear before the **⚙️ Settings** row. Inside Settings, keep `⬆️ Main menu` first and group built-ins by operator meaning rather than alphabet: message presentation (`Draft previews`, `Rendering`, `Voice reply`), technical/public activity (`Activity`, `Proactive push`), prompt context (`Time injection`), then lifecycle (`Thread cleanup`). Extension settings follow the built-in groups using their explicit `settings.order`, then section id; detail-submenu choices keep their own semantic order.
245
246
  - `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
246
247
  - `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
247
248
  - `Callback routing order`: button actions → compact confirmations → queue menu → settings menu → section callbacks → built-in menu handling → `[callback]` fallback. Settings menu callbacks always pass `sectionRegistry` to `updateTelegramSettingsMenuMessage` and `handleTelegramSettingsMenuCallbackAction`
package/BACKLOG.md CHANGED
@@ -2,10 +2,31 @@
2
2
 
3
3
  _This backlog tracks only open release-relevant work: hotfixes, bounded maintenance, live runtime verification, evidence-gated Telegram client follow-ups, and upstream Pi API blockers. Completed outcomes and validation evidence belong in `CHANGELOG.md`, not in this queue._
4
4
 
5
+ ## P1 — 0.25.0 Configurable Activity Verbosity
6
+
7
+ Context: Start the next minor release with an operator-controlled Telegram activity surface. Current behavior remains the quiet default: users receive assistant previews, intermediate public prose, and final answers without model reasoning or tool traffic. A new verbose mode should add compact technical reasoning and tool activity without turning bridge-owned UI into Markdown or mixing it into the semantic answer stream.
8
+
9
+ Bot API evidence: Bot API 10.2 exposes explicit outgoing Rich Message blocks. `InputRichBlockThinking` is draft-only and disappears when the draft lifecycle ends; `InputRichBlockDetails` provides a collapsed disclosure container, and `InputRichBlockPreformatted` provides nested `<pre><code>` content. Exact mobile/Desktop rendering, edit behavior, and practical limits remain live-verification gates.
10
+
11
+ Open work:
12
+
13
+ - [x] Add a persisted `Activity` Settings option backed by `assistant.activity`, with exactly two initial values: `quiet` (default/current behavior) and `verbose` (reasoning plus tool activity). Omitted or invalid configuration must resolve to `quiet`; legacy `assistant.activityVerbosity` is read only when the canonical key is absent and removed on the next write. Settings must follow the existing nested list-option UI and callback/persistence concurrency contracts.
14
+ - [x] In `verbose`, stream reasoning content exposed by supported Pi lifecycle events through a short-lived Telegram Rich Draft `Thinking` block bound to the exact chat/thread, profile, session generation, and direct-owner or follower authority. Finalization, cancellation, failure, replacement, and disconnect must clear local draft ownership without creating a persisted reasoning message or projecting unavailable provider-private chain-of-thought.
15
+ - [x] Persist completed tool activity as bridge-owned compact ordinary HTML messages rather than assistant Markdown or Rich Messages. Render each tool call under one registered semantic icon and tool name with bounded, escaped arguments, updates, result, and error evidence inside a standard expandable blockquote.
16
+ - [x] Coalesce consecutive tool calls from one ordered run into the same editable ordinary message while it remains within Telegram HTML message limits, with one independent expandable blockquote per call. Start a new message when the current message cannot safely accept another block; never reorder tools across assistant prose, reasoning boundaries, targets, runs, or lifecycle generations.
17
+ - [x] Define bounded output, redaction, truncation, retry, edit-ambiguity, and transport-failure behavior so verbose mode cannot leak known secrets, flood the target, replay a possibly committed message, block Pi lifecycle completion, or disturb quiet-mode preview/final ordering. Record failures through existing diagnostics.
18
+ - [x] Reconcile the current no-hidden-reasoning invariant and Rich rendering boundary in `AGENTS.md`, then update README, Settings/configuration docs, architecture/outbound docs, public activity guidance, UI emoji registry, and focused config/menu/activity/delivery/rendering/integration regressions.
19
+ - [x] Order first-level `Settings` by operator meaning while keeping `⬆️ Main menu` first: message presentation (`Draft previews`, `Rendering`, `Voice reply`), technical/public activity (`Activity`, `Proactive push`), prompt context (`Time injection`), then lifecycle (`Thread cleanup`). Append extension-provided rows using their explicit `settings.order` and stable section-id tie-break, preserve each detail submenu's semantic option order, and add focused menu/section regressions.
20
+ - [ ] Live-smoke both modes in classic and Threaded Mode on Telegram mobile and Desktop, including multiple sequential tools, oversized output rollover, cancellation during reasoning, tool failure, session replacement, follower transport, and final-answer ordering.
21
+
22
+ Done when: `quiet` remains behaviorally unchanged, `verbose` shows ephemeral reasoning plus durable collapsed tool-call evidence with exact routing and bounded safe output, first-level Settings entries follow the documented semantic groups with deterministic extension ordering, Settings survives reload and concurrent persistence, all automated validation passes, and live clients confirm the intended draft/disclosure UX.
23
+
5
24
  ## P1 — Native Windows Runtime Smoke
6
25
 
7
26
  Context: Deterministic ownership, persistence, recovery, process, and named-pipe coverage passes on native hosted Windows. A live Telegram client remains the only unverified platform boundary and may be exercised in a later release cycle rather than tied to a specific version.
8
27
 
28
+ Latest automated evidence: the `0.24.11` base commit `313b4ee` passed the complete `windows-latest` typecheck, test, and package job on 2026-07-25 ([Actions run 30174521046](https://github.com/llblab/pi-telegram/actions/runs/30174521046)). This proves native hosted-Windows automation, not the operator-driven Telegram/named-pipe smoke below.
29
+
9
30
  Open work:
10
31
 
11
32
  - [ ] Run a current build through native Windows classic and Threaded Mode smoke: connect, ownership handoff, leader/follower registration, stale recovery, live downgrade, diagnostics rotation, and shutdown cleanup. Record concrete named-pipe, atomic-file, and Telegram-client evidence.
@@ -18,7 +39,7 @@ Blocked: upstream Pi core API remains unavailable. Issue #5952 was auto-closed b
18
39
 
19
40
  Context: Threaded Mode manual followers are separate visible Pi processes. Same-thread `/new` is a different feature: replacing the current Pi session inside the same Telegram thread. Extension-only hacks are rejected because they would desynchronize Pi lifecycle/TUI semantics.
20
41
 
21
- Current upstream evidence: Pi 0.80.6 safely exposes `ctx.newSession()` to registered extension commands through `ExtensionCommandContext`, including fresh-context rebinding after replacement. Telegram update and callback handlers still receive only `ExtensionContext`, and extension-origin `pi.sendUserMessage()` deliberately disables slash-command handling. The upstream maintainer described an async extension bridge as potentially possible after the current refactor, but no supported API exists yet.
42
+ Current upstream evidence (reverified 2026-07-28): issue #5952 remains closed as `not planned` by the new-contributor intake automation. The maintainer described an async extension bridge as potentially possible after the current refactor, subsequent users added supporting use cases through 2026-07-12, and no supported API or implementation was posted. The latest published Pi is 0.82.1; its current `main` `ExtensionAPI` still has no `newSession` or session-replacement method, while `ctx.newSession()` remains limited to registered extension commands through `ExtensionCommandContext`, including fresh-context rebinding after replacement. Telegram update and callback handlers receive only `ExtensionContext`, and extension-origin `pi.sendUserMessage()` deliberately disables slash-command handling.
22
43
 
23
44
  Required upstream shape:
24
45
 
package/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## 0.25.0: Configurable Activity
4
+
5
+ - `Activity`: Added a persisted quiet-by-default `assistant.activity` Settings control. Verbose mode streams only provider-exposed reasoning through ephemeral target-fenced Rich Thinking drafts, projects inline Markdown bold/code markers to native Rich Text, and records completed executed tools through memory/transport-bounded ordinary HTML messages with standard expandable blockquotes; tool activity never uses Rich Messages. Tool headers use `🛠 <tool>: <status>` with a monospace `running`, `done`, or `failed` status, while argument, update, result, and error labels sit directly before their serialized values (`arguments: {`, `result: {`) for compact scanning. Settings refreshes always read the live value; legacy `assistant.activityVerbosity` is accepted only when the canonical key is absent and removed on the next write. Consecutive ordered tools coalesce without crossing assistant/reasoning, target, activity, or transport-generation boundaries. Final delivery waits behind admitted technical activity inside the background delivery task, while replacement sessions abandon queued old-generation work immediately. Impact: operators can inspect compact redacted technical activity without stale menu state, mixing it into assistant answers, exposing it by default, replaying ambiguous sends, reordering the final answer, or delaying Pi lifecycle completion.
6
+ - `Settings Ordering`: Grouped first-level built-in Settings by operator meaning while keeping Main menu first and detail choices semantically ordered: message presentation places Draft previews, Rendering, and Voice reply together; activity, prompt-context, and lifecycle controls follow as distinct clusters. Extension settings retain their explicit order and stable section-id tie-break after the built-ins. Impact: related controls stay adjacent instead of forcing users to reconstruct product domains from an alphabetical list.
4
7
 
5
8
  ## 0.24.11: Assistant Action Markup Hotfix
6
9
 
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  It is a **runtime adapter**, not a remote terminal. Start or supervise work in the Pi TUI, then continue from Telegram while away from the keyboard. Each Telegram destination follows a running Pi instance and sends prompts into that instance's currently active session; it is not permanently bound to one session file or session identity. The bridge preserves Pi session semantics instead of pretending Telegram is a PTY, shell, process launcher, or session browser. That boundary is the product: Telegram gets safe runtime handles, not raw terminal power.
10
10
 
11
- Proactive push is enabled by default. `assistant.proactivePush` projects every completed public assistant text block from local or autonomous work—including visible checkpoints and the final answer—to the authorized Telegram target once and in order; set it explicitly to `false` to disable projection. It never mirrors local prompts, hidden reasoning, tool traffic, token deltas, Telegram-owned turns, or stale-generation work. See [Outbound](docs/outbound.md#proactive-public-output) and the [configuration reference](docs/public-api.md#configuration-api).
11
+ Proactive push is enabled by default. `assistant.proactivePush` projects every completed public assistant text block from local or autonomous work—including visible checkpoints and the final answer—to the authorized Telegram target once and in order; set it explicitly to `false` to disable projection. Proactive push itself never mirrors local prompts, reasoning, tool traffic, token deltas, Telegram-owned turns, or stale-generation work. The separate quiet-by-default `Activity` setting can add ephemeral provider-exposed reasoning and bounded collapsed tool evidence. See [Outbound](docs/outbound.md#proactive-public-output) and the [configuration reference](docs/public-api.md#configuration-api).
12
12
 
13
13
  This repository is an actively maintained fork of [`badlogic/pi-telegram`](https://github.com/badlogic/pi-telegram). It started from upstream commit [`cb34008`](https://github.com/badlogic/pi-telegram/commit/cb34008460b6c1ca036d92322f69d87f626be0fc) and has since diverged substantially.
14
14
 
@@ -101,8 +101,9 @@ The first Telegram user to message the bot becomes the allowed owner. Other user
101
101
  | Model and thinking | Switch model or reasoning level from Telegram through safe continuation flows. | Mobile control can adjust execution strategy without tearing down the current session. |
102
102
  | Compaction | Confirm `/compact`, show native active status during compaction, and preserve Telegram-owned turn semantics. | Context maintenance is visible and safe from the phone. |
103
103
  | Draft previews | Show Telegram's native `…typing` indicator whenever the connected instance is doing agent work, or enable Rich Draft previews for streamed answer text. | Local prompts, Telegram turns, and autonomous continuations remain visibly active while draft visibility stays independent from final rendering. |
104
+ | Activity | Keep the default `quiet` answer-only surface, or select `verbose` for short-lived reasoning drafts and durable collapsed tool disclosures. | Technical activity stays bounded, redacted, target-fenced, and visually separate from semantic assistant answers. |
104
105
  | Assistant rendering | Choose Native Rich Markdown or legacy Markdown-to-HTML for final assistant replies. | Renderer compatibility is explicit instead of being conflated with draft previews. |
105
- | Bridge UI rendering | Render tool rows, reasoning/technical steps, menus, queue controls, status, settings, diagnostics, and sections through explicit Telegram HTML/plain UI. | Harness-owned surfaces remain operationally predictable and visually distinct from model-authored answers. |
106
+ | Bridge UI rendering | Render verbose reasoning through a draft-only Rich Thinking block, tool activity through ordinary expandable HTML messages, and menus, queue controls, status, settings, diagnostics, and sections through Telegram HTML/plain UI. | Harness-owned surfaces remain operationally predictable and visually distinct from model-authored answers. |
106
107
  | Inbound files | Download inbound files to the Pi agent temp directory with size limits. | Screenshots, PDFs, datasets, and artifacts enter Pi as inspectable local files. |
107
108
  | Outbound artifacts | Return generated files through `telegram_attach` during active turns or explicit direct delivery. | Agents send real artifacts as files, not pasted blobs. |
108
109
  | Voice input | Route audio through configured command-template handlers, programmatic handlers, or STT providers. | Voice notes become usable prompt context. |
@@ -171,7 +172,7 @@ Messages sent while Pi is busy become queued turns. Priority lanes support contr
171
172
 
172
173
  ### Native Rich Markdown
173
174
 
174
- Rich Markdown is the default model-answer membrane. Complete assistant and guest model replies use Telegram's native Rich Message APIs, while tool-call rows, reasoning/thinking blocks, menus, status rows, queue controls, settings, diagnostics, and other harness-owned surfaces use explicit Telegram HTML/plain rendering. This keeps meaningful model-authored answers visually distinct from bridge-owned operational UI. Two Settings controls keep the layers separate: `Draft previews` toggles live `sendRichMessageDraft` frames, while `Assistant rendering` chooses final-answer delivery (`rich` Native Rich Markdown or `html` legacy Markdown-to-HTML).
175
+ Rich Markdown is the default model-answer membrane. Complete assistant and guest model replies use Telegram's native Rich Message APIs. In `verbose` activity mode, bridge-owned reasoning uses an ephemeral Rich `Thinking` draft while completed tools use ordinary HTML messages with standard expandable blockquotes and never Rich Messages; menus, status rows, queue controls, settings, diagnostics, and other operational UI retain explicit Telegram HTML/plain rendering. Three Settings controls keep the layers separate: `Draft previews` toggles streamed answer drafts, `Activity` chooses `quiet` or `verbose` technical activity, and `Assistant rendering` chooses final-answer delivery (`rich` Native Rich Markdown or `html` legacy Markdown-to-HTML).
175
176
 
176
177
  ### Files And Artifacts
177
178
 
@@ -214,7 +215,7 @@ Most controls live in Pi commands or the Telegram menu. Environment variables re
214
215
  | Inbound file limit | `PI_TELEGRAM_INBOUND_FILE_MAX_BYTES`, `TELEGRAM_MAX_FILE_SIZE_BYTES` |
215
216
  | Outbound attachment limit | `PI_TELEGRAM_OUTBOUND_ATTACHMENT_MAX_BYTES`, `TELEGRAM_MAX_ATTACHMENT_SIZE_BYTES` |
216
217
 
217
- Defaults are chosen for ordinary private-bot use: saved config in `~/.pi/agent`, inbound temp files in `~/.pi/agent/tmp/telegram`, `assistant: { rendering: "rich", draftPreviews: false }` for assistant answer output, and native Telegram active status for long-running turns.
218
+ Defaults are chosen for ordinary private-bot use: saved config in `~/.pi/agent`, inbound temp files in `~/.pi/agent/tmp/telegram`, `assistant: { rendering: "rich", draftPreviews: false, activity: "quiet" }` for assistant output and activity, and native Telegram active status for long-running turns.
218
219
 
219
220
  ## Extension Platform
220
221
 
package/docs/activity.md CHANGED
@@ -180,7 +180,7 @@ Pi provider events use `thinking_*`; the public product term is `reasoning`. The
180
180
 
181
181
  Tool activity uses Pi's executed-tool lifecycle (`tool_execution_start/update/end`), not provider `toolcall_*` payloads. Provider tool-call boundaries are used only to classify preceding assistant prose. This prevents duplicate tool rows and reports actual execution results.
182
182
 
183
- `args`, `update`, and `result` may contain paths, source text, command output, or other sensitive data. They are available to trusted local extension code but must not be rendered wholesale by default. Reference UI should summarize tool name/state and expose bounded details only through explicit policy.
183
+ `args`, `update`, and `result` may contain paths, source text, command output, or other sensitive data. They are available to trusted local extension code but must not be rendered wholesale by default. Core `quiet` mode renders none of them. Explicit `verbose` mode redacts known secret shapes, truncates every evidence field, and places completed tool evidence in ordinary HTML messages with standard expandable blockquotes rather than Rich Messages.
184
184
 
185
185
  ## Delivery Context
186
186
 
@@ -263,12 +263,12 @@ The first implementation has no public Activity diagnostics getter because handl
263
263
 
264
264
  ## Security And Non-Goals
265
265
 
266
- The Activity API does not:
266
+ The Activity API itself does not:
267
267
 
268
268
  - Enable reasoning visibility by default.
269
269
  - Guarantee reasoning availability across providers.
270
270
  - Expose signed/redacted reasoning metadata.
271
- - Render raw tool arguments or results automatically.
271
+ - Render raw tool arguments or results for public handlers automatically. The separate bridge-owned verbose projector renders only bounded redacted evidence after explicit operator opt-in.
272
272
  - Replace assistant final replies or Rich Draft previews.
273
273
  - Mutate queues, models, thinking levels, sessions, or process state.
274
274
  - Expose Telegram clients, bot tokens, Pi contexts, or private runtime objects.
@@ -289,13 +289,15 @@ The implementation must cover:
289
289
  - Handler error isolation, non-blocking lifecycle, shutdown fencing, and redacted diagnostics.
290
290
  - Public package import without `/lib` reach-through.
291
291
 
292
- ## Consumer Policy Pattern
292
+ ## Core Verbosity And Consumer Policy
293
293
 
294
- The registration and delivery examples above provide the complete public building blocks for issue #126-style visibility policy:
294
+ The bridge now owns the minimal global `quiet`/`verbose` policy. Quiet is the default. Verbose streams available reasoning through an ephemeral Rich Thinking draft and emits bounded tool evidence through ordinary HTML expandable blockquotes without changing public assistant-segment projection or final replies.
295
295
 
296
- - Reasoning can default off and send completed `reasoning-end` blocks only when enabled.
296
+ The registration and delivery examples above remain the public building blocks for companion-specific policy:
297
+
298
+ - Companion reasoning must still default off unless its own explicit policy enables it.
297
299
  - Intermediate prose can default off and send only `assistant-segment` events with `placement: "intermediate"`, never the final assistant segment.
298
- - Tool rows can default on, show only tool name/state, and edit generation-bound logical handles from running to done/failed without exposing arguments or results.
300
+ - Companion tool rows should avoid duplicating the core verbose projection and must retain their own generation-bound handles and disclosure policy.
299
301
  - Interactive toggles belong in a registered Section and Settings row; activity messages can remain non-interactive.
300
302
  - `session_shutdown` should dispose stable registrations and drop retained delivery handles, so reload/session replacement cannot reuse old contexts or handles.
301
303
 
@@ -313,7 +313,9 @@ Queue reactions are shortcut controls for waiting turns. Promotion reactions (`
313
313
 
314
314
  `/telegram-status` records grouped diagnostics for transport/API, polling/update, prompt dispatch, controls, typing, compaction, setup, session lifecycle, attachment queue/delivery, and recent redacted runtime events. Expected preview noise such as unchanged edit responses is filtered out. The compact TUI status renders only `error`; detailed failure text remains in diagnostics and profile-scoped logs instead of expanding the status line.
315
315
 
316
- When `assistant.proactivePush` is enabled and this instance has exact direct or follower transport authority, completed public assistant text blocks from local/autonomous work are sent once and in source order to the instance's authorized target. Visible commentary/checkpoints and the final block use the configured Rich or HTML renderer. Hidden reasoning, tool traffic, token deltas, local prompt text, Telegram-owned turns, and stale generations are not mirrored. Each admitted block remains fenced to its exact target, profile/token stamp, leader epoch or follower registration generation, and session generation; non-idempotent acknowledgement ambiguity never authorizes replay.
316
+ When `assistant.proactivePush` is enabled and this instance has exact direct or follower transport authority, completed public assistant text blocks from local/autonomous work are sent once and in source order to the instance's authorized target. Visible commentary/checkpoints and the final block use the configured Rich or HTML renderer. Proactive projection excludes reasoning, tool traffic, token deltas, local prompt text, Telegram-owned turns, and stale generations. Each admitted block remains fenced to its exact target, profile/token stamp, leader epoch or follower registration generation, and session generation; non-idempotent acknowledgement ambiguity never authorizes replay.
317
+
318
+ `assistant.activity` is an independent bridge-owned projection over normalized Activity events. Omitted or invalid values resolve to `quiet`, which emits no reasoning or tool traffic. `verbose` uses bounded ephemeral Rich Thinking drafts for provider-exposed reasoning and ordinary HTML messages with standard expandable blockquotes for completed executed tools; tool output never uses Rich Messages. It captures the exact target and transport stamp at activity admission, serializes updates, preserves tool-start order, closes coalescing across assistant/reasoning boundaries, redacts and truncates evidence, bounds retained reasoning/update memory plus draft frames and message/tool size, and never replays a possibly committed send. Session generations own independent queues, so replacement drops queued old work without waiting on an old call. Both proactive prose and active-turn final delivery wait for the admitted activity queue inside their extension-owned delivery tasks, preserving technical-before-semantic ordering without delaying Pi lifecycle completion. Settlement, replacement, disconnect, failure, or stale authority clears local ownership without persisting reasoning.
317
319
 
318
320
  Telegram prompt guidance is context- and authority-aware. Only an exact direct owner or live registered follower exposes the three pi-telegram model tools, their active-tool metadata, and the compact local bridge suffix. Disconnect or authority loss removes those surfaces for subsequent requests without touching foreign tools; reconnect/recovery restores only the pi-telegram subset that was active before suspension, including across same-process reload. Telegram-originated turns receive a compact pointer to `telegram_help` plus dynamic prompt blocks such as `[voice] delivery: automatic voice`; full voice/button/direct-delivery/Threaded Mode syntax stays in the help tool rather than every system prompt.
319
321
 
@@ -184,14 +184,17 @@ Native Windows support should not require WSL. The baseline transport uses Windo
184
184
 
185
185
  Manual smoke checklist:
186
186
 
187
- 1. Enable Telegram private-chat Threaded Mode for the paired bot.
188
- 2. Start Pi in one Windows terminal and run `/telegram-connect`; verify it becomes the leader and gets a named Telegram thread.
189
- 3. Start Pi in a second Windows terminal and run `/telegram-connect`; verify it registers as follower rather than offering takeover, creates/uses its assigned thread, terminal status shows `<ThreadName> Follower` while idle, and a follower prompt flips it to `<ThreadName> Active` while work is running.
190
- 4. From the follower thread, send a prompt that requests inline buttons; tap a button and verify the follow-up prompt queues in the follower instance.
191
- 5. From the follower thread, request a voice reply and/or attachment; verify upload routes through the leader transport into the follower thread.
192
- 6. With `🧹 Thread cleanup` enabled (default), quit the follower Pi normally without an explicit disconnect; verify graceful shutdown deletes its current tab through the leader before local suspension. Repeat with a double `Ctrl+C`; if Pi misses the graceful envelope, verify stale-heartbeat recovery deletes the same exact tab only after the OS confirms that follower PID has exited. Disable the setting, quit another follower normally or abruptly, and verify its tab remains as a restart hint. Reconnect, run `/telegram-disconnect`, confirm the prompt, and verify the leader confirms deletion before local polling stops.
193
- 7. With `🧹 Thread cleanup` enabled, quit the leader normally and verify it deletes only its own tab before releasing transport; a remaining follower may then promote without recreating the deleted leader tab. If deletion is interrupted after intent persistence, start or promote a successor and verify it completes the exact pending cleanup before publishing its follower endpoint or provisioning its own tab; a current replacement binding must instead cancel the superseded cleanup without calling Telegram deletion APIs.
194
- 8. Reload the leader and verify status/debug output does not expose raw pipe internals except in explicit diagnostics.
187
+ 1. With Threaded Mode disabled, connect one Pi, attempt a second classic connection, confirm the ownership-handoff prompt, complete takeover, and verify the displaced process loses Bot API mutation authority without losing accepted local queue state.
188
+ 2. Stop all owners, corrupt only a disposable `owners.json`/state snapshot, reconnect, and verify guarded stale recovery quarantines the damaged file while preserving `telegram.json`; inspect the replacement snapshots to confirm complete atomic JSON rather than partial writes.
189
+ 3. Enable Telegram private-chat Threaded Mode for the paired bot.
190
+ 4. Start Pi in one Windows terminal and run `/telegram-connect`; verify it becomes the leader, gets a named Telegram thread, and publishes a native `\\.\pipe\...` endpoint in explicit diagnostics.
191
+ 5. Start Pi in a second Windows terminal and run `/telegram-connect`; verify it registers as follower rather than offering takeover, creates/uses its assigned thread, terminal status shows `<ThreadName> Follower` while idle, and a follower prompt flips it to `<ThreadName> Active` while work is running.
192
+ 6. From the follower thread, send a prompt that requests inline buttons; tap a button and verify the follow-up prompt queues in the follower instance.
193
+ 7. From the follower thread, request a voice reply and/or attachment; verify upload routes through the leader transport into the follower thread.
194
+ 8. Force a live Threaded Mode capability downgrade and verify the current leader keeps classic polling while followers disconnect instead of attempting takeover; restore capability and reconnect explicitly.
195
+ 9. With `🧹 Thread cleanup` enabled (default), quit the follower Pi normally without an explicit disconnect; verify graceful shutdown deletes its current tab through the leader before local suspension. Repeat with a double `Ctrl+C`; if Pi misses the graceful envelope, verify stale-heartbeat recovery deletes the same exact tab only after the OS confirms that follower PID has exited. Disable the setting, quit another follower normally or abruptly, and verify its tab remains as a restart hint. Reconnect, run `/telegram-disconnect`, confirm the prompt, and verify the leader confirms deletion before local polling stops.
196
+ 10. With `🧹 Thread cleanup` enabled, quit the leader normally and verify it deletes only its own tab before releasing transport; a remaining follower may then promote without recreating the deleted leader tab. If deletion is interrupted after intent persistence, start or promote a successor and verify it completes the exact pending cleanup before publishing its follower endpoint or provisioning its own tab; a current replacement binding must instead cancel the superseded cleanup without calling Telegram deletion APIs.
197
+ 11. Generate enough diagnostics to cross the rotation threshold, reload the leader, and verify `logs.jsonl`/`logs._prev.jsonl` preserve complete ordered records. Confirm ordinary status hides raw pipe internals while explicit debug diagnostics show the active `pipe` endpoint and classified request failures.
195
198
 
196
199
  If any step fails, capture `telegram-status --debug`, `tmp/telegram/state.json`, `tmp/telegram/logs.jsonl`, and, after a reload, `tmp/telegram/logs._prev.jsonl`. Debug status prints local leader/follower endpoints with their active transport kind (`pipe` or `socket`), while the runtime log records request-scoped transport failures with envelope kind, request id, retry attempt, endpoint, and classified IPC error. Reloads preserve the prior JSONL log as `logs._prev.jsonl` so the evidence that caused the reload is not immediately overwritten.
197
200
 
package/docs/outbound.md CHANGED
@@ -12,6 +12,28 @@ Proactive projection defaults on. With `assistant.proactivePush` omitted or set
12
12
 
13
13
  Proactive blocks use `assistant.rendering` independently of voice policy. Rich mode sends native Rich Markdown and HTML mode keeps the established HTML renderer; proactive projection does not synthesize voice or attach queued files merely because Rich rendering is active. The queue revalidates exact target, profile/token transport generation, leader epoch or follower registration generation, and session generation before each send. Telegram-owned turns remain on their ordinary reply path, and `commit-unknown` never permits proactive replay.
14
14
 
15
+ ## Verbose Technical Activity
16
+
17
+ `assistant.activity` defaults to `quiet`. In `verbose`, the bridge consumes the same normalized Activity stream without mixing technical UI into assistant Markdown:
18
+
19
+ - Provider-exposed reasoning deltas update a bounded ephemeral `sendRichMessageDraft` containing one `Thinking` block. Inline Markdown bold and code markers are projected to native Rich Text so their delimiters do not appear literally; unmatched streaming delimiters remain plain text until a later complete draft. The draft is fenced to its captured chat/thread and transport generation; settlement, cancellation, replacement, disconnect, or authority loss drops local ownership. It is never converted into a persisted reasoning message, and providers that expose no reasoning produce none.
20
+ - Completed executed tools use ordinary `sendMessage` HTML, never `sendRichMessage`. Each tool header renders as `🛠 <tool>: <status>`, with a stable two-space visual gap after the icon and the `running`, `done`, or `failed` status in monospace. One standard Telegram `<blockquote expandable>` then contains bounded redacted evidence in chronological order. Labels share a line with their serialized value opening, for example `arguments: {`, `update 1: {`, and `result: {` or `error: {`.
21
+ - Consecutive tools coalesce by editing one message only while target, activity, generation, ordering boundary, tool count, and serialized-size bounds still match. Assistant or reasoning content closes the batch. A non-idempotent send with unknown commit state is never replayed; failed or ambiguous edits start no fallback send.
22
+
23
+ Reasoning retains only a bounded latest-text window, tool updates retain only a bounded latest-entry window, and a session reset abandons queued old-generation work without making the replacement session wait for an old transport call. Final-answer delivery waits for the admitted verbose activity queue inside the extension-owned background delivery task, so completed tool evidence cannot be overtaken by the semantic answer and Pi lifecycle completion remains non-blocking.
24
+
25
+ Verbose activity is operational evidence, not part of the semantic answer stream. Final-answer rendering, voice policy, artifacts, and quiet behavior remain unchanged.
26
+
27
+ ### Live Activity Smoke
28
+
29
+ Exercise one classic chat and one Threaded Mode follower target on both Telegram mobile and Desktop:
30
+
31
+ 1. Leave `Activity` on `quiet`; run a reasoning-capable request with two tools and confirm only normal preview/public/final output appears in established order.
32
+ 2. Switch to `verbose`; confirm reasoning appears only as a temporary Thinking draft, two sequential tools become two independently collapsed disclosures in one message, and the final answer follows the completed tool UI.
33
+ 3. Produce oversized arguments, multiple updates, and oversized result/error output; confirm redaction/truncation markers, latest-update retention, and safe rollover to another message without flood or reordering.
34
+ 4. Cancel during reasoning, fail a tool, replace the Pi session, and disconnect/reconnect transport; confirm reasoning never persists, stale activity does not cross generations, failure remains collapsed technical evidence, and subsequent work uses only the current target/authority.
35
+ 5. Repeat through a registered follower and confirm every draft/send/edit stays in its assigned thread. Capture client/version, mode, target role, observed block behavior, and any Bot API/runtime diagnostic for each result.
36
+
15
37
  ## Standard
16
38
 
17
39
  An outbound handler is selected by `type`. Text replies and assistant markup map to handler types:
@@ -32,7 +54,7 @@ The optimization is deliberately narrow. HTML rendering, empty final text, multi
32
54
 
33
55
  This behavior does not generate media or alter voice policy. `telegram_attach` still represents an explicit assistant artifact decision, while `hidden`, `mirror`, and `always` continue to decide voice synthesis independently.
34
56
 
35
- Core assistant output accepts only the Markdown or HTML `InputRichMessage` forms and does not construct explicit block arrays or `InputRichBlockThinking`. Telegram's Thinking block is draft-only and must never become a projection of hidden reasoning or chain-of-thought. Any future use for Activity would require an explicitly public user-visible summary rather than provider reasoning content.
57
+ Core assistant output accepts only the Markdown or HTML `InputRichMessage` forms. `InputRichBlockThinking` is reserved for ephemeral verbose reasoning drafts; durable tool evidence uses ordinary HTML messages and never Rich Message blocks. Reasoning drafts consume only lifecycle content actually exposed by the active provider and never synthesize unavailable private reasoning.
36
58
 
37
59
  ### Guest Mode media boundary
38
60
 
@@ -95,6 +95,7 @@ interface TelegramConfig {
95
95
  draftPreviews?: boolean;
96
96
  rendering?: "rich" | "html";
97
97
  proactivePush?: boolean;
98
+ activity?: "quiet" | "verbose";
98
99
  };
99
100
  voice?: {
100
101
  replyMode?: "hidden" | "mirror" | "always";
@@ -118,6 +119,7 @@ Hidden/default semantics are represented by absence:
118
119
 
119
120
  - `threads.automaticCleanup` defaults to `true`; graceful Pi quit deletes the instance's bound Threaded Mode tab without prompting. Set it to `false`, or use `🧹 Thread cleanup` in Telegram Settings, to preserve the tab as a restart hint. Settings views and cleanup reload shared config before evaluating this switch, so another live Pi instance's update takes effect without restarting. Confirmed leader/follower teardown persists an exact target/runtime-generation cleanup intent before Telegram deletion; an interrupted attempt remains retryable by the current or successor leader under current authority and clears only after confirmed deletion. If a follower's graceful envelope is missed, the leader may create the same fenced cleanup only after its heartbeat is stale, the OS confirms the exact registered PID no longer exists, cleanup remains enabled, and no replacement registration can overtake deletion. Heartbeat loss alone, live/unknown process liveness, IPC failure, and auth failure remain non-destructive. Invalid-config recovery makes the setting unresolved and therefore skips destructive cleanup. Manual `/telegram-disconnect` keeps its confirmation and teardown behavior regardless of this setting.
120
121
  - `assistant.proactivePush` defaults to `true`; omit it to keep projection enabled, or set it explicitly to `false` to disable it. When enabled, each completed public assistant text block from local or autonomous work is projected to the authorized Telegram target once and in source order. This includes visible intermediate commentary/checkpoints and the final block. It excludes token deltas, hidden reasoning, tool calls/arguments/results, Telegram-owned turns, empty blocks, and stale authority. Projection uses the configured Rich or HTML assistant renderer and binds admitted work to the exact target, profile/token transport generation, direct leader epoch or follower registration generation, and session generation. The old top-level `proactivePush` key is ignored; move the setting manually under `assistant`.
122
+ - `assistant.activity` accepts exactly `"quiet"` or `"verbose"` and resolves omitted or invalid values to `"quiet"`. Quiet preserves the answer-only behavior. Verbose adds provider-exposed reasoning as an ephemeral target-bound Rich `Thinking` draft. Completed tool activity uses ordinary HTML `sendMessage`/`editMessageText`, with each tool represented by a standard expandable blockquote containing bounded redacted arguments, retained updates, results, and errors; tool output never uses Rich Messages. Consecutive tools coalesce only inside the same ordered activity segment and bounded message. Legacy `assistant.activityVerbosity` is read only when `assistant.activity` is absent and is removed by the next Activity Settings write.
121
123
  - Voice Reply `hidden`: no `voice.replyMode` key is persisted; legacy `manual` resolves to this silent default. `mirror` adds `[voice] delivery: automatic voice` only to voice/audio-input turns, while `always` adds the same effective line to every Telegram turn.
122
124
  - Agent activity status is not configurable in this release. Telegram uses native `sendChatAction(typing)` / product `...active` status as the only automatic in-chat work signal before the final reply.
123
125
  - Time Injection `hidden`: no `time.injectionMode` key is persisted; if `time` becomes empty, the whole `time` object may be omitted.
package/docs/sections.md CHANGED
@@ -163,7 +163,7 @@ Built-in core rows keep priority. Section errors do not break menu rendering —
163
163
 
164
164
  ### Settings submenu
165
165
 
166
- Extensions with a `settings` block inject rows **before built-in Proactive push**. The `getLabel()` function (if present) is called on every render to produce a dynamic label — use it for status indicators:
166
+ Extensions with a `settings` block follow the semantically grouped built-in settings. The `getLabel()` function (if present) is called on every render to produce a dynamic label — use it for status indicators:
167
167
 
168
168
  ```ts
169
169
  getLabel: () => `${flag ? "🟢" : "⚫️"} Demo settings`;
@@ -171,11 +171,12 @@ getLabel: () => `${flag ? "🟢" : "⚫️"} Demo settings`;
171
171
 
172
172
  ```
173
173
  ⬆️ Main menu
174
+ 📝 Draft previews: on
175
+ 🧾 Rendering: rich
174
176
  🟢 Demo settings ← extension settings (dynamic label)
175
- 🟢 Proactive push
176
177
  ```
177
178
 
178
- Ordered by `settings.order` (lower first), then `id` alphabetically.
179
+ The final Settings menu keeps `⬆️ Main menu` first, then groups built-ins by operator meaning: message presentation, technical/public activity, prompt context, and lifecycle. Extension rows follow those groups and retain their explicit `settings.order` (lower first), then section id as a stable tie-break. Detail-submenu choices keep their own semantic order.
179
180
 
180
181
  ## 7. Callback Routing
181
182
 
package/docs/ui-style.md CHANGED
@@ -33,6 +33,8 @@ Use emoji as stable semantic markers, not decoration. Emoji carry transportable
33
33
  | `👄` | Voice reply policy | Voice reply settings row and detail card | Not a generic audio attachment marker. |
34
34
  | `🕒` | Time injection / wall-clock context | Time injection settings row and detail card | Clock-face marker with hands; not a generic duration/progress marker. |
35
35
  | `📌` | Proactive push / pinned behavior | Proactive push settings row and detail card | Not generic active/selected state. |
36
+ | `🔬` | Activity / technical detail | Activity settings row and detail card | Chooses quiet versus verbose bridge activity; not a generic diagnostics marker. |
37
+ | `🛠` | Executed tool activity | Collapsed verbose tool disclosure summaries | One marker per tool summary; tool result state remains text (`done`/`failed`). |
36
38
  | `📎` | Attachment | Attachment summaries, queue rows for attachment-only turns | Not for thread binding. |
37
39
 
38
40
  ### Command And Control Actions
package/index.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import * as Activity from "./lib/activity.ts";
8
+ import * as ActivityVerbosity from "./lib/activity-verbosity.ts";
8
9
  import * as Bindings from "./lib/bindings.ts";
9
10
  import * as BusApi from "./lib/bus-api.ts";
10
11
  import * as BusFollower from "./lib/bus-follower.ts";
@@ -470,6 +471,9 @@ export default function (pi: Pi.ExtensionAPI) {
470
471
  getHandlers: configStore.getOutboundHandlers,
471
472
  recordRuntimeEvent,
472
473
  });
474
+ let activityVerbosityRuntime:
475
+ | ActivityVerbosity.TelegramActivityVerbosityRuntime
476
+ | undefined;
473
477
  const assistantOutputBindingRuntime =
474
478
  Bindings.createTelegramAssistantOutputBindingRuntime({
475
479
  isEnabled: configControls.isProactivePushEnabled,
@@ -494,12 +498,40 @@ export default function (pi: Pi.ExtensionAPI) {
494
498
  getHandlers: configStore.getOutboundHandlers,
495
499
  recordRuntimeEvent,
496
500
  },
501
+ waitForActivityIdle() {
502
+ return activityVerbosityRuntime?.waitForIdle() ?? Promise.resolve();
503
+ },
497
504
  recordRuntimeEvent,
498
505
  });
499
506
  const assistantOutputRuntime = assistantOutputBindingRuntime.runtime;
507
+ activityVerbosityRuntime =
508
+ ActivityVerbosity.createTelegramActivityVerbosityRuntime({
509
+ isVerbose() {
510
+ return configControls.getActivityVerbosity() === "verbose";
511
+ },
512
+ resolveTarget(event) {
513
+ return event.target ?? proactivePushTargetGetter();
514
+ },
515
+ captureAuthority: assistantOutputBindingRuntime.authority.captureAuthority,
516
+ isAuthorityActive:
517
+ assistantOutputBindingRuntime.authority.isAuthorityActive,
518
+ sendMessage,
519
+ sendRichMessageDraft,
520
+ editMessageText: editTelegramMessageText,
521
+ recordFailure(operation, event, error) {
522
+ recordRuntimeEvent("activity", error, {
523
+ operation,
524
+ eventType: event.type,
525
+ activityId: event.activityId,
526
+ });
527
+ },
528
+ });
500
529
  const activityRuntime = Activity.createTelegramActivityBridgeRuntime({
501
530
  generation: deliveryGenerationSeed,
502
- observeEvent: assistantOutputBindingRuntime.observeEvent,
531
+ observeEvent(event) {
532
+ assistantOutputBindingRuntime.observeEvent(event);
533
+ activityVerbosityRuntime.accept(event);
534
+ },
503
535
  recordFailure(handlerId, event, error) {
504
536
  recordRuntimeEvent("activity", error, {
505
537
  handlerId,
@@ -1054,6 +1086,7 @@ export default function (pi: Pi.ExtensionAPI) {
1054
1086
  },
1055
1087
  onTransportChanged() {
1056
1088
  deliveryLifecycleRuntime.onSessionStart();
1089
+ activityVerbosityRuntime.reset();
1057
1090
  modelContextAvailabilityRuntime.reconcile();
1058
1091
  },
1059
1092
  getStatusLines,
@@ -1081,6 +1114,7 @@ export default function (pi: Pi.ExtensionAPI) {
1081
1114
  onModelSelect: currentModelRuntime.onModelSelect,
1082
1115
  },
1083
1116
  activityRuntime,
1117
+ activityVerbosityRuntime,
1084
1118
  assistantOutputRuntime,
1085
1119
  configStore,
1086
1120
  abort,