Skip to content

fix: add AbortController timeout to all raw-fetch providers#379

Open
SATYAM-PRATIBHAN wants to merge 2 commits into
rohitg00:mainfrom
SATYAM-PRATIBHAN:fix/provider-fetch-timeout
Open

fix: add AbortController timeout to all raw-fetch providers#379
SATYAM-PRATIBHAN wants to merge 2 commits into
rohitg00:mainfrom
SATYAM-PRATIBHAN:fix/provider-fetch-timeout

Conversation

@SATYAM-PRATIBHAN
Copy link
Copy Markdown

@SATYAM-PRATIBHAN SATYAM-PRATIBHAN commented May 14, 2026

Closes #373

What

Adds a shared fetchWithTimeout helper (src/providers/_fetch.ts) and wires it into every raw-fetch provider so outbound HTTP calls can't hang indefinitely.

Why

All raw-fetch providers were calling fetch() with no timeout. A hung upstream (rate-limit hold, TLS stall, slow-loris) would block compress/summarize/embed forever — manifesting as fly machines stuck "warming up" and observation pipelines silently halting.

Changes

  • src/providers/_fetch.ts — new shared helper; reads AGENTMEMORY_LLM_TIMEOUT_MS (default 60s)
  • Replaced bare fetch() with fetchWithTimeout() in all 7 raw-fetch providers:
    • providers/minimax.ts
    • providers/openrouter.ts (covers Gemini LLM path too)
    • providers/embedding/{gemini,openai,cohere,voyage,openrouter}.ts
  • README.md — documents AGENTMEMORY_LLM_TIMEOUT_MS in the env-vars block
  • test/fetch-timeout.test.ts — 11 regression tests; mocks a fetch that only resolves on AbortSignal and asserts each provider rejects within the timeout

Out of scope

Retry/backoff and per-provider timeout overrides (AGENTMEMORY_ANTHROPIC_TIMEOUT_MS etc.) — as noted in the issue.

Summary by CodeRabbit

  • New Features

    • Added configurable timeout for LLM and embedding API calls via AGENTMEMORY_LLM_TIMEOUT_MS (defaults to 60s); outbound requests now honor this timeout.
  • Documentation

    • README updated to document the new timeout setting and its default.
  • Bug Fixes

    • External model and embedding requests now abort on timeout to avoid hanging operations.
  • Tests

    • Added tests validating timeout behavior and that providers abort when upstream requests stall.

Review Change Stack

@vercel
Copy link
Copy Markdown

vercel Bot commented May 14, 2026

@SATYAM-PRATIBHAN is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 06274e4d-a09a-4553-913d-1b382b93062c

📥 Commits

Reviewing files that changed from the base of the PR and between 32c421f and 8ee2926.

📒 Files selected for processing (10)
  • README.md
  • src/providers/_fetch.ts
  • src/providers/embedding/cohere.ts
  • src/providers/embedding/gemini.ts
  • src/providers/embedding/openai.ts
  • src/providers/embedding/openrouter.ts
  • src/providers/embedding/voyage.ts
  • src/providers/minimax.ts
  • src/providers/openrouter.ts
  • test/fetch-timeout.test.ts
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/providers/openrouter.ts
  • src/providers/embedding/cohere.ts
  • src/providers/embedding/openrouter.ts
  • src/providers/_fetch.ts
  • src/providers/embedding/gemini.ts
  • src/providers/embedding/openai.ts
  • src/providers/embedding/voyage.ts
  • src/providers/minimax.ts
  • test/fetch-timeout.test.ts

📝 Walkthrough

Walkthrough

Adds a shared fetchWithTimeout helper (env AGENTMEMORY_LLM_TIMEOUT_MS, default 60s), updates LLM and embedding providers to use it for outbound requests, and adds unit/regression tests plus README documentation.

Changes

Fetch timeout mechanism and provider adoption

Layer / File(s) Summary
fetchWithTimeout helper and documentation
src/providers/_fetch.ts, README.md
fetchWithTimeout wraps fetch with AbortController timeout using optional parameter or AGENTMEMORY_LLM_TIMEOUT_MS env var (default 60000ms), combines signals via AbortSignal.any, clears timeout in finally. README documents AGENTMEMORY_LLM_TIMEOUT_MS and its default.
Embedding provider adoption
src/providers/embedding/cohere.ts, src/providers/embedding/gemini.ts, src/providers/embedding/openai.ts, src/providers/embedding/openrouter.ts, src/providers/embedding/voyage.ts
Cohere, Gemini, OpenAI, OpenRouter, and Voyage embedding providers import and switch embedding HTTP requests from fetch to fetchWithTimeout, preserving request/response handling and error logic.
LLM provider adoption
src/providers/minimax.ts, src/providers/openrouter.ts
Minimax and OpenRouter LLM providers import and switch model request HTTP calls from fetch to fetchWithTimeout, preserving headers, body shape, and error handling.
Timeout behavior and provider regression tests
test/fetch-timeout.test.ts
Adds hangingFetch mock and tests verifying fetchWithTimeout resolves within timeout, aborts on hangs, respects AGENTMEMORY_LLM_TIMEOUT_MS default/fallback, and that multiple providers reject when upstream fetch hangs.

🎯 3 (Moderate) | ⏱️ ~20 minutes

"🐰
I hop through nets with care and rhyme,
I cut long waits to sixty time,
Abort the hang, return the call,
No sleepy fetch will stall us all,
Hooray — the network beats no more!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding an AbortController timeout mechanism to all raw-fetch providers.
Linked Issues check ✅ Passed The PR fully implements the acceptance criteria from #373: shared fetchWithTimeout helper added, all raw-fetch providers updated, env var documented, and regression tests included.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the stated objectives; no unrelated modifications detected in code, documentation, or tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/fetch-timeout.test.ts (1)

18-18: 💤 Low value

Consider a more descriptive DOMException message.

Both DOMException instances use "AbortError" for both the message and name parameters. While functional, it's more idiomatic to use a descriptive message like "The operation was aborted" for the first parameter, reserving "AbortError" for the name only.

♻️ Suggested improvement
       if (init.signal.aborted) {
-        reject(new DOMException("AbortError", "AbortError"));
+        reject(new DOMException("The operation was aborted", "AbortError"));
         return;
       }
       init.signal.addEventListener("abort", () => {
-        reject(new DOMException("AbortError", "AbortError"));
+        reject(new DOMException("The operation was aborted", "AbortError"));
       });

Also applies to: 22-22

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/fetch-timeout.test.ts` at line 18, Replace the two uses of reject(new
DOMException("AbortError", "AbortError")) in the test so the first argument is a
descriptive message (e.g., "The operation was aborted") and the second argument
remains the name "AbortError"; update both occurrences of the reject(new
DOMException(...)) calls in test/fetch-timeout.test.ts accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/providers/_fetch.ts`:
- Around line 8-14: The wrapper currently allows invalid timeout values
(NaN/negative) and unconditionally replaces any caller-provided init.signal with
the timeout controller (ctl), losing upstream abort propagation; fix by
validating and normalizing ms: compute let ms = timeoutMs ??
parseInt(getEnvVar("AGENTMEMORY_LLM_TIMEOUT_MS") ?? "60000", 10) and if ms is
not a finite positive number set ms = 60000, and preserve/compose existing
init.signal by creating the timeout AbortController (ctl) but if init.signal
exists then if init.signal.aborted call ctl.abort() immediately and otherwise
add an event listener init.signal.addEventListener('abort', () => ctl.abort())
so upstream aborts propagate to ctl; pass ctl.signal to fetch and ensure you
remove the event listener in the finally/cleanup (and still clearTimeout(t));
reference symbols: timeoutMs, getEnvVar, ms, AbortController, ctl, init.signal,
t, fetch.

---

Nitpick comments:
In `@test/fetch-timeout.test.ts`:
- Line 18: Replace the two uses of reject(new DOMException("AbortError",
"AbortError")) in the test so the first argument is a descriptive message (e.g.,
"The operation was aborted") and the second argument remains the name
"AbortError"; update both occurrences of the reject(new DOMException(...)) calls
in test/fetch-timeout.test.ts accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8324a3bb-ea06-4412-9351-65f20037ca51

📥 Commits

Reviewing files that changed from the base of the PR and between 4b354b7 and 55c5276.

📒 Files selected for processing (10)
  • README.md
  • src/providers/_fetch.ts
  • src/providers/embedding/cohere.ts
  • src/providers/embedding/gemini.ts
  • src/providers/embedding/openai.ts
  • src/providers/embedding/openrouter.ts
  • src/providers/embedding/voyage.ts
  • src/providers/minimax.ts
  • src/providers/openrouter.ts
  • test/fetch-timeout.test.ts

Comment thread src/providers/_fetch.ts Outdated
…ohitg00#373)

Signed-off-by: Satyam Pratibhan <142714564+SATYAM-PRATIBHAN@users.noreply.github.com.>
…hTimeout

Signed-off-by: Satyam Pratibhan <142714564+SATYAM-PRATIBHAN@users.noreply.github.com.>
@SATYAM-PRATIBHAN SATYAM-PRATIBHAN force-pushed the fix/provider-fetch-timeout branch from 32c421f to 8ee2926 Compare May 14, 2026 17:42
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.

Provider fetch-timeout audit: add AbortController + AGENTMEMORY_LLM_TIMEOUT_MS

1 participant