You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make the embed endpoint optional so memory runs lexical-only (CL-6287)
loadMemoryConfig() hard-required EMBED_BASE_URL and EMBED_MODEL, so a host with a pgvector Postgres and no embeddings account got no memory plane at all — despite the engine already degrading to Postgres full-text search at runtime. That was a config gate standing in front of a capability that already worked.
The embed block is now optional. With no embed config the plane constructs and serves add plus lexical search, skipping the dense channel entirely rather than attempting and failing it, and reports degraded: ["dense_unavailable", "lexical_only"] so the state is observable rather than silent. Capture stores chunks without vectors and never reaches the embed-model registry. Transform/replay still requires an embed endpoint and fails loudly and early without one.
Memory.capabilities.embeddingsConfigured lets a host discover the tier at construction instead of inferring it from a search, and add's degraded field is now a reason array matching search's shape rather than a bare boolean.
Migration note for consumers: dense_unavailable now also fires permanently on a deliberately lexical-only host. An alert keyed on it alone should check lexical_only too.
Known gaps, filed: CL-6292 (documents captured while unembedded are never backfilled), CL-6293 (lexical_only escalates to log.error forever on an intentional config).
Copy file name to clipboardExpand all lines: IMPLEMENTATION.md
+39-5Lines changed: 39 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -88,14 +88,43 @@ fallback)` parses a positive integer or throws.
88
88
|`DATABASE_URL`|**yes**| — | the engine's own pgvector Postgres |
89
89
|`DB_POOL_MAX`| no |`8`| postgres-js pool size |
90
90
|`FTS_LANGUAGE`| no |`english`| text search config for the lexical channel; fixed into the generated column at migration time — changing it later requires rebuilding the column (recipe below), and `runMemoryMigrations` fails loudly if config and column disagree. Unqualified `pg_catalog` config names only — a schema-qualified config (`myschema.mycfg`) is rejected explicitly, both when configuring and when read back from an already-migrated column. |
91
-
|`EMBED_BASE_URL`|**yes**| — | embed endpoint root, no path suffix |
92
-
|`EMBED_MODEL`|**yes**| — | model id/name passed to the embed endpoint |
91
+
|`EMBED_BASE_URL`|no| — | embed endpoint root, no path suffix; absent (with `EMBED_MODEL` also absent) => lexical-only, see below|
92
+
|`EMBED_MODEL`|no| — | model id/name passed to the embed endpoint; must be set together with `EMBED_BASE_URL` (both or neither — one without the other throws)|
93
93
|`EMBED_API_STYLE`| no |`"openai"`|`"openai" \| "tei" \| "ollama"`|
94
94
|`EMBED_API_KEY`| no |`undefined`| forwarded as `Authorization: Bearer <key>`|
95
95
|`RERANK_BASE_URL`| no |`undefined`| absent => search degrades to fusion-only |
96
96
|`RERANK_MODEL`| no |`undefined`| defaults to `bge-reranker-v2-m3` in the client |
97
97
|`RERANK_API_KEY`| no |`undefined`| forwarded as Bearer token to the rerank endpoint |
98
98
99
+
**Lexical-only mode (CL-6287).**`EngineConfig.embed` is optional — leave both
100
+
`EMBED_BASE_URL`/`EMBED_MODEL` unset and the engine still constructs and
101
+
serves `add` + lexical `search` against a pgvector Postgres with no
102
+
embed endpoint configured. Dense retrieval is skipped rather than
103
+
attempted (no doomed HTTP call on every query), `add` still captures
104
+
documents (chunks stored, no vectors), and both verbs report a `degraded`
105
+
reason array — never a bare boolean, so a host can write one "is this
106
+
response degraded" check across both: `search` reports
0 commit comments