Skip to content

Commit d4774b9

Browse files
committed
0.19.1: settings layer hotfix
1 parent 857e3c2 commit d4774b9

13 files changed

Lines changed: 247 additions & 57 deletions

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 0.19.1: Settings Layer Hotfix
4+
5+
- `[Settings]` Split the overloaded Rich Draft setting into two independent controls: `Draft previews` for live `sendRichMessageDraft` streaming and `Assistant rendering` for final-answer delivery mode. Impact: operators can hide/show in-progress drafts without changing how final Markdown is rendered.
6+
- `[Rendering]` Added persisted `assistantRendering: "rich" | "html"`, defaulting to Native Rich Markdown and allowing legacy Markdown-to-HTML final assistant replies when selected. Impact: renderer compatibility is explicit instead of being conflated with preview visibility.
7+
- `[Preview]` Kept `richDraftPreviews` as the stored draft-preview flag for compatibility, but renamed the Settings UI to `Draft previews`. Impact: existing configs keep working while the product vocabulary matches the Bot API layer.
8+
- `[Validation]` Updated menu/settings/reply regressions for the two-axis configuration model.
9+
310
## 0.19.0: Telegram Companion Hub
411

512
- `[Context]` Defined Rich Markdown as the model-answer membrane: complete assistant/guest model replies use native Rich Message delivery, while tool rows, reasoning/thinking blocks, menus, status, queue controls, settings, diagnostics, and other harness-owned surfaces stay on explicit Telegram HTML/plain rendering.

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ The first Telegram user to message the bot becomes the allowed owner. Other user
9393
| Prompt templates | Run Pi prompt templates as Telegram-safe commands such as `/fix_tests`. | Reusable local workflows become phone-accessible without exposing arbitrary terminal commands. |
9494
| 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. |
9595
| Compaction | Confirm `/compact`, show native active status during compaction, and preserve Telegram-owned turn semantics. | Context maintenance is visible and safe from the phone. |
96-
| Streaming previews | Show native active status and, when enabled, Rich Markdown drafts while the agent is still working. | The operator can see progress without making draft rendering the baseline. |
97-
| Final Rich Markdown | Deliver complete assistant/guest model replies through Telegram Rich Message APIs with safe splitting. | Meaningful model answers stay readable on narrow mobile screens without forcing generic HTML conversion. |
96+
| Draft previews | Show native active status by default, or enable Telegram Rich Draft previews while the agent is still working. | The operator can hide/show in-progress text independently from final rendering. |
97+
| 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. |
9898
| 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. |
9999
| 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. |
100100
| Outbound artifacts | Return generated files through `telegram_attach` during active turns or explicit direct delivery. | Agents send real artifacts as files, not pasted blobs. |
@@ -160,7 +160,7 @@ Messages sent while Pi is busy become queued turns. Priority lanes support contr
160160

161161
### Native Rich Markdown
162162

163-
Rich Markdown is the 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. Streaming previews may use rich-message drafts when enabled; final replies persist through `sendRichMessage`.
163+
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).
164164

165165
### Files And Artifacts
166166

@@ -202,7 +202,7 @@ Most controls live in Pi commands or the Telegram menu. Environment variables re
202202
| Inbound file limit | `PI_TELEGRAM_INBOUND_FILE_MAX_BYTES`, `TELEGRAM_MAX_FILE_SIZE_BYTES` |
203203
| Outbound attachment limit | `PI_TELEGRAM_OUTBOUND_ATTACHMENT_MAX_BYTES`, `TELEGRAM_MAX_ATTACHMENT_SIZE_BYTES` |
204204

205-
Defaults are chosen for ordinary private-bot use: saved config in `~/.pi/agent`, inbound temp files in `~/.pi/agent/tmp/telegram`, native Rich Markdown replies, and native Telegram active status for long-running turns.
205+
Defaults are chosen for ordinary private-bot use: saved config in `~/.pi/agent`, inbound temp files in `~/.pi/agent/tmp/telegram`, `assistantRendering: "rich"` for final replies, `richDraftPreviews: false` for no live draft text by default, and native Telegram active status for long-running turns.
206206

207207
## Extension Platform
208208

docs/architecture.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,15 +223,15 @@ During active Telegram-owned turns, assistant message start/update hooks re-arm
223223

224224
### Rendering And Delivery
225225

226-
Rich Markdown is the model-answer membrane. Complete assistant replies send final Markdown directly as `InputRichMessage.markdown` through `sendRichMessage`, and guest replies use native Rich Markdown through `InputRichMessageContent` in `answerGuestQuery` results. Tool-call rows, reasoning/thinking blocks, menus, status rows, queue controls, settings, diagnostics, and other harness-owned surfaces stay on explicit Telegram HTML/plain rendering. Streaming previews may use `sendRichMessageDraft` when enabled and when draft delivery succeeds. The bridge still strips top-level assistant action comments before delivery and may split output only for Telegram transport limits.
226+
Rich Markdown is the default model-answer membrane. Complete assistant replies send final Markdown directly as `InputRichMessage.markdown` through `sendRichMessage` when `assistantRendering` is `rich`, and through the legacy Markdown-to-HTML renderer when `assistantRendering` is `html`; guest replies use native Rich Markdown through `InputRichMessageContent` in `answerGuestQuery` results. Tool-call rows, reasoning/thinking blocks, menus, status rows, queue controls, settings, diagnostics, and other harness-owned surfaces stay on explicit Telegram HTML/plain rendering. Streaming previews may use `sendRichMessageDraft` only when Draft previews are enabled and draft delivery succeeds. The bridge still strips top-level assistant action comments before delivery and may split output only for Telegram transport limits.
227227

