Skip to content

fix: make stream inactivity timeout configurable, increase for Ollama#1993

Open
octo-patch wants to merge 1 commit intoAndyMik90:developfrom
octo-patch:fix/issue-1984-configurable-stream-timeout
Open

fix: make stream inactivity timeout configurable, increase for Ollama#1993
octo-patch wants to merge 1 commit intoAndyMik90:developfrom
octo-patch:fix/issue-1984-configurable-stream-timeout

Conversation

@octo-patch
Copy link
Copy Markdown

@octo-patch octo-patch commented Apr 3, 2026

Fixes #1984

Problem

When using Auto Claude with local Ollama models on slower hardware, tasks silently fail and transfer to Human Review without any error message shown in the frontend logs. This happens because:

  1. STREAM_INACTIVITY_TIMEOUT_MS was hardcoded at 60 seconds in runner.ts
  2. Ollama models running on a slow machine (CPU inference, large models) can take several minutes just to generate the first token
  3. When the timeout fires, the task is aborted without a clear error surfaced to the user

Solution

  • Add an optional streamInactivityTimeoutMs field to RunnerOptions so callers can override the inactivity timeout per-session (defaults to the existing 60s for backward compatibility)
  • Thread the parameter through executeStream() instead of using the hardcoded constant
  • In all three worker session runners (runSingleSession, runDefaultSession, runAgenticSpecOrchestrator), detect the Ollama provider and pass a 5-minute (300s) timeout to accommodate slow local inference

The 60s default is preserved for cloud providers where 60s without a response almost certainly indicates a real problem. The 5-minute timeout for Ollama gives local inference time to complete on slower hardware without hanging indefinitely.

Testing

  • Verified TypeScript types are consistent across the call chain
  • The streamInactivityTimeoutMs parameter flows correctly: RunnerOptionsrunAgentSession()executeStream() with proper default fallback

Summary by CodeRabbit

Release Notes

  • New Features
    • Implemented configurable stream inactivity timeout mechanism for improved session management.
    • Ollama provider now enforces a 5-minute inactivity threshold to automatically handle unresponsive streams and enhance system stability.

…fixes AndyMik90#1984)

Local providers like Ollama on slower hardware can take more than 60 seconds
to generate the first response token. The hardcoded 60s inactivity timeout was
causing tasks to silently fail and transfer to Human Review without any visible
error message in the frontend logs.

- Add streamInactivityTimeoutMs option to RunnerOptions so callers can
  override the inactivity timeout per-session
- Use the configurable value in executeStream() (defaulting to 60s as before)
- Set a 5-minute (300s) timeout for Ollama sessions in all three worker session
  runners (runSingleSession, runDefaultSession, runAgenticSpecOrchestrator)
  to accommodate slow inference on local hardware

Co-Authored-By: Octopus <liyuan851277048@icloud.com>
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

📝 Walkthrough

Walkthrough

Added configurable stream inactivity timeout support to the AI agent runner. Introduced streamInactivityTimeoutMs option in the runner configuration, plumbed through session execution, and set to 300,000 milliseconds for Ollama provider while defaulting to existing behavior for others.

Changes

Cohort / File(s) Summary
Stream Inactivity Timeout Configuration
apps/desktop/src/main/ai/session/runner.ts
Added optional streamInactivityTimeoutMs property to RunnerOptions interface. Plumbed parameter through runAgentSession into executeStream, replacing hardcoded STREAM_INACTIVITY_TIMEOUT_MS constant to allow per-session timeout override.
Ollama Timeout Override
apps/desktop/src/main/ai/agent/worker.ts
Injected streamInactivityTimeoutMs: 300_000 into runner options for three execution paths (runSingleSession, runDefaultSession, runAgenticSpecOrchestrator) when provider is Ollama; remains undefined for other providers.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A timeout too short, oh what a fright!
On Ollama's slow tasks burning the night,
Five minutes we grant with a whisper of code,
Now patience runs deep on the computational road! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 changes: making stream inactivity timeout configurable and increasing it for Ollama provider.
Linked Issues check ✅ Passed The PR addresses both objectives from issue #1984: making the timeout configurable via RunnerOptions and increasing it for Ollama (300s vs 60s default).
Out of Scope Changes check ✅ Passed All changes are focused on the timeout configurability feature; no unrelated modifications detected beyond the stated objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

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

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
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a configurable streamInactivityTimeoutMs for AI sessions, specifically setting a five-minute timeout for the Ollama provider to accommodate slower local hardware. The review feedback suggests refactoring repeated magic numbers and hardcoded strings into constants or enums to improve maintainability, and recommends breaking a long destructuring statement in runner.ts into multiple lines for better readability.

