feat: add sessions_yield tool for cooperative turn-ending (#36537)

Merged via squash.

Prepared head SHA: 75d9204c86
Co-authored-by: jriff <50276+jriff@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
This commit is contained in:
Jacob Riff
2026-03-12 16:46:47 +01:00
committed by GitHub
parent e6897c800b
commit 3fa91cd69d
17 changed files with 848 additions and 39 deletions

View File

@@ -69,7 +69,12 @@ export type TelegramBotOptions = {
export { getTelegramSequentialKey };
function readRequestUrl(input: RequestInfo | URL): string | null {
type TelegramFetchInput = Parameters<NonNullable<ApiClientOptions["fetch"]>>[0];
type TelegramFetchInit = Parameters<NonNullable<ApiClientOptions["fetch"]>>[1];
type GlobalFetchInput = Parameters<typeof globalThis.fetch>[0];
type GlobalFetchInit = Parameters<typeof globalThis.fetch>[1];
function readRequestUrl(input: TelegramFetchInput): string | null {
if (typeof input === "string") {
return input;
}
@@ -83,7 +88,7 @@ function readRequestUrl(input: RequestInfo | URL): string | null {
return null;
}
function extractTelegramApiMethod(input: RequestInfo | URL): string | null {
function extractTelegramApiMethod(input: TelegramFetchInput): string | null {
const url = readRequestUrl(input);
if (!url) {
return null;
@@ -150,7 +155,7 @@ export function createTelegramBot(opts: TelegramBotOptions) {
// Use manual event forwarding instead of AbortSignal.any() to avoid the cross-realm
// AbortSignal issue in Node.js (grammY's signal may come from a different module context,
// causing "signals[0] must be an instance of AbortSignal" errors).
finalFetch = ((input: RequestInfo | URL, init?: RequestInit) => {
finalFetch = ((input: TelegramFetchInput, init?: TelegramFetchInit) => {
const controller = new AbortController();
const abortWith = (signal: AbortSignal) => controller.abort(signal.reason);
const onShutdown = () => abortWith(shutdownSignal);
@@ -162,13 +167,16 @@ export function createTelegramBot(opts: TelegramBotOptions) {
}
if (init?.signal) {
if (init.signal.aborted) {
abortWith(init.signal);
abortWith(init.signal as unknown as AbortSignal);
} else {
onRequestAbort = () => abortWith(init.signal as AbortSignal);
init.signal.addEventListener("abort", onRequestAbort, { once: true });
init.signal.addEventListener("abort", onRequestAbort);
}
}
return callFetch(input, { ...init, signal: controller.signal }).finally(() => {
return callFetch(input as GlobalFetchInput, {
...(init as GlobalFetchInit),
signal: controller.signal,
}).finally(() => {
shutdownSignal.removeEventListener("abort", onShutdown);
if (init?.signal && onRequestAbort) {
init.signal.removeEventListener("abort", onRequestAbort);
@@ -178,7 +186,7 @@ export function createTelegramBot(opts: TelegramBotOptions) {
}
if (finalFetch) {
const baseFetch = finalFetch;
finalFetch = ((input: RequestInfo | URL, init?: RequestInit) => {
finalFetch = ((input: TelegramFetchInput, init?: TelegramFetchInit) => {
return Promise.resolve(baseFetch(input, init)).catch((err: unknown) => {
try {
tagTelegramNetworkError(err, {