okf-agents 0.1.0__tar.gz

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.
Files changed (53) hide show
  1. okf_agents-0.1.0/.gitignore +29 -0
  2. okf_agents-0.1.0/CHANGELOG.md +39 -0
  3. okf_agents-0.1.0/LICENSE +21 -0
  4. okf_agents-0.1.0/PKG-INFO +456 -0
  5. okf_agents-0.1.0/README.md +405 -0
  6. okf_agents-0.1.0/docs/api-reference.md +121 -0
  7. okf_agents-0.1.0/docs/concepts.md +127 -0
  8. okf_agents-0.1.0/docs/launch-checklist.md +71 -0
  9. okf_agents-0.1.0/docs/navigator-and-budgets.md +106 -0
  10. okf_agents-0.1.0/docs/testing.md +76 -0
  11. okf_agents-0.1.0/docs/vector-stores.md +108 -0
  12. okf_agents-0.1.0/okf_agents/__init__.py +39 -0
  13. okf_agents-0.1.0/okf_agents/_internal/__init__.py +1 -0
  14. okf_agents-0.1.0/okf_agents/_internal/graph_utils.py +86 -0
  15. okf_agents-0.1.0/okf_agents/_internal/parser.py +285 -0
  16. okf_agents-0.1.0/okf_agents/bundle.py +288 -0
  17. okf_agents-0.1.0/okf_agents/exceptions.py +66 -0
  18. okf_agents-0.1.0/okf_agents/indexing.py +172 -0
  19. okf_agents-0.1.0/okf_agents/models.py +106 -0
  20. okf_agents-0.1.0/okf_agents/navigator.py +407 -0
  21. okf_agents-0.1.0/okf_agents/py.typed +0 -0
  22. okf_agents-0.1.0/okf_agents/retriever.py +157 -0
  23. okf_agents-0.1.0/okf_agents/router.py +120 -0
  24. okf_agents-0.1.0/okf_agents/tools.py +228 -0
  25. okf_agents-0.1.0/pyproject.toml +127 -0
  26. okf_agents-0.1.0/tests/__init__.py +0 -0
  27. okf_agents-0.1.0/tests/conftest.py +23 -0
  28. okf_agents-0.1.0/tests/e2e/__init__.py +0 -0
  29. okf_agents-0.1.0/tests/e2e/conftest.py +25 -0
  30. okf_agents-0.1.0/tests/e2e/test_full_workflow.py +119 -0
  31. okf_agents-0.1.0/tests/fixtures/sample_bundle/concepts/customers.md +13 -0
  32. okf_agents-0.1.0/tests/fixtures/sample_bundle/concepts/index.md +4 -0
  33. okf_agents-0.1.0/tests/fixtures/sample_bundle/concepts/orders.md +22 -0
  34. okf_agents-0.1.0/tests/fixtures/sample_bundle/concepts/payments.md +13 -0
  35. okf_agents-0.1.0/tests/fixtures/sample_bundle/guides/getting-started.md +10 -0
  36. okf_agents-0.1.0/tests/fixtures/sample_bundle/index.md +7 -0
  37. okf_agents-0.1.0/tests/fixtures/sample_bundle/log.md +3 -0
  38. okf_agents-0.1.0/tests/integration/__init__.py +0 -0
  39. okf_agents-0.1.0/tests/integration/conftest.py +144 -0
  40. okf_agents-0.1.0/tests/integration/test_hybrid_retriever.py +188 -0
  41. okf_agents-0.1.0/tests/integration/test_navigator.py +107 -0
  42. okf_agents-0.1.0/tests/provider_support.py +85 -0
  43. okf_agents-0.1.0/tests/unit/__init__.py +0 -0
  44. okf_agents-0.1.0/tests/unit/test_bundle.py +272 -0
  45. okf_agents-0.1.0/tests/unit/test_exceptions.py +82 -0
  46. okf_agents-0.1.0/tests/unit/test_graph_utils.py +80 -0
  47. okf_agents-0.1.0/tests/unit/test_indexing.py +302 -0
  48. okf_agents-0.1.0/tests/unit/test_models.py +161 -0
  49. okf_agents-0.1.0/tests/unit/test_navigator.py +614 -0
  50. okf_agents-0.1.0/tests/unit/test_parser.py +392 -0
  51. okf_agents-0.1.0/tests/unit/test_retriever.py +298 -0
  52. okf_agents-0.1.0/tests/unit/test_router.py +249 -0
  53. okf_agents-0.1.0/tests/unit/test_tools.py +238 -0
