getbased-agent-stack 0.5.9__tar.gz → 0.6.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 (25) hide show
  1. {getbased_agent_stack-0.5.9/src/getbased_agent_stack.egg-info → getbased_agent_stack-0.6.0}/PKG-INFO +14 -8
  2. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/README.md +7 -1
  3. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/pyproject.toml +8 -8
  4. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/__init__.py +1 -1
  5. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/cli.py +8 -2
  6. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/env_file.py +15 -2
  7. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0/src/getbased_agent_stack.egg-info}/PKG-INFO +14 -8
  8. getbased_agent_stack-0.6.0/src/getbased_agent_stack.egg-info/requires.txt +11 -0
  9. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_cli.py +32 -0
  10. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_env_file.py +46 -0
  11. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_integration.py +42 -0
  12. getbased_agent_stack-0.5.9/src/getbased_agent_stack.egg-info/requires.txt +0 -11
  13. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/LICENSE +0 -0
  14. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/setup.cfg +0 -0
  15. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/mcp_configs.py +0 -0
  16. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/systemd/getbased-dashboard.service +0 -0
  17. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/systemd/getbased-rag.service +0 -0
  18. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/units.py +0 -0
  19. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack.egg-info/SOURCES.txt +0 -0
  20. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack.egg-info/dependency_links.txt +0 -0
  21. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack.egg-info/entry_points.txt +0 -0
  22. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack.egg-info/top_level.txt +0 -0
  23. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_mcp_configs.py +0 -0
  24. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_systemd_units.py +0 -0
  25. {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_units.py +0 -0
@@ -1,18 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: getbased-agent-stack
3
- Version: 0.5.9
3
+ Version: 0.6.0
4
4
  Summary: One-command install of the full getbased agent stack — getbased-mcp + getbased-rag + getbased-dashboard
5
5
  License-Expression: AGPL-3.0-or-later
6
- Requires-Python: >=3.10
6
+ Requires-Python: >=3.11
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
- Requires-Dist: getbased-mcp>=0.2.9
10
- Requires-Dist: getbased-rag>=0.7.5
11
- Requires-Dist: getbased-dashboard>=0.6.8
9
+ Requires-Dist: getbased-mcp>=0.3.0
10
+ Requires-Dist: getbased-rag>=0.8.0
11
+ Requires-Dist: getbased-dashboard>=0.7.0
12
12
  Provides-Extra: full
13
- Requires-Dist: getbased-rag[full]>=0.7.5; extra == "full"
13
+ Requires-Dist: getbased-rag[full]>=0.8.0; extra == "full"
14
14
  Provides-Extra: test
15
- Requires-Dist: pytest>=8.0; extra == "test"
15
+ Requires-Dist: pytest>=9.1.1; extra == "test"
16
16
  Requires-Dist: httpx>=0.27; extra == "test"
17
17
  Requires-Dist: pytest-timeout>=2.3; extra == "test"
18
18
  Dynamic: license-file
@@ -25,6 +25,10 @@ Part of the [getbased-agents monorepo](https://github.com/elkimek/getbased-agent
25
25
 
26
26
  ## Install
27
27
 
28
+ Requires Python 3.11 or newer. To rebuild an existing Python 3.10 tool
29
+ environment while preserving configuration and library data, follow the
30
+ [migration instructions](../../README.md#migrating-an-existing-python-310-installation).
31
+
28
32
  Linux, one command:
29
33
 
30
34
  ```bash
@@ -44,7 +48,7 @@ That setup payload contains private credentials. Keep it out of logs and public
44
48
  Manual — pipx:
45
49
 
46
50
  ```bash
47
- pipx install --include-deps "getbased-agent-stack[full]"
51
+ pipx install --python python3.12 --include-deps "getbased-agent-stack[full]"
48
52
  ```
49
53
 
50
54
  The `--include-deps` flag is required — it exposes `getbased-mcp`, `lens`, and `getbased-dashboard` alongside `getbased-stack` on your PATH. Without it, pipx only links the stack's own entry point and the MCP/rag/dashboard binaries stay hidden inside the venv.
@@ -53,6 +57,7 @@ Manual — uv (0.11+):
53
57
 
54
58
  ```bash
55
59
  uv tool install \
60
+ --python 3.12 \
56
61
  --with-executables-from getbased-rag \
57
62
  --with-executables-from getbased-dashboard \
58
63
  --with-executables-from getbased-mcp \
@@ -177,6 +182,7 @@ The dashboard is likewise stateless — it proxies rag for Knowledge operations,
177
182
  | 0.2.x | ≥0.2.2 | ≥0.6.0 | ≥0.5.0 | v1 (+ streaming ingest, per-library models) |
178
183
  | 0.4.x | ≥0.2.3 | ≥0.7.1 | ≥0.6.1 | v1 (+ shared env file, `getbased-stack init`, systemd units) |
179
184
  | 0.5.x | ≥0.2.9 | ≥0.7.5 | ≥0.6.8 | v1 (+ `getbased-stack connect`, multi-client setup targets; explicit local-only scripted init) |
185
+ | 0.6.x | ≥0.3.0 | ≥0.8.0 | ≥0.7.0 | v1 (Python ≥3.11, ONNX Runtime ≥1.31, security updates) |
180
186
 
181
187
  Bump the meta's major when sibling protocols break; bump siblings freely for normal features.
182
188
 
@@ -6,6 +6,10 @@ Part of the [getbased-agents monorepo](https://github.com/elkimek/getbased-agent
6
6
 
7
7
  ## Install
8
8
 
9
+ Requires Python 3.11 or newer. To rebuild an existing Python 3.10 tool
10
+ environment while preserving configuration and library data, follow the
11
+ [migration instructions](../../README.md#migrating-an-existing-python-310-installation).
12
+
9
13
  Linux, one command:
10
14
 
11
15
  ```bash
@@ -25,7 +29,7 @@ That setup payload contains private credentials. Keep it out of logs and public
25
29
  Manual — pipx:
26
30
 
27
31
  ```bash
28
- pipx install --include-deps "getbased-agent-stack[full]"
32
+ pipx install --python python3.12 --include-deps "getbased-agent-stack[full]"
29
33
  ```
30
34
 
31
35
  The `--include-deps` flag is required — it exposes `getbased-mcp`, `lens`, and `getbased-dashboard` alongside `getbased-stack` on your PATH. Without it, pipx only links the stack's own entry point and the MCP/rag/dashboard binaries stay hidden inside the venv.
@@ -34,6 +38,7 @@ Manual — uv (0.11+):
34
38
 
35
39
  ```bash
36
40
  uv tool install \
41
+ --python 3.12 \
37
42
  --with-executables-from getbased-rag \
38
43
  --with-executables-from getbased-dashboard \
39
44
  --with-executables-from getbased-mcp \
@@ -158,6 +163,7 @@ The dashboard is likewise stateless — it proxies rag for Knowledge operations,
158
163
  | 0.2.x | ≥0.2.2 | ≥0.6.0 | ≥0.5.0 | v1 (+ streaming ingest, per-library models) |
159
164
  | 0.4.x | ≥0.2.3 | ≥0.7.1 | ≥0.6.1 | v1 (+ shared env file, `getbased-stack init`, systemd units) |
160
165
  | 0.5.x | ≥0.2.9 | ≥0.7.5 | ≥0.6.8 | v1 (+ `getbased-stack connect`, multi-client setup targets; explicit local-only scripted init) |
166
+ | 0.6.x | ≥0.3.0 | ≥0.8.0 | ≥0.7.0 | v1 (Python ≥3.11, ONNX Runtime ≥1.31, security updates) |
161
167
 
162
168
  Bump the meta's major when sibling protocols break; bump siblings freely for normal features.
163
169
 
@@ -1,28 +1,28 @@
1
1
  [build-system]
2
- requires = ["setuptools>=83.0.0", "wheel"]
2
+ requires = ["setuptools>=84.0.0", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "getbased-agent-stack"
7
- version = "0.5.9"
7
+ version = "0.6.0"
8
8
  description = "One-command install of the full getbased agent stack — getbased-mcp + getbased-rag + getbased-dashboard"
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0-or-later"
11
- requires-python = ">=3.10"
11
+ requires-python = ">=3.11"
12
12
  # Pulls every sibling package. Bump this meta when a sibling protocol
13
13
  # bump requires coordinated release.
14
14
  dependencies = [
15
- "getbased-mcp>=0.2.9",
16
- "getbased-rag>=0.7.5",
17
- "getbased-dashboard>=0.6.8",
15
+ "getbased-mcp>=0.3.0",
16
+ "getbased-rag>=0.8.0",
17
+ "getbased-dashboard>=0.7.0",
18
18
  ]
19
19
 
20
20
  [project.optional-dependencies]
21
21
  # `full` includes PDF/DOCX parsers and ONNX acceleration (pre-exported
22
22
  # weights — no PyTorch/transformers/optimum dance).
23
- full = ["getbased-rag[full]>=0.7.5"]
23
+ full = ["getbased-rag[full]>=0.8.0"]
24
24
  # For contributors running the integration test harness.
25
- test = ["pytest>=8.0", "httpx>=0.27", "pytest-timeout>=2.3"]
25
+ test = ["pytest>=9.1.1", "httpx>=0.27", "pytest-timeout>=2.3"]
26
26
 
27
27
  # In the monorepo (elkimek/getbased-agents), the workspace-root pyproject
28
28
  # overrides these with `workspace = true` sources. From PyPI, the
@@ -5,4 +5,4 @@ plus a small CLI that proxies to the real binaries. Everything
5
5
  interesting lives in the sibling repos.
6
6
  """
7
7
 
8
- __version__ = "0.5.9"
8
+ __version__ = "0.6.0"
@@ -42,8 +42,14 @@ def _ensure_api_key(path: Path) -> str:
42
42
  return path.read_text(encoding="utf-8").strip()
43
43
  path.parent.mkdir(parents=True, exist_ok=True)
44
44
  key = secrets.token_urlsafe(32)
45
- path.write_text(key + "\n", encoding="utf-8")
46
- os.chmod(path, 0o600)
45
+ try:
46
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
47
+ except FileExistsError:
48
+ # A concurrent initializer won; retain its key instead of rotating
49
+ # credentials behind the already-starting services.
50
+ return path.read_text(encoding="utf-8").strip()
51
+ with os.fdopen(fd, "w", encoding="utf-8") as stream:
52
+ stream.write(key + "\n")
47
53
  return key
48
54
 
49
55
 
@@ -9,6 +9,7 @@ without `getbased-stack init` clobbering their comments.
9
9
  from __future__ import annotations
10
10
 
11
11
  import os
12
+ import tempfile
12
13
  from pathlib import Path
13
14
 
14
15
 
@@ -82,8 +83,20 @@ def write_env_file(
82
83
  if not k or not all(c.isalnum() or c == "_" for c in k):
83
84
  raise ValueError(f"invalid env key: {k!r}")
84
85
  lines.append(f"{k}={v}\n")
85
- p.write_text("".join(lines), encoding="utf-8")
86
- os.chmod(p, 0o600)
86
+ # mkstemp creates an exclusive, private file before any secrets are
87
+ # written. Replace atomically so readers never see a partial update,
88
+ # and a destination symlink cannot redirect the write to another file.
89
+ fd, temporary_name = tempfile.mkstemp(prefix=f".{p.name}-", dir=p.parent)
90
+ temporary = Path(temporary_name)
91
+ try:
92
+ with os.fdopen(fd, "w", encoding="utf-8") as stream:
93
+ os.chmod(temporary, 0o600)
94
+ stream.write("".join(lines))
95
+ stream.flush()
96
+ os.fsync(stream.fileno())
97
+ os.replace(temporary, p)
98
+ finally:
99
+ temporary.unlink(missing_ok=True)
87
100
  return p
88
101
 
89
102
 
@@ -1,18 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: getbased-agent-stack
3
- Version: 0.5.9
3
+ Version: 0.6.0
4
4
  Summary: One-command install of the full getbased agent stack — getbased-mcp + getbased-rag + getbased-dashboard
5
5
  License-Expression: AGPL-3.0-or-later
6
- Requires-Python: >=3.10
6
+ Requires-Python: >=3.11
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
- Requires-Dist: getbased-mcp>=0.2.9
10
- Requires-Dist: getbased-rag>=0.7.5
11
- Requires-Dist: getbased-dashboard>=0.6.8
9
+ Requires-Dist: getbased-mcp>=0.3.0
10
+ Requires-Dist: getbased-rag>=0.8.0
11
+ Requires-Dist: getbased-dashboard>=0.7.0
12
12
  Provides-Extra: full
13
- Requires-Dist: getbased-rag[full]>=0.7.5; extra == "full"
13
+ Requires-Dist: getbased-rag[full]>=0.8.0; extra == "full"
14
14
  Provides-Extra: test
15
- Requires-Dist: pytest>=8.0; extra == "test"
15
+ Requires-Dist: pytest>=9.1.1; extra == "test"
16
16
  Requires-Dist: httpx>=0.27; extra == "test"
17
17
  Requires-Dist: pytest-timeout>=2.3; extra == "test"
18
18
  Dynamic: license-file
@@ -25,6 +25,10 @@ Part of the [getbased-agents monorepo](https://github.com/elkimek/getbased-agent
25
25
 
26
26
  ## Install
27
27
 
28
+ Requires Python 3.11 or newer. To rebuild an existing Python 3.10 tool
29
+ environment while preserving configuration and library data, follow the
30
+ [migration instructions](../../README.md#migrating-an-existing-python-310-installation).
31
+
28
32
  Linux, one command:
29
33
 
30
34
  ```bash
@@ -44,7 +48,7 @@ That setup payload contains private credentials. Keep it out of logs and public
44
48
  Manual — pipx:
45
49
 
46
50
  ```bash
47
- pipx install --include-deps "getbased-agent-stack[full]"
51
+ pipx install --python python3.12 --include-deps "getbased-agent-stack[full]"
48
52
  ```
49
53
 
50
54
  The `--include-deps` flag is required — it exposes `getbased-mcp`, `lens`, and `getbased-dashboard` alongside `getbased-stack` on your PATH. Without it, pipx only links the stack's own entry point and the MCP/rag/dashboard binaries stay hidden inside the venv.
@@ -53,6 +57,7 @@ Manual — uv (0.11+):
53
57
 
54
58
  ```bash
55
59
  uv tool install \
60
+ --python 3.12 \
56
61
  --with-executables-from getbased-rag \
57
62
  --with-executables-from getbased-dashboard \
58
63
  --with-executables-from getbased-mcp \
@@ -177,6 +182,7 @@ The dashboard is likewise stateless — it proxies rag for Knowledge operations,
177
182
  | 0.2.x | ≥0.2.2 | ≥0.6.0 | ≥0.5.0 | v1 (+ streaming ingest, per-library models) |
178
183
  | 0.4.x | ≥0.2.3 | ≥0.7.1 | ≥0.6.1 | v1 (+ shared env file, `getbased-stack init`, systemd units) |
179
184
  | 0.5.x | ≥0.2.9 | ≥0.7.5 | ≥0.6.8 | v1 (+ `getbased-stack connect`, multi-client setup targets; explicit local-only scripted init) |
185
+ | 0.6.x | ≥0.3.0 | ≥0.8.0 | ≥0.7.0 | v1 (Python ≥3.11, ONNX Runtime ≥1.31, security updates) |
180
186
 
181
187
  Bump the meta's major when sibling protocols break; bump siblings freely for normal features.
182
188
 
@@ -0,0 +1,11 @@
1
+ getbased-mcp>=0.3.0
2
+ getbased-rag>=0.8.0
3
+ getbased-dashboard>=0.7.0
4
+
5
+ [full]
6
+ getbased-rag[full]>=0.8.0
7
+
8
+ [test]
9
+ pytest>=9.1.1
10
+ httpx>=0.27
11
+ pytest-timeout>=2.3
@@ -8,6 +8,7 @@ from __future__ import annotations
8
8
 
9
9
  import io
10
10
  import os
11
+ import stat
11
12
  import sys
12
13
  from pathlib import Path
13
14
 
@@ -65,6 +66,37 @@ def _run(argv: "list[str]") -> "tuple[int, str, str]":
65
66
  # ── help / version ────────────────────────────────────────────────────
66
67
 
67
68
 
69
+ def test_api_key_is_private_before_first_write(tmp_path, monkeypatch):
70
+ path = tmp_path / "key"
71
+ fdopen = os.fdopen
72
+ modes = []
73
+
74
+ def check_fdopen(fd, *args, **kwargs):
75
+ modes.append(stat.S_IMODE(os.fstat(fd).st_mode))
76
+ return fdopen(fd, *args, **kwargs)
77
+
78
+ monkeypatch.setattr(os, "fdopen", check_fdopen)
79
+ previous_umask = os.umask(0)
80
+ try:
81
+ key = cli._ensure_api_key(path)
82
+ finally:
83
+ os.umask(previous_umask)
84
+ assert modes == [0o600]
85
+ assert path.read_text().strip() == key
86
+
87
+
88
+ def test_api_key_preserves_concurrent_initializer_key(tmp_path, monkeypatch):
89
+ path = tmp_path / "key"
90
+
91
+ def concurrent_initializer(size):
92
+ path.write_text("synthetic-winning-key\n")
93
+ return "synthetic-losing-key"
94
+
95
+ monkeypatch.setattr(cli.secrets, "token_urlsafe", concurrent_initializer)
96
+ assert cli._ensure_api_key(path) == "synthetic-winning-key"
97
+ assert path.read_text() == "synthetic-winning-key\n"
98
+
99
+
68
100
  def test_bare_invocation_shows_help():
69
101
  rc, out, _ = _run([])
70
102
  assert rc == 0
@@ -62,6 +62,52 @@ def test_write_sets_mode_0600(tmp_env_path):
62
62
  assert mode == 0o600
63
63
 
64
64
 
65
+ def test_write_publishes_private_complete_file(tmp_env_path, monkeypatch):
66
+ tmp_env_path.parent.mkdir(parents=True)
67
+ tmp_env_path.write_text("TOKEN=old\n")
68
+ replace = os.replace
69
+ published = []
70
+
71
+ def check_replace(source, destination):
72
+ source = Path(source)
73
+ assert stat.S_IMODE(source.stat().st_mode) == 0o600
74
+ assert source.read_text() == "TOKEN=synthetic-new\n"
75
+ assert tmp_env_path.read_text() == "TOKEN=old\n"
76
+ published.append(destination)
77
+ replace(source, destination)
78
+
79
+ monkeypatch.setattr(os, "replace", check_replace)
80
+ env_file.write_env_file({"TOKEN": "synthetic-new"}, path=tmp_env_path, header="")
81
+ assert published == [tmp_env_path]
82
+ assert tmp_env_path.read_text() == "TOKEN=synthetic-new\n"
83
+
84
+
85
+ def test_write_failure_preserves_previous_file_and_cleans_temporary(tmp_env_path, monkeypatch):
86
+ tmp_env_path.parent.mkdir(parents=True)
87
+ tmp_env_path.write_text("TOKEN=old\n")
88
+
89
+ def fail_replace(source, destination):
90
+ raise OSError("synthetic replacement failure")
91
+
92
+ monkeypatch.setattr(os, "replace", fail_replace)
93
+ with pytest.raises(OSError, match="synthetic replacement failure"):
94
+ env_file.write_env_file({"TOKEN": "synthetic-new"}, path=tmp_env_path)
95
+ assert tmp_env_path.read_text() == "TOKEN=old\n"
96
+ assert list(tmp_env_path.parent.iterdir()) == [tmp_env_path]
97
+
98
+
99
+ def test_write_does_not_follow_destination_symlink(tmp_env_path, tmp_path):
100
+ target = tmp_path / "unrelated"
101
+ target.write_text("retain this content")
102
+ tmp_env_path.parent.mkdir(parents=True)
103
+ tmp_env_path.symlink_to(target)
104
+
105
+ env_file.write_env_file({"TOKEN": "synthetic-new"}, path=tmp_env_path, header="")
106
+ assert target.read_text() == "retain this content"
107
+ assert not tmp_env_path.is_symlink()
108
+ assert tmp_env_path.read_text() == "TOKEN=synthetic-new\n"
109
+
110
+
65
111
  def test_write_rejects_invalid_keys(tmp_env_path):
66
112
  with pytest.raises(ValueError, match="invalid env key"):
67
113
  env_file.write_env_file({"has space": "x"}, path=tmp_env_path)
@@ -14,6 +14,7 @@ from __future__ import annotations
14
14
 
15
15
  import asyncio
16
16
  import contextlib
17
+ import math
17
18
  import os
18
19
  import socket
19
20
  import subprocess
@@ -153,6 +154,47 @@ def mcp_env(seeded_lens: dict, monkeypatch: pytest.MonkeyPatch):
153
154
 
154
155
  # ── Tests ────────────────────────────────────────────────────────────
155
156
 
157
+ @pytest.mark.timeout(180)
158
+ def test_local_embedder_dependency_round_trip() -> None:
159
+ """Validate the PyTorch fallback as well as the preferred ONNX backend.
160
+
161
+ The full-stack fixture uses ONNX, so it cannot catch incompatible
162
+ sentence-transformers / transformers upgrades on its own.
163
+ """
164
+ from lens.embedder import LocalEmbedder
165
+
166
+ embedder = LocalEmbedder("sentence-transformers/all-MiniLM-L6-v2")
167
+ vectors = embedder.encode([
168
+ "Synthetic dependency upgrade smoke test.",
169
+ "Another sentence for a batched embedding.",
170
+ ])
171
+
172
+ assert len(vectors) == 2
173
+ assert embedder.dimension() == 384
174
+ for vector in vectors:
175
+ assert len(vector) == 384
176
+ assert all(math.isfinite(value) for value in vector)
177
+ assert sum(value * value for value in vector) == pytest.approx(1, abs=1e-4)
178
+
179
+
180
+ @pytest.mark.timeout(180)
181
+ def test_onnx_embedder_batch_matches_individual_encodings() -> None:
182
+ """Native runtime upgrades must preserve unequal-length batch padding."""
183
+ from lens.embedder import OnnxEmbedder
184
+
185
+ embedder = OnnxEmbedder("sentence-transformers/all-MiniLM-L6-v2", provider="cpu")
186
+ texts = ["A short synthetic sentence.", "A longer synthetic sentence exercises padded embedding batches."]
187
+ batch = embedder.encode(texts)
188
+
189
+ assert len(batch) == len(texts)
190
+ assert embedder.dimension() == 384
191
+ for text, vector in zip(texts, batch):
192
+ assert len(vector) == 384
193
+ assert all(math.isfinite(value) for value in vector)
194
+ assert sum(value * value for value in vector) == pytest.approx(1, abs=1e-4)
195
+ assert vector == pytest.approx(embedder.encode([text])[0], abs=1e-5)
196
+
197
+
156
198
  def test_pdf_ingest_dependency_round_trip(tmp_path: Path) -> None:
157
199
  """Exercise the optional PDF parser pinned by the full stack extra.
158
200
 
@@ -1,11 +0,0 @@
1
- getbased-mcp>=0.2.9
2
- getbased-rag>=0.7.5
3
- getbased-dashboard>=0.6.8
4
-
5
- [full]
6
- getbased-rag[full]>=0.7.5
7
-
8
- [test]
9
- pytest>=8.0
10
- httpx>=0.27
11
- pytest-timeout>=2.3