agentops-accelerator 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. agentops/__init__.py +10 -0
  2. agentops/__main__.py +6 -0
  3. agentops/agent/__init__.py +12 -0
  4. agentops/agent/_legacy_ids.py +92 -0
  5. agentops/agent/analyzer.py +207 -0
  6. agentops/agent/checks/__init__.py +1 -0
  7. agentops/agent/checks/catalog.py +880 -0
  8. agentops/agent/checks/errors.py +279 -0
  9. agentops/agent/checks/foundry_config.py +75 -0
  10. agentops/agent/checks/latency.py +84 -0
  11. agentops/agent/checks/opex.py +157 -0
  12. agentops/agent/checks/opex_workspace.py +874 -0
  13. agentops/agent/checks/posture.py +36 -0
  14. agentops/agent/checks/posture_rules/__init__.py +53 -0
  15. agentops/agent/checks/posture_rules/content_filter.py +59 -0
  16. agentops/agent/checks/posture_rules/diagnostics.py +74 -0
  17. agentops/agent/checks/posture_rules/local_auth.py +55 -0
  18. agentops/agent/checks/posture_rules/managed_identity.py +59 -0
  19. agentops/agent/checks/posture_rules/network.py +68 -0
  20. agentops/agent/checks/regression.py +78 -0
  21. agentops/agent/checks/release_readiness.py +182 -0
  22. agentops/agent/checks/safety.py +247 -0
  23. agentops/agent/checks/spec_conformance.py +375 -0
  24. agentops/agent/cockpit.py +5159 -0
  25. agentops/agent/config.py +240 -0
  26. agentops/agent/findings.py +113 -0
  27. agentops/agent/history.py +142 -0
  28. agentops/agent/knowledge/__init__.py +182 -0
  29. agentops/agent/knowledge/waf-checklist.csv +39 -0
  30. agentops/agent/llm_assist/__init__.py +16 -0
  31. agentops/agent/llm_assist/_base.py +124 -0
  32. agentops/agent/llm_assist/_bundle_rule.py +154 -0
  33. agentops/agent/llm_assist/_client.py +347 -0
  34. agentops/agent/llm_assist/_dataset_rules.py +191 -0
  35. agentops/agent/llm_assist/_engine.py +106 -0
  36. agentops/agent/llm_assist/_prompt_rules.py +291 -0
  37. agentops/agent/llm_assist/_spec_rules.py +235 -0
  38. agentops/agent/production_telemetry.py +430 -0
  39. agentops/agent/report.py +207 -0
  40. agentops/agent/server/__init__.py +1 -0
  41. agentops/agent/server/app.py +84 -0
  42. agentops/agent/server/auth.py +94 -0
  43. agentops/agent/server/chat.py +44 -0
  44. agentops/agent/server/protocol.py +72 -0
  45. agentops/agent/sources/__init__.py +1 -0
  46. agentops/agent/sources/azure_monitor.py +523 -0
  47. agentops/agent/sources/azure_resources.py +602 -0
  48. agentops/agent/sources/foundry_control.py +174 -0
  49. agentops/agent/sources/results_history.py +494 -0
  50. agentops/agent/sources/spec_detectors/__init__.py +42 -0
  51. agentops/agent/sources/spec_detectors/_base.py +58 -0
  52. agentops/agent/sources/spec_detectors/agents_md.py +75 -0
  53. agentops/agent/sources/spec_detectors/spec_kit.py +172 -0
  54. agentops/agent/time_range.py +117 -0
  55. agentops/cli/__init__.py +1 -0
  56. agentops/cli/app.py +4823 -0
  57. agentops/core/__init__.py +1 -0
  58. agentops/core/agentops_config.py +592 -0
  59. agentops/core/config_loader.py +22 -0
  60. agentops/core/evaluators.py +480 -0
  61. agentops/core/release_evidence.py +56 -0
  62. agentops/core/results.py +117 -0
  63. agentops/mcp/__init__.py +10 -0
  64. agentops/mcp/server.py +232 -0
  65. agentops/pipeline/__init__.py +8 -0
  66. agentops/pipeline/cloud_results.py +189 -0
  67. agentops/pipeline/cloud_runner.py +901 -0
  68. agentops/pipeline/comparison.py +108 -0
  69. agentops/pipeline/diagnostics.py +51 -0
  70. agentops/pipeline/invocations.py +535 -0
  71. agentops/pipeline/official_eval.py +414 -0
  72. agentops/pipeline/orchestrator.py +775 -0
  73. agentops/pipeline/prompt_deploy.py +377 -0
  74. agentops/pipeline/publisher.py +121 -0
  75. agentops/pipeline/reporter.py +202 -0
  76. agentops/pipeline/runtime.py +409 -0
  77. agentops/pipeline/thresholds.py +84 -0
  78. agentops/services/__init__.py +1 -0
  79. agentops/services/cicd.py +720 -0
  80. agentops/services/eval_analysis.py +848 -0
  81. agentops/services/evidence_pack.py +757 -0
  82. agentops/services/initializer.py +86 -0
  83. agentops/services/preflight.py +470 -0
  84. agentops/services/setup_wizard.py +709 -0
  85. agentops/services/skills.py +643 -0
  86. agentops/services/trace_promotion.py +300 -0
  87. agentops/services/workflow_analysis.py +1129 -0
  88. agentops/templates/.gitignore +15 -0
  89. agentops/templates/__init__.py +1 -0
  90. agentops/templates/agent-server/Dockerfile +23 -0
  91. agentops/templates/agent-server/README.md +61 -0
  92. agentops/templates/agent-server/main.bicep +94 -0
  93. agentops/templates/agent.yaml +87 -0
  94. agentops/templates/agentops.yaml +58 -0
  95. agentops/templates/foundry.svg +71 -0
  96. agentops/templates/icon.png +0 -0
  97. agentops/templates/pipelines/azuredevops/agentops-deploy-dev-azd.yml +118 -0
  98. agentops/templates/pipelines/azuredevops/agentops-deploy-dev.yml +73 -0
  99. agentops/templates/pipelines/azuredevops/agentops-deploy-prod-azd.yml +141 -0
  100. agentops/templates/pipelines/azuredevops/agentops-deploy-prod.yml +94 -0
  101. agentops/templates/pipelines/azuredevops/agentops-deploy-prompt-agent.yml +167 -0
  102. agentops/templates/pipelines/azuredevops/agentops-deploy-qa-azd.yml +118 -0
  103. agentops/templates/pipelines/azuredevops/agentops-deploy-qa.yml +68 -0
  104. agentops/templates/pipelines/azuredevops/agentops-pr-prompt-agent.yml +210 -0
  105. agentops/templates/pipelines/azuredevops/agentops-pr.yml +155 -0
  106. agentops/templates/pipelines/azuredevops/agentops-watchdog.yml +106 -0
  107. agentops/templates/project.gitignore +36 -0
  108. agentops/templates/sample-traces.jsonl +3 -0
  109. agentops/templates/skills/agentops-agent/SKILL.md +137 -0
  110. agentops/templates/skills/agentops-config/SKILL.md +113 -0
  111. agentops/templates/skills/agentops-dataset/SKILL.md +84 -0
  112. agentops/templates/skills/agentops-eval/SKILL.md +189 -0
  113. agentops/templates/skills/agentops-report/SKILL.md +71 -0
  114. agentops/templates/skills/agentops-workflow/SKILL.md +471 -0
  115. agentops/templates/smoke.jsonl +3 -0
  116. agentops/templates/waf-checklist.README.md +84 -0
  117. agentops/templates/waf-checklist.csv +22 -0
  118. agentops/templates/workflows/agentops-deploy-dev-azd.yml +166 -0
  119. agentops/templates/workflows/agentops-deploy-dev.yml +187 -0
  120. agentops/templates/workflows/agentops-deploy-prod-azd.yml +183 -0
  121. agentops/templates/workflows/agentops-deploy-prod.yml +171 -0
  122. agentops/templates/workflows/agentops-deploy-prompt-agent.yml +197 -0
  123. agentops/templates/workflows/agentops-deploy-qa-azd.yml +156 -0
  124. agentops/templates/workflows/agentops-deploy-qa.yml +145 -0
  125. agentops/templates/workflows/agentops-pr-prompt-agent.yml +210 -0
  126. agentops/templates/workflows/agentops-pr.yml +148 -0
  127. agentops/templates/workflows/agentops-watchdog.yml +122 -0
  128. agentops/utils/__init__.py +1 -0
  129. agentops/utils/azd_env.py +435 -0
  130. agentops/utils/azure_endpoints.py +62 -0
  131. agentops/utils/colors.py +47 -0
  132. agentops/utils/dotenv_loader.py +105 -0
  133. agentops/utils/foundry_discovery.py +229 -0
  134. agentops/utils/logging.py +59 -0
  135. agentops/utils/telemetry.py +554 -0
  136. agentops/utils/yaml.py +36 -0
  137. agentops_accelerator-0.3.0.dist-info/METADATA +278 -0
  138. agentops_accelerator-0.3.0.dist-info/RECORD +142 -0
  139. agentops_accelerator-0.3.0.dist-info/WHEEL +5 -0
  140. agentops_accelerator-0.3.0.dist-info/entry_points.txt +2 -0
  141. agentops_accelerator-0.3.0.dist-info/licenses/LICENSE +21 -0
  142. agentops_accelerator-0.3.0.dist-info/top_level.txt +1 -0