228228
Assistant delivery guarantees:
229229

230-
- Model-authored Markdown is the source of truth; the bridge does not pre-render assistant Markdown to HTML.
230+
- Model-authored Markdown is the source of truth; the bridge does not pre-render assistant Markdown to HTML unless the operator selects `assistantRendering: "html"` for compatibility.
231231
- Before native Rich Markdown delivery, the bridge normalizes known Bot-API-fragile source forms without changing visible meaning, including space-after-marker blockquotes and dollar-prefixed ticker atoms that Telegram may otherwise treat as unterminated math.
232232
- Quoted rich replies use Telegram `rich_message` blocks as the prompt-context source when available, so `[reply]` context receives rendered plain text instead of raw `InputRichMessage.markdown` fallback text.
233233
- Long native Markdown replies are split only at Telegram Rich Message transport limits; oversized fenced code, display-math, and fully wrapped inline-formatting blocks are rewrapped per chunk so persisted Rich Markdown chunks remain structurally valid.
234-
- When enabled, streaming previews pass structurally closed assistant Markdown prefixes through to `sendRichMessageDraft` with ownership checks, voice suppression, and serialized flushes. Unclosed inline spans, links, fenced code, comments, and display-math blocks are held back until a safe boundary exists. Draft failures are recorded and the failing frame is skipped instead of degrading to raw plain-message previews, because partial Markdown can be invalid while the final message remains valid.
234+
- When Draft previews are enabled, streaming previews pass structurally closed assistant Markdown prefixes through to `sendRichMessageDraft` with ownership checks, voice suppression, and serialized flushes. Unclosed inline spans, links, fenced code, comments, and display-math blocks are held back until a safe boundary exists. Draft failures are recorded and the failing frame is skipped instead of degrading to raw plain-message previews, because partial Markdown can be invalid while the final message remains valid.
235235
- Preview flushes are serialized so older edits cannot race newer drafts; final delivery waits for active draft flushes and does not perform a post-final draft-clear call.
236236

237237
UI/compat rendering guarantees:

index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ export default function (pi: Pi.ExtensionAPI) {
443443
},
444444
sendMessage,
445445
sendRichMessage,
446+
getAssistantRenderingMode: configControls.getAssistantRenderingMode,
446447
editMessage: editTelegramMessageText,
447448
});
448449
const { replyTransport, editInteractiveMessage, sendInteractiveMessage } =

lib/config.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export interface ResolvedTelegramTimeConfig {
4747
timezone: string;
4848
}
4949

50+
export type TelegramAssistantRenderingMode = "rich" | "html";
51+
5052
export interface TelegramConfig {
5153
botToken?: string;
5254
botUsername?: string;
@@ -58,6 +60,7 @@ export interface TelegramConfig {
5860
outboundHandlers?: TelegramOutboundHandlerConfig[];
5961
proactivePush?: boolean;
6062
richDraftPreviews?: boolean;
63+
assistantRendering?: TelegramAssistantRenderingMode;
6164
voice?: {
6265
replyMode?: "manual" | "mirror" | "always";
6366
/** Whether to attach the provider's transcriptText as caption on voice messages */
@@ -277,6 +280,26 @@ export function createTelegramRichDraftPreviewsSetter(
277280
};
278281
}
279282

283+
export function createTelegramAssistantRenderingModeGetter(
284+
configStore: Pick<TelegramConfigStore, "get">,
285+
): () => TelegramAssistantRenderingMode {
286+
return () => {
287+
const mode = configStore.get().assistantRendering;
288+
return mode === "html" ? "html" : "rich";
289+
};
290+
}
291+
292+
export function createTelegramAssistantRenderingModeSetter(
293+
configStore: TelegramMutableConfigStore,
294+
): (mode: TelegramAssistantRenderingMode) => Promise<void> {
295+
return async (mode) => {
296+
await loadLatestTelegramConfig(configStore);
297+
const config = { ...configStore.get(), assistantRendering: mode };
298+
configStore.set(config);
299+
await configStore.persist(config);
300+
};
301+
}
302+
280303
export function createTelegramVoiceReplyModeGetter(
281304
configStore: Pick<TelegramConfigStore, "get">,
282305
): () => "manual" | "mirror" | "always" {
@@ -416,6 +439,10 @@ export function createTelegramConfigControls(
416439
createTelegramRichDraftPreviewsChecker(configStore),
417440
setRichDraftPreviewsEnabled:
418441
createTelegramRichDraftPreviewsSetter(configStore),
442+
getAssistantRenderingMode:
443+
createTelegramAssistantRenderingModeGetter(configStore),
444+
setAssistantRenderingMode:
445+
createTelegramAssistantRenderingModeSetter(configStore),
419446
getVoiceReplyMode: createTelegramVoiceReplyModeGetter(configStore),
420447
isVoiceReplyModeConfigured:
421448
createTelegramVoiceReplyModeConfiguredChecker(configStore),

0 commit comments

Comments
 (0)