Skip to content

fix(ollama): remote Ollama streaming stalls at model_call:started on slow hosts#96635

Open
henrybrewer00-dotcom wants to merge 1 commit into
openclaw:mainfrom
henrybrewer00-dotcom:fix-ollama-remote-stream
Open

fix(ollama): remote Ollama streaming stalls at model_call:started on slow hosts#96635
henrybrewer00-dotcom wants to merge 1 commit into
openclaw:mainfrom
henrybrewer00-dotcom:fix-ollama-remote-stream

Conversation

@henrybrewer00-dotcom

Copy link
Copy Markdown

Closes #94251

What Problem This Solves

Fixes an issue where users running a remote Ollama provider (Ollama on a different machine than OpenClaw, especially slow CPU-only inference) would never receive a chat response. The session stalls indefinitely at model_call:started, and the remote Ollama host shows the model going to Stopping... mid-generation — the server sees the client disconnect. Direct curl from the same host streams fine, so the failure is specific to OpenClaw's native Ollama stream client.

Why This Change Was Made

The native Ollama stream path (createRawOllamaStreamFn) requests a stream through fetchWithSsrFGuard, which arms an AbortController-based deadline (buildTimeoutAbortSignal) and returns a refreshTimeout callback. That callback is the documented contract for converting the deadline into a no-progress (idle) timeout: it must be called as the body is consumed. The OpenAI-compatible transport (src/agents/provider-transport-fetch.ts) and MCP HTTP fetch (src/agents/mcp-http-fetch.ts) both call refreshTimeout() on every chunk. The Ollama native path destructured only { response, release } and never called it, so the configured request timeout acted as a hard wall-clock cap. Once a configured timeoutSeconds elapsed while a slow remote model was still streaming, the request was aborted mid-stream, the server saw a disconnect, and the run stalled. The fix calls refreshTimeout?.() for each consumed NDJSON chunk, matching the existing sibling contract.

User Impact

Remote/slow Ollama hosts now stream to completion: the request deadline behaves as a no-progress timeout (reset on every chunk) rather than a total wall-clock cap. Chat sessions backed by a remote Ollama model return responses instead of hanging at model_call:started. No config or API changes.

Evidence

Added a regression test asserting refreshTimeout is called once per streamed NDJSON chunk.

Before the production fix (test reverted), the test fails:

× refreshes the guarded-fetch idle timeout for each streamed chunk
AssertionError: expected "vi.fn()" to be called 3 times, but got 0 times
 ❯ extensions/ollama/src/stream.test.ts:491:28
   491| expect(refreshTimeout).toHaveBeenCalledTimes(chunks.length);
 Test Files  1 failed (1)
      Tests  1 failed | 15 passed (16)

After the fix:

 Test Files  1 passed (1)
      Tests  16 passed (16)

Also green on the touched area: tsgo extensions typecheck (exit 0), oxlint (exit 0), oxfmt --check (all files correctly formatted).

@clawsweeper

clawsweeper Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 7, 2026, 2:17 PM ET / 18:17 UTC.

Summary
The PR refreshes the native Ollama guarded-fetch timeout on each consumed NDJSON chunk and adds a regression test for that callback.

PR surface: Source +6, Tests +41. Total +47 across 2 files.

Reproducibility: no. live current-main reproduction was run in this read-only review. Source inspection shows the native Ollama path consumes a guarded response body without refreshing its timeout, and the linked issue provides field evidence for the same remote-stream stall.

Review metrics: 1 noteworthy metric.

  • Provider timeout behavior: 1 native Ollama stream path changed; 0 config keys added. Maintainers should notice that existing timeoutSeconds semantics change for streamed Ollama responses without adding a new operator-facing option.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #94251
Summary: This PR is the open candidate fix for the canonical remote Ollama streaming stall report; earlier overlapping candidates are closed unmerged.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted real behavior proof showing an OpenClaw chat or infer run completes against a remote or slow Ollama host after this patch.
  • State the exact command or chat path used and redact private IPs, API keys, phone numbers, non-public endpoints, and other private details.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body includes regression-test and tool-check output, but no after-fix real remote or slow Ollama run; the contributor should add redacted terminal output, logs, or a recording and update the PR body to trigger a fresh ClawSweeper review.

Risk before merge

  • [P1] The PR still has no after-fix run proving a remote or slow Ollama-backed OpenClaw chat/infer path completes instead of stalling.
  • [P2] Merging changes native Ollama timeoutSeconds behavior for active streams from a wall-clock cap to an idle/progress timeout, which maintainers should explicitly accept for compatibility.

Maintainer options:

  1. Require remote Ollama proof (recommended)
    Ask the contributor for redacted terminal output, logs, or a short recording showing an OpenClaw Ollama chat or infer run completing against a remote or slow host after this patch.
  2. Accept idle-timeout parity
    Maintainers can explicitly accept that native Ollama streams should match sibling stream transports by treating timeoutSeconds as a no-progress timeout while chunks arrive.

Next step before merge

  • [P2] Human review is needed for live proof and timeout-semantics acceptance; there is no narrow code repair for ClawSweeper to automate on this branch.

Maintainer decision needed

  • Question: Should native Ollama streams use timeoutSeconds as an idle/progress timeout while chunks arrive, matching sibling streaming transports, once live remote or slow-Ollama proof is added?
  • Rationale: The source evidence supports the narrow fix, but it intentionally changes timeout semantics for existing Ollama streaming users, so maintainer intent is needed before accepting that compatibility risk.
  • Likely owner: vincentkoc — Most recent and strongest history signal on the native Ollama stream path.
  • Options:
    • Accept after live proof (recommended): Require redacted real behavior proof, then allow this narrow idle-timeout parity fix to merge.
    • Preserve wall-clock cap: Ask for an alternative that preserves current wall-clock timeout semantics or makes idle timeout behavior explicit.

Security
Cleared: The diff only changes Ollama stream timeout handling and a focused test; no dependency, workflow, credential, permission, or supply-chain surface changed.

Review details

Best possible solution:

Merge only after redacted real behavior proof shows the affected remote or slow Ollama path completes and maintainers accept idle-timeout parity for native Ollama streams.

Do we have a high-confidence way to reproduce the issue?

No live current-main reproduction was run in this read-only review. Source inspection shows the native Ollama path consumes a guarded response body without refreshing its timeout, and the linked issue provides field evidence for the same remote-stream stall.

Is this the best way to solve the issue?

Yes, likely: refreshing the existing guarded-fetch timer in the native Ollama chunk loop is the narrow provider-owned fix and matches sibling stream wrappers. The remaining gap is real after-fix remote-Ollama proof and maintainer acceptance of the timeout semantics.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against a6768d9de567.

Label changes

Label justifications:

  • P1: The PR targets an open provider bug where Ollama-backed chat sessions can stall before delivering a response.
  • merge-risk: 🚨 compatibility: The diff changes existing Ollama streaming timeout behavior from a wall-clock cap to a progress-refreshed idle timeout.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body includes regression-test and tool-check output, but no after-fix real remote or slow Ollama run; the contributor should add redacted terminal output, logs, or a recording and update the PR body to trigger a fresh ClawSweeper review.
Evidence reviewed

PR surface:

Source +6, Tests +41. Total +47 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 7 1 +6
Tests 1 41 0 +41
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 48 1 +47

What I checked:

  • Repository policy applied: Root AGENTS.md and scoped extensions/AGENTS.md were read fully; provider/plugin boundary, sibling-surface, compatibility, and real-behavior-proof guidance affected this review. (AGENTS.md:1, a6768d9de567)
  • Current main lacks the timeout refresh: Current main passes request timeoutMs into fetchWithSsrFGuard but destructures only response and release, then consumes parseNdjsonStream without calling refreshTimeout in the native Ollama loop. (extensions/ollama/src/stream.ts:1164, a6768d9de567)
  • Guarded-fetch timeout contract: fetchWithSsrFGuard returns refreshTimeout, and buildTimeoutAbortSignal documents refresh as restarting only the internal timeout timer. (src/utils/fetch-timeout.ts:104, a6768d9de567)
  • Sibling streaming precedent: OpenAI-compatible provider transport and MCP HTTP fetch wrap guarded response bodies with refreshTimeout, and wrapGuardedBodyStream calls it as chunks are pulled. (src/infra/net/guarded-body-stream.ts:53, a6768d9de567)
  • PR diff and regression coverage: The PR adds refreshTimeout to the native Ollama guarded fetch result, calls it inside the NDJSON loop, and adds a test asserting one refresh per consumed chunk. (extensions/ollama/src/stream.ts:1195, 7b6b41ee98e0)
  • Canonical issue linkage: The PR closes the open remote Ollama stall report, whose comments show working curl controls, OpenClaw 2026.6.8 config, and stalled model_call:started logs for web console/chat usage.

Likely related people:

  • vincentkoc: Recent history shows multiple Ollama stream/runtime changes, and current blame for the native Ollama stream loop points at Vincent Koc's refreshed stream file snapshot. (role: recent area contributor; confidence: high; commits: 6037d1a85cf1, 6fcc9457020e, c7b190beec73; files: extensions/ollama/src/stream.ts)
  • steipete: History shows substantial provider runtime and Ollama-adjacent refactor work, including the runtime extraction that touched the Ollama stream file. (role: provider-runtime contributor; confidence: medium; commits: bb46b79d3c14; files: extensions/ollama/src/stream.ts, docs/providers/ollama.md, src/infra/net/fetch-guard.ts)
  • DranboFieldston: A directly related guarded-dispatcher timeout propagation fix is in the network fetch history used by provider streams. (role: adjacent network timeout contributor; confidence: medium; commits: 977a4b24afd0; files: src/infra/net/fetch-guard.ts, src/infra/net/undici-runtime.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-06-25T02:42:17.230Z sha 7b6b41e :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 25, 2026
@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@henrybrewer00-dotcom thanks for the PR. ClawSweeper is still waiting on real behavior proof before this can move forward.

Useful proof can be a screenshot, short video, terminal output, copied live output, linked artifact, or redacted logs that show the changed behavior after the fix. Please redact private tokens, phone numbers, private endpoints, customer data, and anything else sensitive.

Once proof is added to the PR body or a comment, ClawSweeper or a maintainer can re-check it.

@barnacle-openclaw

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@barnacle-openclaw barnacle-openclaw Bot added the stale Marked as stale due to inactivity label Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: ollama merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS stale Marked as stale due to inactivity status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Ollama remote provider streaming not consumed — model_call:started never progresses in chat sessions

2 participants