agentops/__init__.py ADDED
@@ -0,0 +1,10 @@
1
+ """AgentOps CLI package."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("agentops-accelerator")
7
+ except PackageNotFoundError:
8
+ __version__ = "0.0.0-dev"
9
+
10
+ __all__ = ["__version__"]
agentops/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Entrypoint for `python -m agentops`."""
2
+
3
+ from agentops.cli.app import app
4
+
5
+ if __name__ == "__main__":
6
+ app()
@@ -0,0 +1,12 @@
1
+ """AgentOps Watchdog Agent.
2
+
3
+ The watchdog agent reads three signal sources (AgentOps eval history,
4
+ Azure Monitor / App Insights traces, Foundry control plane), runs a
5
+ set of checks over the gathered data, and produces a Markdown findings
6
+ report. It is exposed both as a CLI (``agentops doctor``) and as
7
+ a Copilot Extension HTTP server (``agentops agent serve``).
8
+ """
9
+
10
+ from agentops.agent.findings import Finding, Severity
11
+
12
+ __all__ = ["Finding", "Severity"]
@@ -0,0 +1,92 @@
1
+ """Legacy id / category aliases for the WAF-aligned rename.
2
+
3
+ This module is the single auditable home for the
4
+ ``genaiops`` -> ``operational_excellence`` / ``genaiops.*`` ->
5
+ ``opex.*`` rename. It exists to soften the upgrade for users with
6
+ existing ``agent.yaml`` files that reference the old names; the
7
+ canonical surface of every other module already uses the new names.
8
+
9
+ The shim is read-only: it rewrites legacy keys in memory at config
10
+ load time and emits a one-shot deprecation warning per process. No
11
+ persistent dual surface.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import logging
17
+ from typing import List, Optional
18
+
19
+ log = logging.getLogger(__name__)
20
+
21
+ # Legacy category key -> canonical category key.
22
+ LEGACY_CATEGORY_ALIASES = {
23
+ "genaiops": "operational_excellence",
24
+ }
25
+
26
+ # Legacy finding / rule id prefix -> canonical prefix.
27
+ # Any id that starts with the left-hand string is rewritten by
28
+ # substituting the right-hand string for the matching prefix.
29
+ LEGACY_ID_PREFIXES = (
30
+ ("genaiops.", "opex."),
31
+ )
32
+
33
+ _warned_categories: set[str] = set()
34
+ _warned_ids: set[str] = set()
35
+
36
+
37
+ def canonical_category(value: str) -> str:
38
+ """Return the canonical category key for ``value``.
39
+
40
+ If ``value`` is a legacy alias, emit a one-shot deprecation
41
+ warning and return the canonical key. Unknown values are
42
+ returned unchanged.
43
+ """
44
+ if not isinstance(value, str):
45
+ return value
46
+ key = value.strip().lower()
47
+ canonical = LEGACY_CATEGORY_ALIASES.get(key)
48
+ if canonical is None:
49
+ return value
50
+ if key not in _warned_categories:
51
+ _warned_categories.add(key)
52
+ log.warning(
53
+ "agentops doctor: category '%s' has been renamed to '%s' "
54
+ "(WAF-AI alignment). Update your config / CLI flag; the "
55
+ "legacy name will be removed in a future release.",
56
+ key,
57
+ canonical,
58
+ )
59
+ return canonical
60
+
61
+
62
+ def canonical_id(value: str) -> str:
63
+ """Return the canonical finding-id for ``value``.
64
+
65
+ If ``value`` starts with a legacy prefix, rewrite it and emit a
66
+ one-shot deprecation warning. Unknown values are returned
67
+ unchanged.
68
+ """
69
+ if not isinstance(value, str):
70
+ return value
71
+ for legacy, canonical in LEGACY_ID_PREFIXES:
72
+ if value.startswith(legacy):
73
+ rewritten = canonical + value[len(legacy):]
74
+ if value not in _warned_ids:
75
+ _warned_ids.add(value)
76
+ log.warning(
77
+ "agentops doctor: finding/rule id '%s' has been "
78
+ "renamed to '%s' (WAF-AI alignment). Update your "
79
+ "config; the legacy id will be removed in a "
80
+ "future release.",
81
+ value,
82
+ rewritten,
83
+ )
84
+ return rewritten
85
+ return value
86
+
87
+
88
+ def canonicalize_id_list(values: Optional[List[str]]) -> List[str]:
89
+ """Apply :func:`canonical_id` element-wise. Preserves order."""
90
+ if not values:
91
+ return list(values or [])
92
+ return [canonical_id(v) for v in values]
@@ -0,0 +1,207 @@
1
+ """Analyzer orchestration for the watchdog agent."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time
6
+ from concurrent.futures import Future, ThreadPoolExecutor
7
+ from dataclasses import dataclass, field
8
+ from pathlib import Path
9
+ from typing import Any, Callable, Dict, Iterable, List, Optional, Set, TypeVar
10
+
11
+ from agentops.agent.checks.errors import run_errors_check
12
+ from agentops.agent.checks.foundry_config import run_foundry_config_check
13
+ from agentops.agent.checks.latency import run_latency_check
14
+ from agentops.agent.checks.opex_workspace import run_opex_workspace_check
15
+ from agentops.agent.checks.opex import run_opex_check
16
+ from agentops.agent.checks.posture import run_posture_check
17
+ from agentops.agent.checks.regression import run_regression_check
18
+ from agentops.agent.checks.release_readiness import run_release_readiness_check
19
+ from agentops.agent.checks.safety import run_safety_check
20
+ from agentops.agent.checks.spec_conformance import run_spec_conformance_check
21
+ from agentops.agent.llm_assist import run_llm_assist_check
22
+ from agentops.agent.llm_assist._spec_rules import (
23
+ run_spec_implementation_gap_rule,
24
+ )
25
+ from agentops.agent.config import AgentConfig
26
+ from agentops.agent.findings import Category, Finding, Severity
27
+ from agentops.agent.sources.azure_monitor import (
28
+ AzureMonitorPayload,
29
+ collect_azure_monitor,
30
+ )
31
+ from agentops.agent.sources.azure_resources import (
32
+ AzureResourcesPayload,
33
+ collect_azure_resources,
34
+ )
35
+ from agentops.agent.sources.foundry_control import (
36
+ FoundryControlPayload,
37
+ collect_foundry_control,
38
+ )
39
+ from agentops.agent.sources.results_history import (
40
+ ResultsHistory,
41
+ collect_results_history,
42
+ )
43
+
44
+ _T = TypeVar("_T")
45
+
46
+
47
+ @dataclass
48
+ class AnalysisResult:
49
+ findings: List[Finding] = field(default_factory=list)
50
+ history: Optional[ResultsHistory] = None
51
+ monitor: Optional[AzureMonitorPayload] = None
52
+ foundry: Optional[FoundryControlPayload] = None
53
+ resources: Optional[AzureResourcesPayload] = None
54
+ diagnostics: Dict[str, Any] = field(default_factory=dict)
55
+ workspace: Optional[Path] = None
56
+
57
+ @property
58
+ def max_severity(self) -> Optional[Severity]:
59
+ if not self.findings:
60
+ return None
61
+ return max(f.severity for f in self.findings)
62
+
63
+
64
+ def _normalize_categories(
65
+ categories: Optional[Iterable[str]],
66
+ ) -> Optional[Set[Category]]:
67
+ if categories is None:
68
+ return None
69
+ from agentops.agent._legacy_ids import canonical_category
70
+
71
+ out: Set[Category] = set()
72
+ for c in categories:
73
+ if not c:
74
+ continue
75
+ normalized = canonical_category(c.strip().lower())
76
+ try:
77
+ out.add(Category(normalized))
78
+ except ValueError:
79
+ continue
80
+ return out or None
81
+
82
+
83
+ def analyze(
84
+ workspace: Path,
85
+ config: AgentConfig,
86
+ *,
87
+ categories: Optional[Iterable[str]] = None,
88
+ exclude_rules: Optional[Iterable[str]] = None,
89
+ progress: Optional[Callable[[str], None]] = None,
90
+ ) -> AnalysisResult:
91
+ """Run every configured source + check and return the merged result.
92
+
93
+ ``categories`` (when provided) limits the findings to the listed
94
+ :class:`Category` values. ``exclude_rules`` is forwarded to the
95
+ posture check to skip individual WAF rule ids on top of any
96
+ exclusions configured in ``agent.yaml``.
97
+ """
98
+ notify = progress or (lambda _msg: None)
99
+ notify("doctor: collecting local history, Azure Monitor, and Foundry control plane")
100
+
101
+ with ThreadPoolExecutor(max_workers=3, thread_name_prefix="agentops-doctor") as pool:
102
+ monitor_future = pool.submit(
103
+ _timed,
104
+ lambda: collect_azure_monitor(config.sources.azure_monitor, config.lookback_days),
105
+ )
106
+ foundry_future = pool.submit(
107
+ _timed,
108
+ lambda: collect_foundry_control(config.sources.foundry_control),
109
+ )
110
+ history_future = pool.submit(
111
+ _timed,
112
+ lambda: collect_results_history(
113
+ workspace,
114
+ config.sources.results_history,
115
+ foundry_config=config.sources.foundry_control,
116
+ ),
117
+ )
118
+
119
+ monitor, monitor_seconds = _finish_source("Azure Monitor", monitor_future, notify)
120
+ foundry, foundry_seconds = _finish_source("Foundry control plane", foundry_future, notify)
121
+ history, history_seconds = _finish_source("results history", history_future, notify)
122
+
123
+ resources_started = time.perf_counter()
124
+ resources = collect_azure_resources(
125
+ config.sources.azure_resources,
126
+ workspace=workspace,
127
+ project_endpoint=(foundry.diagnostics or {}).get("endpoint"),
128
+ )
129
+ resources_seconds = time.perf_counter() - resources_started
130
+ notify(f"doctor: source Azure resources complete ({resources_seconds:.1f}s)")
131
+ notify("doctor: running readiness checks")
132
+
133
+ posture_config = config.checks.posture
134
+ if exclude_rules:
135
+ merged = list(posture_config.exclude_rules) + [
136
+ r.strip() for r in exclude_rules if r and r.strip()
137
+ ]
138
+ posture_config = posture_config.model_copy(update={"exclude_rules": merged})
139
+
140
+ findings: List[Finding] = []
141
+ findings.extend(run_regression_check(history, config.checks.regression))
142
+ findings.extend(run_latency_check(history, monitor, config.checks.latency))
143
+ findings.extend(run_errors_check(monitor, foundry, config.checks.errors))
144
+ findings.extend(run_safety_check(history, config.checks.safety, monitor, foundry))
145
+ findings.extend(run_posture_check(resources, posture_config))
146
+ findings.extend(run_opex_workspace_check(workspace))
147
+ findings.extend(run_opex_check(history, config.checks.opex))
148
+ findings.extend(run_release_readiness_check(workspace, history, foundry))
149
+ findings.extend(
150
+ run_spec_conformance_check(
151
+ workspace, config.checks.operational_excellence.spec_conformance
152
+ )
153
+ )
154
+ findings.extend(run_foundry_config_check(foundry))
155
+ findings.extend(
156
+ run_llm_assist_check(workspace, config.checks.llm_assist, foundry)
157
+ )
158
+ findings.extend(
159
+ run_spec_implementation_gap_rule(
160
+ workspace,
161
+ config.checks.llm_assist,
162
+ config.checks.operational_excellence.spec_conformance,
163
+ )
164
+ )
165
+
166
+ allowed = _normalize_categories(categories)
167
+ if allowed is not None:
168
+ findings = [f for f in findings if f.category in allowed]
169
+
170
+ findings.sort(key=lambda f: (-f.severity.rank, f.category.value, f.id))
171
+
172
+ return AnalysisResult(
173
+ findings=findings,
174
+ history=history,
175
+ monitor=monitor,
176
+ foundry=foundry,
177
+ resources=resources,
178
+ diagnostics={
179
+ "results_history": history.diagnostics,
180
+ "azure_monitor": monitor.diagnostics,
181
+ "foundry_control": foundry.diagnostics,
182
+ "azure_resources": resources.diagnostics,
183
+ "source_timings_seconds": {
184
+ "results_history": round(history_seconds, 3),
185
+ "azure_monitor": round(monitor_seconds, 3),
186
+ "foundry_control": round(foundry_seconds, 3),
187
+ "azure_resources": round(resources_seconds, 3),
188
+ },
189
+ },
190
+ workspace=workspace,
191
+ )
192
+
193
+
194
+ def _timed(fn: Callable[[], _T]) -> tuple[_T, float]:
195
+ started = time.perf_counter()
196
+ value = fn()
197
+ return value, time.perf_counter() - started
198
+
199
+
200
+ def _finish_source(
201
+ label: str,
202
+ future: Future[tuple[_T, float]],
203
+ progress: Callable[[str], None],
204
+ ) -> tuple[_T, float]:
205
+ value, seconds = future.result()
206
+ progress(f"doctor: source {label} complete ({seconds:.1f}s)")
207
+ return value, seconds
@@ -0,0 +1 @@
1
+ """Watchdog agent checks."""