Context
After #13941 and #13943 landed, the harness and orchestrator were restarted with all local models ejected. The orchestrator started a KB sync, LM Studio loaded the OpenAI-compatible embedding model, and the LM Studio log showed a silent embedding truncation:
[WARNING] Number of tokens in input string (12746) exceeds model context length (8192). Truncating to 8192 tokens.
Live local probes after the incident confirmed the relevant shape:
lms load --help defines --parallel as maximum concurrent predictions, separate from --context-length.
lms load text-embedding-qwen3-embedding-8b --context-length 32768 --parallel 4 --estimate-only reports Context Length: 32,768; parallel does not divide context into 32768 / 4.
- Neo's resolved preload config still targets
text-embedding-qwen3-embedding-8b with localModels.embedding.contextLimitTokens = 32768.
- The same LM Studio model advertises max context
40960 locally, so 8192 is neither the model max nor Neo's configured target.
Release classification: deployment-readiness / Agent OS ingestion hardening, boardless unless the operator promotes it to the active deployment closeout gate.
The Problem
The embedding provider can be live and answer /v1/embeddings while loaded below Neo's configured embedding context window. In that state, KB sync and Memory Core ingestion can hand LM Studio a large input, receive an embedding, and only the provider log reveals that the input was truncated.
That is wrong on multiple levels:
- It corrupts vector quality silently: the stored embedding represents only the provider-truncated prefix.
- It bypasses Neo's configured
localModels.embedding.* contract.
- It can hide parser/chunking gaps, especially in deployments where tenant-repo ingestion does not yet have custom parsers/chunking for large code files.
- It makes #13941's "replace stale exact model with configured shape" insufficient if the embedding role is JIT/default-loaded before preload, preload does not run, or the provider later drifts.
The Architectural Reality
ai/config.template.mjs declares localModels.embedding.contextLimitTokens and safeProcessingLimitTokens for embedding-path consumers.
ai/services/graph/providerReadinessHelper.mjs builds the LM Studio preload contextLengths map for the embedding role when embeddingProvider === 'openAiCompatible'.
ensureLmsModelsLoaded() can compare lms ps --json loaded context against the configured context, but KB sync can still reach /v1/embeddings with a provider that is loaded at the wrong context.
TextEmbeddingService / VectorService embedding callers need fail-loud or skip-with-diagnostics behavior when the provider's loaded context is below the input, not silent acceptance of provider-side truncation.
- ADR-0019 applies: any fix must read resolved
AiConfig leaves at use sites and avoid hidden defaults, env rereads, type coercion wrappers, or config subtree pass-through.
The Fix
Add a focused guard for OpenAI-compatible local embedding context enforcement:
- Ensure the orchestrator preload path cannot leave the embedding model resident below
localModels.embedding.contextLimitTokens after a restart/JIT-load ordering race. If the exact embedding identifier is resident but too small, unload/reload with the configured context before KB sync relies on it.
- Add an embedding-call guard that refuses or skips inputs which would be provider-truncated by the currently loaded local embedding context, surfacing a bounded diagnostic instead of accepting a silently truncated embedding.
- Revisit the default embedding context cap for
text-embedding-qwen3-embedding-8b: local LM Studio reports max 40960, while Neo defaults to 32768. The implementation should either justify the 32K operational cap or raise the local embedding default/safe band with explicit memory evidence.
- Add runtime diagnostics that make loaded embedding context visible in #13914/#13936 proof surfaces.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
localModels.embedding.contextLimitTokens |
ai/config.template.mjs |
Defines the minimum loaded local embedding context expected for OpenAI-compatible embeddings |
If provider cannot load it, fail/skip with diagnostic; do not silently embed truncated input |
Config JSDoc |
Unit + live lms ps evidence |
| LM Studio preload for embedding role |
buildLmsPreloadConfig() / ensureLmsModelsLoaded() |
Embedding model is loaded/replaced to the configured embedding context before ingestion relies on it |
Explicit degraded readiness if reload fails |
Helper JSDoc |
Unit coverage for stale embedding context replacement |
| Embedding request path |
TextEmbeddingService / VectorService |
Reject or skip inputs that exceed the observed loaded provider context before provider-side truncation |
Bounded diagnostic with model, observed context, configured context, token estimate, caller surface |
Service JSDoc + logs |
Unit coverage with oversized local embedding input |
| Deployment proof surface |
#13914 / #13936 |
Expose loaded embedding context and truncation/skip diagnostics through approved public read surfaces |
If public tool unavailable, local logs remain advisory only |
Tool payload docs |
L3 smoke after deployment |
Decision Record impact
Aligned with ADR-0019 and ADR-0025. This does not amend those ADRs; it enforces the existing config/provider readiness contract and improves diagnosis for an observed ingestion failure.
Acceptance Criteria
Out of Scope
- Changing chat-model context or chat
--parallel behavior from #13700.
- Adding a public privileged MCP route.
- Implementing full tenant-repo custom parsers/chunking for every codebase.
- Solving native Ollama embedding CPU burn from
#13928; this ticket is the OpenAI-compatible/LM Studio loaded-context truncation path.
Avoided Traps
- Do not blame
--parallel for dividing context; local lms load --estimate-only falsified that.
- Do not rely on LM Studio warnings as the only signal; by then the embedding request has already been truncated.
- Do not lower Neo's embedding input contract to match a stale loaded context.
- Do not accept graph-only proof for deployment incidents where the embedding/model path may be wedged or truncating.
Related
Related: #13700, #13941, #13914, #13936, #13928, ADR-0019, ADR-0025.
Origin Session ID: cd2b88d7-8134-4ef8-a10f-0b1e80c03db4
Handoff Retrieval Hints: LM Studio embedding context truncation 8192 qwen3 12746 KB sync, localModels.embedding.contextLimitTokens provider-side truncation
Context
After #13941 and #13943 landed, the harness and orchestrator were restarted with all local models ejected. The orchestrator started a KB sync, LM Studio loaded the OpenAI-compatible embedding model, and the LM Studio log showed a silent embedding truncation:
Live local probes after the incident confirmed the relevant shape:
lms load --helpdefines--parallelas maximum concurrent predictions, separate from--context-length.lms load text-embedding-qwen3-embedding-8b --context-length 32768 --parallel 4 --estimate-onlyreportsContext Length: 32,768; parallel does not divide context into32768 / 4.text-embedding-qwen3-embedding-8bwithlocalModels.embedding.contextLimitTokens = 32768.40960locally, so8192is neither the model max nor Neo's configured target.Release classification: deployment-readiness / Agent OS ingestion hardening, boardless unless the operator promotes it to the active deployment closeout gate.
The Problem
The embedding provider can be live and answer
/v1/embeddingswhile loaded below Neo's configured embedding context window. In that state, KB sync and Memory Core ingestion can hand LM Studio a large input, receive an embedding, and only the provider log reveals that the input was truncated.That is wrong on multiple levels:
localModels.embedding.*contract.The Architectural Reality
ai/config.template.mjsdeclareslocalModels.embedding.contextLimitTokensandsafeProcessingLimitTokensfor embedding-path consumers.ai/services/graph/providerReadinessHelper.mjsbuilds the LM Studio preloadcontextLengthsmap for the embedding role whenembeddingProvider === 'openAiCompatible'.ensureLmsModelsLoaded()can comparelms ps --jsonloaded context against the configured context, but KB sync can still reach/v1/embeddingswith a provider that is loaded at the wrong context.TextEmbeddingService/ VectorService embedding callers need fail-loud or skip-with-diagnostics behavior when the provider's loaded context is below the input, not silent acceptance of provider-side truncation.AiConfigleaves at use sites and avoid hidden defaults, env rereads, type coercion wrappers, or config subtree pass-through.The Fix
Add a focused guard for OpenAI-compatible local embedding context enforcement:
localModels.embedding.contextLimitTokensafter a restart/JIT-load ordering race. If the exact embedding identifier is resident but too small, unload/reload with the configured context before KB sync relies on it.text-embedding-qwen3-embedding-8b: local LM Studio reports max40960, while Neo defaults to32768. The implementation should either justify the 32K operational cap or raise the local embedding default/safe band with explicit memory evidence.Contract Ledger Matrix
localModels.embedding.contextLimitTokensai/config.template.mjslms psevidencebuildLmsPreloadConfig()/ensureLmsModelsLoaded()TextEmbeddingService/ VectorServiceDecision Record impact
Aligned with ADR-0019 and ADR-0025. This does not amend those ADRs; it enforces the existing config/provider readiness contract and improves diagnosis for an observed ingestion failure.
Acceptance Criteria
AiConfig.localModels.embedding.contextLimitTokensis detected before KB/Memory Core embedding work accepts provider output.text-embedding-qwen3-embedding-8bconfigured context path and assert the embedding role participates in context enforcement.40960) and the current32768default is either retained with rationale or adjusted with explicit memory evidence.Out of Scope
--parallelbehavior from #13700.#13928; this ticket is the OpenAI-compatible/LM Studio loaded-context truncation path.Avoided Traps
--parallelfor dividing context; locallms load --estimate-onlyfalsified that.Related
Related: #13700, #13941, #13914, #13936, #13928, ADR-0019, ADR-0025.
Origin Session ID: cd2b88d7-8134-4ef8-a10f-0b1e80c03db4
Handoff Retrieval Hints:
LM Studio embedding context truncation 8192 qwen3 12746 KB sync,localModels.embedding.contextLimitTokens provider-side truncation