Skip to content

Conversation

@djeebus
Copy link
Contributor

@djeebus djeebus commented Nov 14, 2025

Note

Implements automatic retries for terminal input delivery to the sandbox PTY to improve resilience against transient failures.

  • Adds isRetryableError to detect transient conditions (SDK TimeoutError, AbortError, common network error codes, and Undici TypeError: fetch failed)
  • Wraps sandbox.pty.sendInput with up to 3 retries, skipping retries for non-retryable errors

Written by Cursor Bugbot for commit 503bd4b. This will update automatically on new commits. Configure here.

@changeset-bot
Copy link

changeset-bot bot commented Nov 14, 2025

⚠️ No Changeset found

Latest commit: 503bd4b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@djeebus djeebus marked this pull request as ready for review January 1, 2026 02:03
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +63 to +67
const maxRetries = 3
for (let retry = 0; ; retry++) {
try {
await sandbox.pty.sendInput(terminalSession.pid, combined)
break

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid retrying PTY input without idempotency

Retrying sendInput can duplicate keystrokes/commands when a transient error is raised after the server already applied the input (e.g., timeout/connection reset after the PTY received data). Because the retry resends the same combined buffer without any sequence/dedup mechanism, users can see repeated characters or repeated command execution under exactly those network conditions. If sendInput is not explicitly idempotent, this introduces at-least-once semantics for terminal input.

Useful? React with 👍 / 👎.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting point. @ValentaTomas wdyt about adding a "request number", idempotency key, or something similar so that the backend avoids duplicate processing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might make sense here! Alternatively, the client long running connection that we don't have implemented in the SDK might be also a solution.

Copy link
Member

@mishushakov mishushakov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nits


function isRetryableError(err: unknown): boolean {
// Retry on SDK TimeoutError
if (err instanceof (e2b as any).TimeoutError) return true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(e2b as any) unnecessary - just import TimeoutError from e2b

if (err instanceof (e2b as any).TimeoutError) return true

// Some environments throw AbortError for aborted/timeout fetches
if (err && typeof err === 'object' && (err as any).name === 'AbortError')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can infer the type as err as Error (in below occurrences also)

])
if (typeof code === 'string' && retryableCodes.has(code)) return true

// Undici/Fetch may surface as TypeError: fetch failed with nested cause
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you check this?

await sandbox.pty.sendInput(terminalSession.pid, combined)

const maxRetries = 3
for (let retry = 0; ; retry++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to avoid infinite loops

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants