LearnNewsExamplesServices
Frontmatter
id14052
titleBound native Ollama embedding calls with timeouts
stateClosed
labels
enhancementaitestingarchitecture
assigneesneo-gpt
createdAtJun 26, 2026, 5:29 AM
updatedAtJun 26, 2026, 11:04 AM
githubUrlhttps://github.com/neomjs/neo/issues/14052
authorneo-gpt
commentsCount1
parentIssue14036
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 26, 2026, 11:04 AM

Bound native Ollama embedding calls with timeouts

Closed v13.1.0/archive-v13-1-0-chunk-6 enhancementaitestingarchitecture
neo-gpt
neo-gpt commented on Jun 26, 2026, 5:29 AM

Context

Vega's Approve+Follow-Up review on #14047 approved the OpenAI-compatible production path for #14036, but explicitly asked whether the native Ollama embedding path is reachable and still unbounded. I verified it is reachable through the existing provider selector and explicit dispatch path, so this is durable follow-up work rather than PR-thread prose.

Freshness evidence:

  • Live latest-open sweep: checked latest 20 open issues at 2026-06-26T03:29:15Z; no equivalent native-Ollama timeout child found. The broad parent #14036 remains open and is the correct anchor.
  • A2A in-flight sweep: checked last 30 messages at 2026-06-26T03:29:15Z; no [lane-claim] / [lane-intent] overlapped this native Ollama timeout slice.
  • KB/local duplicate sweep: #13946 covers native Ollama truncation/request-shape (truncate:false + options.num_ctx), not request duration bounds.

The Problem

#14036 says each embed call should be bounded so one wedged provider request cannot stall the deferred-embed WAL drain indefinitely. PR #14047 correctly bounded the openAiCompatible batch path, which is the deployment default and the current production path. The native Ollama path remains outside that bound: if a deployment sets NEO_EMBEDDING_PROVIDER=ollama, or a runtime adapter explicitly calls embedTexts(texts, 'ollama'), the call can still wait forever on provider.embed().

That leaves a smaller but real version of the same failure mode: native Ollama can hang a batch embedding call with no per-call timeout, no timeout-shaped ConsumerFriction, and no row-level fail-loud handoff for the caller.

The Architectural Reality

  • ai/config.template.mjs:157 exposes embeddingProvider as the deployment-wide embedding selector.
  • ai/config.template.mjs:161-162 documents that runtime adapters can explicitly select the native ollama provider.
  • ai/services/memory-core/TextEmbeddingService.mjs:603-611 routes embedText(..., 'ollama') directly to provider.embed().
  • ai/services/memory-core/TextEmbeddingService.mjs:645-653 routes embedTexts(..., 'ollama') directly to provider.embed() with no request timeout.
  • #13946 already fixed the native Ollama truncation/request-shape risk by passing truncate:false and num_ctx; this ticket is the separate duration-bound parity gap.

The Fix

Add the symmetric timeout bound for the native Ollama embedding path at the use site, preserving ADR-0019:

  1. Resolve the timeout through AiConfig at the native Ollama embedding call site.
  2. Bound both embedText(..., 'ollama') and embedTexts(..., 'ollama') provider calls.
  3. On timeout, throw a fail-loud timeout error that callers can route through existing retry/unrecoverable paths.
  4. Emit timeout-shaped ConsumerFriction or the nearest existing diagnostic signal with provider ollama, matching the operational visibility shipped for openAiCompatible.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
TextEmbeddingService.embedText(text, 'ollama') TextEmbeddingService provider dispatch + #14036 per-call timeout contract Native Ollama single-text embedding is bounded by an AiConfig leaf and fails loud on timeout Throw timeout error; caller handles existing failure path JSDoc/comment if needed Unit with hanging fake Ollama provider
TextEmbeddingService.embedTexts(texts, 'ollama') TextEmbeddingService provider dispatch + #14036 per-call timeout contract Native Ollama batch embedding is bounded by an AiConfig leaf and fails loud on timeout Throw timeout error; caller handles existing failure path JSDoc/comment if needed Unit with hanging fake Ollama provider
Timeout diagnostic/friction signal #14047 openAiCompatible timeout-friction precedent Timed-out native Ollama request emits provider-scoped timeout signal Error propagation remains fail-loud if signal emission is unavailable None Unit captures timeout signal payload
Config leaf ADR 0019 AiConfig Provider SSOT Timeout is read from the owning AiConfig surface at use site; no env re-read/pass-through hidden default Invalid value fails loud Config template JSDoc Config/template unit if a new leaf is added

Decision Record impact

Aligned with ADR 0019. The implementation must keep AiConfig as the reactive provider SSOT: no direct env re-read, no copied config pass-through across modules, and no defensive optional-chain fallback that masks invalid config.

Acceptance Criteria

  • embedText(..., 'ollama') is bounded by a native Ollama embedding timeout.
  • embedTexts(..., 'ollama') is bounded by a native Ollama embedding timeout.
  • Timed-out native Ollama embedding calls fail loud instead of hanging indefinitely.
  • Timed-out native Ollama embedding calls emit a provider-scoped timeout diagnostic/friction signal.
  • Focused unit coverage proves single and batch native Ollama calls reject on a hanging fake provider.
  • Existing OpenAI-compatible and Gemini embedding behavior remains unchanged.

Out of Scope

  • OpenAI-compatible batch timeout behavior already delivered by PR #14047.
  • Native Ollama truncation/request-shape parity already tracked by #13946.
  • CPU-saturation-with-no-throughput heuristics from #14036; this ticket is duration-bound parity only.
  • Changing the default embedding provider.

Avoided Traps

  • Do not treat native Ollama as unreachable just because openAiCompatible is the default. The selector and explicit dispatch remain supported surfaces.
  • Do not add a provider-agnostic config pass-through object to satisfy this; that would violate ADR 0019's AiConfig boundary.
  • Do not bundle CPU-saturation detection into this leaf. The release-critical parity gap is the bounded call.

Related

Origin Session ID: 35f83031-f1a6-41a7-9c3b-089b87307db9

Handoff Retrieval Hints: query_raw_memories("native Ollama embedTexts timeout ConsumerFriction #14047 follow-up"); source anchors: ai/services/memory-core/TextEmbeddingService.mjs:603-653, ai/config.template.mjs:151-170, PR #14047 Vega Approve+Follow-Up review.

Authored by Euclid (GPT-5, Codex Desktop).

tobiu referenced in commit 81c7156 - "fix(ai): bound native ollama embedding timeout (#14052) (#14076)" on Jun 26, 2026, 11:04 AM
tobiu closed this issue on Jun 26, 2026, 11:04 AM