@@ -0,0 +1,29 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+
13
+ # Tooling caches
14
+ .pytest_cache/
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+ .coverage
18
+ coverage.xml
19
+ htmlcov/
20
+
21
+ # Editors and OS
22
+ .idea/
23
+ .vscode/
24
+ .DS_Store
25
+
26
+ # Local planning docs
27
+ docs/tasks/
28
+ langgraph-okf-spec.md
29
+ okf-agents-spec.md
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-07-14
11
+
12
+ Initial alpha release.
13
+
14
+ ### Added
15
+
16
+ - Deterministic OKF v0.1 bundle loading, parsing, link-graph construction,
17
+ and weighted lexical search (`OKFBundle`).
18
+ - Domain models for concepts, frontmatter, link edges, and the bundle
19
+ index (`Concept`, `ConceptFrontmatter`, `LinkEdge`, `BundleIndex`).
20
+ - Four deterministic LangChain agent tools over a loaded bundle
21
+ (`create_okf_tools`): `read_concept`, `search_concepts`, `list_links`,
22
+ `read_index`.
23
+ - A keyword `BaseRetriever` backed by bundle search (`OKFRetriever`) and a
24
+ shared concept-to-`Document` conversion helper.
25
+ - A query-routing LangGraph node that classifies queries as `bundle`,
26
+ `vector`, or `both`, with an offline heuristic and optional classifier
27
+ fallback (`create_okf_router`).
28
+ - A bounded LangGraph navigator subgraph that reads the bundle index,
29
+ plans traversal, expands linked concepts within hard budgets, and
30
+ returns a grounded, citation-validated answer (`create_okf_navigator`).
31
+ - Idempotent synchronization of bundles into LangChain vector stores
32
+ (`sync_bundle_to_vector_store`) and a graph-expanding retriever
33
+ (`OKFGraphRetriever`) that expands semantic hits through the link graph.
34
+ - Offline integration tests, opt-in provider-integration tests
35
+ (`RUN_INTEGRATION_TESTS=1`), and opt-in end-to-end tests
36
+ (`RUN_E2E_TESTS=1`).
37
+
38
+ [Unreleased]: https://github.com/RonCodes88/okf-agents/compare/v0.1.0...HEAD
39
+ [0.1.0]: https://github.com/RonCodes88/okf-agents/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ronald Li
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,456 @@
1
+ Metadata-Version: 2.4
2
+ Name: okf-agents
3
+ Version: 0.1.0
4
+ Summary: Open Knowledge Format (OKF) agent tools, navigator, and graph-aware retrieval for LangGraph
5
+ Project-URL: Homepage, https://github.com/RonCodes88/langgraph-okf
6
+ Project-URL: Documentation, https://github.com/RonCodes88/langgraph-okf/tree/main/docs
7
+ Project-URL: Repository, https://github.com/RonCodes88/langgraph-okf
8
+ Project-URL: Issue Tracker, https://github.com/RonCodes88/langgraph-okf/issues
9
+ Project-URL: Changelog, https://github.com/RonCodes88/langgraph-okf/blob/main/CHANGELOG.md
10
+ Author-email: Ronald Li <ronaldliyh@gmail.com>
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: ai-agents,knowledge,knowledge-graph,knowledge-management,langchain,langgraph,markdown,okf,open-knowledge-format,rag,retriever
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: langchain-core>=0.3
27
+ Requires-Dist: langgraph>=0.2
28
+ Requires-Dist: pydantic>=2.0
29
+ Requires-Dist: pyyaml>=6.0
30
+ Provides-Extra: dev
31
+ Requires-Dist: mypy>=1.11; extra == 'dev'
32
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.6; extra == 'dev'
35
+ Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
36
+ Provides-Extra: lint
37
+ Requires-Dist: ruff>=0.6; extra == 'lint'
38
+ Provides-Extra: release
39
+ Requires-Dist: build>=1.2; extra == 'release'
40
+ Requires-Dist: twine>=5.0; extra == 'release'
41
+ Provides-Extra: test
42
+ Requires-Dist: pytest-cov>=5.0; extra == 'test'
43
+ Requires-Dist: pytest>=8.0; extra == 'test'
44
+ Provides-Extra: typecheck
45
+ Requires-Dist: mypy>=1.11; extra == 'typecheck'
46
+ Requires-Dist: types-pyyaml>=6.0; extra == 'typecheck'
47
+ Provides-Extra: vector-test
48
+ Requires-Dist: chromadb>=0.5; extra == 'vector-test'
49
+ Requires-Dist: langchain-chroma>=0.1; extra == 'vector-test'
50
+ Description-Content-Type: text/markdown
51
+
52
+ <div align="center">
53
+
54
+ # okf-agents
55
+
56
+ **Open Knowledge Format bundles as first-class LangGraph and LangChain building blocks.**
57
+
58
+ [![CI](https://github.com/RonCodes88/okf-agents/actions/workflows/ci.yml/badge.svg)](https://github.com/RonCodes88/okf-agents/actions/workflows/ci.yml)
59
+ [![License: MIT](https://img.shields.io/github/license/RonCodes88/okf-agents)](LICENSE)
60
+ [![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](pyproject.toml)
61
+
62
+ [Installation](#installation) &nbsp;•&nbsp;
63
+ [Quick Start](#quick-start) &nbsp;•&nbsp;
64
+ [Documentation](docs/) &nbsp;•&nbsp;
65
+ [Examples](#examples) &nbsp;•&nbsp;
66
+ [Contributing](CONTRIBUTING.md) &nbsp;•&nbsp;
67
+ [Security](SECURITY.md) &nbsp;•&nbsp;
68
+ [Changelog](CHANGELOG.md)
69
+
70
+ *Not yet published to PyPI — see [the launch checklist](docs/launch-checklist.md).*
71
+
72
+ </div>
73
+
74
+ ---
75
+
76
+ `okf-agents` turns an [Open Knowledge Format (OKF)](https://okf.md) bundle
77
+ — a directory of linked, frontmattered Markdown concepts — into deterministic
78
+ LangGraph and LangChain building blocks: bundle loading and weighted lexical
79
+ search, four ready-made agent tools, a keyword retriever, a bounded navigator
80
+ subgraph that reads and cites its sources, a query router, and idempotent
81
+ vector-store synchronization with graph-aware retrieval. It's for teams
82
+ building retrieval or agentic workflows over structured Markdown knowledge
83
+ bases who want small, typed, independently testable pieces rather than
84
+ another end-to-end RAG framework to learn.
85
+
86
+ Loading arbitrary Markdown gives you text; a vector store alone gives you
87
+ semantically similar chunks with no sense of how concepts relate to each
88
+ other. `okf-agents` keeps the bundle's link graph as a first-class
89
+ citizen: search results and semantic hits can be expanded through resolved
90
+ links (`OKFGraphRetriever`), the navigator subgraph follows links breadth
91
+ -first or on model guidance within hard token/hop budgets, and every
92
+ answer's citations are validated against concepts it actually read — so
93
+ retrieval reflects the bundle's real structure, not just embedding-space
94
+ proximity.
95
+
96
+ This library implements the [OKF specification](https://okf.md/spec/); it
97
+ is an integration layer for OKF, not the standard itself.
98
+
99
+ ## Installation
100
+
101
+ ```bash
102
+ pip install okf-agents
103
+ ```
104
+
105
+ Only `langgraph`, `langchain-core`, `pydantic`, and `pyyaml` are required.
106
+ Provider SDKs (`langchain-anthropic`, `langchain-openai`, ...) and
107
+ vector-store packages (`chromadb`, ...) are never installed as hard
108
+ dependencies — bring the ones you need.
109
+
110
+ For local development instead, see [Development](#development).
111
+
112
+ ## Quick Start
113
+
114
+ ```python
115
+ import tempfile
116
+ from pathlib import Path
117
+ from okf_agents import OKFBundle
118
+
119
+ tmp_dir = tempfile.mkdtemp()
120
+ concepts_dir = Path(tmp_dir) / "concepts"
121
+ concepts_dir.mkdir()
122
+ (concepts_dir / "orders.md").write_text(
123
+ "---\ntype: table\ntitle: Orders\ntags: [sales]\n---\n\n"
124
+ "# Orders\n\nEach order belongs to a [customer](customers.md).\n"
125
+ )
126
+ (concepts_dir / "customers.md").write_text(
127
+ "---\ntype: table\ntitle: Customers\ntags: [crm]\n---\n\n"
128
+ "# Customers\n\nCustomer accounts and contact details.\n"
129
+ )
130
+
131
+ bundle = OKFBundle.load(tmp_dir)
132
+ print(bundle.concept_count, "concepts loaded")
133
+ print(sorted(concept.id for concept in bundle.all_concepts()))
134
+ # 2 concepts loaded
135
+ # ['concepts/customers', 'concepts/orders']
136
+ ```
137
+
138
+ That's the whole contract: point `OKFBundle.load()` at a directory of
139
+ Markdown files with `type` frontmatter, and get back a typed, queryable
140
+ bundle. No index file is required — see [docs/concepts.md](docs/concepts.md).
141
+
142
+ ## Why use okf-agents?
143
+
144
+ - **Deterministic by default.** Search, traversal, and routing heuristics
145
+ are dependency-free and offline; a real model is only involved where you
146
+ explicitly ask for one (the navigator, an optional router classifier).
147
+ - **The link graph is not thrown away.** Broken links are tolerated and
148
+ surfaced, not hidden; resolved links drive graph expansion and
149
+ traversal, not just chunk similarity.
150
+ - **Small, typed, independently useful pieces.** Use just the bundle
151
+ loader, just the retriever, just the tools — nothing requires the
152
+ navigator or a vector store.
153
+ - **Budgets are real limits.** The navigator's hop/concept/token budgets
154
+ are provable bounds on the graph, not soft guidelines a model can blow
155
+ through.
156
+
157
+ ## When should I not use it?
158
+
159
+ - You need a general-purpose document loader for arbitrary file formats
160
+ (PDFs, HTML, docx) — `okf-agents` only reads OKF-shaped Markdown
161
+ bundles.
162
+ - You need semantic chunking, reranking, or multi-vector-store fan-out —
163
+ this library intentionally keeps vector-store integration minimal (see
164
+ [docs/vector-stores.md](docs/vector-stores.md)).
165
+ - You want a hosted, batteries-included RAG product — this is a library
166
+ of composable pieces for your own LangGraph app, not an application.
167
+
168
+ ## Examples
169
+
170
+ Each example below continues from the `bundle` loaded in
171
+ [Quick Start](#quick-start).
172
+
173
+ ### LangChain agent tools
174
+
175
+ ```python
176
+ from okf_agents import create_okf_tools
177
+
178
+ tools = create_okf_tools(bundle)
179
+ search_tool = next(tool for tool in tools if tool.name == "search_concepts")
180
+ print(search_tool.invoke({"query": "customer"}))
181
+ ```
182
+
183
+ `create_okf_tools` also returns `read_concept`, `list_links`, and
184
+ `read_index` — deterministic, plain-text tools ready to bind to any
185
+ tool-calling agent.
186
+
187
+ ### Keyword retriever
188
+
189
+ ```python
190
+ from okf_agents import OKFRetriever
191
+
192
+ retriever = OKFRetriever(bundle=bundle, top_k=3)
193
+ for document in retriever.invoke("orders"):
194
+ print(document.metadata["concept_id"], "-", document.metadata["title"])
195
+ ```
196
+
197
+ ### Router
198
+
199
+ ```python
200
+ from okf_agents import create_okf_router
201
+
202
+ router = create_okf_router(bundle)
203
+ print(router({"query": "Orders"})) # exact title match -> "bundle"
204
+ print(router({"query": "how do refunds work?"})) # vague, no vector store -> "bundle"
205
+ ```
206
+
207
+ Pass `vector_store=` to route vague queries to `"vector"` instead, or
208
+ `classifier=` to let a model choose `"bundle"` / `"vector"` / `"both"`.
209
+ `create_okf_router` never performs retrieval itself — it only labels the
210
+ query for a downstream conditional edge.
211
+
212
+ ### Navigator subgraph
213
+
214
+ The navigator needs a chat model. This example uses LangChain's
215
+ `FakeListChatModel` so it runs fully offline; swap in `ChatAnthropic`,
216
+ `ChatOpenAI`, or any other `BaseChatModel` in production.
217
+
218
+ ```python
219
+ import json
220
+ from langchain_core.language_models.fake_chat_models import FakeListChatModel
221
+ from okf_agents import create_okf_navigator
222
+
223
+ model = FakeListChatModel(
224
+ responses=[
225
+ json.dumps({"concept_ids": ["concepts/orders"]}),
226
+ json.dumps({"sufficient": True}),
227
+ json.dumps({
228
+ "answer": "Orders belong to customers.",
229
+ "citations": ["concepts/orders"],
230
+ }),
231
+ ]
232
+ )
233
+ navigator = create_okf_navigator(bundle, model, max_hops=2)
234
+ result = navigator.invoke({"question": "How do orders relate to customers?"})
235
+ print(result["answer"])
236
+ print(result["citations"])
237
+ ```
238
+
239
+ See [docs/navigator-and-budgets.md](docs/navigator-and-budgets.md) for the
240
+ full traversal and budget contract.
241
+
242
+ ### Vector-store sync and graph-aware retrieval (optional)
243
+
244
+ `sync_bundle_to_vector_store` and `OKFGraphRetriever` work with any
245
+ LangChain `VectorStore` that supports ID-based lookup and stable-ID
246
+ writes. This example uses a tiny in-process store and hashed-word
247
+ embeddings so it runs offline; swap in Chroma, pgvector, or another real
248
+ `VectorStore` with a real embeddings model in production.
249
+
250
+ ```python
251
+ import hashlib
252
+ import math
253
+ import re
254
+ from typing import Any
255
+
256
+ from langchain_core.documents import Document
257
+ from langchain_core.embeddings import Embeddings
258
+ from langchain_core.vectorstores import VectorStore
259
+ from okf_agents import OKFGraphRetriever, sync_bundle_to_vector_store
260
+
261
+
262
+ class DemoEmbeddings(Embeddings):
263
+ def embed_documents(self, texts: list[str]) -> list[list[float]]:
264
+ return [self._embed(text) for text in texts]
265
+
266
+ def embed_query(self, text: str) -> list[float]:
267
+ return self._embed(text)
268
+
269
+ def _embed(self, text: str, dimensions: int = 32) -> list[float]:
270
+ vector = [0.0] * dimensions
271
+ for token in re.findall(r"\w+", text.casefold()):
272
+ vector[int(hashlib.sha256(token.encode()).hexdigest(), 16) % dimensions] += 1.0
273
+ norm = math.sqrt(sum(v * v for v in vector)) or 1.0
274
+ return [v / norm for v in vector]
275
+
276
+
277
+ class DemoVectorStore(VectorStore):
278
+ def __init__(self, embedding: Embeddings) -> None:
279
+ self.embedding = embedding
280
+ self._docs: dict[str, Document] = {}
281
+ self._vectors: dict[str, list[float]] = {}
282
+
283
+ def add_documents(self, documents: list[Document], **kwargs: Any) -> list[str]:
284
+ ids = kwargs["ids"]
285
+ vectors = self.embedding.embed_documents([d.page_content for d in documents])
286
+ for doc_id, document, vector in zip(ids, documents, vectors, strict=True):
287
+ self._docs[doc_id] = document
288
+ self._vectors[doc_id] = vector
289
+ return list(ids)
290
+
291
+ def get_by_ids(self, ids: list[str], /) -> list[Document]:
292
+ return [self._docs[i] for i in ids if i in self._docs]
293
+
294
+ def similarity_search(self, query: str, k: int = 4, **kwargs: Any) -> list[Document]:
295
+ query_vector = self.embedding.embed_query(query)
296
+ ranked = sorted(
297
+ self._vectors,
298
+ key=lambda i: -sum(x * y for x, y in zip(query_vector, self._vectors[i], strict=True)),
299
+ )
300
+ return [self._docs[i] for i in ranked[:k]]
301
+
302
+ @classmethod
303
+ def from_texts(cls, texts: Any, embedding: Any, metadatas: Any = None, **kwargs: Any) -> Any:
304
+ raise NotImplementedError
305
+
306
+
307
+ vector_store = DemoVectorStore(DemoEmbeddings())
308
+ sync_bundle_to_vector_store(bundle, vector_store)
309
+
310
+ graph_retriever = OKFGraphRetriever(
311
+ bundle=bundle, vector_store=vector_store, top_k=1, expand_hops=1
312
+ )
313
+ for document in graph_retriever.invoke("order belongs"):
314
+ print(document.metadata["concept_id"])
315
+ # concepts/orders
316
+ # concepts/customers (reached via the "customer" link, not just similarity)
317
+ ```
318
+
319
+ See [docs/vector-stores.md](docs/vector-stores.md) for the idempotency and
320
+ store-capability contract.
321
+
322
+ ## Architecture overview
323
+
324
+ ```text
325
+ OKF bundle (directory of Markdown)
326
+
327
+
328
+ OKFBundle.load() deterministic parse + link graph + lexical search
329
+
330
+ ├── create_okf_tools() four LangChain tools (no model required)
331
+ ├── OKFRetriever keyword BaseRetriever
332
+ ├── sync_bundle_to_vector_store + OKFGraphRetriever
333
+ │ idempotent sync + graph-aware semantic retrieval
334
+ ├── create_okf_router() bundle / vector / both classification node
335
+ └── create_okf_navigator() bounded read → expand → cite subgraph
336
+ ```
337
+
338
+ Every arrow above is independently usable; nothing requires wiring the
339
+ whole diagram together.
340
+
341
+ ## Feature status
342
+
343
+ | Feature | Status |
344
+ | ------------------------------------------ | ------ |
345
+ | Bundle loading, link graph, lexical search | Stable |
346
+ | LangChain agent tools | Stable |
347
+ | Keyword retriever | Stable |
348
+ | Router node | Stable |
349
+ | Navigator subgraph | Stable |
350
+ | Vector-store sync + graph-aware retriever | Stable |
351
+ | Async APIs | Not implemented (v0.1 is sync-only by design) |
352
+ | Multi-vector-store adapters | Out of scope — any LangChain `VectorStore` with ID lookup + stable-ID writes works |
353
+
354
+ "Stable" means covered by unit and offline integration tests and used
355
+ across the examples above — the package itself is still pre-1.0 alpha, so
356
+ APIs may change between minor versions.
357
+
358
+ ## Public API map
359
+
360
+ ```python
361
+ from okf_agents import (
362
+ OKFBundle,
363
+ Concept, ConceptFrontmatter, LinkEdge, BundleIndex, SyncResult,
364
+ create_okf_tools,
365
+ OKFRetriever, OKFGraphRetriever,
366
+ create_okf_router,
367
+ create_okf_navigator,
368
+ sync_bundle_to_vector_store,
369
+ OKFError, BundleNotFoundError, BundleValidationError,
370
+ ConceptNotFoundError, LinkResolutionError,
371
+ )
372
+ ```
373
+
374
+ Full signatures and behavior contracts: [docs/api-reference.md](docs/api-reference.md).
375
+
376
+ ## Optional dependencies
377
+
378
+ | Extra | Installs | Needed for |
379
+ | ----------- | ------------------------------- | ------------------------------------ |
380
+ | `dev` | test + lint + typecheck tools | Local development |
381
+ | `test` | `pytest`, `pytest-cov` | Running the test suite |
382
+ | `lint` | `ruff` | Linting |
383
+ | `typecheck` | `mypy`, `types-PyYAML` | Strict type checking |
384
+ | `vector-test` | `chromadb`, `langchain-chroma` | Vector-store integration testing |
385
+ | `release` | `build`, `twine` | Building/publishing packages |
386
+
387
+ None of these are required to use `OKFBundle`, the tools, the retriever,
388
+ the router, or the navigator with your own chat model and vector store.
389
+
390
+ ## Compatibility
391
+
392
+ - Python 3.11, 3.12, 3.13
393
+ - `langgraph` >= 0.2
394
+ - `langchain-core` >= 0.3
395
+ - `pydantic` >= 2.0
396
+
397
+ ## Limitations
398
+
399
+ - v0.1 parses standard inline Markdown links only — reference-style
400
+ links, images, and autolinks are not graph edges (see
401
+ [docs/concepts.md](docs/concepts.md#links-and-resolution)).
402
+ - Lexical search is a weighted substring match, not TF-IDF or embeddings
403
+ — use `OKFGraphRetriever` with a real vector store for semantic recall.
404
+ - The navigator does not stream, checkpoint, or support human-in-the-loop
405
+ approval in v0.1.
406
+
407
+ ## Development
408
+
409
+ ```bash
410
+ git clone https://github.com/RonCodes88/okf-agents.git
411
+ cd okf-agents
412
+ python -m venv .venv && source .venv/bin/activate
413
+ pip install -e ".[dev]"
414
+ ```
415
+
416
+ ## Testing
417
+
418
+ ```bash
419
+ pytest # unit tests + offline integration tests, no secrets required
420
+ pytest --cov # with coverage (>= 85% required)
421
+ ruff check .
422
+ mypy okf_agents tests
423
+ ```
424
+
425
+ Provider-integration and end-to-end tests are opt-in
426
+ (`RUN_INTEGRATION_TESTS=1`, `RUN_E2E_TESTS=1`) and skip cleanly without a
427
+ provider key. See [docs/testing.md](docs/testing.md).
428
+
429
+ ## Contributing
430
+
431
+ Contributions are welcome — please read [CONTRIBUTING.md](CONTRIBUTING.md)
432
+ for branch/commit conventions and local setup, and open an issue before
433
+ starting a large change.
434
+
435
+ ## Security
436
+
437
+ See [SECURITY.md](SECURITY.md) for how to privately report a
438
+ vulnerability.
439
+
440
+ ## License
441
+
442
+ [MIT](LICENSE) © Ronald Li
443
+
444
+ ## Acknowledgements
445
+
446
+ Built against the [Open Knowledge Format specification](https://okf.md/spec/)
447
+ and the [LangGraph](https://github.com/langchain-ai/langgraph) /
448
+ [LangChain](https://github.com/langchain-ai/langchain) ecosystem.
449
+
450
+ ---
451
+
452
+ <div align="center">
453
+
454
+ If this project is useful to you, a ⭐ helps others find it.
455
+
456
+ </div>