Commit Graph

90 Commits

Author SHA1 Message Date
Peter Steinberger
538605ff44 [codex] Extract filesystem safety primitives (#77918)
* refactor: extract filesystem safety primitives

* refactor: use fs-safe for file access helpers

* refactor: reuse fs-safe for media reads

* refactor: use fs-safe for image reads

* refactor: reuse fs-safe in qqbot media opener

* refactor: reuse fs-safe for local media checks

* refactor: consume cleaner fs-safe api

* refactor: align fs-safe json option names

* fix: preserve fs-safe migration contracts

* refactor: use fs-safe primitive subpaths

* refactor: use grouped fs-safe subpaths

* refactor: align fs-safe api usage

* refactor: adapt private state store api

* chore: refresh proof gate

* refactor: follow fs-safe json api split

* refactor: follow reduced fs-safe surface

* build: default fs-safe python helper off

* fix: preserve fs-safe plugin sdk aliases

* refactor: consolidate fs-safe usage

* refactor: unify fs-safe store usage

* refactor: trim fs-safe temp workspace usage

* refactor: hide low-level fs-safe primitives

* build: use published fs-safe package

* fix: preserve outbound recovery durability after rebase

* chore: refresh pr checks
2026-05-06 02:15:17 +01:00
Vincent Koc
b0b5983ce3 fix(telegram): send interactive fallback replies 2026-05-03 19:17:14 -07:00
Kelaw - Keshav's Agent
01a22d4ec9 fix(telegram): render interactive reply buttons 2026-05-04 02:47:03 +01:00
Peter Steinberger
c33e578554 feat: add channel progress drafts
Adds unified progress-draft streaming for chat channels, with docs and per-channel regressions.
2026-05-03 22:01:08 +01:00
Peter Steinberger
a7d2953956 fix: remove duplicate Telegram DM thread helper 2026-05-02 10:59:46 +01:00
Peter Steinberger
7db255150c fix: keep Telegram DM thread IDs on flat sessions 2026-05-02 10:59:46 +01:00
Peter Steinberger
b8c0a1e9ff fix(telegram): keep dm reply threads on main session 2026-05-02 09:58:08 +01:00
Peter Steinberger
d5736710a9 refactor: trim telegram helper exports 2026-05-01 17:12:09 +01:00
Peter Steinberger
3b75898bee refactor: trim extension internal type exports 2026-05-01 14:00:05 +01:00
Peter Steinberger
426107d2f8 fix(telegram): retry invalid native quotes 2026-04-30 00:02:13 +01:00
Peter Steinberger
1fb58ca5ee fix(telegram): recover transient polling and reply sends 2026-04-29 12:42:31 +01:00
peter
e71d7d48fb fix(telegram): probe video dimensions through sdk
Fix Telegram portrait video distortion by probing video dimensions through the shared media helper and passing width/height to sendVideo.

Validation:
- Targeted Telegram/media tests passed locally.
- Plugin SDK API baseline check passed locally.
- Formatter and git diff whitespace checks passed locally.

CI note: current boundary drift observed on prior run came from existing src/plugin-sdk/discord.ts and src/plugin-sdk/telegram-account.ts, not this PR diff.
2026-04-29 01:58:25 -05:00
Peter Steinberger
74e62c32c3 test: route extension tests through sdk subpaths 2026-04-27 21:58:48 +01:00
Peter Steinberger
f0000ab72d refactor(plugin-sdk): split infra runtime barrel 2026-04-27 20:50:35 +01:00
Peter Steinberger
4336a7f3a9 refactor(plugin-sdk): narrow config runtime imports 2026-04-27 14:58:32 +01:00
Peter Steinberger
257e767e5b fix(telegram): include native quote excerpts for replies 2026-04-26 06:32:46 +01:00
Rubén Cuevas
f9146cabfc fix(telegram): preserve native quote replies
Preserve exact Telegram selected quote text for native quote replies, share Telegram reply parameter construction between bot delivery and direct outbound sends, and retry with legacy replies when Telegram rejects native quote parameters.\n\nThanks @rubencu.
2026-04-26 06:09:43 +01:00
Peter Steinberger
d85dc46e37 perf: narrow telegram reply imports 2026-04-24 09:31:47 +01:00
Peter Steinberger
0a7668595c test(telegram): reset forum metadata cache 2026-04-23 10:11:12 +01:00
Ayaan Zaidi
8a078acaa6 perf(telegram): bound forum metadata cache 2026-04-23 14:33:17 +05:30
Ayaan Zaidi
50e6c0a3b2 perf(telegram): cache forum metadata lookup 2026-04-23 14:33:17 +05:30
Vincent Koc
02da7350ad test(telegram): pin outbound hook routing fields 2026-04-22 23:47:06 -07:00
Peter Steinberger
0b0662b1c9 chore: apply extension lint cleanups 2026-04-23 05:30:49 +01:00
Vincent Koc
e593122465 fix(hooks): standardize outbound routing metadata 2026-04-22 10:53:44 -07:00
Tak Hoffman
f328c21046 feat: Add /models add hot-reload model registration (#70211)
* feat(models): add chat model registration with hot reload

* docs(changelog): add models entry for pr 70211

* fix(models): harden add flow follow-ups

* fix models add review follow-ups

* harden models add config writes

* tighten plugin boundary invariant

* move models add adapters behind sdk facades

* avoid ollama-specific core facade
2026-04-22 12:00:30 -05:00
Peter Steinberger
fd0970c077 refactor(channels): decouple presentation rendering 2026-04-21 21:29:44 +01:00
Tak Hoffman
1303b03241 fix: add silent reply policy by conversation type (#68644)
Thanks @Takhoffman.
2026-04-21 05:17:55 +01:00
Peter Steinberger
60fea81cf1 fix(telegram): harden polling transport liveness (#69476)
* fix(telegram): release undici dispatchers via TelegramTransport.close()

TelegramTransport now exposes an explicit close() that destroys every
owned undici dispatcher (default Agent plus lazily-created IPv4 and
IP-pinned fallback Agents) and the TCP sockets they hold. Dispatcher
constructors are also given bounded keep-alive defaults
(keepAliveTimeout, keepAliveMaxTimeout, connections, pipelining) as a
defence-in-depth layer so the pool cannot grow unbounded even if a
caller forgets to call close().

Without this, every transport that went through a fallback retry left
its fallback Agents anchored forever in a closure; long-running polling
sessions accumulated hundreds of ESTABLISHED keep-alive sockets to
api.telegram.org, saturating the per-IP quota on upstream forward
proxies and making the currently-active outbound node time out while
every other node still tested healthy.

Mock dispatchers in fetch.test.ts gain destroy() spies so the close()
chain is assertable. Call sites that built caller-owned transports from
globalThis.fetch (delivery.resolve-media, test helpers) return an async
no-op close(), matching the new required surface.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(telegram): dispose polling transport on shutdown and dirty rebuild

Every recoverable network error and stall-watchdog trip sets
TelegramPollingTransportState.#transportDirty so the next polling
cycle rebuilds the transport inside acquireForNextCycle(). Previously
the rebuild simply overwrote the field, leaving the old transport's
keep-alive sockets anchored in the now-unreferenced dispatcher — the
polling loop has no natural GC point for these resources, and Node's
object GC never touches OS-level sockets.

acquireForNextCycle() now closes the previous transport (fire-and-
forget so the polling cycle is not blocked by a slow destroy) before
swapping in the rebuilt one. dispose() is a new method that the owning
TelegramPollingSession calls from the finally block of runUntilAbort(),
so a single transport is always tied to a single polling session
lifetime. After dispose(), acquireForNextCycle() returns undefined to
prevent zombie rebuilds.

Under high sustained polling traffic over long-lived sessions, this is
what stops the per-gateway connection count to api.telegram.org from
growing indefinitely and saturating upstream proxy quotas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(changelog): note Telegram undici dispatcher lifecycle fix

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(telegram): disable HTTP/2 for all Telegram polling dispatchers

Undici 8 enables HTTP/2 ALPN by default, but Telegram's long-polling
connections stall on Windows due to IPv6 + H2 multiplexing issues. The
core fetch-guard already sets allowH2:false for guarded paths, but the
Telegram extension creates its own Agent/ProxyAgent/EnvHttpProxyAgent
instances directly from undici without this flag.

Apply allowH2:false to all dispatcher constructors in the Telegram
transport layer, matching the approach used in src/infra/net/undici-runtime.ts.

Fixes #66885

* fix: avoid false telegram polling stall restarts

* fix(telegram): publish polling health liveness

---------

Co-authored-by: Ethan Chen <ethanbit@qq.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Magicray1217 <magicray1217@users.noreply.github.com>
Co-authored-by: aoao <aoao@openclaw>
2026-04-20 23:03:57 +01:00
François Martin
734bb9c2e7 Telegram/documents: sanitize binary payloads to prevent prompt input inflation (#66877)
Merged via squash.

Prepared head SHA: 09a87c184f
Co-authored-by: martinfrancois <14319020+martinfrancois@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-14 20:53:00 -04:00
OfflynAI
3a371a32e2 fix: filter telegram binary caption text (#66663) (thanks @joelnishanth)
* Telegram: filter binary content from msg.caption to prevent token explosion (#66647)

When a user sends a binary document (e.g. .mobi, .epub) via Telegram, raw
binary bytes can leak into msg.caption. getTelegramTextParts() passes this
through to the LLM prompt, causing catastrophic token explosion (~460K tokens).

Add isBinaryContent() that detects non-printable control characters (0x00-0x08,
0x0E-0x1F) and use it to sanitize the text in getTelegramTextParts() before it
reaches the prompt pipeline. When binary content is detected, the text and
entities are both replaced with empty values so the message is still processed
(media placeholder still works) but the binary junk is dropped.

Made-with: Cursor

* fix: distill telegram binary caption filtering

* fix: filter telegram binary caption text (#66663) (thanks @joelnishanth)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-14 22:14:50 +05:30
Vincent Koc
e58d50b7a8 fix(telegram): trust explicit proxy DNS for media downloads (#66461) 2026-04-14 10:42:33 +01:00
Peter Steinberger
96fe85fb77 refactor: dedupe telegram trimmed readers 2026-04-08 00:09:41 +01:00
Peter Steinberger
179ccb952c refactor: dedupe telegram matrix lowercase helpers 2026-04-07 20:57:04 +01:00
Peter Steinberger
ce19b6bf6a refactor: dedupe channel extension readers 2026-04-07 08:40:34 +01:00
Vincent Koc
bbfc46fe02 test(telegram): use canonical web-media sdk path 2026-04-07 08:10:00 +01:00
Peter Steinberger
ad0c4309e6 refactor: dedupe shared trim readers 2026-04-07 07:36:11 +01:00
Peter Steinberger
9e2a1e12fd refactor: dedupe channel runtime error formatting 2026-04-07 02:03:34 +01:00
Vincent Koc
2815e8ecc0 chore(telegram): drop dead bot helper lint comments 2026-04-06 15:40:13 +01:00
Peter Steinberger
af62a2c2e4 style: fix extension lint violations 2026-04-06 14:53:55 +01:00
Ayaan Zaidi
cfc52fcf2b fix(telegram): trust local bot api media roots 2026-04-04 11:35:36 +05:30
Peter Steinberger
e4b5027c5e refactor(plugins): move extension seams into extensions 2026-04-04 00:10:16 +01:00
Peter Steinberger
14c863dc4a test: reduce telegram media harness imports 2026-04-03 18:33:47 +01:00
Peter Steinberger
225431665a test: trim telegram media retry import cost 2026-04-03 12:01:10 +01:00
Peter Steinberger
bb3ea2137b test: move telegram fetch coverage into extensions 2026-04-03 11:37:41 +01:00
Peter Steinberger
80c5764482 refactor(telegram): streamline media runtime options 2026-04-03 19:09:13 +09:00
Peter Steinberger
4bfa9260ce fix(telegram): add dangerous private-network media opt-in 2026-04-03 18:39:17 +09:00
v1p0r
3a7555a27b "fix(telegram): surface media placeholder and file_id when download f… (#59948)
* "fix(telegram): surface media placeholder and file_id when download fails"

* fix: unify telegram media placeholder selection

* fix: preserve telegram media context on captioned download failures (#59948) (thanks @v1p0r)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-03 09:08:05 +05:30
saram ali
985533efbc fix: cover buffered Telegram apiRoot downloads (#59544) (thanks @SARAMALI15792)
* test(telegram): add URL construction tests for custom apiRoot

Add comprehensive test cases to verify that file download URLs are correctly
constructed when using a custom apiRoot configuration for local Bot API servers.

Tests validate:
- Document downloads use the custom apiRoot in the constructed URL
- Sticker downloads use the custom apiRoot in the constructed URL
- SSRF policy correctly includes the custom hostname

This ensures issue #59512 (Telegram file downloads with local Bot API) is
properly covered by regression tests.

* refactor(telegram): improve media resolution code quality

Apply KISS and YAGNI principles to reduce code duplication and improve maintainability:

1. Extract media metadata resolution
   - Consolidate resolveMediaFileRef(), resolveTelegramFileName(), and
     resolveTelegramMimeType() into single resolveMediaMetadata() function
   - Returns typed MediaMetadata object with fileRef, fileName, mimeType
   - Reduces duplication and improves readability

2. Add logging for apiRoot parsing failures
   - Log when custom apiRoot URL parsing fails in buildTelegramMediaSsrfPolicy()
   - Helps debug configuration issues with local Bot API servers

3. Fix missing apiRoot in buffered messages
   - Add telegramCfg.apiRoot parameter to resolveMedia() calls in
     bot-handlers.buffers.ts (lines 150-159, 189)
   - Ensures reply media in buffered contexts respects custom apiRoot config
   - Fixes inconsistency where runtime handler passed apiRoot but buffers didn't

These changes improve code quality while maintaining backward compatibility and
ensuring issue #59512 (Telegram file downloads with local Bot API) works correctly
in all contexts.

* fix(telegram): resolve bot review issues

Address critical issues identified by Greptile code review:

1. Define telegramCfg in bot-handlers.buffers.ts
   - Extract telegramCfg from cfg.channels?.telegram
   - Fixes ReferenceError when accessing telegramCfg.apiRoot
   - Ensures buffered message handlers can access apiRoot configuration

2. Restore type safety for MediaMetadata.fileRef
   - Change from 'unknown' to proper union type
   - Preserves type information for downstream file_id access
   - Prevents TypeScript strict mode compilation errors

These fixes ensure the PR compiles correctly and handles buffered
media downloads with custom apiRoot configuration.

* fix(telegram): use optional chaining for telegramCfg.apiRoot

TypeScript strict mode requires optional chaining when accessing
properties on potentially undefined objects. Changed telegramCfg.apiRoot
to telegramCfg?.apiRoot to handle cases where telegramCfg is undefined.

Fixes TypeScript errors:
- TS18048: 'telegramCfg' is possibly 'undefined' (line 160)
- TS18048: 'telegramCfg' is possibly 'undefined' (line 191)

* fix(telegram): add missing optional chaining on line 191

Complete the fix for telegramCfg optional chaining.
Previous commit only fixed line 160, but line 191 also needs
the same fix to prevent TS18048 error.

* fix: cover buffered Telegram apiRoot downloads (#59544) (thanks @SARAMALI15792)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-03 08:41:41 +05:30
Josh Lehman
ed8d5b3797 fix: add Telegram native progress placeholder opt-in for plugin commands (#59300)
Merged via squash.

Prepared head SHA: 4f5bc22a89
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-02 15:55:46 -07:00
Peter Steinberger
694d12a90b refactor: apply context visibility across channels 2026-04-03 04:34:57 +09:00