nat-engine 1__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.
Files changed (299) hide show
  1. mannf/__init__.py +33 -0
  2. mannf/__main__.py +10 -0
  3. mannf/_version.py +8 -0
  4. mannf/agents/__init__.py +7 -0
  5. mannf/agents/analyzer_agent.py +9 -0
  6. mannf/agents/base.py +9 -0
  7. mannf/agents/bdi_agent.py +9 -0
  8. mannf/agents/belief_state.py +9 -0
  9. mannf/agents/coordinator_agent.py +9 -0
  10. mannf/agents/executor_agent.py +9 -0
  11. mannf/agents/monitor_agent.py +9 -0
  12. mannf/agents/oracle_agent.py +9 -0
  13. mannf/agents/planner_agent.py +9 -0
  14. mannf/agents/test_agent.py +9 -0
  15. mannf/anomaly/__init__.py +7 -0
  16. mannf/anomaly/enhanced_detector.py +9 -0
  17. mannf/cli.py +9 -0
  18. mannf/core/__init__.py +26 -0
  19. mannf/core/agents/__init__.py +52 -0
  20. mannf/core/agents/accessibility_scanner_agent.py +245 -0
  21. mannf/core/agents/analyzer_agent.py +224 -0
  22. mannf/core/agents/autonomous_loop_agent.py +1086 -0
  23. mannf/core/agents/autonomous_loop_models.py +62 -0
  24. mannf/core/agents/autonomous_run_differ.py +427 -0
  25. mannf/core/agents/base.py +128 -0
  26. mannf/core/agents/bdi_agent.py +330 -0
  27. mannf/core/agents/belief_state.py +202 -0
  28. mannf/core/agents/browser_coordinator_agent.py +224 -0
  29. mannf/core/agents/browser_executor_agent.py +410 -0
  30. mannf/core/agents/coordinator_agent.py +262 -0
  31. mannf/core/agents/executor_agent.py +222 -0
  32. mannf/core/agents/monitor_agent.py +188 -0
  33. mannf/core/agents/oracle_agent.py +150 -0
  34. mannf/core/agents/performance_testing_agent.py +279 -0
  35. mannf/core/agents/planner_agent.py +128 -0
  36. mannf/core/agents/test_agent.py +249 -0
  37. mannf/core/agents/visual_regression_agent.py +311 -0
  38. mannf/core/agents/web_crawler_agent.py +510 -0
  39. mannf/core/agents/worker_pool.py +366 -0
  40. mannf/core/anomaly/__init__.py +14 -0
  41. mannf/core/anomaly/enhanced_detector.py +541 -0
  42. mannf/core/browser/__init__.py +63 -0
  43. mannf/core/browser/accessibility_scanner.py +424 -0
  44. mannf/core/browser/discovery_model.py +178 -0
  45. mannf/core/browser/dom_snapshot.py +349 -0
  46. mannf/core/browser/ingestor_bridge.py +371 -0
  47. mannf/core/browser/performance_metrics.py +217 -0
  48. mannf/core/browser/reflection_analyzer.py +442 -0
  49. mannf/core/browser/scenario_generator.py +1100 -0
  50. mannf/core/browser/security_scenario_generator.py +695 -0
  51. mannf/core/browser/visual_comparer.py +159 -0
  52. mannf/core/diagnostics/__init__.py +28 -0
  53. mannf/core/diagnostics/failure_clusterer.py +211 -0
  54. mannf/core/diagnostics/flake_detector.py +233 -0
  55. mannf/core/diagnostics/root_cause_analyzer.py +273 -0
  56. mannf/core/distributed/__init__.py +16 -0
  57. mannf/core/distributed/endpoint.py +139 -0
  58. mannf/core/distributed/system_under_test.py +207 -0
  59. mannf/core/functional_orchestrator.py +428 -0
  60. mannf/core/messaging/__init__.py +11 -0
  61. mannf/core/messaging/bus.py +113 -0
  62. mannf/core/messaging/messages.py +89 -0
  63. mannf/core/nat_orchestrator.py +342 -0
  64. mannf/core/neural/__init__.py +183 -0
  65. mannf/core/orchestrator.py +272 -0
  66. mannf/core/prioritization/__init__.py +17 -0
  67. mannf/core/prioritization/adaptive_controller.py +509 -0
  68. mannf/core/prioritization/belief_prioritizer.py +231 -0
  69. mannf/core/prioritization/risk_scorer.py +430 -0
  70. mannf/core/reporting/__init__.py +12 -0
  71. mannf/core/reporting/unified_report.py +664 -0
  72. mannf/core/testing/__init__.py +17 -0
  73. mannf/core/testing/adaptive_controller.py +149 -0
  74. mannf/core/testing/models.py +179 -0
  75. mannf/core/validation/__init__.py +10 -0
  76. mannf/core/validation/self_validation_runner.py +180 -0
  77. mannf/dashboard/__init__.py +7 -0
  78. mannf/dashboard/app.py +9 -0
  79. mannf/dashboard/models.py +9 -0
  80. mannf/dashboard/static/index.html +2538 -0
  81. mannf/dashboard/telemetry.py +9 -0
  82. mannf/distributed/__init__.py +7 -0
  83. mannf/distributed/endpoint.py +9 -0
  84. mannf/distributed/system_under_test.py +9 -0
  85. mannf/healing/__init__.py +7 -0
  86. mannf/healing/graphql_schema_diff.py +9 -0
  87. mannf/healing/healer.py +9 -0
  88. mannf/healing/models.py +9 -0
  89. mannf/healing/schema_diff.py +9 -0
  90. mannf/integrations/__init__.py +7 -0
  91. mannf/integrations/auth.py +9 -0
  92. mannf/integrations/graphql_parser.py +9 -0
  93. mannf/integrations/graphql_sut.py +9 -0
  94. mannf/integrations/http_sut.py +9 -0
  95. mannf/integrations/openapi_parser.py +9 -0
  96. mannf/integrations/postman_parser.py +9 -0
  97. mannf/llm/__init__.py +7 -0
  98. mannf/llm/anthropic_provider.py +9 -0
  99. mannf/llm/base.py +9 -0
  100. mannf/llm/config.py +9 -0
  101. mannf/llm/factory.py +9 -0
  102. mannf/llm/openai_provider.py +9 -0
  103. mannf/llm/prompts.py +9 -0
  104. mannf/messaging/__init__.py +7 -0
  105. mannf/messaging/bus.py +9 -0
  106. mannf/messaging/messages.py +9 -0
  107. mannf/nat_orchestrator.py +9 -0
  108. mannf/neural/__init__.py +7 -0
  109. mannf/orchestrator.py +9 -0
  110. mannf/prioritization/__init__.py +7 -0
  111. mannf/prioritization/adaptive_controller.py +9 -0
  112. mannf/prioritization/belief_prioritizer.py +9 -0
  113. mannf/prioritization/risk_scorer.py +9 -0
  114. mannf/product/__init__.py +29 -0
  115. mannf/product/admin/__init__.py +3 -0
  116. mannf/product/admin/routes.py +514 -0
  117. mannf/product/auth/__init__.py +5 -0
  118. mannf/product/auth/saml.py +212 -0
  119. mannf/product/billing/__init__.py +5 -0
  120. mannf/product/billing/audit.py +160 -0
  121. mannf/product/billing/feature_gates.py +180 -0
  122. mannf/product/billing/metering.py +179 -0
  123. mannf/product/billing/notifications.py +181 -0
  124. mannf/product/billing/plans.py +133 -0
  125. mannf/product/billing/rate_limits.py +35 -0
  126. mannf/product/billing/stripe_billing.py +906 -0
  127. mannf/product/billing/tenant_auth.py +233 -0
  128. mannf/product/billing/tenant_manager.py +873 -0
  129. mannf/product/cli.py +3900 -0
  130. mannf/product/cli_admin.py +408 -0
  131. mannf/product/dashboard/__init__.py +61 -0
  132. mannf/product/dashboard/app.py +3567 -0
  133. mannf/product/dashboard/models.py +460 -0
  134. mannf/product/dashboard/static/index.html +6347 -0
  135. mannf/product/dashboard/static/manifest.json +25 -0
  136. mannf/product/dashboard/static/pwa-icon-192.png +0 -0
  137. mannf/product/dashboard/static/pwa-icon-512.png +0 -0
  138. mannf/product/dashboard/static/sw.js +64 -0
  139. mannf/product/dashboard/telemetry.py +547 -0
  140. mannf/product/database.py +145 -0
  141. mannf/product/demo.py +844 -0
  142. mannf/product/doctor.py +509 -0
  143. mannf/product/exporters/__init__.py +65 -0
  144. mannf/product/exporters/azuredevops_exporter.py +257 -0
  145. mannf/product/exporters/base.py +307 -0
  146. mannf/product/exporters/bugzilla_exporter.py +200 -0
  147. mannf/product/exporters/dedup.py +275 -0
  148. mannf/product/exporters/finding_adapter.py +216 -0
  149. mannf/product/exporters/github_exporter.py +197 -0
  150. mannf/product/exporters/gitlab_exporter.py +215 -0
  151. mannf/product/exporters/jira_exporter.py +180 -0
  152. mannf/product/exporters/linear_exporter.py +195 -0
  153. mannf/product/exporters/loader.py +233 -0
  154. mannf/product/exporters/pagerduty_exporter.py +363 -0
  155. mannf/product/exporters/sentry_exporter.py +322 -0
  156. mannf/product/exporters/servicenow_exporter.py +240 -0
  157. mannf/product/exporters/shortcut_exporter.py +231 -0
  158. mannf/product/exporters/webhook_exporter.py +383 -0
  159. mannf/product/formatters/__init__.py +18 -0
  160. mannf/product/formatters/allure_formatter.py +161 -0
  161. mannf/product/formatters/ctrf_formatter.py +149 -0
  162. mannf/product/healing/__init__.py +30 -0
  163. mannf/product/healing/graphql_schema_diff.py +152 -0
  164. mannf/product/healing/healer.py +141 -0
  165. mannf/product/healing/models.py +175 -0
  166. mannf/product/healing/schema_diff.py +251 -0
  167. mannf/product/ingestors/__init__.py +77 -0
  168. mannf/product/ingestors/base.py +256 -0
  169. mannf/product/ingestors/bgstm_ingestor.py +764 -0
  170. mannf/product/ingestors/curl_ingestor.py +1019 -0
  171. mannf/product/ingestors/cypress_ingestor.py +487 -0
  172. mannf/product/ingestors/gherkin_ingestor.py +967 -0
  173. mannf/product/ingestors/graphql_ingestor.py +845 -0
  174. mannf/product/ingestors/grpc_ingestor.py +591 -0
  175. mannf/product/ingestors/har_ingestor.py +976 -0
  176. mannf/product/ingestors/loader.py +284 -0
  177. mannf/product/ingestors/models.py +146 -0
  178. mannf/product/ingestors/openapi_ingestor.py +606 -0
  179. mannf/product/ingestors/playwright_ingestor.py +449 -0
  180. mannf/product/ingestors/postman_ingestor.py +631 -0
  181. mannf/product/ingestors/traffic_ingestor.py +679 -0
  182. mannf/product/ingestors/websocket_ingestor.py +526 -0
  183. mannf/product/integrations/__init__.py +21 -0
  184. mannf/product/integrations/auth.py +190 -0
  185. mannf/product/integrations/graphql_parser.py +436 -0
  186. mannf/product/integrations/graphql_sut.py +247 -0
  187. mannf/product/integrations/grpc_sut.py +469 -0
  188. mannf/product/integrations/http_sut.py +237 -0
  189. mannf/product/integrations/kafka_adapter.py +342 -0
  190. mannf/product/integrations/openapi_parser.py +513 -0
  191. mannf/product/integrations/postman_parser.py +467 -0
  192. mannf/product/integrations/webhook_receiver.py +344 -0
  193. mannf/product/integrations/websocket_sut.py +434 -0
  194. mannf/product/llm/__init__.py +25 -0
  195. mannf/product/llm/anthropic_provider.py +94 -0
  196. mannf/product/llm/base.py +267 -0
  197. mannf/product/llm/config.py +48 -0
  198. mannf/product/llm/factory.py +42 -0
  199. mannf/product/llm/openai_provider.py +93 -0
  200. mannf/product/llm/prompts.py +403 -0
  201. mannf/product/llm/root_cause_service.py +311 -0
  202. mannf/product/llm/test_plan_models.py +78 -0
  203. mannf/product/metrics.py +149 -0
  204. mannf/product/middleware/__init__.py +3 -0
  205. mannf/product/middleware/audit_middleware.py +112 -0
  206. mannf/product/middleware/tenant_isolation.py +114 -0
  207. mannf/product/models.py +347 -0
  208. mannf/product/notifications/__init__.py +24 -0
  209. mannf/product/notifications/dispatcher.py +411 -0
  210. mannf/product/onboarding.py +190 -0
  211. mannf/product/orchestration/__init__.py +39 -0
  212. mannf/product/orchestration/ingest_scan_orchestrator.py +339 -0
  213. mannf/product/orchestration/pipeline.py +401 -0
  214. mannf/product/orchestrator.py +987 -0
  215. mannf/product/orchestrator_models.py +269 -0
  216. mannf/product/regression/__init__.py +36 -0
  217. mannf/product/regression/differ.py +172 -0
  218. mannf/product/regression/masking.py +100 -0
  219. mannf/product/regression/models.py +232 -0
  220. mannf/product/regression/recorder.py +124 -0
  221. mannf/product/regression/replayer.py +168 -0
  222. mannf/product/reports/__init__.py +10 -0
  223. mannf/product/reports/pdf.py +132 -0
  224. mannf/product/scheduling/__init__.py +57 -0
  225. mannf/product/scheduling/cron_utils.py +251 -0
  226. mannf/product/scheduling/engine.py +473 -0
  227. mannf/product/scheduling/models.py +86 -0
  228. mannf/product/scheduling/queue.py +894 -0
  229. mannf/product/scheduling/store.py +235 -0
  230. mannf/product/security/__init__.py +21 -0
  231. mannf/product/security/belief_guided.py +143 -0
  232. mannf/product/security/checks/__init__.py +55 -0
  233. mannf/product/security/checks/base.py +69 -0
  234. mannf/product/security/checks/bfla.py +77 -0
  235. mannf/product/security/checks/bola.py +77 -0
  236. mannf/product/security/checks/bopla.py +80 -0
  237. mannf/product/security/checks/broken_auth.py +86 -0
  238. mannf/product/security/checks/graphql_security.py +299 -0
  239. mannf/product/security/checks/inventory.py +70 -0
  240. mannf/product/security/checks/misconfig.py +158 -0
  241. mannf/product/security/checks/resource_consumption.py +70 -0
  242. mannf/product/security/checks/sensitive_flows.py +80 -0
  243. mannf/product/security/checks/ssrf.py +101 -0
  244. mannf/product/security/checks/unsafe_consumption.py +120 -0
  245. mannf/product/security/models.py +92 -0
  246. mannf/product/security/plugin_loader.py +182 -0
  247. mannf/product/security/reporter.py +92 -0
  248. mannf/product/security/scanner.py +183 -0
  249. mannf/product/server.py +6220 -0
  250. mannf/product/setup_wizard.py +873 -0
  251. mannf/product/status.py +404 -0
  252. mannf/product/storage/__init__.py +10 -0
  253. mannf/product/storage/artifact_store.py +343 -0
  254. mannf/product/telemetry.py +300 -0
  255. mannf/product/uninstall.py +169 -0
  256. mannf/product/upgrade.py +139 -0
  257. mannf/product/weights/__init__.py +13 -0
  258. mannf/product/weights/blob_store.py +299 -0
  259. mannf/product/weights/factory.py +42 -0
  260. mannf/product/weights/registry.py +159 -0
  261. mannf/product/weights/store.py +210 -0
  262. mannf/regression/__init__.py +7 -0
  263. mannf/regression/differ.py +9 -0
  264. mannf/regression/masking.py +9 -0
  265. mannf/regression/models.py +9 -0
  266. mannf/regression/recorder.py +9 -0
  267. mannf/regression/replayer.py +9 -0
  268. mannf/security/__init__.py +7 -0
  269. mannf/security/belief_guided.py +9 -0
  270. mannf/security/checks/__init__.py +7 -0
  271. mannf/security/checks/base.py +9 -0
  272. mannf/security/checks/bfla.py +9 -0
  273. mannf/security/checks/bola.py +9 -0
  274. mannf/security/checks/bopla.py +9 -0
  275. mannf/security/checks/broken_auth.py +9 -0
  276. mannf/security/checks/graphql_security.py +9 -0
  277. mannf/security/checks/inventory.py +9 -0
  278. mannf/security/checks/misconfig.py +9 -0
  279. mannf/security/checks/resource_consumption.py +9 -0
  280. mannf/security/checks/sensitive_flows.py +9 -0
  281. mannf/security/checks/ssrf.py +9 -0
  282. mannf/security/checks/unsafe_consumption.py +9 -0
  283. mannf/security/models.py +9 -0
  284. mannf/security/reporter.py +9 -0
  285. mannf/security/scanner.py +9 -0
  286. mannf/server.py +9 -0
  287. mannf/testing/__init__.py +7 -0
  288. mannf/testing/adaptive_controller.py +9 -0
  289. mannf/testing/models.py +9 -0
  290. mannf/weights/__init__.py +7 -0
  291. mannf/weights/registry.py +9 -0
  292. mannf/weights/store.py +9 -0
  293. nat_engine-1.dist-info/METADATA +555 -0
  294. nat_engine-1.dist-info/RECORD +299 -0
  295. nat_engine-1.dist-info/WHEEL +5 -0
  296. nat_engine-1.dist-info/entry_points.txt +4 -0
  297. nat_engine-1.dist-info/licenses/LICENSE +651 -0
  298. nat_engine-1.dist-info/licenses/NOTICE +178 -0
  299. nat_engine-1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,159 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ """Weight snapshot registry.
7
+
8
+ :class:`WeightRegistry` maintains a JSON index file (default location:
9
+ ``~/.nat/weight_registry.json``) that maps human-readable snapshot names to
10
+ file paths and optional metadata. This lets users refer to weight snapshots
11
+ by a stable name rather than a raw file path.
12
+
13
+ Index file format::
14
+
15
+ {
16
+ "version": "1.0",
17
+ "snapshots": {
18
+ "<name>": {
19
+ "path": "<absolute file path>",
20
+ "registered_at": "<ISO-8601 timestamp>",
21
+ "metadata": {<arbitrary dict>}
22
+ }
23
+ }
24
+ }
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import json
30
+ import logging
31
+ import os
32
+ from datetime import datetime, timezone
33
+ from typing import Any, Dict, List, Optional
34
+
35
+ logger = logging.getLogger(__name__)
36
+
37
+ _DEFAULT_REGISTRY_PATH = os.path.join(
38
+ os.path.expanduser("~"), ".nat", "weight_registry.json"
39
+ )
40
+ _REGISTRY_VERSION = "1.0"
41
+
42
+
43
+ class WeightRegistry:
44
+ """Persistent registry of named weight snapshots.
45
+
46
+ Parameters
47
+ ----------
48
+ index_path:
49
+ Path to the JSON index file. Defaults to ``~/.nat/weight_registry.json``.
50
+ The file and its parent directory are created on first write if they do
51
+ not exist.
52
+ """
53
+
54
+ def __init__(self, index_path: Optional[str] = None) -> None:
55
+ self._path = index_path if index_path is not None else _DEFAULT_REGISTRY_PATH
56
+
57
+ # ------------------------------------------------------------------
58
+ # Public API
59
+ # ------------------------------------------------------------------
60
+
61
+ def register(
62
+ self,
63
+ name: str,
64
+ path: str,
65
+ metadata: Optional[Dict[str, Any]] = None,
66
+ ) -> None:
67
+ """Register a weight snapshot under *name*.
68
+
69
+ Parameters
70
+ ----------
71
+ name:
72
+ Human-readable identifier (must be unique; overwrites existing).
73
+ path:
74
+ Absolute or relative file path of the weight file.
75
+ metadata:
76
+ Optional arbitrary metadata dict (e.g. ``{"api": "petstore", "scans": 5}``).
77
+ """
78
+ index = self._load_index()
79
+ index["snapshots"][name] = {
80
+ "path": os.path.abspath(path),
81
+ "registered_at": datetime.now(timezone.utc).isoformat(),
82
+ "metadata": metadata or {},
83
+ }
84
+ self._save_index(index)
85
+ logger.debug("WeightRegistry: registered %r → %s", name, path)
86
+
87
+ def list(self) -> List[Dict[str, Any]]:
88
+ """Return all registered snapshots as a list of dicts.
89
+
90
+ Each entry has keys ``name``, ``path``, ``registered_at``, and
91
+ ``metadata``.
92
+ """
93
+ index = self._load_index()
94
+ result = []
95
+ for name, info in index["snapshots"].items():
96
+ result.append({
97
+ "name": name,
98
+ "path": info["path"],
99
+ "registered_at": info["registered_at"],
100
+ "metadata": info.get("metadata", {}),
101
+ })
102
+ return sorted(result, key=lambda e: e["registered_at"])
103
+
104
+ def get(self, name: str) -> str:
105
+ """Resolve *name* to its file path.
106
+
107
+ Raises
108
+ ------
109
+ KeyError
110
+ If *name* is not registered.
111
+ """
112
+ index = self._load_index()
113
+ if name not in index["snapshots"]:
114
+ raise KeyError(f"Weight snapshot {name!r} not registered")
115
+ return index["snapshots"][name]["path"]
116
+
117
+ def delete(self, name: str) -> None:
118
+ """Remove the snapshot registered as *name*.
119
+
120
+ Does not delete the underlying weight file.
121
+
122
+ Raises
123
+ ------
124
+ KeyError
125
+ If *name* is not registered.
126
+ """
127
+ index = self._load_index()
128
+ if name not in index["snapshots"]:
129
+ raise KeyError(f"Weight snapshot {name!r} not registered")
130
+ del index["snapshots"][name]
131
+ self._save_index(index)
132
+ logger.debug("WeightRegistry: deleted %r", name)
133
+
134
+ # ------------------------------------------------------------------
135
+ # Internal helpers
136
+ # ------------------------------------------------------------------
137
+
138
+ def _load_index(self) -> Dict[str, Any]:
139
+ """Load the index file, returning an empty index if it does not exist."""
140
+ if not os.path.isfile(self._path):
141
+ return {"version": _REGISTRY_VERSION, "snapshots": {}}
142
+ try:
143
+ with open(self._path, encoding="utf-8") as fh:
144
+ data = json.load(fh)
145
+ if not isinstance(data, dict) or "snapshots" not in data:
146
+ logger.warning(
147
+ "WeightRegistry: corrupt index at %s, starting fresh", self._path
148
+ )
149
+ return {"version": _REGISTRY_VERSION, "snapshots": {}}
150
+ return data
151
+ except (json.JSONDecodeError, OSError) as exc:
152
+ logger.warning("WeightRegistry: could not read index %s: %s", self._path, exc)
153
+ return {"version": _REGISTRY_VERSION, "snapshots": {}}
154
+
155
+ def _save_index(self, index: Dict[str, Any]) -> None:
156
+ """Persist *index* to disk, creating parent directories as needed."""
157
+ os.makedirs(os.path.dirname(os.path.abspath(self._path)), exist_ok=True)
158
+ with open(self._path, "w", encoding="utf-8") as fh:
159
+ json.dump(index, fh, indent=2)
@@ -0,0 +1,210 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ """Weight serialisation helpers.
7
+
8
+ :class:`WeightStore` provides JSON-based save/load for agent weight snapshots.
9
+ The on-disk format is::
10
+
11
+ {
12
+ "version": "1.0",
13
+ "saved_at": "<ISO-8601 timestamp>",
14
+ "agents": {
15
+ "<agent_id>": {
16
+ "role": "<role string>",
17
+ "layers": [{"W": [...], "b": [...]}, ...]
18
+ }
19
+ }
20
+ }
21
+
22
+ numpy arrays are converted to nested Python lists for JSON compatibility and
23
+ restored to ``np.ndarray`` on load.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import json
29
+ import logging
30
+ import os
31
+ from datetime import datetime, timezone
32
+ from typing import Any, Dict, List
33
+
34
+ import numpy as np
35
+
36
+ logger = logging.getLogger(__name__)
37
+
38
+ _FORMAT_VERSION = "1.0"
39
+
40
+
41
+ def _layers_to_serialisable(layers: List[dict]) -> List[dict]:
42
+ """Convert a list of ``{"W": ndarray, "b": ndarray}`` dicts to JSON-safe lists."""
43
+ result = []
44
+ for layer in layers:
45
+ result.append({
46
+ "W": layer["W"].tolist(),
47
+ "b": layer["b"].tolist(),
48
+ })
49
+ return result
50
+
51
+
52
+ def _layers_from_serialisable(layers: List[dict]) -> List[dict]:
53
+ """Restore a list of layer dicts from JSON-loaded lists back to ndarrays."""
54
+ result = []
55
+ for layer in layers:
56
+ result.append({
57
+ "W": np.array(layer["W"], dtype=float),
58
+ "b": np.array(layer["b"], dtype=float),
59
+ })
60
+ return result
61
+
62
+
63
+ class WeightStore:
64
+ """Serialise and deserialise agent weight snapshots to/from JSON files.
65
+
66
+ All methods are static so the class can be used without instantiation.
67
+ """
68
+
69
+ @staticmethod
70
+ def save(path: str, agent_weights: Dict[str, Dict[str, Any]]) -> None:
71
+ """Save all agent weights to *path*.
72
+
73
+ Parameters
74
+ ----------
75
+ path:
76
+ File path to write (created or overwritten).
77
+ agent_weights:
78
+ Mapping of ``agent_id`` → ``{"role": str, "layers": List[dict]}``.
79
+ Each layer dict must have ``"W"`` and ``"b"`` numpy arrays.
80
+ """
81
+ agents_serialisable: Dict[str, Any] = {}
82
+ for agent_id, info in agent_weights.items():
83
+ agents_serialisable[agent_id] = {
84
+ "role": info.get("role", ""),
85
+ "layers": _layers_to_serialisable(info["layers"]),
86
+ }
87
+
88
+ payload = {
89
+ "version": _FORMAT_VERSION,
90
+ "saved_at": datetime.now(timezone.utc).isoformat(),
91
+ "agents": agents_serialisable,
92
+ }
93
+
94
+ os.makedirs(os.path.dirname(os.path.abspath(path)), exist_ok=True)
95
+ with open(path, "w", encoding="utf-8") as fh:
96
+ json.dump(payload, fh, indent=2)
97
+
98
+ logger.info("Weights saved to %s (%d agents)", path, len(agent_weights))
99
+
100
+ @staticmethod
101
+ def load(path: str) -> Dict[str, Any]:
102
+ """Load agent weights from *path*.
103
+
104
+ Returns
105
+ -------
106
+ dict
107
+ ``{"version": str, "saved_at": str, "agents": {agent_id: {"role": str, "layers": [...]}}}``
108
+ where each layer dict contains ``np.ndarray`` values for ``"W"`` and ``"b"``.
109
+
110
+ Raises
111
+ ------
112
+ FileNotFoundError
113
+ If *path* does not exist.
114
+ ValueError
115
+ If the file cannot be parsed or fails structure validation.
116
+ """
117
+ if not os.path.isfile(path):
118
+ raise FileNotFoundError(f"Weight file not found: {path!r}")
119
+
120
+ try:
121
+ with open(path, encoding="utf-8") as fh:
122
+ data = json.load(fh)
123
+ except json.JSONDecodeError as exc:
124
+ raise ValueError(f"Corrupt weight file {path!r}: {exc}") from exc
125
+
126
+ WeightStore._validate_structure(data)
127
+
128
+ agents_out: Dict[str, Any] = {}
129
+ for agent_id, info in data["agents"].items():
130
+ agents_out[agent_id] = {
131
+ "role": info.get("role", ""),
132
+ "layers": _layers_from_serialisable(info["layers"]),
133
+ }
134
+
135
+ return {
136
+ "version": data["version"],
137
+ "saved_at": data["saved_at"],
138
+ "agents": agents_out,
139
+ }
140
+
141
+ @staticmethod
142
+ def save_single(path: str, agent_id: str, role: str, weights: List[dict]) -> None:
143
+ """Save a single agent's weights to *path*.
144
+
145
+ Parameters
146
+ ----------
147
+ path:
148
+ File path to write.
149
+ agent_id:
150
+ Agent identifier stored in the file.
151
+ role:
152
+ Human-readable role label (e.g. ``"planner"``).
153
+ weights:
154
+ List of ``{"W": ndarray, "b": ndarray}`` layer dicts.
155
+ """
156
+ WeightStore.save(path, {agent_id: {"role": role, "layers": weights}})
157
+
158
+ @staticmethod
159
+ def load_single(path: str) -> Dict[str, Any]:
160
+ """Load a single-agent weight file written by :meth:`save_single`.
161
+
162
+ Returns
163
+ -------
164
+ dict
165
+ ``{"agent_id": str, "role": str, "layers": List[dict]}``
166
+
167
+ Raises
168
+ ------
169
+ ValueError
170
+ If the file contains weights for more than one agent.
171
+ """
172
+ data = WeightStore.load(path)
173
+ agents = data["agents"]
174
+ if len(agents) != 1:
175
+ raise ValueError(
176
+ f"load_single expects exactly one agent in {path!r}, found {len(agents)}"
177
+ )
178
+ agent_id, info = next(iter(agents.items()))
179
+ return {
180
+ "agent_id": agent_id,
181
+ "role": info["role"],
182
+ "layers": info["layers"],
183
+ }
184
+
185
+ # ------------------------------------------------------------------
186
+ # Internal helpers
187
+ # ------------------------------------------------------------------
188
+
189
+ @staticmethod
190
+ def _validate_structure(data: Any) -> None:
191
+ """Raise :class:`ValueError` if *data* does not match the expected schema."""
192
+ if not isinstance(data, dict):
193
+ raise ValueError("Weight file root must be a JSON object")
194
+ if data.get("version") != _FORMAT_VERSION:
195
+ raise ValueError(
196
+ f"Unsupported weight file version {data.get('version')!r} "
197
+ f"(expected {_FORMAT_VERSION!r})"
198
+ )
199
+ if "agents" not in data or not isinstance(data["agents"], dict):
200
+ raise ValueError("Weight file missing 'agents' mapping")
201
+ for agent_id, info in data["agents"].items():
202
+ if not isinstance(info, dict):
203
+ raise ValueError(f"Agent entry {agent_id!r} is not a dict")
204
+ if "layers" not in info or not isinstance(info["layers"], list):
205
+ raise ValueError(f"Agent {agent_id!r} missing 'layers' list")
206
+ for i, layer in enumerate(info["layers"]):
207
+ if not isinstance(layer, dict) or "W" not in layer or "b" not in layer:
208
+ raise ValueError(
209
+ f"Agent {agent_id!r} layer {i} must have 'W' and 'b' keys"
210
+ )
@@ -0,0 +1,7 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.regression
7
+ from mannf.product.regression import * # noqa: F401, F403
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.regression.differ
7
+ import sys
8
+ import mannf.product.regression.differ as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.regression.masking
7
+ import sys
8
+ import mannf.product.regression.masking as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.regression.models
7
+ import sys
8
+ import mannf.product.regression.models as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.regression.recorder
7
+ import sys
8
+ import mannf.product.regression.recorder as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.regression.replayer
7
+ import sys
8
+ import mannf.product.regression.replayer as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,7 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security
7
+ from mannf.product.security import * # noqa: F401, F403
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.belief_guided
7
+ import sys
8
+ import mannf.product.security.belief_guided as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,7 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks
7
+ from mannf.product.security.checks import * # noqa: F401, F403
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.base
7
+ import sys
8
+ import mannf.product.security.checks.base as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.bfla
7
+ import sys
8
+ import mannf.product.security.checks.bfla as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.bola
7
+ import sys
8
+ import mannf.product.security.checks.bola as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.bopla
7
+ import sys
8
+ import mannf.product.security.checks.bopla as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.broken_auth
7
+ import sys
8
+ import mannf.product.security.checks.broken_auth as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.graphql_security
7
+ import sys
8
+ import mannf.product.security.checks.graphql_security as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.inventory
7
+ import sys
8
+ import mannf.product.security.checks.inventory as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.misconfig
7
+ import sys
8
+ import mannf.product.security.checks.misconfig as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.resource_consumption
7
+ import sys
8
+ import mannf.product.security.checks.resource_consumption as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.sensitive_flows
7
+ import sys
8
+ import mannf.product.security.checks.sensitive_flows as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.ssrf
7
+ import sys
8
+ import mannf.product.security.checks.ssrf as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.checks.unsafe_consumption
7
+ import sys
8
+ import mannf.product.security.checks.unsafe_consumption as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.models
7
+ import sys
8
+ import mannf.product.security.models as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.reporter
7
+ import sys
8
+ import mannf.product.security.reporter as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.security.scanner
7
+ import sys
8
+ import mannf.product.security.scanner as _real
9
+ sys.modules[__name__] = _real
mannf/server.py ADDED
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.product.server
7
+ import sys
8
+ import mannf.product.server as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,7 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.core.testing
7
+ from mannf.core.testing import * # noqa: F401, F403
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.core.testing.adaptive_controller
7
+ import sys
8
+ import mannf.core.testing.adaptive_controller as _real
9
+ sys.modules[__name__] = _real
@@ -0,0 +1,9 @@
1
+ # Copyright (C) 2026 Brad Guider
2
+ # This file is part of NAT (Neural Agent Testing Framework).
3
+ # Licensed under the AGPL-3.0. See LICENSE for details.
4
+ # Commercial licensing available — see COMMERCIAL_LICENSE.md.
5
+
6
+ # Backward-compatible shim — source of truth has moved to mannf.core.testing.models
7
+ import sys
8
+ import mannf.core.testing.models as _real
9
+ sys.modules[__name__] = _real