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.
- {getbased_agent_stack-0.5.9/src/getbased_agent_stack.egg-info → getbased_agent_stack-0.6.0}/PKG-INFO +14 -8
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/README.md +7 -1
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/pyproject.toml +8 -8
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/__init__.py +1 -1
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/cli.py +8 -2
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/env_file.py +15 -2
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0/src/getbased_agent_stack.egg-info}/PKG-INFO +14 -8
- getbased_agent_stack-0.6.0/src/getbased_agent_stack.egg-info/requires.txt +11 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_cli.py +32 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_env_file.py +46 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_integration.py +42 -0
- getbased_agent_stack-0.5.9/src/getbased_agent_stack.egg-info/requires.txt +0 -11
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/LICENSE +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/setup.cfg +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/mcp_configs.py +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/systemd/getbased-dashboard.service +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/systemd/getbased-rag.service +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/units.py +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack.egg-info/SOURCES.txt +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack.egg-info/dependency_links.txt +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack.egg-info/entry_points.txt +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack.egg-info/top_level.txt +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_mcp_configs.py +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_systemd_units.py +0 -0
- {getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/tests/test_units.py +0 -0
{getbased_agent_stack-0.5.9/src/getbased_agent_stack.egg-info → getbased_agent_stack-0.6.0}/PKG-INFO
RENAMED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: getbased-agent-stack
|
|
3
|
-
Version: 0.
|
|
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.
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
9
|
-
Requires-Dist: getbased-mcp>=0.
|
|
10
|
-
Requires-Dist: getbased-rag>=0.
|
|
11
|
-
Requires-Dist: getbased-dashboard>=0.
|
|
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.
|
|
13
|
+
Requires-Dist: getbased-rag[full]>=0.8.0; extra == "full"
|
|
14
14
|
Provides-Extra: test
|
|
15
|
-
Requires-Dist: pytest>=
|
|
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>=
|
|
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.
|
|
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.
|
|
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.
|
|
16
|
-
"getbased-rag>=0.
|
|
17
|
-
"getbased-dashboard>=0.
|
|
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.
|
|
23
|
+
full = ["getbased-rag[full]>=0.8.0"]
|
|
24
24
|
# For contributors running the integration test harness.
|
|
25
|
-
test = ["pytest>=
|
|
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
|
|
@@ -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
|
-
|
|
46
|
-
|
|
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
|
|
{getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/env_file.py
RENAMED
|
@@ -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
|
-
|
|
86
|
-
|
|
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
|
|
{getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0/src/getbased_agent_stack.egg-info}/PKG-INFO
RENAMED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: getbased-agent-stack
|
|
3
|
-
Version: 0.
|
|
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.
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
9
|
-
Requires-Dist: getbased-mcp>=0.
|
|
10
|
-
Requires-Dist: getbased-rag>=0.
|
|
11
|
-
Requires-Dist: getbased-dashboard>=0.
|
|
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.
|
|
13
|
+
Requires-Dist: getbased-rag[full]>=0.8.0; extra == "full"
|
|
14
14
|
Provides-Extra: test
|
|
15
|
-
Requires-Dist: pytest>=
|
|
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
|
|
|
@@ -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
|
|
|
File without changes
|
|
File without changes
|
{getbased_agent_stack-0.5.9 → getbased_agent_stack-0.6.0}/src/getbased_agent_stack/mcp_configs.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|