moca-reader-langchain 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,67 @@
1
+ """A LangChain retriever over MOCA packages (Reader interface §7).
2
+
3
+ ``MocaRetriever`` wraps a host-built ``moca_reader.Search``: its backend, audiences and hooks. Every call goes
4
+ through the Reader's gate, so the retrieval policy and the host's audience filter always apply, and nothing a
5
+ caller passes can widen them. Each citation record becomes a ``Document``: the text as ``page_content``, the
6
+ whole record under ``metadata["moca_citation"]``, and the consuming guide's flat ``moca_*`` fields beside it.
7
+
8
+ Package text is untrusted input to a model: pass ``page_content`` to a model as quoted reference material to cite,
9
+ never as instructions (Reader contract §12).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Any
15
+
16
+ from langchain_core.callbacks import CallbackManagerForRetrieverRun
17
+ from langchain_core.documents import Document
18
+ from langchain_core.retrievers import BaseRetriever
19
+ from pydantic import ConfigDict
20
+
21
+ from moca_reader import CitationRecord, Search, flat_metadata
22
+
23
+ __all__ = ["MocaRetriever", "document_id", "to_document"]
24
+ __version__ = "0.6.0"
25
+
26
+
27
+ def document_id(record: CitationRecord) -> str:
28
+ """A unique id: the node's versioned reference, then the byte span, since one node can return several chunks."""
29
+ span = record.get("span")
30
+ ref = str(record["node"]["ref"])
31
+ return f"{ref}:{span['start']}-{span['end']}" if isinstance(span, dict) else ref
32
+
33
+
34
+ def to_document(record: CitationRecord) -> Document:
35
+ """A citation record as a LangChain ``Document``."""
36
+ metadata: dict[str, Any] = {"moca_citation": record, **flat_metadata(record)}
37
+ if isinstance(record.get("score"), (int, float)):
38
+ metadata["moca_score"] = record["score"]
39
+ return Document(page_content=record.get("text") or "", id=document_id(record), metadata=metadata)
40
+
41
+
42
+ class MocaRetriever(BaseRetriever):
43
+ """Retrieves citation records from MOCA packages as LangChain ``Document``s.
44
+
45
+ ``search`` is the host's ``moca_reader.Search``. The other fields are the search options for every call; they
46
+ are the host's, set when the retriever is built.
47
+ """
48
+
49
+ model_config = ConfigDict(arbitrary_types_allowed=True)
50
+
51
+ search: Search
52
+ limit: int = 5
53
+ locale: str | None = None
54
+ concepts: list[str] | None = None
55
+ scope: str | None = None
56
+ include_all: bool = False
57
+
58
+ def _get_relevant_documents(self, query: str, *, run_manager: CallbackManagerForRetrieverRun) -> list[Document]:
59
+ records = self.search.search(
60
+ query,
61
+ limit=self.limit,
62
+ include_all=self.include_all,
63
+ locale=self.locale,
64
+ concepts=self.concepts,
65
+ scope=self.scope,
66
+ )
67
+ return [to_document(r) for r in records]
File without changes
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.5
2
+ Name: moca-reader-langchain
3
+ Version: 0.6.0
4
+ Summary: A LangChain retriever over MOCA packages: citation records as Documents, through the MOCA Reader's gate.
5
+ Project-URL: Homepage, https://openmoca.org
6
+ Project-URL: Source, https://github.com/openmoca/moca-reader-python
7
+ Author: MOCA Standard Contributors
8
+ License-Expression: Apache-2.0
9
+ Keywords: citations,langchain,moca,rag,retriever
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Typing :: Typed
13
+ Requires-Python: >=3.11
14
+ Requires-Dist: langchain-core>=1.0
15
+ Requires-Dist: moca-reader==0.6.0
16
+ Description-Content-Type: text/markdown
17
+
18
+ # moca-reader-langchain
19
+
20
+ A [LangChain](https://python.langchain.com) retriever over MOCA packages,
21
+ built on the [MOCA Reader for Python](https://github.com/openmoca/moca-reader-python).
22
+
23
+ ```sh
24
+ pip install moca-reader-langchain
25
+ ```
26
+
27
+ ```python
28
+ from moca_reader import LexicalBackend, Library, Search, read_package
29
+ from moca_reader_langchain import MocaRetriever
30
+
31
+ pkg = read_package("support-kb.moca", trust_root="trust-root.json")
32
+ library = Library().add(pkg)
33
+ search = Search(library, LexicalBackend(library), audiences=["public"])
34
+
35
+ retriever = MocaRetriever(search=search, limit=3)
36
+ for doc in retriever.invoke("How long is the refund window?"):
37
+ print(doc.metadata["moca_node_ref"], doc.metadata["moca_score"])
38
+ print(doc.page_content[:80])
39
+ ```
40
+
41
+ `MocaRetriever` wraps the `Search` you build: its backend (lexical, dense,
42
+ hybrid or your own store), its audiences and its hooks. Every call goes through
43
+ the Reader's gate, so content that is out of force, superseded, deprecated or
44
+ outside your audiences never comes back, and nothing a caller passes can widen
45
+ that. `limit`, `locale`, `concepts`, `scope` and `include_all` are set when you
46
+ build the retriever.
47
+
48
+ Each result is a LangChain `Document`:
49
+
50
+ | Field | Holds |
51
+ | --- | --- |
52
+ | `page_content` | The text of the node, or of a sidecar chunk |
53
+ | `id` | The node's versioned reference and byte span |
54
+ | `metadata["moca_citation"]` | The whole citation record: package, version and digest, trust signals, evidence |
55
+ | `metadata["moca_*"]` | The flat fields of the consuming guide (`moca_node_ref`, `moca_package_digest`, `moca_status`, `moca_signed`, ...), for vector stores that need flat metadata |
56
+ | `metadata["moca_score"]` | The search score |
57
+
58
+ **Package text is untrusted input.** Put `page_content` in a prompt as quoted
59
+ reference material to cite, never as instructions
60
+ ([Reader contract §12](https://github.com/openmoca/moca-spec/blob/main/spec/moca-reader-contract.md#12-handing-content-to-a-model)).
61
+ Show users the source (`moca_node_ref`, the package version) with each answer.
62
+
63
+ The async path (`ainvoke`) runs the same search.
64
+
65
+ ## Licence
66
+
67
+ Apache-2.0.
@@ -0,0 +1,5 @@
1
+ moca_reader_langchain/__init__.py,sha256=X14-LUa5FFCfpKWsXy26F5ShWdjhe-uk0vgBog665k4,2722
2
+ moca_reader_langchain/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ moca_reader_langchain-0.6.0.dist-info/METADATA,sha256=oPYya2y07f9nsiWDP4yf138C8qBDmqBCv2ybXke0bC4,2781
4
+ moca_reader_langchain-0.6.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
5
+ moca_reader_langchain-0.6.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.33.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any