: undefined,
// Local providers like Ollama can take much longer than 60s to generate a
// response on slower hardware. Use a 5-minute timeout instead of the default.
streamInactivityTimeoutMs: baseSession.provider === 'ollama' ? 300_000 : undefined,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The magic number 300_000 (representing a 5-minute timeout) and the hardcoded string 'ollama' are repeated in three different locations within this file (lines 346, 523, and 1120). This duplication makes the code harder to maintain and prone to inconsistency if the timeout needs to be adjusted in the future. Consider defining a constant for the Ollama inactivity timeout and using the SupportedProvider.Ollama enum instead of a string literal.

options: RunnerOptions = {},
): Promise<SessionResult> {
const { onEvent, onAuthRefresh, onModelRefresh, tools, memoryContext, onAccountSwitch, currentAccountId } = options;
const { onEvent, onAuthRefresh, onModelRefresh, tools, memoryContext, onAccountSwitch, currentAccountId, streamInactivityTimeoutMs } = options;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This line has become excessively long and difficult to read due to the addition of streamInactivityTimeoutMs. Breaking the destructuring of options into multiple lines would improve maintainability and follow common TypeScript style conventions.

  const {
    onEvent,
    onAuthRefresh,
    onModelRefresh,
    tools,
    memoryContext,
    onAccountSwitch,
    currentAccountId,
    streamInactivityTimeoutMs,
  } = options;

Copy link
Copy Markdown
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/main/ai/session/runner.ts (1)

159-169: ⚠️ Potential issue | 🟠 Major

Recompute inactivity timeout after provider account-switch retries.

streamInactivityTimeoutMs is captured once from initial options and reused on retries. If onAccountSwitch changes provider (for example to Ollama), executeStream() still uses the old timeout, which can reintroduce premature stream timeouts.

💡 Proposed fix
 export async function runAgentSession(
   config: SessionConfig,
   options: RunnerOptions = {},
 ): Promise<SessionResult> {
   const { onEvent, onAuthRefresh, onModelRefresh, tools, memoryContext, onAccountSwitch, currentAccountId, streamInactivityTimeoutMs } = options;
   const startTime = Date.now();

   let authRetries = 0;
   let activeConfig = config;
   let activeAccountId = currentAccountId;
+  let activeStreamInactivityTimeoutMs = streamInactivityTimeoutMs;

   // Retry loop for auth refresh and account switching
   while (authRetries <= MAX_AUTH_RETRIES) {
     try {
-      const result = await executeStream(activeConfig, tools, onEvent, memoryContext, streamInactivityTimeoutMs);
+      const result = await executeStream(activeConfig, tools, onEvent, memoryContext, activeStreamInactivityTimeoutMs);
       return {
         ...result,
         durationMs: Date.now() - startTime,
       };
     } catch (error: unknown) {
@@
         if (newAuth) {
@@
           activeAccountId = newAuth.accountId;
+          if (streamInactivityTimeoutMs == null) {
+            activeStreamInactivityTimeoutMs =
+              newAuth.resolvedProvider === 'ollama' ? 300_000 : undefined;
+          }
           continue;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/ai/session/runner.ts` around lines 159 - 169, The loop
captures streamInactivityTimeoutMs once from options causing executeStream to
keep using the stale timeout across account-switch retries; before each call to
executeStream (inside the auth retry loop) re-read/recompute the timeout from
the current options/provider (i.e., get options.streamInactivityTimeoutMs or
derive it from the updated provider after onAccountSwitch) and pass that fresh
value into executeStream so timeouts reflect any provider/account change
(symbols to update: streamInactivityTimeoutMs, options, executeStream,
onAccountSwitch, activeAccountId, activeConfig, authRetries).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/main/ai/agent/worker.ts`:
- Around line 344-346: Refactor the duplicated Ollama timeout check by
extracting a single constant and/or helper (e.g., OLLAMA_STREAM_TIMEOUT_MS =
300_000 and a small helper getProviderStreamInactivityTimeout(provider) or
isOllamaProvider(provider)) and replace each inline occurrence of
baseSession.provider === 'ollama' ? 300_000 : undefined (including places that
set streamInactivityTimeoutMs) with a call to that helper or the constant
lookup; update the three duplicated sites so they all reference the new symbol
(streamInactivityTimeoutMs assignments should use the helper/constant) to
centralize future policy changes.

---

Outside diff comments:
In `@apps/desktop/src/main/ai/session/runner.ts`:
- Around line 159-169: The loop captures streamInactivityTimeoutMs once from
options causing executeStream to keep using the stale timeout across
account-switch retries; before each call to executeStream (inside the auth retry
loop) re-read/recompute the timeout from the current options/provider (i.e., get
options.streamInactivityTimeoutMs or derive it from the updated provider after
onAccountSwitch) and pass that fresh value into executeStream so timeouts
reflect any provider/account change (symbols to update:
streamInactivityTimeoutMs, options, executeStream, onAccountSwitch,
activeAccountId, activeConfig, authRetries).
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3edb350a-d380-44f9-b9cb-0e1c4f5f991c

📥 Commits

Reviewing files that changed from the base of the PR and between cba7a02 and 1f37e45.

📒 Files selected for processing (2)
  • apps/desktop/src/main/ai/agent/worker.ts
  • apps/desktop/src/main/ai/session/runner.ts

Comment on lines +344 to +346
// Local providers like Ollama can take much longer than 60s to generate a
// response on slower hardware. Use a 5-minute timeout instead of the default.
streamInactivityTimeoutMs: baseSession.provider === 'ollama' ? 300_000 : undefined,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Centralize the Ollama timeout policy to avoid divergence across callsites.

The same provider check and 300_000 literal are duplicated in three places. Extract a shared constant/helper so future timeout policy changes are one-line updates.

♻️ Proposed refactor
+const OLLAMA_STREAM_INACTIVITY_TIMEOUT_MS = 300_000;
+
+function getStreamInactivityTimeoutMs(provider: string): number | undefined {
+  return provider === 'ollama' ? OLLAMA_STREAM_INACTIVITY_TIMEOUT_MS : undefined;
+}
@@
-    streamInactivityTimeoutMs: baseSession.provider === 'ollama' ? 300_000 : undefined,
+    streamInactivityTimeoutMs: getStreamInactivityTimeoutMs(baseSession.provider),
@@
-      streamInactivityTimeoutMs: session.provider === 'ollama' ? 300_000 : undefined,
+      streamInactivityTimeoutMs: getStreamInactivityTimeoutMs(session.provider),
@@
-      streamInactivityTimeoutMs: session.provider === 'ollama' ? 300_000 : undefined,
+      streamInactivityTimeoutMs: getStreamInactivityTimeoutMs(session.provider),

Also applies to: 523-523, 1120-1120

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/ai/agent/worker.ts` around lines 344 - 346, Refactor
the duplicated Ollama timeout check by extracting a single constant and/or
helper (e.g., OLLAMA_STREAM_TIMEOUT_MS = 300_000 and a small helper
getProviderStreamInactivityTimeout(provider) or isOllamaProvider(provider)) and
replace each inline occurrence of baseSession.provider === 'ollama' ? 300_000 :
undefined (including places that set streamInactivityTimeoutMs) with a call to
that helper or the constant lookup; update the three duplicated sites so they
all reference the new symbol (streamInactivityTimeoutMs assignments should use
the helper/constant) to centralize future policy changes.

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.

Timeout Silent Error

2 participants