LearnNewsExamplesServices
Frontmatter
id13964
titleCap REM Tri-Vector output generation
stateClosed
labels
bugaiarchitectureperformancemodel-experience
assigneesneo-gpt
createdAtJun 24, 2026, 8:33 PM
updatedAtJun 24, 2026, 8:42 PM
githubUrlhttps://github.com/neomjs/neo/issues/13964
authorneo-gpt
commentsCount1
parentIssue13835
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 24, 2026, 8:42 PM

Cap REM Tri-Vector output generation

Closed v13.1.0/archive-v13-1-0-chunk-6 bugaiarchitectureperformancemodel-experience
neo-gpt
neo-gpt commented on Jun 24, 2026, 8:33 PM

Release classification: boardless operational P0 — local/cloud model-burn prevention, not a release-board expansion.

Context

Live operator evidence on 2026-06-24: during an active REM sleep graph extraction dream lease, LM Studio's loaded-model counter for google/gemma-4-26b-a4b grew from Gen 131,951 tok to Gen 140,439 tok. This happened while the orchestrator reported other maintenance tasks deferring behind REM.

This is not the same failure shape as the closed input-overflow ticket #13918. The important falsifier is that the visible counter keeps increasing after the request starts. A prompt/context input budget is fixed at send time; a growing Gen counter indicates an active generation/output path. The existing input guardrail still matters, but this incident exposes the other half of the budget: generated Tri-Vector output is not bounded at the call site.

Live duplicate sweep: checked latest 20 open issues at 2026-06-24T18:32Z; no equivalent found. Targeted GitHub searches for SemanticGraphExtractor max_tokens output cap, OpenAiCompatible finish_reason length streaming, tri-vector num_predict max_tokens, and LM Studio generated tokens runaway returned no equivalent issue. A2A all-status latest-30 sweep at 2026-06-24T18:32Z found no competing lane claim for this scope. Memory-mining queries for REM context/output cap and LMS generated-token runaway returned no prior mapping.

The Problem

SemanticGraphExtractor already has input guardrails and retry-loop truncation handling, but the Tri-Vector generation call does not pass an output-token cap or timeout:

  • ai/services/graph/SemanticGraphExtractor.mjs:333-334 calls provider.generate(messages, {reasoning_effort, responseSchema, responseSchemaName}) with no max_tokens, no Ollama num_predict, and no timeoutMs.
  • ai/services/graph/SemanticGraphExtractor.mjs:351-353 asks getCompletionFinishReason() / isLengthTruncatedCompletion() to classify provider length truncation, but that only works if the provider wrapper preserves the finish reason.
  • ai/provider/OpenAiCompatible.mjs:155-169 implements generate() by consuming stream() and returning only {content, raw: {message: {content}}}. It discards OpenAI-compatible choices[0].finish_reason, so the extractor's length-truncation branch is unreachable for LM Studio/OpenAI-compatible streaming.
  • ai/provider/OpenAiCompatible.mjs:253-299 only creates a timeout controller when timeoutMs or an upstream signal is provided. The Tri-Vector caller provides neither.
  • ai/provider/Ollama.mjs:372-450 defaults chat generation timeout to one hour and supports native options through preparePayload(), but the Tri-Vector caller does not pass num_predict, so Ollama can hit the same generated-output burn shape in cloud.

Result: a schema-constrained REM extraction can spend massive time/tokens generating output even when the input prompt is inside the safe band. If the provider eventually truncates, LM Studio/OpenAI-compatible currently drops the finish_reason, so existing fail-closed handling cannot observe the reason.

The Architectural Reality

The owner surface is the graph extraction call path, not global model config or deployment docs:

  • SemanticGraphExtractor.executeTriVectorExtraction() owns Tri-Vector prompt construction, schema-constrained output, retry semantics, and ConsumerFriction emission.
  • OpenAiCompatibleProvider.generate()/stream() owns LM Studio/OpenAI-compatible response normalization.
  • OllamaProvider.generate() owns native Ollama response normalization and already carries raw finish metadata if the caller requests bounded native options.
  • AiConfig.localModels.chat.* is the ADR 0019 source for local chat-model budgets. New budget leaves must be read at the use site and passed to providers; do not re-derive env values, mutate config, or silently fall back.

