Conversation
Agent calls used an absolute PERPLEXITY_TIMEOUT_MS deadline but inherited Undici's independent 300-second headers and body-idle limits. Valid quiet streams could therefore stop before a longer configured deadline. Use a per-call dispatcher with aligned transport limits for Agent requests only, and destroy the dispatcher after timer and abort-listener cleanup. Preserve safe Undici cause codes to distinguish idle timeouts from socket loss without exposing nested metadata. Do not retry accepted requests. Validated: - Eight new defect tests fail on the unchanged base; seven guards pass. - Full suite: 105 tests pass. TypeScript build passes. - Packaged stdio checks pass on Node 24 and actual remote Node 22: delayed headers, silent body, socket loss, and timeout cancellation. - Search network-error regression added after independent review. The historical interruption cannot be attributed conclusively because the old error discarded its nested cause. Genuine network failures remain errors, not automatically resubmitted requests.
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Problem
Agent requests have an absolute
PERPLEXITY_TIMEOUT_MSdeadline, but native fetch and default ProxyAgent inherit Undici's independent 300000ms headers/body-idle limits. A valid quiet stream can fail before a longer configured deadline.Streaming errors also discard
error.cause.code, making body timeouts and peer socket loss indistinguishable. Both reproduceTypeError: terminated. A historical 401-second interruption cannot be attributed conclusively because that evidence was discarded.Solution
Give each Agent call a dispatcher whose headers/body limits match the application deadline. Destroy that dispatcher after timer/listener cleanup. Retain only allowlisted
UND_ERR_*cause codes in streaming errors.Scope
Only Agent transport configuration and regression tests change. Public tools, schemas, presets, proxy precedence, search/cancel behavior and connect timeout remain unchanged. No retry, background API migration, new dependency, global dispatcher change, or version bump.
Validation
npm test: 105/105 pass, five files, no skipped tests.npm run build: pass.npm pack --dry-run: no compiled tests in package.Evidence and context
Related prior reports: #51 (transport timeout surviving application timeout), #110/#122 (MCP client progress), #83/#85 (old Sonar streaming). This correction addresses the current Agent transport path, not those older paths.
Base:
c73c8561bbc2d9eb666334a53c311b50f4f4cf76. Reviewed head:e2ce829ba490f0fd190e8cdea78588f79018c2d6.Local untracked plan:
~/.hermes/plans/modelcontextprotocol/2026-09-16-agent-stream-termination.md; canonical SHA2565ad3982b8995c014ccd9ac5359dc6026bf809e369c9b01e2841aeb525e46f380(declared digest token replaced with PENDING).Risk
Genuine provider/socket interruptions remain errors; accepted requests are never blindly resubmitted. Per-call dispatchers sacrifice cross-call keep-alive reuse for explicit lifecycle and independently configured deadlines.
Notes / accepted debt
Invalid URLrather than the previous prefixed error; still fail closed.Attribution and delivery
Standard implementation: GJC investigative/direct. Test-only repair: GJC procedural/direct. Heavy review: Claude Fable 5.1, high effort. One repair round. Human-facing PR text: Oren.
Open and unmerged. No upstream merge requested.