---
id: 12114
title: 'Provider-agnostic context-limits via localModels.{chat,embedding} role-keyed split + retire SessionService hidden default'
state: CLOSED
labels:
  - enhancement
  - ai
  - architecture
  - model-experience
assignees:
  - neo-opus-ada
createdAt: '2026-05-27T21:56:21Z'
updatedAt: '2026-05-27T22:35:05Z'
githubUrl: 'https://github.com/neomjs/neo/issues/12114'
author: neo-opus-ada
commentsCount: 0
parentIssue: 12101
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy: []
blocking: []
closedAt: '2026-05-27T22:35:05Z'
---
# Provider-agnostic context-limits via localModels.{chat,embedding} role-keyed split + retire SessionService hidden default

## Premise

6 consumer sites hardcode `aiConfig.openAiCompatible.contextLimitTokens` / `safeProcessingLimitTokens`. The actual model-context-window axis is **model-role (chat vs embedding)**, not provider-namespace. For deployments using `ollama` as graphProvider, friction telemetry reflects openAiCompatible's 262144 regardless of the actual Ollama context window → wrong substrate, wrong calibration.

**Operator direction** (synthesis): remote providers (gemini) are API-bound — no operator control over context cap, so no template keys needed. Local-model context caps belong on **the model-role axis**, shared across local providers — one config for chat, one for embedding. Provider-namespace duplication is over-the-top.

## Substrate shape (cross-family V-B-A converged with @neo-gpt)

- **Remote providers** (`gemini`, future API-only): no `contextLimitTokens` in template
- **Local-model-role-keyed**: `localModels.chat.{context,safe}LimitTokens` + `localModels.embedding.{context,safe}LimitTokens`
- **Namespace boundary** (`localModels.*`) states the actual constraint: locally controlled context caps; top-level `chat`/`embedding` would be too close to provider-selector primitive

## Surface enumeration (V-B-A 2026-05-27)

| Site | Role | Current state |
|---|---|---|
| `SemanticGraphExtractor.mjs:125-126` | chat | pre-existing local vars (cascade fix point) |
| `TopologyInferenceEngine.mjs:83-84` | chat | added in PR #12113 (consistent with pre-existing pattern) |
| `SessionService.mjs:612-613` | chat | pre-existing + hidden default fallback `\|\| 32768` (violates §no_hidden_default_fallbacks) |
| `mcp/server/memory-core/config.template.mjs:186,197` | derivation | config-resolved doc-baseline |

Template current state: `aiConfig.openAiCompatible.contextLimitTokens=262144` + `safeProcessingLimitTokens=200000`. `aiConfig.ollama` namespace has NO context-limit keys.

## Contract Ledger

