Repository navigation
Add per-tool timeout and response size to REST tools - #1378
Merged
Merged
Conversation
REST calls had a fixed 30 s timeout and the global 10 MB body cap, which fail Gemini 2K/4K image generation after the picture is already billed: the body carries the base64 image before responseMapping.images takes it out, and generation can take longer than 30 s. - endpointMapping.timeoutMs (clamped to 1-180 s, default 30 s) and endpointMapping.maxResponseBytes (at most 50 MB, default TOOL_MAX_RESPONSE_BYTES) for REST tools. - A call that ran past a raised timeout is never retried. - Gemini and OpenAI generation tools get 120 s; their image tools also get 40 MB for the inline base64 pictures. - Document both keys in docs/tool-definition.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On 31 Oct, in one Cloud workspace,
gemini_generate_image(modelgemini-3-pro-image, 2K/4K) failed 22 of 138 calls. The logs show 18 × "API response is larger than 10 MB" and 11 ×ECONNABORTEDat exactly 30 s. Successful calls took 14 to 48 s. Every failure is a picture that Google had already generated and billed.There are two causes in the REST engine:
timeout: 30000is hard-coded for every tool, and a 2K/4K generation regularly takes longer.maxContentLength: toolMaxResponseBytes()(10 MB) applies to the raw upstream body. That body still holds the base64 image, whichresponseMapping.imagesonly takes out later. The second check inDynamicMcpTools.renderResultalready measures the text after extraction (the image is replaced by a short placeholder), so it lets an extracted image through and is left unchanged.This PR lets a REST tool set its own timeout and body limit, both clamped, and sets them on the slow generation tools in the catalog.
Changes
connectors/engines/request-limits.util.ts:endpointMapping.timeoutMsis clamped to 1 000 to 180 000 ms. Without it, the timeout stays 30 000.endpointMapping.maxResponseBytesis capped at 50 MB, or atTOOL_MAX_RESPONSE_BYTESif an admin set that higher. A tool may set a lower value. Without it, the limit staysTOOL_MAX_RESPONSE_BYTES.rest.engine.tspasses both values to the axios config.MAYBE_SENT_CODES). In addition, a call that times out with a raisedtimeoutMsis no longer retried for any method. Otherwise a GET with 180 s could wait up to 4 × 180 s. Calls that never left (ECONNREFUSED,EAI_AGAIN,EPROTO) are still retried.engine-types.ts: both keys added toRestEndpointMapping. The adapter validator and catalog spec do not reject unknown mapping keys, so they needed no change.gemini_generate_image,gemini_edit_image,openai_generate_image,openai_edit_image: 120 s and 40 MB, because their images come back inline as base64.gemini_generate_text,gemini_generate_content,gemini_analyze_file_url,openai_create_response: 120 s only.taskIdstraight away.docs/tool-definition.md: new section "Slow or large responses (timeoutMs,maxResponseBytes)".Behaviour is the same on Cloud and self-hosted: no
isCloud()branch, and the env var keeps its meaning. Tools without these keys behave exactly as before.Type
Testing
New specs:
request-limits.util.spec.ts: defaults, clamping, string values, and a global limit above 50 MB.rest.engine.spec.ts› "per-tool timeout and response size": the values reach the axios config, clamping works, absent keys keep 30 s and the global cap, a raised-timeout call is not retried after a timeout, and a call that never left is still retried.gemini.live.spec.tsandopenai.live.spec.ts: the catalog values reach axios, and other tools keep 30 s / 10 MB.Commands, results as run. Backend commands ran in
packages/backend; the last three ran from the repository root:npx jest src/connectors/engines/rest.engine.spec.ts src/connectors/engines/request-limits.util.spec.ts src/adapters/intl/gemini.live.spec.ts src/adapters/intl/openai.live.spec.ts: 4 suites passed, 208 passed, 6 skipped (live).npx jest src/adapters: 671 suites passed.cloudflare.live.spec.tsandsupabase.live.spec.tsfailed 5 tests while a second Jest run was going in parallel. Re-run alone, both pass (27 passed, 14 skipped). Neither adapter is touched.npx jest src/common/response-size-limit.spec.ts src/connectors/engines src/mcp-server/dynamic-mcp-tools: 42 suites passed. Five suites (xml-body,response-error.util,response-size-limit.engines,rest.engine.binary,rest.engine.redirect) failed under the same parallel load. Re-run alone: 5 suites, 52 tests passed.npx eslinton the 7 changed TS files: clean.npx tsc --noEmit -p tsconfig.json: clean.node scripts/validate-adapters.mjs --warn: exit 0. Output is identical toorigin/main(diffed), so there are no new warnings.node scripts/regenerate-catalog.mjs: no diff tocatalog.ts.node scripts/adapter-count.mjs --check: OK.Notes:
endpointMappingthey were installed with. The new values reach an existing Gemini or OpenAI connector only through a full catalog resync, which is a structural change.responseMapping.imagesstill caps each image at 4 MiB decoded by default. A 4K picture above that now arrives as a placeholder that says why, together with the text and usage, instead of a 10 MB error. Raisingimages.maxBytes(hard max 8 MiB) is left out on purpose, because of client-side image size limits.Checklist
npm test): backend catalog and engine specs listed above; full backendnpm testnot runRelated Issues
Daily check 2026-11-01, cloud.md candidate 2