WaveGuardClient 2.3.0__tar.gz → 3.2.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.
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/PKG-INFO +4 -4
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/README.md +1 -1
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/WaveGuardClient.egg-info/PKG-INFO +4 -4
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/mcp_server/server.py +19 -5
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/pyproject.toml +6 -3
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/waveguard/client.py +154 -2
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/LICENSE +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/WaveGuardClient.egg-info/SOURCES.txt +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/WaveGuardClient.egg-info/dependency_links.txt +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/WaveGuardClient.egg-info/entry_points.txt +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/WaveGuardClient.egg-info/requires.txt +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/WaveGuardClient.egg-info/top_level.txt +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/mcp_server/__init__.py +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/setup.cfg +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/tests/test_client.py +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/tests/test_mcp_server.py +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/waveguard/__init__.py +0 -0
- {waveguardclient-2.3.0 → waveguardclient-3.2.0}/waveguard/exceptions.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: WaveGuardClient
|
|
3
|
-
Version: 2.
|
|
4
|
-
Summary: Python SDK for WaveGuard — physics-based anomaly detection API
|
|
3
|
+
Version: 3.2.0
|
|
4
|
+
Summary: Python SDK for WaveGuard — physics-based anomaly detection, fingerprinting & crypto risk API
|
|
5
5
|
Author: Greg Partin
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/gpartin/WaveGuardClient
|
|
@@ -9,7 +9,7 @@ Project-URL: Documentation, https://github.com/gpartin/WaveGuardClient/tree/main
|
|
|
9
9
|
Project-URL: Repository, https://github.com/gpartin/WaveGuardClient
|
|
10
10
|
Project-URL: Issues, https://github.com/gpartin/WaveGuardClient/issues
|
|
11
11
|
Project-URL: API, https://gpartin--waveguard-api-fastapi-app.modal.run/docs
|
|
12
|
-
Keywords: anomaly-detection,api-client,sdk,waveguard,physics-based,mcp,model-context-protocol,
|
|
12
|
+
Keywords: anomaly-detection,api-client,sdk,waveguard,physics-based,mcp,model-context-protocol,fingerprinting,crypto,token-risk,x402
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: Intended Audience :: System Administrators
|
|
@@ -36,7 +36,7 @@ Dynamic: license-file
|
|
|
36
36
|
|
|
37
37
|
<p align="center">
|
|
38
38
|
<img src="https://img.shields.io/pypi/v/WaveGuardClient?style=for-the-badge&color=blueviolet" alt="PyPI">
|
|
39
|
-
<img src="https://img.shields.io/badge/API-
|
|
39
|
+
<img src="https://img.shields.io/badge/API-v3.1.0_stateless-brightgreen?style=for-the-badge" alt="v3.1.0">
|
|
40
40
|
<img src="https://img.shields.io/badge/GPU-CUDA_accelerated-76B900?style=for-the-badge&logo=nvidia" alt="CUDA">
|
|
41
41
|
<img src="https://img.shields.io/badge/MCP-Claude_Desktop-orange?style=for-the-badge" alt="MCP">
|
|
42
42
|
<a href="https://smithery.ai/servers/emergentphysicslab/waveguard"><img src="https://smithery.ai/badge/emergentphysicslab/waveguard" alt="Smithery"></a>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<img src="https://img.shields.io/pypi/v/WaveGuardClient?style=for-the-badge&color=blueviolet" alt="PyPI">
|
|
3
|
-
<img src="https://img.shields.io/badge/API-
|
|
3
|
+
<img src="https://img.shields.io/badge/API-v3.1.0_stateless-brightgreen?style=for-the-badge" alt="v3.1.0">
|
|
4
4
|
<img src="https://img.shields.io/badge/GPU-CUDA_accelerated-76B900?style=for-the-badge&logo=nvidia" alt="CUDA">
|
|
5
5
|
<img src="https://img.shields.io/badge/MCP-Claude_Desktop-orange?style=for-the-badge" alt="MCP">
|
|
6
6
|
<a href="https://smithery.ai/servers/emergentphysicslab/waveguard"><img src="https://smithery.ai/badge/emergentphysicslab/waveguard" alt="Smithery"></a>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: WaveGuardClient
|
|
3
|
-
Version: 2.
|
|
4
|
-
Summary: Python SDK for WaveGuard — physics-based anomaly detection API
|
|
3
|
+
Version: 3.2.0
|
|
4
|
+
Summary: Python SDK for WaveGuard — physics-based anomaly detection, fingerprinting & crypto risk API
|
|
5
5
|
Author: Greg Partin
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/gpartin/WaveGuardClient
|
|
@@ -9,7 +9,7 @@ Project-URL: Documentation, https://github.com/gpartin/WaveGuardClient/tree/main
|
|
|
9
9
|
Project-URL: Repository, https://github.com/gpartin/WaveGuardClient
|
|
10
10
|
Project-URL: Issues, https://github.com/gpartin/WaveGuardClient/issues
|
|
11
11
|
Project-URL: API, https://gpartin--waveguard-api-fastapi-app.modal.run/docs
|
|
12
|
-
Keywords: anomaly-detection,api-client,sdk,waveguard,physics-based,mcp,model-context-protocol,
|
|
12
|
+
Keywords: anomaly-detection,api-client,sdk,waveguard,physics-based,mcp,model-context-protocol,fingerprinting,crypto,token-risk,x402
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: Intended Audience :: System Administrators
|
|
@@ -36,7 +36,7 @@ Dynamic: license-file
|
|
|
36
36
|
|
|
37
37
|
<p align="center">
|
|
38
38
|
<img src="https://img.shields.io/pypi/v/WaveGuardClient?style=for-the-badge&color=blueviolet" alt="PyPI">
|
|
39
|
-
<img src="https://img.shields.io/badge/API-
|
|
39
|
+
<img src="https://img.shields.io/badge/API-v3.1.0_stateless-brightgreen?style=for-the-badge" alt="v3.1.0">
|
|
40
40
|
<img src="https://img.shields.io/badge/GPU-CUDA_accelerated-76B900?style=for-the-badge&logo=nvidia" alt="CUDA">
|
|
41
41
|
<img src="https://img.shields.io/badge/MCP-Claude_Desktop-orange?style=for-the-badge" alt="MCP">
|
|
42
42
|
<a href="https://smithery.ai/servers/emergentphysicslab/waveguard"><img src="https://smithery.ai/badge/emergentphysicslab/waveguard" alt="Smithery"></a>
|
|
@@ -371,7 +371,7 @@ class MCPStdioServer:
|
|
|
371
371
|
def __init__(self) -> None:
|
|
372
372
|
self.server_info = {
|
|
373
373
|
"name": "waveguard",
|
|
374
|
-
"version": "
|
|
374
|
+
"version": "3.1.0",
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
def handle_message(self, msg: dict) -> Optional[dict]:
|
|
@@ -403,6 +403,20 @@ class MCPStdioServer:
|
|
|
403
403
|
"result": {"tools": TOOLS},
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
elif method == "resources/list":
|
|
407
|
+
return {
|
|
408
|
+
"jsonrpc": "2.0",
|
|
409
|
+
"id": msg_id,
|
|
410
|
+
"result": {"resources": []},
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
elif method == "prompts/list":
|
|
414
|
+
return {
|
|
415
|
+
"jsonrpc": "2.0",
|
|
416
|
+
"id": msg_id,
|
|
417
|
+
"result": {"prompts": []},
|
|
418
|
+
}
|
|
419
|
+
|
|
406
420
|
elif method == "tools/call":
|
|
407
421
|
tool_name = params.get("name", "")
|
|
408
422
|
arguments = params.get("arguments", {})
|
|
@@ -435,7 +449,7 @@ class MCPStdioServer:
|
|
|
435
449
|
def run_stdio(self) -> None:
|
|
436
450
|
"""Run the MCP server on stdin/stdout."""
|
|
437
451
|
sys.stderr.write(
|
|
438
|
-
f"WaveGuard MCP server
|
|
452
|
+
f"WaveGuard MCP server v3.1.0 started (API: {API_URL})\n"
|
|
439
453
|
)
|
|
440
454
|
sys.stderr.flush()
|
|
441
455
|
|
|
@@ -470,7 +484,7 @@ def run_http_server(port: int = 3001) -> None:
|
|
|
470
484
|
print("HTTP transport requires: pip install fastapi uvicorn")
|
|
471
485
|
sys.exit(1)
|
|
472
486
|
|
|
473
|
-
mcp_app = FA(title="WaveGuard MCP Server", version="
|
|
487
|
+
mcp_app = FA(title="WaveGuard MCP Server", version="3.1.0")
|
|
474
488
|
server = MCPStdioServer()
|
|
475
489
|
|
|
476
490
|
@mcp_app.post("/mcp")
|
|
@@ -481,7 +495,7 @@ def run_http_server(port: int = 3001) -> None:
|
|
|
481
495
|
async def mcp_tools() -> dict: # type: ignore[type-arg]
|
|
482
496
|
return {"tools": TOOLS}
|
|
483
497
|
|
|
484
|
-
print(f"WaveGuard MCP HTTP server
|
|
498
|
+
print(f"WaveGuard MCP HTTP server v3.1.0 on port {port}")
|
|
485
499
|
uvicorn.run(mcp_app, host="0.0.0.0", port=port)
|
|
486
500
|
|
|
487
501
|
|
|
@@ -492,7 +506,7 @@ def run_http_server(port: int = 3001) -> None:
|
|
|
492
506
|
def main():
|
|
493
507
|
"""Entry point for `waveguard-mcp` console script."""
|
|
494
508
|
parser = argparse.ArgumentParser(
|
|
495
|
-
description="WaveGuard MCP Server
|
|
509
|
+
description="WaveGuard MCP Server v3.0.0"
|
|
496
510
|
)
|
|
497
511
|
parser.add_argument(
|
|
498
512
|
"--http",
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "WaveGuardClient"
|
|
7
|
-
version = "2.
|
|
8
|
-
description = "Python SDK for WaveGuard — physics-based anomaly detection API"
|
|
7
|
+
version = "3.2.0"
|
|
8
|
+
description = "Python SDK for WaveGuard — physics-based anomaly detection, fingerprinting & crypto risk API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
requires-python = ">=3.9"
|
|
@@ -20,7 +20,10 @@ keywords = [
|
|
|
20
20
|
"physics-based",
|
|
21
21
|
"mcp",
|
|
22
22
|
"model-context-protocol",
|
|
23
|
-
"
|
|
23
|
+
"fingerprinting",
|
|
24
|
+
"crypto",
|
|
25
|
+
"token-risk",
|
|
26
|
+
"x402",
|
|
24
27
|
]
|
|
25
28
|
classifiers = [
|
|
26
29
|
"Development Status :: 4 - Beta",
|
|
@@ -42,7 +42,7 @@ from .exceptions import (
|
|
|
42
42
|
ServerError,
|
|
43
43
|
)
|
|
44
44
|
|
|
45
|
-
__version__ = "2.
|
|
45
|
+
__version__ = "3.2.0"
|
|
46
46
|
|
|
47
47
|
logger = logging.getLogger("waveguard")
|
|
48
48
|
|
|
@@ -138,6 +138,71 @@ class TierInfo:
|
|
|
138
138
|
raw: Dict[str, Any] = field(default_factory=dict)
|
|
139
139
|
|
|
140
140
|
|
|
141
|
+
@dataclass
|
|
142
|
+
class FingerprintResult:
|
|
143
|
+
"""Result of a ``/v1/fingerprint`` call.
|
|
144
|
+
|
|
145
|
+
Attributes
|
|
146
|
+
----------
|
|
147
|
+
fingerprint : list[float]
|
|
148
|
+
Physics embedding vector (52-dim at L0, 62-dim at L1).
|
|
149
|
+
dimensions : int
|
|
150
|
+
Number of dimensions (52 at Level 0, 62 at Level 1).
|
|
151
|
+
labels : list[str]
|
|
152
|
+
Human-readable label for each dimension.
|
|
153
|
+
encoder_type : str
|
|
154
|
+
Encoder used to map input data onto the lattice.
|
|
155
|
+
latency_ms : float
|
|
156
|
+
Server-side processing time.
|
|
157
|
+
field_level : int
|
|
158
|
+
Field level used (0=real scalar, 1=complex).
|
|
159
|
+
raw : dict
|
|
160
|
+
Full JSON response.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
fingerprint: List[float]
|
|
164
|
+
dimensions: int
|
|
165
|
+
labels: List[str]
|
|
166
|
+
encoder_type: str
|
|
167
|
+
latency_ms: float
|
|
168
|
+
field_level: int = 0
|
|
169
|
+
raw: Dict[str, Any] = field(default_factory=dict)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@dataclass
|
|
173
|
+
class CompareResult:
|
|
174
|
+
"""Result of a ``/v1/compare`` call.
|
|
175
|
+
|
|
176
|
+
Attributes
|
|
177
|
+
----------
|
|
178
|
+
similarity : float
|
|
179
|
+
Cosine similarity (0–1). >0.95 = very similar.
|
|
180
|
+
distance : float
|
|
181
|
+
Euclidean distance between fingerprints.
|
|
182
|
+
fingerprint_a : list[float]
|
|
183
|
+
Physics embedding of data_a.
|
|
184
|
+
fingerprint_b: List[float]
|
|
185
|
+
Physics embedding of data_b.
|
|
186
|
+
dimensions : int
|
|
187
|
+
Number of dimensions.
|
|
188
|
+
encoder_type : str
|
|
189
|
+
Encoder used.
|
|
190
|
+
latency_ms : float
|
|
191
|
+
Server-side processing time.
|
|
192
|
+
raw : dict
|
|
193
|
+
Full JSON response.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
similarity: float
|
|
197
|
+
distance: float
|
|
198
|
+
fingerprint_a: List[float]
|
|
199
|
+
fingerprint_b: List[float]
|
|
200
|
+
dimensions: int
|
|
201
|
+
encoder_type: str
|
|
202
|
+
latency_ms: float
|
|
203
|
+
raw: Dict[str, Any] = field(default_factory=dict)
|
|
204
|
+
|
|
205
|
+
|
|
141
206
|
# ─────────────────────────────── Client ───────────────────────────────────
|
|
142
207
|
|
|
143
208
|
|
|
@@ -204,6 +269,7 @@ class WaveGuard:
|
|
|
204
269
|
test: List[Any],
|
|
205
270
|
encoder_type: Optional[str] = None,
|
|
206
271
|
sensitivity: Optional[float] = None,
|
|
272
|
+
field_level: int = 0,
|
|
207
273
|
) -> ScanResult:
|
|
208
274
|
"""Scan test data for anomalies against a training baseline.
|
|
209
275
|
|
|
@@ -220,11 +286,15 @@ class WaveGuard:
|
|
|
220
286
|
1+ samples to check for anomalies.
|
|
221
287
|
encoder_type : str, optional
|
|
222
288
|
Force a specific encoder: ``"json"``, ``"numeric"``,
|
|
223
|
-
``"text"``, ``"timeseries"``, ``"tabular"
|
|
289
|
+
``"text"``, ``"timeseries"``, ``"tabular"``,
|
|
290
|
+
``"complex_numeric"``.
|
|
224
291
|
Leave *None* for auto-detection (recommended).
|
|
225
292
|
sensitivity : float, optional
|
|
226
293
|
Detection sensitivity in the range 0.5–3.0.
|
|
227
294
|
Lower values are more sensitive (flag more anomalies).
|
|
295
|
+
field_level : int
|
|
296
|
+
Physics field complexity. 0 = real scalar (default).
|
|
297
|
+
1 = complex field (phase-aware, 62-dim fingerprints).
|
|
228
298
|
|
|
229
299
|
Returns
|
|
230
300
|
-------
|
|
@@ -240,10 +310,92 @@ class WaveGuard:
|
|
|
240
310
|
body["encoder_type"] = encoder_type
|
|
241
311
|
if sensitivity is not None:
|
|
242
312
|
body["sensitivity"] = sensitivity
|
|
313
|
+
if field_level:
|
|
314
|
+
body["field_level"] = field_level
|
|
243
315
|
|
|
244
316
|
resp = self._post("/v1/scan", body)
|
|
245
317
|
return self._parse_scan(resp, len(training), len(test))
|
|
246
318
|
|
|
319
|
+
def fingerprint(
|
|
320
|
+
self,
|
|
321
|
+
data: Any,
|
|
322
|
+
encoder_type: Optional[str] = None,
|
|
323
|
+
field_level: int = 0,
|
|
324
|
+
) -> FingerprintResult:
|
|
325
|
+
"""Get a physics embedding of any data item.
|
|
326
|
+
|
|
327
|
+
Parameters
|
|
328
|
+
----------
|
|
329
|
+
data : any
|
|
330
|
+
A single data item to fingerprint (JSON object, list, string, etc.).
|
|
331
|
+
encoder_type : str, optional
|
|
332
|
+
Force a specific encoder. Leave *None* for auto-detection.
|
|
333
|
+
field_level : int
|
|
334
|
+
0 = real scalar (52-dim, default).
|
|
335
|
+
1 = complex field (62-dim, includes phase statistics).
|
|
336
|
+
|
|
337
|
+
Returns
|
|
338
|
+
-------
|
|
339
|
+
FingerprintResult
|
|
340
|
+
``.fingerprint`` is the embedding vector (52 or 62 dims).
|
|
341
|
+
``.labels`` names each dimension.
|
|
342
|
+
"""
|
|
343
|
+
body: Dict[str, Any] = {"data": data}
|
|
344
|
+
if encoder_type is not None:
|
|
345
|
+
body["encoder_type"] = encoder_type
|
|
346
|
+
if field_level:
|
|
347
|
+
body["field_level"] = field_level
|
|
348
|
+
|
|
349
|
+
resp = self._post("/v1/fingerprint", body)
|
|
350
|
+
return FingerprintResult(
|
|
351
|
+
fingerprint=resp.get("fingerprint", []),
|
|
352
|
+
dimensions=resp.get("dimensions", 0),
|
|
353
|
+
labels=resp.get("labels", []),
|
|
354
|
+
encoder_type=resp.get("encoder_type", "auto"),
|
|
355
|
+
latency_ms=resp.get("latency_ms", 0.0),
|
|
356
|
+
field_level=resp.get("field_level", 0),
|
|
357
|
+
raw=resp,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
def compare(
|
|
361
|
+
self,
|
|
362
|
+
data_a: Any,
|
|
363
|
+
data_b: Any,
|
|
364
|
+
encoder_type: Optional[str] = None,
|
|
365
|
+
) -> CompareResult:
|
|
366
|
+
"""Compare two data items for structural similarity.
|
|
367
|
+
|
|
368
|
+
Parameters
|
|
369
|
+
----------
|
|
370
|
+
data_a : any
|
|
371
|
+
First data item.
|
|
372
|
+
data_b : any
|
|
373
|
+
Second data item (same type as data_a).
|
|
374
|
+
encoder_type : str, optional
|
|
375
|
+
Force a specific encoder. Leave *None* for auto-detection.
|
|
376
|
+
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
CompareResult
|
|
380
|
+
``.similarity`` is cosine similarity (0–1).
|
|
381
|
+
``.distance`` is Euclidean distance.
|
|
382
|
+
"""
|
|
383
|
+
body: Dict[str, Any] = {"data_a": data_a, "data_b": data_b}
|
|
384
|
+
if encoder_type is not None:
|
|
385
|
+
body["encoder_type"] = encoder_type
|
|
386
|
+
|
|
387
|
+
resp = self._post("/v1/compare", body)
|
|
388
|
+
return CompareResult(
|
|
389
|
+
similarity=resp.get("similarity", 0.0),
|
|
390
|
+
distance=resp.get("distance", 0.0),
|
|
391
|
+
fingerprint_a=resp.get("fingerprint_a", []),
|
|
392
|
+
fingerprint_b=resp.get("fingerprint_b", []),
|
|
393
|
+
dimensions=resp.get("dimensions", 0),
|
|
394
|
+
encoder_type=resp.get("encoder_type", "auto"),
|
|
395
|
+
latency_ms=resp.get("latency_ms", 0.0),
|
|
396
|
+
raw=resp,
|
|
397
|
+
)
|
|
398
|
+
|
|
247
399
|
# ── Utility ───────────────────────────────────────────────────────
|
|
248
400
|
|
|
249
401
|
def health(self) -> HealthStatus:
|
|
File without changes
|
|
File without changes
|
{waveguardclient-2.3.0 → waveguardclient-3.2.0}/WaveGuardClient.egg-info/dependency_links.txt
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
|