Commit Graph

40 Commits

Author SHA1 Message Date
Peter Steinberger
453c049ac8 test(telegram): table-drive funnel-parity chunk boundaries for streamed final pagination (#104760)
The behavior fix landed on main in #104608 (fe3884a7ad): draft-stream final
pagination now routes markdownSource previews through markdownToTelegramChunks,
the same chunker the durable reply funnel uses (delivery.replies.ts
buildChunkTextResolver), and the overflow-pagination golden was re-recorded on
safe boundaries there. This adds the missing parity regression coverage:
table-driven cases for mid-word, mid-entity, mid-tag, and fenced code-block
page boundaries assert the streamed pages equal the durable chunker's HTML
chunks exactly, and that retained/current page snapshots carry the durable
plainText projection so an HTML-parse 400 degrades both funnels identically.

Formatting proof: Testbox tbx_01kx9n9q7rksfxgr5baj0esw57 check:changed format
lane passed on this diff (local worktree has no node_modules for the hook).
2026-07-11 16:12:48 -07:00
Peter Steinberger
fe3884a7ad fix(telegram): keep streamed final pages on word boundaries (#104608)
* fix(telegram): align draft final pagination

* chore: drop release-owned changelog entry

* style(telegram): format pagination parity test
2026-07-11 11:44:09 -07:00
chenyangjun-xy
b58029f4fd fix(telegram): preserve outbound prompt context projections (#102469)
* fix(telegram): preserve outbound prompt context projections

Co-authored-by: 陈杨俊0668000971 <chen.yangjun@xydigit.com>

* fix(telegram): satisfy legacy sender lint

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 18:25:54 -07:00
Ayaan Zaidi
f48ff25b3b fix(telegram): unify rich plain fallback 2026-07-03 23:57:08 -07:00
Peter Lindsey
9dfa7dc87a fix(telegram): red-team hardening for the progress collapse bar
Addresses five codex red-team findings on the streamed progress-window
collapse bar. Channel-side only; no core src/** changes.

F1 (transcript pollution): the collapse bar went through
sendPayload({durable:true}), which unconditionally passed the transcript
mirror to the deliverReplies fallback, writing the cosmetic digest
("💬 1 note · 🛠️ 1 tool call · ⏱️ 4s") into the session transcript so the
model read it back as its own prior turn. Added a mirrorTranscript option to
sendPayload; the bar now sends durably with mirrorTranscript:false. Discord
parity: its summary bar (monitor/reply-delivery.ts deliverDiscordReply →
sendDurableMessageBatch) has no transcript-mirror seam at all. Real finals
keep mirroring.

F4 (tool overcount): progressSummary.noteToolCall() fired for ANY start-phase
tool, but the compositor renders a line only for work tools
(isChannelProgressDraftWorkToolName) and only when toolProgress is on, so
codex/message_tool_only turns showed "🛠️ 1 tool call" with no tool line. The
count is now gated by the same public work-tool-name check plus
streamToolProgressEnabled; non-counting tool starts still close the
reasoning/commentary bursts as a boundary.

F2 (silent collapse drop): finalizeToPreview ignored a false return from the
in-place edit (flood-wait 429 / terminal error), so applyProgressCollapseSummary
assumed "edited", cleared state, posted no bar, and left the tall window.
finalizeToPreview now returns undefined when the edit did not apply, so the
dispatch falls back to the existing durable-post path.

F3 (cosmetic send fails the turn): the cleanup-time deliverProgressCollapseSummary
could throw (429/network) and propagate out of dispatch after the real final
already delivered. The bar send is now wrapped: failures log via logVerbose and
never fail the turn; the once-guard is preserved.

F5 (ghost-preview race): rotateToNewMessageDeferringDelete rewound while a FIRST
send was still in flight; the late send landed as superseded {retain:true}, which
the dispatch handler kept as an orphaned stale bubble. A reposition now records
the in-flight generation and deletes its late-landing message (deferred), while
forceNewMessage's retain-as-durable-chunk contract is unchanged.

Tests: added unit tests for each invariant (bar delivered but absent from the
transcript mirror; message-tool start → no 🛠️ count and toolProgress-off → no
count; failed edit → undefined; bar send throw → turn still succeeds; reposition
race → superseded send deleted not retained). Telegram suites green
(bot-message-dispatch 165, draft-stream 58, progress-summary 16); extensions
tsgo clean for telegram.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:38:39 -07:00
Peter Lindsey
3932f4abb4 fix(telegram): reposition streaming window post-first, delete-old-deferred
Peter isolated the on-off focus-jump precisely: when a durable 🧠 posts BELOW
the streaming window, the window (now above the reasoning) is repositioned to
stay newest by DELETING it and reposting below. Telegram cannot move messages,
so the delete-then-repost order scroll-jumps the client.

Root cause: rotateAnswerLaneAfterToolProgress rewound the tool-progress window
with stream.clear(), which deletes the old message IMMEDIATELY when it has been
on screen past the dwell — before the replacement message is sent. Delete-first,
post-second.

Fix — invert the order, preserving arrival order:
- draft-stream: new rotateToNewMessageDeferringDelete() rewinds the stream so the
  NEXT update creates a fresh message, and schedules the superseded message's
  delete for AFTER it (detached, floored at 1.5s so the new message lands first).
  Extracted the shared deferred-delete scheduler (scheduleDetachedDelete) used by
  both clear() and the reposition. (draft-stream.ts)
- dispatch: rotateAnswerLaneAfterToolProgress now repositions via that method
  instead of clear()+forceNewMessage, so no window reposition deletes before the
  replacement lands. (bot-message-dispatch.ts:1259)

Tests: draft-stream unit tests prove the sequencing (new message sent before the
old is deleted; delete deferred; no-op with no live message). Added a dispatch
repro (durable 🧠 then answer text mid-turn -> reposition, no clear). Updated the
predating tool-progress-rotation tests to assert the deferred-delete reposition
and that any deliverer-cleanup clear() runs only AFTER the rewind. 228 green
across bot-message-dispatch, draft-stream, progress-summary; extensions/telegram
typechecks clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:38:39 -07:00
Peter Lindsey
7933c8cdea fix(telegram): make progress-window collapse consistent across all modes
Live on-off finding: the collapse path was inconsistent. Edit-in-place worked
in off-off/stream-off, but in on-off (tool-progress-only window, reasoning
durable) finalizeToPreview returned undefined and the caller fell into a bare
clear() -> deleteMessage -> Telegram focus-jump; a sibling sub-branch dropped
the bar entirely. Two divergent outcomes from one fallback.

Root cause: a throttled tool-progress preview could still be pending (coalesced,
never sent) when the turn ended, so the window had no message id even though it
had "rendered". finalizeToPreview gave up and the dispatch fallback deleted the
(late-landing) window.

Fixes:
- draft-stream finalizeToPreview: settle the stream, then MATERIALIZE a still-
  pending preview (send it, as a final flush would) so the window message exists
  and can be edited in place. Only when no message could be established does it
  return undefined. (draft-stream.ts:597)
- dispatch collapse: one deterministic path returning "edited" | "posted" |
  "none". A bar is ALWAYS surfaced when one exists — edited in place, or posted
  durably with ZERO deleteMessage. clear()/delete now runs ONLY for the "none"
  case (error final or nothing to summarize), never when a bar exists, so no
  collapse path can focus-jump. Split into resolveProgressCollapseSummaryLine /
  collapseProgressWindowIntoSummary / resetAnswerLaneAfterCollapse /
  teardownProgressWindow for a readable branch. (bot-message-dispatch.ts:1949)

Tests: added on-off dispatch repro (tool-progress-only + durable reasoning +
mid-turn rotation + final -> edits into bar, no clear, exactly one bar), the
no-live-message durable-bar-without-delete case, and three draft-stream
finalizeToPreview cases (edit-in-place, pending-materialize, no-window).
225 green across bot-message-dispatch, draft-stream, progress-summary;
extensions/telegram typechecks clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:38:39 -07:00
Peter Lindsey
b95fe7f00f fix(telegram): keep the streaming preview on screen >=4s before deleting
The streaming "gerund" progress box was deleteMessage'd immediately at
teardown, so on fast turns it flashed and vanished before it could be read,
and the delete could race a just-persisted message (intermittently dropping
the first verbose commentary). Add MIN_PREVIEW_DWELL_MS (4000ms) and schedule
the delete DETACHED via setTimeout for max(0, 4000 - timeVisible), measured
from when the box first appeared. The delete never awaits, so turn teardown
is never stalled.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:38:39 -07:00
Peter Lindsey
f5f3a2a571 fix(telegram): convert <br> joins to newlines for parse_mode=HTML previews
Progress drafts join their rendered lines with <br>, but the Bot API
parse_mode=HTML entity set has no <br> tag — line breaks must be literal
newlines. Telegram therefore rejected every multi-line preview edit with
"can't parse entities", and the parse-error fallback silently downgraded
the whole streamed progress draft (all lanes) to unformatted plain text.
Convert <br> to newlines in the parse-mode transport branch, matching what
the rich-message branch already does.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:38:39 -07:00
Ayaan Zaidi
a3b4e8102f test(telegram): fold draft preview surrogate clamp coverage 2026-06-25 09:10:07 -07:00
杨浩宇0668001029
4bd68aef65 fix(telegram): keep draft preview chunks surrogate-safe 2026-06-25 09:10:07 -07:00
Ayaan Zaidi
2aa9d67635 refactor(telegram): simplify rich email entity detection 2026-06-24 06:23:08 -07:00
Kelaw - Keshav's Agent
51eec3a757 fix(telegram): skip rich entity detection for oauth emails 2026-06-24 06:23:08 -07:00
snowzlmbot
e37b0f8cd3 fix(telegram): render progress drafts with clean HTML transport
Render Telegram progress draft rows with clean plain previews while preserving Telegram HTML formatting through parse_mode.

The progress HTML path now stays transport-owned, including richMessages=false progress messages, while debug/plain/sanitized text remains readable without raw markup.

Thanks @snowzlmbot!
2026-06-22 05:54:44 +05:30
snowzlmbot
6441e56465 fix(telegram): materialize streaming progress placeholders (#95183)
* fix(telegram): materialize streaming progress placeholders

* fix(telegram): cancel delayed progress drafts before final

* fix(telegram): satisfy progress placeholder lint

* fix(telegram): cancel delayed draft preview on clear

* refactor(telegram): simplify delayed preview flush

---------

Co-authored-by: snowzlmbot <snowzlmbot@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-06-21 19:48:41 +05:30
Ayaan Zaidi
42dcf7075f Fix Telegram rich progress detail updates (#93698)
Merged via squash.

Prepared head SHA: 77da499825
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Reviewed-by: @obviyus
2026-06-16 22:48:12 +05:30
NianJiu
a375d6c849 fix(telegram): gate rich messages behind opt-in (#93279)
Restore readable standard Telegram text delivery by default after Bot API 10.1 rich messages rendered as unsupported in current clients. Keep native rich tables and structured messages available through the account-level richMessages opt-in, with account-aware capability advertising and documented structural limits.

Fixes #93263.
2026-06-15 17:22:41 -07:00
Ayaan Zaidi
da92615816 feat(telegram): send rich messages as rich html (#93286)
* feat(telegram): render rich messages through rich html

* docs(telegram): teach agents rich formatting

* fix(telegram): bound rich draft payloads (#93286)

* fix(telegram): narrow rich draft payload type (#93286)

* fix(telegram): preserve rich table cell formatting (#93286)

* fix(telegram): honor rich table mode config (#93286)

* fix(telegram): default rich markdown tables (#93286)

* fix(telegram): gate rich table block mode (#93286)

* fix(telegram): normalize raw rich html limits (#93286)

* fix(telegram): preserve link preview suppression (#93286)

* fix(telegram): preserve rich markdown headings (#93286)

* fix(telegram): reject unsupported rich media sources (#93286)

* fix(telegram): honor link preview off in rich chunks (#93286)

* fix(telegram): avoid double escaping markdown media (#93286)

* fix(telegram): render markdown media via placeholders (#93286)

* fix(telegram): preserve table text in prompt context (#93286)
2026-06-15 20:38:41 +05:30
Ayaan Zaidi
663fabbe30 fix(telegram): render progress drafts as rich previews 2026-06-15 08:52:27 +05:30
Ayaan Zaidi
e8b142feb1 refactor(telegram): remove native draft previews 2026-06-13 21:45:22 +05:30
Ayaan Zaidi
ff04e24ead fix(telegram): retry transient draft preview failures instead of killing the stream 2026-06-12 10:18:11 +05:30
Peter Steinberger
efd1a9ace6 docs: document messaging extension sources 2026-06-04 22:03:15 -04:00
Ayaan Zaidi
b3b203bf67 test(telegram): simplify preview race harness 2026-06-03 18:28:13 +05:30
张贵萍0668001030
0a4927d0b8 fix(telegram): retain preview on generation race 2026-06-03 18:28:13 +05:30
Ayaan Zaidi
bda924b639 fix(telegram): preserve final overflow state 2026-05-28 19:08:27 +05:30
Ayaan Zaidi
8677310fb5 fix(telegram): skip stopped draft finalization 2026-05-28 19:08:27 +05:30
Ayaan Zaidi
a048cbc4f0 test(telegram): cover draft preview overflow 2026-05-28 19:08:27 +05:30
Peter Steinberger
69cea57f69 fix(telegram): fail closed on missing topic threads (#83381)
* fix(telegram): fail closed on missing topic threads

* docs(changelog): reference telegram topic cleanup
2026-05-18 03:07:12 +01:00
Peter Steinberger
6a230a108a test: guard extension messaging mock calls 2026-05-12 11:15:37 +01:00
Shakker
610b695a12 test: pin Telegram draft stream checks 2026-05-11 14:26:31 +01:00
Ayaan Zaidi
7a2cc4b8d6 fix(telegram): stop DM topic threadless fallback (#78575) (thanks @tmimmanuel) 2026-05-09 09:07:42 +05:30
Ayaan Zaidi
10bbed8a6d fix(telegram): chain over-limit stream previews 2026-05-08 18:41:49 +05:30
Vincent Koc
f3145f6db8 fix(telegram): remove unused draft stream helper 2026-04-30 06:19:08 -07:00
Ayaan Zaidi
c9d9067931 test(telegram): cover message-only previews 2026-04-30 18:07:57 +05:30
Peter Steinberger
e1acb61317 refactor: expose SDK test helper subpaths 2026-04-28 03:28:17 +01:00
Vincent Koc
d5063d5b16 fix(telegram): avoid materializing tool-progress drafts
Address Clownfish follow-up on Telegram native draft finalization. Requires real streamed assistant partials before materializing drafts, clears stale native draft previews, and keeps media/buttons on normal send path.
2026-04-26 19:43:23 -07:00
Rubén Cuevas
a08b65a90a fix(telegram): send fresh finals for stale previews (#72038)
* fix(telegram): send fresh finals for stale previews

* test(telegram): cover stale preview send fallback

* fix(telegram): keep stale archived preview fallback

* fix(telegram): clear stale active previews

* fix(telegram): reset preview state after fresh finals
2026-04-26 15:44:30 -07:00
Rubén Cuevas
996eb9a024 fix: fence Telegram stale reply delivery after abort (#68100) (thanks @rubencu)
* fix(telegram): fence stale reply delivery after abort

* refactor(telegram): narrow abort fence scope

* fix(telegram): ignore stale reply finalization after abort

* fix(telegram): close abort supersession races

* fix(telegram): release abort fences on setup errors

* fix(telegram): discard superseded draft cleanup

* refactor(telegram): distill abort fence cleanup

* fix: fence Telegram stale reply delivery after abort (#68100) (thanks @rubencu)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-18 10:02:38 +05:30
Peter Steinberger
6237cfc6a6 fix: finish telegram reply fallback landing (#52524) (thanks @moltbot886) 2026-03-22 18:54:01 -07:00
scoootscooob
e5bca0832f refactor: move Telegram channel implementation to extensions/ (#45635)
* refactor: move Telegram channel implementation to extensions/telegram/src/

Move all Telegram channel code (123 files + 10 bot/ files + 8 channel plugin
files) from src/telegram/ and src/channels/plugins/*/telegram.ts to
extensions/telegram/src/. Leave thin re-export shims at original locations so
cross-cutting src/ imports continue to resolve.

- Fix all relative import paths in moved files (../X/ -> ../../../src/X/)
- Fix vi.mock paths in 60 test files
- Fix inline typeof import() expressions
- Update tsconfig.plugin-sdk.dts.json rootDir to "." for cross-directory DTS
- Update write-plugin-sdk-entry-dts.ts for new rootDir structure
- Move channel plugin files with correct path remapping

* fix: support keyed telegram send deps

* fix: sync telegram extension copies with latest main

* fix: correct import paths and remove misplaced files in telegram extension

* fix: sync outbound-adapter with main (add sendTelegramPayloadMessages) and fix delivery.test import path
2026-03-14 02:50:17 -07:00