bendex 0.1.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.
- bendex/__init__.py +4 -0
- bendex/monitor.py +63 -0
- bendex/patch.py +65 -0
- bendex-0.1.0.dist-info/METADATA +22 -0
- bendex-0.1.0.dist-info/RECORD +7 -0
- bendex-0.1.0.dist-info/WHEEL +5 -0
- bendex-0.1.0.dist-info/top_level.txt +1 -0
bendex/__init__.py
ADDED
bendex/monitor.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bendex Monitor -- geometric LLM inference monitoring.
|
|
3
|
+
Grounds drift detection in Fisher-Rao information geometry.
|
|
4
|
+
"""
|
|
5
|
+
import os
|
|
6
|
+
import httpx
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
SENTRY_URL = "https://web-production-6e47f.up.railway.app"
|
|
10
|
+
_config = {}
|
|
11
|
+
|
|
12
|
+
def monitor(
|
|
13
|
+
deployment: str,
|
|
14
|
+
model: str = "gpt-4o",
|
|
15
|
+
sentry_url: str = SENTRY_URL,
|
|
16
|
+
api_key: Optional[str] = None,
|
|
17
|
+
verbose: bool = True,
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Initialize Bendex monitoring for an LLM deployment.
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
import bendex
|
|
24
|
+
bendex.monitor(deployment="my-app", model="gpt-4o")
|
|
25
|
+
|
|
26
|
+
# Then use OpenAI as normal -- all calls are monitored
|
|
27
|
+
from openai import OpenAI
|
|
28
|
+
client = OpenAI()
|
|
29
|
+
response = client.chat.completions.create(...)
|
|
30
|
+
"""
|
|
31
|
+
_config["deployment"] = deployment
|
|
32
|
+
_config["model"] = model
|
|
33
|
+
_config["sentry_url"] = sentry_url
|
|
34
|
+
_config["api_key"] = api_key or os.environ.get("BENDEX_API_KEY", "")
|
|
35
|
+
_config["verbose"] = verbose
|
|
36
|
+
_config["active"] = True
|
|
37
|
+
|
|
38
|
+
# Patch OpenAI client
|
|
39
|
+
from bendex.patch import patch_openai
|
|
40
|
+
patch_openai(_config)
|
|
41
|
+
|
|
42
|
+
if verbose:
|
|
43
|
+
print(f"✓ Bendex monitoring active")
|
|
44
|
+
print(f" deployment : {deployment}")
|
|
45
|
+
print(f" model : {model}")
|
|
46
|
+
print(f" sentry : {sentry_url}")
|
|
47
|
+
print(f" dashboard : {sentry_url}/dashboard")
|
|
48
|
+
print(f" τ* : 1.2247 (Landauer threshold)")
|
|
49
|
+
|
|
50
|
+
def status():
|
|
51
|
+
"""Check connection to Sentry."""
|
|
52
|
+
if not _config.get("active"):
|
|
53
|
+
print("Bendex not initialized. Call bendex.monitor() first.")
|
|
54
|
+
return
|
|
55
|
+
try:
|
|
56
|
+
r = httpx.get(f"{_config['sentry_url']}/sentry/health", timeout=5)
|
|
57
|
+
data = r.json()
|
|
58
|
+
print(f"✓ Sentry connected: {data}")
|
|
59
|
+
except Exception as e:
|
|
60
|
+
print(f"✗ Sentry unreachable: {e}")
|
|
61
|
+
|
|
62
|
+
def get_config():
|
|
63
|
+
return _config.copy()
|
bendex/patch.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OpenAI client patcher -- routes calls through Bendex Sentry.
|
|
3
|
+
Patches the OpenAI Python SDK transparently.
|
|
4
|
+
"""
|
|
5
|
+
import functools
|
|
6
|
+
|
|
7
|
+
_original_create = None
|
|
8
|
+
_patched = False
|
|
9
|
+
|
|
10
|
+
def patch_openai(config: dict):
|
|
11
|
+
"""Patch the OpenAI chat completions client to route through Sentry."""
|
|
12
|
+
global _original_create, _patched
|
|
13
|
+
|
|
14
|
+
if _patched:
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
import openai
|
|
19
|
+
from openai.resources.chat.completions import Completions
|
|
20
|
+
|
|
21
|
+
_original_create = Completions.create
|
|
22
|
+
|
|
23
|
+
@functools.wraps(_original_create)
|
|
24
|
+
def patched_create(self, *args, **kwargs):
|
|
25
|
+
# Inject Sentry routing headers
|
|
26
|
+
extra_headers = kwargs.pop("extra_headers", {}) or {}
|
|
27
|
+
extra_headers["X-Sentry-Deployment"] = config.get("deployment", "bendex")
|
|
28
|
+
extra_headers["X-Sentry-Model-Version"] = kwargs.get("model", config.get("model", "gpt-4o"))
|
|
29
|
+
|
|
30
|
+
if config.get("api_key"):
|
|
31
|
+
extra_headers["X-Bendex-API-Key"] = config["api_key"]
|
|
32
|
+
|
|
33
|
+
kwargs["extra_headers"] = extra_headers
|
|
34
|
+
|
|
35
|
+
# Redirect base URL to Sentry proxy
|
|
36
|
+
original_base = self._client.base_url
|
|
37
|
+
sentry_url = config.get("sentry_url", "https://web-production-6e47f.up.railway.app")
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
self._client.base_url = f"{sentry_url}/v1"
|
|
41
|
+
result = _original_create(self, *args, **kwargs)
|
|
42
|
+
return result
|
|
43
|
+
finally:
|
|
44
|
+
self._client.base_url = original_base
|
|
45
|
+
|
|
46
|
+
Completions.create = patched_create
|
|
47
|
+
_patched = True
|
|
48
|
+
|
|
49
|
+
if config.get("verbose"):
|
|
50
|
+
print(f" patch : openai.chat.completions.create → Sentry proxy")
|
|
51
|
+
|
|
52
|
+
except ImportError:
|
|
53
|
+
if config.get("verbose"):
|
|
54
|
+
print(" openai not installed -- install with: pip install openai")
|
|
55
|
+
except Exception as e:
|
|
56
|
+
if config.get("verbose"):
|
|
57
|
+
print(f" patch failed: {e}")
|
|
58
|
+
|
|
59
|
+
def unpatch_openai():
|
|
60
|
+
"""Restore original OpenAI client."""
|
|
61
|
+
global _original_create, _patched
|
|
62
|
+
if _patched and _original_create:
|
|
63
|
+
from openai.resources.chat.completions import Completions
|
|
64
|
+
Completions.create = _original_create
|
|
65
|
+
_patched = False
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bendex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Geometric LLM inference monitor grounded in Fisher-Rao information geometry
|
|
5
|
+
Home-page: https://bendexgeometry.com
|
|
6
|
+
Author: Hannah Nine
|
|
7
|
+
Author-email: 9hannahnine@gmail.com
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Requires-Dist: httpx>=0.27.0
|
|
15
|
+
Requires-Dist: openai>=1.0.0
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: requires-dist
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
Dynamic: summary
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
bendex/__init__.py,sha256=tEub5BSI1N6wFukvl35ycC2etSH3ofh8pxgQLXSwq6g,124
|
|
2
|
+
bendex/monitor.py,sha256=N2SNMYbxc_lMw7EIVcdQ2iHlNoT3-B2wi5LsO9Pt8ys,1848
|
|
3
|
+
bendex/patch.py,sha256=ckQaUxSFYK7koEnXZqelhI8KU2MWGwhBDM-z-c-GAqs,2208
|
|
4
|
+
bendex-0.1.0.dist-info/METADATA,sha256=3G3roVBtCPlHNA4JHgITSe6yHqqAQGNWEAqiccW7qTo,710
|
|
5
|
+
bendex-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
6
|
+
bendex-0.1.0.dist-info/top_level.txt,sha256=NALpCIi35gDcZbh0Y-sD8EoDgCrrFnO51r29uuxkmTQ,7
|
|
7
|
+
bendex-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bendex
|