Files
composiohq__composio/.changeset/disable-retries-execute-proxy.md
T
Alberto Schiabel 4c3a321550 fix(core): disable retries on non-idempotent tools.execute/proxyExecute (#3716)
This PR:

- Closes https://github.com/ComposioHQ/composio/issues/3586
- disables client retries on `tools.execute` and `tools.proxyExecute` —
the two non-idempotent writes — so a request that succeeds server-side
but times out client-side is no longer silently replayed (the cause of
duplicate `GMAIL_SEND_EMAIL` sends)
- routes both through a sibling client built with `withOptions({
maxRetries: 0 })`; reads keep the client's default retries (`maxRetries:
2`)
- caches that sibling per `Tools` instance (`clientWithoutRetries`)
since `withOptions` constructs a fresh client and execute/proxy is the
hottest path; mirrors the Python SDK's `client.without_retries`
- adds regression tests asserting both paths route through `maxRetries:
0` and that the sibling is built once across multiple executes

## Context

The original hang on attachments larger than ~25 KB was a backend defect
and has already been fixed server-side. The remaining gap was a
cross-SDK parity one: the Python SDK already disabled retries on these
non-idempotent writes, but `@composio/core` still inherited the client
default of 2 retries (3 attempts total), with no public knob to turn
them off. This is the TypeScript parity port — scoped to exactly
`tools.execute` / `tools.proxy`, leaving `toolRouter.session.execute`
and all reads on their default retry behaviour, matching Python.
2026-06-30 21:53:46 +04:00

356 B

@composio/core
@composio/core
patch

Disable client retries on tools.execute and tools.proxyExecute. These are non-idempotent writes, so a silent retry after a read timeout could duplicate the side effect (e.g. send the same email more than once). Both now route through a sibling client built with maxRetries: 0; reads keep the default retry behaviour.