From 7150268f840cf519f900d07f75dc74f2dd928fca Mon Sep 17 00:00:00 2001 From: spiceoogway Date: Fri, 30 Jan 2026 02:21:37 -0500 Subject: [PATCH 1/2] fix(telegram): use undici fetch for proxy to fix dispatcher option Fixes #4038 The global fetch in Node.js doesn't support undici's dispatcher option, which is required for ProxyAgent to work. This fix imports fetch from undici directly to enable proper proxy support for Telegram API calls. Root cause: makeProxyFetch() was using global fetch with { dispatcher: agent }, but Node.js's global fetch ignores the dispatcher option. Using undici.fetch ensures the ProxyAgent dispatcher is properly respected. Tested: Build passes, TypeScript compilation successful. --- src/telegram/proxy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/telegram/proxy.ts b/src/telegram/proxy.ts index 19d53d569..84251d7fe 100644 --- a/src/telegram/proxy.ts +++ b/src/telegram/proxy.ts @@ -1,11 +1,11 @@ // @ts-nocheck -import { ProxyAgent } from "undici"; +import { ProxyAgent, fetch as undiciFetch } from "undici"; import { wrapFetchWithAbortSignal } from "../infra/fetch.js"; export function makeProxyFetch(proxyUrl: string): typeof fetch { const agent = new ProxyAgent(proxyUrl); return wrapFetchWithAbortSignal((input: RequestInfo | URL, init?: RequestInit) => { const base = init ? { ...init } : {}; - return fetch(input, { ...base, dispatcher: agent }); + return undiciFetch(input, { ...base, dispatcher: agent }); }); } From 3a85cb18330ef7b426668191d0acb7ec7b6a86cf Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Fri, 30 Jan 2026 14:37:17 +0530 Subject: [PATCH 2/2] fix: honor Telegram proxy dispatcher (#4456) (thanks @spiceoogway) --- CHANGELOG.md | 1 + src/telegram/proxy.test.ts | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/telegram/proxy.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c0549c16..ec0fc3fb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ Status: stable. - **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed). ### Fixes +- Telegram: use undici fetch for per-account proxy dispatcher. (#4456) Thanks @spiceoogway. - Telegram: avoid silent empty replies by tracking normalization skips before fallback. (#3796) - Telegram: scope native skill commands to bound agent per bot. (#4360) Thanks @robhparker. - Mentions: honor mentionPatterns even when explicit mentions are present. (#3303) Thanks @HirokiKobayashi-R. diff --git a/src/telegram/proxy.test.ts b/src/telegram/proxy.test.ts new file mode 100644 index 000000000..71fd5f88e --- /dev/null +++ b/src/telegram/proxy.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, it, vi } from "vitest"; + +const { ProxyAgent, undiciFetch, proxyAgentSpy, getLastAgent } = vi.hoisted(() => { + const undiciFetch = vi.fn(); + const proxyAgentSpy = vi.fn(); + class ProxyAgent { + static lastCreated: ProxyAgent | undefined; + proxyUrl: string; + constructor(proxyUrl: string) { + this.proxyUrl = proxyUrl; + ProxyAgent.lastCreated = this; + proxyAgentSpy(proxyUrl); + } + } + + return { + ProxyAgent, + undiciFetch, + proxyAgentSpy, + getLastAgent: () => ProxyAgent.lastCreated, + }; +}); + +vi.mock("undici", () => ({ + ProxyAgent, + fetch: undiciFetch, +})); + +import { makeProxyFetch } from "./proxy.js"; + +describe("makeProxyFetch", () => { + it("uses undici fetch with ProxyAgent dispatcher", async () => { + const proxyUrl = "http://proxy.test:8080"; + undiciFetch.mockResolvedValue({ ok: true }); + + const proxyFetch = makeProxyFetch(proxyUrl); + await proxyFetch("https://api.telegram.org/bot123/getMe"); + + expect(proxyAgentSpy).toHaveBeenCalledWith(proxyUrl); + expect(undiciFetch).toHaveBeenCalledWith( + "https://api.telegram.org/bot123/getMe", + expect.objectContaining({ dispatcher: getLastAgent() }), + ); + }); +});