dirsql-plugin-embeddings 0.1.0__tar.gz → 0.1.2__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 (19) hide show
  1. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/.gitignore +3 -0
  2. dirsql_plugin_embeddings-0.1.2/PKG-INFO +68 -0
  3. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/README.md +9 -6
  4. dirsql_plugin_embeddings-0.1.0/e2e-attestations/claude-open-issues-review-le8hm5-531.json → dirsql_plugin_embeddings-0.1.2/e2e-attestations/claude-on-file-integration-e2e-lpeicb.json +3 -3
  5. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/pyproject.toml +2 -1
  6. dirsql_plugin_embeddings-0.1.2/src/dirsql_plugin_embeddings/on_file/__init__.py +11 -0
  7. dirsql_plugin_embeddings-0.1.2/src/dirsql_plugin_embeddings/on_file/build_rows.py +13 -0
  8. dirsql_plugin_embeddings-0.1.2/src/dirsql_plugin_embeddings/on_file/on_file.py +25 -0
  9. dirsql_plugin_embeddings-0.1.2/src/dirsql_plugin_embeddings/on_file/read_text.py +11 -0
  10. dirsql_plugin_embeddings-0.1.0/PKG-INFO +0 -5
  11. dirsql_plugin_embeddings-0.1.0/src/dirsql_plugin_embeddings/on_file.py +0 -33
  12. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/src/dirsql_plugin_embeddings/__init__.py +0 -0
  13. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/src/dirsql_plugin_embeddings/dirsql.toml +0 -0
  14. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/src/dirsql_plugin_embeddings/embedder.py +0 -0
  15. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/src/dirsql_plugin_embeddings/pre_query.py +0 -0
  16. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/testing-conventions.toml +0 -0
  17. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/tests/conftest.py +0 -0
  18. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/tests/e2e/__init__.py +0 -0
  19. {dirsql_plugin_embeddings-0.1.0 → dirsql_plugin_embeddings-0.1.2}/tests/integration/__init__.py +0 -0
@@ -56,3 +56,6 @@ docs/playwright-report/
56
56
  docs/blob-report/
57
57
  docs/.playwright/
58
58
  actionlint
