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,401 @@
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
+ """Higher-level Pipeline builder for composing ingestor → orchestrator → exporter chains.
7
+
8
+ The :class:`Pipeline` class provides a fluent builder API for constructing and
9
+ running a complete Ingest → Prioritize → Scan → Export → Learn workflow from
10
+ configuration or CLI arguments.
11
+
12
+ Usage::
13
+
14
+ from mannf.product.orchestration import Pipeline
15
+
16
+ result = await (
17
+ Pipeline()
18
+ .with_source("openapi.yaml", format="openapi")
19
+ .with_base_url("http://localhost:8080")
20
+ .with_auth_token("Bearer eyJ...")
21
+ .with_severity_threshold("high")
22
+ .with_exporter("github-issues", repo="org/repo", token="ghp_...")
23
+ .with_feedback_path("/tmp/nat_feedback.json")
24
+ .run()
25
+ )
26
+
27
+ print(f"Found {len(result.scan_results.findings)} findings")
28
+ print(f"Exported {result.export_summaries[0].succeeded} issues")
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import logging
34
+ from typing import Any
35
+
36
+ from mannf.product.exporters.base import ExporterPlugin
37
+ from mannf.product.ingestors.models import IngestResult
38
+ from mannf.product.orchestration.ingest_scan_orchestrator import IngestScanOrchestrator
39
+ from mannf.product.orchestrator_models import (
40
+ OrchestrationConfig,
41
+ OrchestrationResult,
42
+ )
43
+
44
+ logger = logging.getLogger(__name__)
45
+
46
+
47
+ class Pipeline:
48
+ """Fluent builder for a complete Ingest → Prioritize → Scan → Export → Learn run.
49
+
50
+ Each ``with_*`` method returns ``self`` to allow method chaining. Call
51
+ :meth:`run` (or :meth:`plan`) to execute the pipeline.
52
+
53
+ Parameters
54
+ ----------
55
+ config:
56
+ Optional pre-built :class:`~mannf.product.orchestrator_models.OrchestrationConfig`.
57
+ If provided, all ``with_*`` calls merge into/override this base config.
58
+ extra_exporters:
59
+ Optional additional exporter plugin instances to make available in
60
+ addition to the built-in exporters.
61
+ """
62
+
63
+ def __init__(
64
+ self,
65
+ config: OrchestrationConfig | None = None,
66
+ extra_exporters: list[ExporterPlugin] | None = None,
67
+ ) -> None:
68
+ self._config = config or OrchestrationConfig()
69
+ self._extra_exporters: list[ExporterPlugin] = extra_exporters or []
70
+
71
+ # ------------------------------------------------------------------
72
+ # Builder methods
73
+ # ------------------------------------------------------------------
74
+
75
+ def with_source(
76
+ self,
77
+ path_or_url: str,
78
+ *,
79
+ format: str | None = None, # noqa: A002
80
+ ingestor_name: str | None = None,
81
+ ingestor_config: dict | None = None,
82
+ ) -> "Pipeline":
83
+ """Set the ingestion source.
84
+
85
+ Parameters
86
+ ----------
87
+ path_or_url:
88
+ File system path or URL of the source to ingest.
89
+ format:
90
+ Optional format hint (e.g. ``"openapi"``, ``"har"``).
91
+ ingestor_name:
92
+ Optional explicit ingestor plugin name (overrides auto-detection).
93
+ ingestor_config:
94
+ Extra config dict passed to the ingestor's ``ingest()`` method.
95
+
96
+ Returns
97
+ -------
98
+ Pipeline
99
+ """
100
+ if path_or_url.startswith("http://") or path_or_url.startswith("https://"):
101
+ self._config.source_url = path_or_url
102
+ self._config.source_path = None
103
+ else:
104
+ self._config.source_path = path_or_url
105
+ self._config.source_url = None
106
+ if format is not None:
107
+ self._config.source_format = format
108
+ if ingestor_name is not None:
109
+ self._config.ingestor_name = ingestor_name
110
+ if ingestor_config is not None:
111
+ self._config.ingestor_config = {**self._config.ingestor_config, **ingestor_config}
112
+ return self
113
+
114
+ def with_base_url(self, base_url: str) -> "Pipeline":
115
+ """Set the API base URL for the scan engine.
116
+
117
+ Parameters
118
+ ----------
119
+ base_url:
120
+ The root URL of the API under test (e.g. ``"http://localhost:8080"``).
121
+
122
+ Returns
123
+ -------
124
+ Pipeline
125
+ """
126
+ self._config.scan_config = {**self._config.scan_config, "base_url": base_url}
127
+ return self
128
+
129
+ def with_auth_token(self, token: str) -> "Pipeline":
130
+ """Set a Bearer auth token for scan requests.
131
+
132
+ Parameters
133
+ ----------
134
+ token:
135
+ Bearer token (``"Bearer eyJ..."`` or just the token value).
136
+
137
+ Returns
138
+ -------
139
+ Pipeline
140
+ """
141
+ self._config.scan_config = {**self._config.scan_config, "auth_token": token}
142
+ return self
143
+
144
+ def with_api_key(self, api_key: str, header: str = "X-API-Key") -> "Pipeline":
145
+ """Set an API key for scan requests.
146
+
147
+ Parameters
148
+ ----------
149
+ api_key:
150
+ The API key value.
151
+ header:
152
+ The header name to send the key in (default ``"X-API-Key"``).
153
+
154
+ Returns
155
+ -------
156
+ Pipeline
157
+ """
158
+ self._config.scan_config = {
159
+ **self._config.scan_config,
160
+ "api_key": api_key,
161
+ "api_key_header": header,
162
+ }
163
+ return self
164
+
165
+ def with_severity_threshold(self, severity: str) -> "Pipeline":
166
+ """Set the minimum finding severity to include in the report.
167
+
168
+ Parameters
169
+ ----------
170
+ severity:
171
+ One of ``"critical"``, ``"high"``, ``"medium"``, ``"low"``,
172
+ ``"info"``.
173
+
174
+ Returns
175
+ -------
176
+ Pipeline
177
+ """
178
+ self._config.scan_config = {
179
+ **self._config.scan_config,
180
+ "severity_threshold": severity,
181
+ }
182
+ return self
183
+
184
+ def with_exporter(self, exporter_name: str, **kwargs: Any) -> "Pipeline":
185
+ """Configure an exporter plugin to run after scanning.
186
+
187
+ Parameters
188
+ ----------
189
+ exporter_name:
190
+ Name of the exporter plugin (e.g. ``"github-issues"``, ``"jira"``).
191
+ **kwargs:
192
+ Exporter-specific config (e.g. ``repo="org/repo"``, ``token="ghp_..."``).
193
+
194
+ Returns
195
+ -------
196
+ Pipeline
197
+ """
198
+ self._config.exporter_config = {
199
+ "exporter_name": exporter_name,
200
+ **kwargs,
201
+ }
202
+ return self
203
+
204
+ def with_feedback_path(self, path: str) -> "Pipeline":
205
+ """Set the file path to persist feedback JSON after scanning.
206
+
207
+ Parameters
208
+ ----------
209
+ path:
210
+ Absolute or relative path to write the feedback JSON.
211
+
212
+ Returns
213
+ -------
214
+ Pipeline
215
+ """
216
+ self._config.feedback_config = {**self._config.feedback_config, "save_path": path}
217
+ return self
218
+
219
+ def with_belief_guided(self, enabled: bool = True) -> "Pipeline":
220
+ """Enable or disable belief-guided prioritization.
221
+
222
+ Parameters
223
+ ----------
224
+ enabled:
225
+ Whether to use the belief-guided prioritizer (default ``True``).
226
+
227
+ Returns
228
+ -------
229
+ Pipeline
230
+ """
231
+ self._config.scan_config = {
232
+ **self._config.scan_config,
233
+ "belief_guided": enabled,
234
+ }
235
+ return self
236
+
237
+ def with_scan_config(self, **kwargs: Any) -> "Pipeline":
238
+ """Merge arbitrary key/value pairs into the scan config.
239
+
240
+ Parameters
241
+ ----------
242
+ **kwargs:
243
+ Arbitrary scan-level config overrides.
244
+
245
+ Returns
246
+ -------
247
+ Pipeline
248
+ """
249
+ self._config.scan_config = {**self._config.scan_config, **kwargs}
250
+ return self
251
+
252
+ def with_extra_exporters(self, *exporters: ExporterPlugin) -> "Pipeline":
253
+ """Register additional exporter plugin instances.
254
+
255
+ Parameters
256
+ ----------
257
+ *exporters:
258
+ One or more :class:`~mannf.product.exporters.base.ExporterPlugin`
259
+ instances to make available alongside the built-in exporters.
260
+
261
+ Returns
262
+ -------
263
+ Pipeline
264
+ """
265
+ self._extra_exporters.extend(exporters)
266
+ return self
267
+
268
+ def with_llm(
269
+ self,
270
+ provider: str = "openai",
271
+ *,
272
+ model: str = "",
273
+ api_key: str | None = None,
274
+ priority_threshold: float = 0.7,
275
+ n_cases: int = 3,
276
+ **kwargs: Any,
277
+ ) -> "Pipeline":
278
+ """Enable LLM-augmented edge-case generation for high-priority endpoints.
279
+
280
+ When enabled, the orchestrator will call the configured LLM to generate
281
+ additional test cases for every endpoint whose priority score meets or
282
+ exceeds *priority_threshold* before running the security scan.
283
+
284
+ Parameters
285
+ ----------
286
+ provider:
287
+ LLM provider name: ``"openai"`` or ``"anthropic"``
288
+ (default ``"openai"``).
289
+ model:
290
+ Model identifier. Defaults to the provider's built-in default
291
+ (``"gpt-4o-mini"`` for OpenAI, ``"claude-3-haiku-20240307"`` for
292
+ Anthropic).
293
+ api_key:
294
+ API key. When ``None``, the provider reads from the environment
295
+ variable (``OPENAI_API_KEY`` / ``ANTHROPIC_API_KEY``).
296
+ priority_threshold:
297
+ Minimum ``priority_score`` (0–1) for a target to receive LLM-generated
298
+ test cases (default ``0.7``).
299
+ n_cases:
300
+ Number of edge-case test cases to generate per qualifying endpoint
301
+ (default ``3``).
302
+ **kwargs:
303
+ Additional key/value pairs merged into
304
+ :class:`~mannf.product.llm.config.LLMConfig`.
305
+
306
+ Returns
307
+ -------
308
+ Pipeline
309
+ """
310
+ llm_cfg: dict[str, Any] = {
311
+ "enabled": True,
312
+ "provider": provider,
313
+ "priority_threshold": priority_threshold,
314
+ "n_cases": n_cases,
315
+ **kwargs,
316
+ }
317
+ if model:
318
+ llm_cfg["model"] = model
319
+ if api_key is not None:
320
+ llm_cfg["api_key"] = api_key
321
+ self._config.llm_config = llm_cfg
322
+ return self
323
+
324
+ # ------------------------------------------------------------------
325
+ # Execution
326
+ # ------------------------------------------------------------------
327
+
328
+ async def run(self) -> OrchestrationResult:
329
+ """Execute the full Ingest → Prioritize → Scan → Export → Learn pipeline.
330
+
331
+ Returns
332
+ -------
333
+ OrchestrationResult
334
+ Complete pipeline result.
335
+ """
336
+ orch = IngestScanOrchestrator(self._config, self._extra_exporters)
337
+ return await orch.orchestrate()
338
+
339
+ async def plan(self) -> OrchestrationResult:
340
+ """Dry-run mode: ingest + prioritize without scanning.
341
+
342
+ Returns
343
+ -------
344
+ OrchestrationResult
345
+ Pipeline result with ``scan_plan`` populated but no scan results.
346
+ """
347
+ orch = IngestScanOrchestrator(self._config, self._extra_exporters)
348
+ return await orch.plan()
349
+
350
+ async def run_from_result(self, ingest_result: IngestResult) -> OrchestrationResult:
351
+ """Run the pipeline from a pre-built :class:`~mannf.product.ingestors.models.IngestResult`.
352
+
353
+ Bypasses the file/URL ingest phase — useful when the caller already holds
354
+ an ``IngestResult`` from any ingestor plugin.
355
+
356
+ Parameters
357
+ ----------
358
+ ingest_result:
359
+ A completed ingest result.
360
+
361
+ Returns
362
+ -------
363
+ OrchestrationResult
364
+ Complete pipeline result.
365
+ """
366
+ orch = IngestScanOrchestrator(self._config, self._extra_exporters)
367
+ return await orch.orchestrate_from_result(ingest_result)
368
+
369
+ async def plan_from_result(self, ingest_result: IngestResult) -> OrchestrationResult:
370
+ """Dry-run from a pre-built :class:`~mannf.product.ingestors.models.IngestResult`.
371
+
372
+ Parameters
373
+ ----------
374
+ ingest_result:
375
+ A completed ingest result.
376
+
377
+ Returns
378
+ -------
379
+ OrchestrationResult
380
+ Pipeline result with ``scan_plan`` populated but no scan results.
381
+ """
382
+ orch = IngestScanOrchestrator(self._config, self._extra_exporters)
383
+ return await orch.plan_from_result(ingest_result)
384
+
385
+ # ------------------------------------------------------------------
386
+ # Properties
387
+ # ------------------------------------------------------------------
388
+
389
+ @property
390
+ def config(self) -> OrchestrationConfig:
391
+ """The current :class:`~mannf.product.orchestrator_models.OrchestrationConfig`."""
392
+ return self._config
393
+
394
+ def build(self) -> IngestScanOrchestrator:
395
+ """Build and return the :class:`IngestScanOrchestrator` without running it.
396
+
397
+ Returns
398
+ -------
399
+ IngestScanOrchestrator
400
+ """
401
+ return IngestScanOrchestrator(self._config, self._extra_exporters)