feat: port template upgrades (citations, eval, chunking, nomic prefixes)

mcp 2.x already on origin/main (#10). Does not change BM25-first
search_docs — n=6 is too small to flip the default.

- Numbered [1] citations via docs_mcp/format.py
- Eval P@1 + JSONL sidecar + eval.pvalue + eval.trace
- Heading-recursive chunker, keep chunk-0 and MAX_CHARS=4000
- Nomic prefixes at embed time only; stored text unprefixed

Closes #12
This commit is contained in:
claude committed 2026-09-30 08:33:12 -04:00
1 parent 6897fbb19a
commit fda572f59e
13 files changed
+812 -77

No files matched your search

+23 -2
View File
@@ -22,8 +22,14 @@ import logging
import time
from typing import Any
import httpx
from chromadb import EmbeddingFunction, Documents, Embeddings
try:
import httpx
from chromadb import Documents, EmbeddingFunction, Embeddings
except ImportError:
httpx = None # type: ignore[assignment]
EmbeddingFunction = object # type: ignore[misc,assignment]
Documents = list # type: ignore[misc,assignment]
Embeddings = list # type: ignore[misc,assignment]
log = logging.getLogger(__name__)
@@ -41,6 +47,21 @@ def _resolve_urls() -> list[str]:
OLLAMA_URLS = _resolve_urls()
EMBED_MODEL = os.environ.get("EMBED_MODEL", "nomic-embed-text")
EMBED_DIM = int(os.environ.get("EMBED_DIM", "768"))
# nomic asymmetric prefixes — embed time only. Empty string disables.
EMBED_QUERY_PREFIX = os.environ.get("EMBED_QUERY_PREFIX", "search_query: ")
EMBED_DOC_PREFIX = os.environ.get("EMBED_DOC_PREFIX", "search_document: ")
def apply_prefix(text: str, prefix: str) -> str:
if not prefix:
return text
return prefix + text
def embed_texts(texts: list[str], *, prefix: str, ef: Any | None = None) -> list[list[float]]:
"""Embed texts after applying prefix. Callers store the original strings."""
fn = ef if ef is not None else embedding_function()
return list(fn([apply_prefix(t, prefix) for t in texts]))
class OllamaEmbeddings(EmbeddingFunction):