The Fix

Add a bounded generated-output budget for REM Tri-Vector extraction and make both supported local providers expose enough finish metadata for the existing extractor checks to work.

Recommended narrow shape:

  1. Add/read an AiConfig leaf for Tri-Vector generated-output cap, or a role-scoped graph extraction output cap if the existing config taxonomy has a better local home.
  2. Pass that cap from SemanticGraphExtractor.executeTriVectorExtraction() to providers:
    • OpenAI-compatible / LM Studio: max_tokens or the compatible field accepted by the server.
    • Ollama: num_predict via the native options path.
  3. Pass a task timeout for Tri-Vector generation so an output runaway is bounded by time as well as tokens.
  4. Preserve OpenAI-compatible streaming finish metadata in OpenAiCompatibleProvider.generate() so SemanticGraphExtractor.getCompletionFinishReason() can see length / max_tokens and emit context-overflow instead of treating the output as an ordinary malformed JSON repair candidate.
  5. Keep the existing input guardrail intact. This ticket does not change the bytes/token estimator or safe input band.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
SemanticGraphExtractor.executeTriVectorExtraction() provider call This incident; #13918 retry-loop hardening Tri-Vector generation passes a finite output cap and timeout on every local provider call. Missing/invalid config fails loud per ADR 0019; no hidden defaults at the call site. Method JSDoc / inline budget comment. Unit test asserts OpenAI-compatible receives max_tokens; Ollama receives num_predict; timeout is passed.
OpenAiCompatibleProvider.generate()/stream() normalized result Existing getCompletionFinishReason() contract Streaming completions preserve finish reason in raw so extractor truncation handling is reachable. If a server omits finish reason, behavior remains current content-only result. Provider JSDoc. Unit/provider test with SSE finish_reason: "length" reaches extractor abort path.
OllamaProvider.generate() Tri-Vector options Cloud parity requirement Caller-supplied output cap maps to native options.num_predict; raw done_reason remains visible. If Ollama returns timeout/error, existing ConsumerFriction timeout/error path handles it. Provider option comment if touched. Unit test for payload shape and extractor done_reason length classification.
ConsumerFriction / REM run state #13918 visibility contract Length-capped output is surfaced as deterministic context-overflow / bounded-output friction, not silent JSON repair. No retry append after a capped/truncated response. PR evidence. Regression fixture proves generated-output truncation does not append-grow prompt and does not run unbounded.

Decision Record impact

Aligned with ADR 0019. Any new config must be an AiConfig leaf read at the use site. No ADR amendment expected.

Acceptance Criteria

  • Tri-Vector extraction passes a finite generated-output cap to LM Studio/OpenAI-compatible requests.
  • Tri-Vector extraction passes the equivalent finite generated-output cap to native Ollama requests.
  • Tri-Vector extraction passes a finite task timeout instead of relying on provider defaults.
  • OpenAI-compatible streaming preserves completion finish reason in the normalized result.
  • A length/max-token finish reason causes the existing retry-loop abort path to fire; it must not append the truncated assistant output into a repair prompt.
  • Focused tests cover LM Studio/OpenAI-compatible payload shape, Ollama payload shape, and extractor behavior for a truncated completion.
  • No changes to input safe-band estimator, session chunking, or deployment guides.

Out of Scope

  • Full chunk-map/reduce REM graph extraction (#12073 / Discussion #12439).
  • Input token estimator calibration or over-band re-serve termination (#13918 already closed that incident class).
  • Killing or interrupting any currently running local model request.
  • LM Studio model ejection/downscaling policy.

Avoided Traps

  • Do not treat a growing Gen counter as proof that prompt input exceeded context. A prompt is fixed at send time; growing token count points at generated output or provider accounting.
  • Do not fix only LM Studio. Cloud uses Ollama, so the output cap must cover both provider families.
  • Do not add defensive Number() / fallback conversions around AiConfig leaves. ADR 0019 leaves define type and should fail loud.

Related

Related: #13918 Related: #12073 Related: #12065

Handoff Retrieval Hints: REM Tri-Vector generated output cap max_tokens num_predict finish_reason length LM Studio Gen counter; SemanticGraphExtractor provider.generate responseSchema no max_tokens OpenAiCompatible streaming finish_reason dropped