@llblab/pi-telegram 0.45.3 → 0.45.4
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/CHANGELOG.md +4 -0
- package/docs/outbound.md +1 -1
- package/lib/preview.ts +20 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.45.4: Draft Cadence Hotfix
|
|
8
|
+
|
|
9
|
+
- `Draft Cadence`: Each preview segment now holds its first frame for one full two-second interval from its first visible text, so the opening draft is an accumulated passage instead of a single streamed word. Later frames keep the trailing cadence, message/turn rollover preserves the remaining interval and reopens the window, and sealing or final publication still cancels the pending timer; first frames no longer ship immediately.
|
|
10
|
+
|
|
7
11
|
## 0.45.3: Thread Display Names Hotfix
|
|
8
12
|
|
|
9
13
|
- `Thread Display Names`: Settings again offers the dictionary naming mode as the second chooser between Letters and Directories. Names shows each Workspace's generated slot-letter palette word, such as `Anchor` for slot `A`; switching renames live tabs and fresh tabs start under the active projection. `profiles.<name>.threadDisplayMode` persists all three values, absent or invalid ones resolve to Letters, and Names works with legacy followers that predate `thread-display-mode-v1`.
|
package/docs/outbound.md
CHANGED
|
@@ -16,7 +16,7 @@ Projected blocks use `assistant.rendering` independently of voice policy. Rich m
|
|
|
16
16
|
|
|
17
17
|
Assistant-message completion seals its preview state: queued follow-up drafts and late updates are suppressed. Native final delivery still waits for the already-issued draft request before sending the permanent answer, so an older draft is not deliberately allowed to overtake the final. Intermediate publication seals and drains its captured preview before sending permanent text. Preview rollover itself sends no permanent message: it carries the preceding delivery boundary and draft identity into the next state without holding the Pi message-start hook. The next draft waits for that publication to settle, including failure or cancellation. Active-turn final delivery captures its preview operations before entering the background queue: it drains only the originating draft, leaves a successor's preview untouched, and cannot wait for a successor publication queued behind itself. Delivery authority is rechecked after the captured flush; if the original preview has been replaced, ordinary final sending remains the queue's responsibility. This does not promise instant delivery or eliminate Telegram/client latency.
|
|
18
18
|
|
|
19
|
-
Assistant previews use a two-second
|
|
19
|
+
Assistant previews use a two-second trailing throttle per preview controller, with at most one request in flight. Each preview segment holds its first frame for one full interval from its first visible text, so the opening frame is an accumulated passage instead of the first streamed word even when the previous cadence boundary has already passed (fresh turn, slow first token, or rollover after tool work); changes inside the window replace pending text, and one trailing timer sends the latest safe snapshot without moving its deadline on every delta. Message/turn rollover preserves the remaining interval and reopens the initial window for the next segment. Sealing, clearing, or replacing preview state cancels its timer; final publication drains only an already-issued request and never waits for the throttle deadline.
|
|
20
20
|
|
|
21
21
|
The Bot API client does not replay draft snapshots through API retry backoff. After a retryable draft HTTP failure (`429` or `5xx`), it defers new draft requests for that bot/chat/thread using the existing `Retry-After` or default backoff delay; it stores a deadline, not a body or a background retry. A deferred update does not advance the preview's last-delivered text. Fresh updates can send after the deadline, while a sealed preview cannot resume. Different bots and thread targets have independent cooldowns; credential rotation for the same bot does not bypass its deadline. Permanent replies retain their existing retry policy. Already-issued requests and Telegram/client rendering can still delay visible completion.
|
|
22
22
|
|
package/lib/preview.ts
CHANGED
|
@@ -15,6 +15,9 @@ import { shouldSuppressPreviewForVoice } from "./voice.ts";
|
|
|
15
15
|
|
|
16
16
|
const TELEGRAM_DRAFT_ID_MAX = 2_147_483_647;
|
|
17
17
|
const TELEGRAM_DRAFT_PREVIEW_MAX_CHARS = 4096;
|
|
18
|
+
// Native draft cadence: at most one frame per interval, and a fresh preview
|
|
19
|
+
// segment holds its first frame for one full interval so the opening frame is
|
|
20
|
+
// an accumulated passage rather than a single streamed word.
|
|
18
21
|
const TELEGRAM_DRAFT_INTERVAL_MS = 2_000;
|
|
19
22
|
|
|
20
23
|
export type TelegramDraftSupport = "unknown" | "supported";
|
|
@@ -90,6 +93,7 @@ export interface TelegramAssistantMessagePreviewUpdateDeps<TMessage> {
|
|
|
90
93
|
createPreviewState: () => TelegramPreviewRuntimeState;
|
|
91
94
|
canSend?: () => boolean;
|
|
92
95
|
getMessageText: (message: TMessage) => string;
|
|
96
|
+
minDraftIntervalMs?: number;
|
|
93
97
|
schedulePreviewFlush: (
|
|
94
98
|
chatId: number,
|
|
95
99
|
options?: { target?: TelegramTarget },
|
|
@@ -305,6 +309,7 @@ export function createTelegramAssistantPreviewRuntime<
|
|
|
305
309
|
createPreviewState: controller.createState,
|
|
306
310
|
canSend: deps.canSend,
|
|
307
311
|
getMessageText: deps.getMessageText,
|
|
312
|
+
minDraftIntervalMs: TELEGRAM_DRAFT_INTERVAL_MS,
|
|
308
313
|
schedulePreviewFlush: controller.scheduleFlush,
|
|
309
314
|
}),
|
|
310
315
|
};
|
|
@@ -466,9 +471,24 @@ export async function handleTelegramAssistantMessagePreviewUpdate<TMessage>(
|
|
|
466
471
|
deps.setState(state);
|
|
467
472
|
}
|
|
468
473
|
if (state.sealed) return;
|
|
474
|
+
const hadVisibleText = state.pendingText.length > 0;
|
|
469
475
|
state.pendingText = stripTelegramCommentMarkupForPreview(
|
|
470
476
|
deps.getMessageText(message),
|
|
471
477
|
);
|
|
478
|
+
// The first visible text of a preview segment opens an initial accumulation
|
|
479
|
+
// window, so the segment's first frame cannot ship as a single word even
|
|
480
|
+
// when the previous cadence boundary has already passed (fresh turn, slow
|
|
481
|
+
// first token, or message rollover after tool work). Later deltas keep the
|
|
482
|
+
// trailing deadline instead of sliding it on every update.
|
|
483
|
+
const interval = deps.minDraftIntervalMs ?? 0;
|
|
484
|
+
if (
|
|
485
|
+
interval > 0 &&
|
|
486
|
+
!hadVisibleText &&
|
|
487
|
+
!state.lastSentText &&
|
|
488
|
+
state.pendingText.length > 0
|
|
489
|
+
) {
|
|
490
|
+
state.nextDraftAt = Math.max(state.nextDraftAt ?? 0, Date.now() + interval);
|
|
491
|
+
}
|
|
472
492
|
deps.schedulePreviewFlush(turn.chatId, { target: turn.target });
|
|
473
493
|
}
|
|
474
494
|
|