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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: WaveGuardClient
3
- Version: 2.3.0
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,azure-migration
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-v2.2.0_stateless-brightgreen?style=for-the-badge" alt="v2.2.0">
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-v2.2.0_stateless-brightgreen?style=for-the-badge" alt="v2.2.0">
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.3.0
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,azure-migration
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-v2.2.0_stateless-brightgreen?style=for-the-badge" alt="v2.2.0">
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": "2.3.0",
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 v2.3.0 started (API: {API_URL})\n"
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="2.3.0")
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 v2.3.0 on port {port}")
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 v2.3.0"
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.3.0"
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
- "azure-migration",
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.3.0"
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