> For the complete documentation index, see [llms.txt](https://docs.telys.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.telys.ai/recipes/framework-bridge.md).

# Framework bridge

{% hint style="warning" %}
This is a **pattern, not a shipped integration.** Telys ships no LangChain or LlamaIndex package — there is no `telys.langchain` or `telys.llamaindex` module. What follows is a thin adapter **you** write on top of the public SDK: a few dozen lines that expose a Telys collection behind your framework's interface. You own it and upgrade it as those interfaces change.
{% endhint %}

Both frameworks share one vector-store contract: *add texts with metadata*, and *given a query, return the most similar texts*. Telys provides both — `add_texts` and `search_text` — so the adapter is mostly plumbing. Get one thing right: the **embedding space**. Use `CallableEmbedder` to wrap the same embedding model your framework uses elsewhere, so the vectors match.

## A framework-agnostic core

Start with an adapter that depends only on `telys`. With no framework imports, it runs and tests standalone; the wrappers below are thin shims over it.

{% code title="telys\_store.py" lineNumbers="true" %}

```python
import numpy as np

from telys import Telys, Eq
from telys.embedding import CallableEmbedder, EmbeddingProfile


class TelysStore:
    """A minimal, framework-neutral vector store over one Telys collection."""

    def __init__(self, embed_fn, dimension: int, path: str = "./telys-store",
                 name: str = "docs", model_id: str = "byo-model"):
        profile = EmbeddingProfile(
            provider="bridge",
            model_id=model_id,
            model_version="1",
            dimension=dimension,
            normalization="l2",
            distance="ip",
        )
        embedder = CallableEmbedder(
            lambda texts: np.asarray(embed_fn(texts), dtype="float32"),
            profile,
        )
        self.telys = Telys(path)
        try:
            self.col = self.telys.open_collection(name, embedder=embedder)
        except FileNotFoundError:
            self.col = self.telys.create_collection(
                name, dim=dimension, partition_by="source", embedder=embedder,
                # Only declared filter_columns round-trip through
                # search_text(..., with_metadata=True). Any dynamic `extra` keys
                # you pass to add_texts must ALSO be listed here, or they will
                # NOT be returned in each hit's metadata.
                filter_columns=("source", "text"),
            )
            self.col.save()

    def add_texts(self, texts, ids, sources=None, extra=None):
        sources = sources or ["default"] * len(texts)
        extra = extra or [{}] * len(texts)
        metas = [
            {"source": s, "text": t, **e}
            for t, s, e in zip(texts, sources, extra)
        ]
        self.col.add_texts(list(texts), list(ids), metas)
        self.col.save()
        return ids

    def similarity_search(self, query: str, k: int = 4, source: str | None = None):
        res = self.col.search_text(
            query,
            top_k=k,
            where=Eq("source", source) if source else None,
            with_metadata=True,
        )
        return [
            {"id": i, "score": s, "text": m["text"], "metadata": m}
            for i, s, m in zip(res["ids"], res["scores"], res["metadata"])
        ]
```

{% endcode %}

## Wrap it as a LangChain retriever

LangChain's retriever contract is one method, `_get_relevant_documents`, returning `Document` objects. The shim maps a `TelysStore` result onto that shape.

{% hint style="info" %}
This snippet imports `langchain_core`, which you must install yourself (`pip install langchain-core`). It is not a Telys dependency.
{% endhint %}

{% code title="langchain\_bridge.py" lineNumbers="true" %}

```python
from langchain_core.documents import Document
from langchain_core.retrievers import BaseRetriever

from telys_store import TelysStore


class TelysRetriever(BaseRetriever):
    """Adapter exposing a TelysStore as a LangChain retriever."""

    store: TelysStore
    k: int = 4

    class Config:
        arbitrary_types_allowed = True

    def _get_relevant_documents(self, query: str, *, run_manager=None):
        hits = self.store.similarity_search(query, k=self.k)
        return [
            Document(page_content=h["text"], metadata={"score": h["score"], **h["metadata"]})
            for h in hits
        ]


# Usage — plug your own embedding model into `embed_fn`.
def embed_fn(texts):
    ...  # call your embedding model, return a list of vectors

store = TelysStore(embed_fn, dimension=768)
store.add_texts(
    ["Telys runs on-device.", "Search is lexical or dense."],
    ["a", "b"],
)
retriever = TelysRetriever(store=store, k=4)
docs = retriever.invoke("where does Telys run?")
```

{% endcode %}

## Wrap it for LlamaIndex

LlamaIndex expects a retriever whose `_retrieve` returns `NodeWithScore` objects. Same `TelysStore` underneath — only the result mapping changes.

<details>

<summary>LlamaIndex adapter (requires <code>pip install llama-index-core</code>)</summary>

```python
from llama_index.core.retrievers import BaseRetriever
from llama_index.core.schema import NodeWithScore, TextNode

from telys_store import TelysStore


class TelysLlamaRetriever(BaseRetriever):
    def __init__(self, store: TelysStore, k: int = 4):
        self.store = store
        self.k = k
        super().__init__()

    def _retrieve(self, query_bundle):
        hits = self.store.similarity_search(query_bundle.query_str, k=self.k)
        return [
            NodeWithScore(
                node=TextNode(text=h["text"], id_=h["id"], metadata=h["metadata"]),
                score=h["score"],
            )
            for h in hits
        ]
```

</details>

## What you will see

Driving the LangChain shim returns ranked `Document` objects whose `page_content` is the stored text and whose `metadata` carries the Telys score and stored fields:

```
[Document(page_content='Telys runs on-device.', metadata={'score': 0.71, 'source': 'default', ...})]
```

Because the adapter wraps `add_texts` / `search_text`, everything else in these docs — partitions, `Eq` filters, IVF, persistence — is available through the same `TelysStore`.

{% hint style="warning" %}
Keep the embedding model **identical** to the one your framework pipeline uses. If your chain embeds queries with model X but you indexed Telys with model Y, the vectors live in different spaces and results are meaningless. `CallableEmbedder` plus a stable `EmbeddingProfile` pins that. See [EmbeddingProfile & space compatibility](/embeddings/embedding-profile.md).
{% endhint %}

## Next steps

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>CallableEmbedder (bring your own)</strong></td><td>Wrap any embedding function — the key to matching your framework's space.</td><td><a href="/pages/Xzd0BXJbxW07haNz0M1J">/pages/Xzd0BXJbxW07haNz0M1J</a></td></tr><tr><td><strong>Use with OpenAI &#x26; Anthropic</strong></td><td>Retrieval-augmented prompting with a hosted chat model.</td><td><a href="/pages/rqi1E0G8vx4MwH31ox8y">/pages/rqi1E0G8vx4MwH31ox8y</a></td></tr><tr><td><strong>Filter results</strong></td><td>Scope retrieval with Eq inside your adapter.</td><td><a href="/pages/f1kH8mnLEAKBG7sEkDOZ">/pages/f1kH8mnLEAKBG7sEkDOZ</a></td></tr></tbody></table>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.telys.ai/recipes/framework-bridge.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