59
+
60
+ # cargo-mutants run output (never commit)
61
+ mutants.out/
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: dirsql-plugin-embeddings
3
+ Version: 0.1.2
4
+ Summary: First-party dirsql plugin: semantic search via an OpenAI-compatible embeddings endpoint.
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+
8
+ # dirsql-plugin-embeddings
9
+
10
+ A first-party [`dirsql`](https://github.com/thekevinscott/dirsql) plugin that
11
+ adds **semantic search** over a directory of Markdown files. It is the worked
12
+ implementation behind the [Search documents by
13
+ meaning](https://thekevinscott.github.io/dirsql/howto/search-by-meaning) how-to,
14
+ swapping that guide's local `model2vec` model for any OpenAI-compatible
15
+ `/v1/embeddings` endpoint.
16
+
17
+ ```sh
18
+ uvx --with dirsql-plugin-embeddings dirsql
19
+ ```
20
+
21
+ Deliberately minimal (v0.1): one embedding provider shape, one table, no
22
+ chunking, no config surface beyond three environment variables.
23
+
24
+ ## How it works
25
+
26
+ The plugin ships a `dirsql.toml` fragment that dirsql discovers when the package
27
+ is installed alongside it. The fragment declares:
28
+
29
+ - the [`sqlite-vec`](https://github.com/asg017/sqlite-vec) extension, for
30
+ `vec_distance_cosine()`;
31
+ - a `documents` table whose `on-file` hook embeds each `**/*.md` file into a
32
+ TEXT `embedding` column;
33
+ - a `pre-query` hook that embeds the incoming question and emits the
34
+ nearest-neighbor SQL.
35
+
36
+ Both hooks are console scripts that call the same embedder.
37
+
38
+ ## Configuration
39
+
40
+ The embedder reads three environment variables (point them at any hosted or
41
+ self-managed OpenAI-compatible inference server):
42
+
43
+ | Variable | Meaning |
44
+ |---|---|
45
+ | `DIRSQL_EMBEDDINGS_BASE_URL` | Base URL; `/v1/embeddings` is appended. |
46
+ | `DIRSQL_EMBEDDINGS_MODEL` | Model name sent in the request. |
47
+ | `DIRSQL_EMBEDDINGS_API_KEY` | Bearer token for `Authorization`. |
48
+
49
+ ## Console scripts
50
+
51
+ | Script | Hook | Input | Output |
52
+ |---|---|---|---|
53
+ | `dirsql-embeddings-on-file` | `on-file` | a file's absolute path (`argv[1]`) | one-line JSON row array with `path`, `text`, `embedding` |
54
+ | `dirsql-embeddings-pre-query` | `pre-query` | a raw request body (`argv[1]`) | nearest-neighbor SQL over `documents` |
55
+
56
+ `pre-query` accepts both a verbatim server body (`{"q": ...}`) and the CLI
57
+ `query` subcommand's `{"sql": <arg>}` wrapper, so `dirsql query '{"q": ...}'` and
58
+ a real `POST /query` both work.
59
+
60
+ ## Tests
61
+
62
+ Three tiers, per the dirsql testing conventions:
63
+
64
+ - **unit** (colocated, mocked seams) — `src/dirsql_plugin_embeddings/*_test.py`
65
+ - **integration** (`tests/integration/`) — each console script as a real
66
+ subprocess against a local stub `/v1/embeddings` server
67
+ - **e2e** (`tests/e2e/`) — the full loop through the real launcher + `dirsql`
68
+ binary + `sqlite-vec`, nothing mocked but the embedding endpoint
@@ -3,13 +3,16 @@
3
3
  A first-party [`dirsql`](https://github.com/thekevinscott/dirsql) plugin that
4
4
  adds **semantic search** over a directory of Markdown files. It is the worked
5
5
  implementation behind the [Search documents by
6
- meaning](../../docs/howto/search-by-meaning.md) how-to, swapping that guide's
7
- local `model2vec` model for any OpenAI-compatible `/v1/embeddings` endpoint.
6
+ meaning](https://thekevinscott.github.io/dirsql/howto/search-by-meaning) how-to,
7
+ swapping that guide's local `model2vec` model for any OpenAI-compatible
8
+ `/v1/embeddings` endpoint.
8
9
 
9
- This is an **in-repo, repo-only** package (not published to an index). It exists
10
- to prove the dirsql plugin conventions (#531, part of #363) and power the
11
- semantic-search demo. Deliberately minimal (v0.1): one embedding provider shape,
12
- one table, no chunking, no config surface beyond three environment variables.
10
+ ```sh
11
+ uvx --with dirsql-plugin-embeddings dirsql
12
+ ```
13
+
14
+ Deliberately minimal (v0.1): one embedding provider shape, one table, no
15
+ chunking, no config surface beyond three environment variables.
13
16
 
14
17
  ## How it works
15
18
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "command": "uv run --with sqlite-vec --with-editable . --with-editable ../../packages/python python -m pytest tests/e2e -x -q",
3
- "ran_at": 1784022840,
3
+ "ran_at": 1785323892,
4
4
  "exit_code": 0,
5
- "commit": "5f6caffd4996dfdf09cf798c1deb55f6e216fde5",
6
- "branch": "claude/open-issues-review-le8hm5-531"
5
+ "commit": "35c1c6929c4a8b517032cc51e0cc6720f43b58f4",
6
+ "branch": "claude/on-file-integration-e2e-lpeicb"
7
7
  }
@@ -10,6 +10,7 @@ build-backend = "hatchling.build"
10
10
  name = "dirsql-plugin-embeddings"
11
11
  dynamic = ["version"]
12
12
  description = "First-party dirsql plugin: semantic search via an OpenAI-compatible embeddings endpoint."
13
+ readme = "README.md"
13
14
  requires-python = ">=3.11"
14
15
 
15
16
  [tool.hatch.version]
@@ -38,7 +39,7 @@ git_describe_command = ["git", "describe", "--dirty", "--tags", "--long", "--mat
38
39
  [project.scripts]
39
40
  # The two command hooks the fragment invokes; installing the package puts them
40
41
  # on PATH so `dirsql` resolves them when it spawns the hooks.
41
- dirsql-embeddings-on-file = "dirsql_plugin_embeddings.on_file:main"
42
+ dirsql-embeddings-on-file = "dirsql_plugin_embeddings.on_file:on_file"
42
43
  dirsql-embeddings-pre-query = "dirsql_plugin_embeddings.pre_query:main"
43
44
 
44
45
  [project.entry-points.dirsql]
@@ -0,0 +1,11 @@
1
+ """``on-file`` console script: embed one matched file into a dirsql row.
2
+
3
+ The package barrel: ``pyproject.toml`` points the ``dirsql-embeddings-on-file``
4
+ script at ``dirsql_plugin_embeddings.on_file:on_file``, which resolves here, so
5
+ this re-export is the shipped command's public surface -- moving the callable
6
+ between modules is free, dropping it from ``__all__`` breaks the install.
7
+ """
8
+
9
+ from .on_file import on_file
10
+
11
+ __all__ = ["on_file"]
@@ -0,0 +1,13 @@
1
+ """Shape one embedded file into the command hook's row array.
2
+
3
+ Annotations are evaluated at runtime (no ``from __future__ import
4
+ annotations``) so a mutated ``X | None`` union in a signature fails at import
5
+ rather than surviving as an inert string.
6
+ """
7
+
8
+ import json
9
+
10
+
11
+ def build_rows(path: str, text: str, vector: list[float]) -> list[dict]:
12
+ # The embedding is stored as JSON text, which `sqlite-vec` accepts directly.
13
+ return [{"path": path, "text": text, "embedding": json.dumps(vector)}]
@@ -0,0 +1,25 @@
1
+ """The ``on-file`` hook entry point.
2
+
3
+ Reads the file at ``argv[1]``, embeds its text, and prints a one-line JSON row
4
+ array (``path``, ``text``, ``embedding``).
5
+
6
+ Annotations are evaluated at runtime (no ``from __future__ import
7
+ annotations``) so a mutated ``X | None`` union in a signature fails at import
8
+ rather than surviving as an inert string.
9
+ """
10
+
11
+ import json
12
+ import sys
13
+
14
+ from ..embedder import embed
15
+ from .build_rows import build_rows
16
+ from .read_text import read_text
17
+
18
+
19
+ def on_file(argv: list[str] | None = None) -> int:
20
+ if argv is None:
21
+ argv = sys.argv
22
+ path = argv[1]
23
+ text = read_text(path)
24
+ print(json.dumps(build_rows(path, text, embed(text))))
25
+ return 0
@@ -0,0 +1,11 @@
1
+ """Read the matched file's text off disk.
2
+
3
+ Annotations are evaluated at runtime (no ``from __future__ import
4
+ annotations``) so a mutated ``X | None`` union in a signature fails at import
5
+ rather than surviving as an inert string.
6
+ """
7
+
8
+
9
+ def read_text(path: str) -> str:
10
+ with open(path, encoding="utf-8") as handle:
11
+ return handle.read()
@@ -1,5 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: dirsql-plugin-embeddings
3
- Version: 0.1.0
4
- Summary: First-party dirsql plugin: semantic search via an OpenAI-compatible embeddings endpoint.
5
- Requires-Python: >=3.11
@@ -1,33 +0,0 @@
1
- """``on-file`` console script: embed one matched file into a dirsql row.
2
-
3
- Reads the file at ``argv[1]``, embeds its text, and prints a one-line JSON row
4
- array (``path``, ``text``, ``embedding``) -- the embedding stored as JSON text,
5
- which ``sqlite-vec`` accepts directly.
6
-
7
- Annotations are evaluated at runtime (no ``from __future__ import annotations``)
8
- so a mutated ``X | None`` union in a signature fails at import rather than
9
- surviving as an inert string.
10
- """
11
-
12
- import json
13
- import sys
14
-
15
- from .embedder import embed
16
-
17
-
18
- def _read_text(path: str) -> str:
19
- with open(path, encoding="utf-8") as handle:
20
- return handle.read()
21
-
22
-
23
- def build_rows(path: str, text: str, vector: list[float]) -> list[dict]:
24
- return [{"path": path, "text": text, "embedding": json.dumps(vector)}]
25
-
26
-
27
- def main(argv: list[str] | None = None) -> int:
28
- if argv is None:
29
- argv = sys.argv
30
- path = argv[1]
31
- text = _read_text(path)
32
- print(json.dumps(build_rows(path, text, embed(text))))
33
- return 0