| Surface | Before | After | Consumer |
|---|---|---|---|
| Chat context limits | `aiConfig.openAiCompatible.contextLimitTokens=262144` + `safeProcessingLimitTokens=200000` | `aiConfig.localModels.chat.contextLimitTokens=262144` + `safeProcessingLimitTokens=200000` (preserve current values per AC1) | SemanticGraphExtractor + TopologyInferenceEngine + SessionService chat-path consumers |
| Embedding context limits | NOT present in template | `aiConfig.localModels.embedding.{context,safe}LimitTokens` (concrete value per AC6 V-B-A) | Future TextEmbeddingService consumer (pre-positions for #11393/#11395 retry-on-unload telemetry) |
| Hidden default fallback | `SessionService.mjs:612` `\|\| 32768` | Loud-fail on missing config | (eliminates §no_hidden_default_fallbacks contract violation) |

## Acceptance Criteria

- [ ] AC1: `localModels.chat.contextLimitTokens=262144` + `safeProcessingLimitTokens=200000` added to `ai/config.template.mjs` (preserves current shipped defaults per @neo-gpt V-B-A)
- [ ] AC2: `localModels.embedding.{context,safe}LimitTokens` added to `ai/config.template.mjs` with concrete defaults — value requires V-B-A per AC6
- [ ] AC3: 4 consumer sites migrated from `aiConfig.openAiCompatible.{context,safe}*` to `aiConfig.localModels.{chat,embedding}.*` based on consumer role
- [ ] AC4: `SessionService.mjs:612` hidden default fallback (`|| 32768`) deleted; loud-fail on missing config (matches `feedback_no_hidden_default_fallbacks` operator contract)
- [ ] AC5: `SemanticGraphExtractor.mjs:121` JSDoc rationale (openAiCompatible-as-conservative-baseline-for-both-families) rewritten to reflect role-keyed substrate; pre-existing ticket-anchor archaeology (`#11965 AC5 / #12059`) stripped per AGENTS_ATLAS.md §15.6
- [ ] AC6: Embedding context-cap concrete default value verified against the configured embedding model (LM Studio qwen3-8b-embedding OR Ollama equivalent) BEFORE implementing PR opens. Placeholder 8192/6144 acceptable in template if V-B-A defers to follow-up.
- [ ] AC7: Open question — `aiConfig.openAiCompatible.contextLimitTokens` legacy retention strategy (keep as deprecated passthrough vs delete in same PR). Operator/Stage-1 sequencing call.

## Timing + scope

**Recommendation (lean B-with-escape-hatch per @neo-gpt):** fold into Epic #12101 Stage 1+ rewrite to avoid double migration. Stage 1 (#12103) establishes meta-leaf primitives; Stage 2 (#12104) rewrites template; this ticket's substrate semantic naturally rides on Stage 2's template rewrite. If operator requires the SessionService hidden-default-fallback retirement (AC4) before Stage 1/2 lands, carve a tiny interim PR with explicit retirement path documented.

## Empirical anchor

PR #12113 (just-shipped) preserved the existing `aiConfig.openAiCompatible.contextLimitTokens` reference for interim consistency with pre-existing pattern. Operator surfaced the substrate-shape issue during cycle-1 V-B-A: "klarso wants to use ollama". This ticket retires those references as the next substrate-evolution step.

## Related

- Parent: Epic #12101 (greenfield aiConfig substrate redesign — graduated from Discussion #12100)
- Sibling: #12104 (Stage 2 template rewrite — this ticket's substrate semantic rides on Stage 2)
- Sibling: #12090 (provider multi-model coexistence; orthogonal but adjacent)
- Sibling: #11976 (graphProvider routing — the consumer-side discriminator)
- PR #12113 (interim consistency baseline; this ticket retires the deferred reference)

## Discipline anchor

@neo-gpt's V-B-A surfaced: chat default = preserve current 262144/200000 (already live after #12064). Embedding default = NOT memory-asserted — requires V-B-A against actual model before AC6 closure. `SessionService.mjs:612` hidden default fallback retirement (AC4) = highest-value invariant per `feedback_no_hidden_default_fallbacks` operator contract (2026-05-27).

## Timeline

- 2026-05-27T21:56:22Z @neo-opus-ada assigned to @neo-opus-ada
- 2026-05-27T21:56:22Z @neo-opus-ada added the `enhancement` label
- 2026-05-27T21:56:22Z @neo-opus-ada added the `ai` label
- 2026-05-27T21:56:22Z @neo-opus-ada added the `architecture` label
- 2026-05-27T21:56:23Z @neo-opus-ada added the `model-experience` label
- 2026-05-27T21:56:37Z @neo-opus-ada added parent issue #12101
- 2026-05-27T22:15:10Z @neo-opus-ada cross-referenced by PR #12115
- 2026-05-27T22:24:53Z @neo-opus-ada referenced in commit `c0b3c5b` - "test(ai): migrate config.template + fixture assertions to localModels.{chat,embedding} (#12114)

CI unit failure on the prior commit: config.template.spec.mjs:75 + aiConfigDefaults.mjs
fixture still asserted the deleted openAiCompatible.contextLimitTokens /
safeProcessingLimitTokens fields. Scoped the openAiCompatible toMatchObject down to
its remaining real fields + added a Config.localModels assertion matching the new
role-keyed structure. Fixture mirrors the same shape change.

Local: config.template.spec.mjs 5/5 + aiConfigDefaults.spec.mjs 5/5 pass."
- 2026-05-27T22:33:57Z @neo-opus-ada cross-referenced by #12116
- 2026-05-27T22:35:05Z @tobiu referenced in commit `ea1d481` - "feat(ai): split context-limits into localModels.{chat,embedding} role-keyed config (#12114) (#12115)

* feat(ai): split context-limits into localModels.{chat,embedding} role-keyed config (#12114)

Operator surfaced during PR #12113 V-B-A: aiConfig.openAiCompatible.contextLimitTokens
was the hardcoded source for all 4 consumer sites regardless of active provider, but the
actual context-window axis is model-role (chat vs embedding), not provider-namespace.
Remote providers (Gemini) are API-bound — no operator control over context cap.
Local providers (openAiCompatible, ollama) share these caps because the practical limit
comes from the loaded model, not the provider transport.

Adds aiConfig.localModels.{chat,embedding}.{contextLimitTokens,safeProcessingLimitTokens}
to the template + envBindings, mirrors through to MC overlay as a passthrough block,
migrates 4 consumer sites (SemanticGraphExtractor, TopologyInferenceEngine, SessionService
summarizer, MC config derivation) to read from the role-keyed path, deletes the orphan
openAiCompatible.{context,safe}* keys, and removes the SessionService.mjs:612 hidden
default fallback (|| 32768) — loud-fail on missing config per the operator's strict
no-hidden-default-fallback contract.

Embedding defaults are conservative placeholders (8192/6144) marked operator-tunable; no
active consumer reads these yet — pre-positioned for the future TextEmbeddingService
consumer surface.

* test(ai): migrate config.template + fixture assertions to localModels.{chat,embedding} (#12114)

CI unit failure on the prior commit: config.template.spec.mjs:75 + aiConfigDefaults.mjs
fixture still asserted the deleted openAiCompatible.contextLimitTokens /
safeProcessingLimitTokens fields. Scoped the openAiCompatible toMatchObject down to
its remaining real fields + added a Config.localModels assertion matching the new
role-keyed structure. Fixture mirrors the same shape change.

Local: config.template.spec.mjs 5/5 + aiConfigDefaults.spec.mjs 5/5 pass.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-27T22:35:05Z @tobiu closed this issue
- 2026-05-27T22:51:08Z @neo-opus-ada cross-referenced by #12117
- 2026-05-27T23:07:12Z @neo-opus-ada cross-referenced by PR #12119
- 2026-05-27T23:29:43Z @neo-opus-ada cross-referenced by PR #12118
- 2026-05-28T00:41:11Z @neo-gpt cross-referenced by #12101
- 2026-05-28T00:46:43Z @neo-opus-ada cross-referenced by PR #12120
- 2026-05-28T00:48:01Z @neo-gpt cross-referenced by PR #12121
- 2026-06-03T07:48:42Z @neo-gpt cross-referenced by #10484

