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
@@ -0,0 +1,229 @@
1
+ """Discover Foundry-attached resources from a project endpoint.
2
+
3
+ Currently exposes one helper: :func:`resolve_appinsights_connection`,
4
+ which asks a Foundry project for the connection string of the
5
+ Application Insights resource attached to it. Used by
6
+ :func:`agentops.utils.telemetry.init_tracing` as a fallback when the
7
+ user has configured ``AZURE_AI_FOUNDRY_PROJECT_ENDPOINT`` but not the
8
+ explicit ``APPLICATIONINSIGHTS_CONNECTION_STRING`` env var.
9
+
10
+ All Azure SDK imports are lazy; the discovery is best-effort and never
11
+ raises into callers - a missing SDK, a 404, or any unexpected response
12
+ shape returns ``None`` and the caller falls back to its no-op path.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ import os
19
+ import threading
20
+ import time
21
+ from typing import Optional, Tuple
22
+
23
+ log = logging.getLogger(__name__)
24
+
25
+
26
+ # Per-process cache so the cockpit does not re-query Foundry on every
27
+ # page load. Successful results are remembered for a long window
28
+ # (discovery rarely changes); failures are remembered for a short
29
+ # window so transient blips do not pin the cockpit into the error
30
+ # state across many reloads.
31
+ _SUCCESS_TTL_SECONDS = 30 * 60
32
+ _FAILURE_TTL_SECONDS = 60
33
+ _cache_lock = threading.Lock()
34
+ _cache: dict[str, Tuple[float, Optional[str], Optional[str]]] = {}
35
+
36
+
37
+ def _store(key: str, conn: Optional[str], reason: Optional[str]) -> None:
38
+ with _cache_lock:
39
+ _cache[key] = (time.time(), conn, reason)
40
+
41
+
42
+ def _lookup(key: str) -> Optional[Tuple[Optional[str], Optional[str]]]:
43
+ with _cache_lock:
44
+ entry = _cache.get(key)
45
+ if entry is None:
46
+ return None
47
+ ts, conn, reason = entry
48
+ ttl = _SUCCESS_TTL_SECONDS if conn else _FAILURE_TTL_SECONDS
49
+ if time.time() - ts > ttl:
50
+ return None
51
+ return conn, reason
52
+
53
+
54
+ def reset_cache() -> None:
55
+ """Clear the per-process discovery cache (test helper)."""
56
+ with _cache_lock:
57
+ _cache.clear()
58
+
59
+
60
+ def _summarize_discovery_exception(exc: Exception, *, context: str) -> str:
61
+ text = str(exc)
62
+ lower = text.lower()
63
+ auth_markers = (
64
+ "defaultazurecredential failed to retrieve a token",
65
+ "azureclicredential: failed to invoke the azure cli",
66
+ "azurepowershellcredential: failed to invoke powershell",
67
+ "environmentcredential authentication unavailable",
68
+ "sharedtokencachecredential authentication unavailable",
69
+ "clientauthenticationerror",
70
+ )
71
+ if type(exc).__name__ == "ClientAuthenticationError" or any(
72
+ marker in lower for marker in auth_markers
73
+ ):
74
+ return (
75
+ "Foundry authentication failed while reading telemetry metadata. "
76
+ "Run `az login` in this shell, confirm the active account has "
77
+ "Reader on the Foundry project resource group, then re-run."
78
+ )
79
+
80
+ permission_markers = (
81
+ "authorizationfailed",
82
+ "forbidden",
83
+ "does not have authorization",
84
+ "insufficient privileges",
85
+ )
86
+ if any(marker in lower for marker in permission_markers):
87
+ return (
88
+ "Foundry telemetry metadata is not readable by the signed-in "
89
+ "identity. Grant Reader on the Foundry project resource group "
90
+ "or set APPLICATIONINSIGHTS_CONNECTION_STRING manually."
91
+ )
92
+
93
+ snippet = text.splitlines()[0].strip() if text else type(exc).__name__
94
+ if len(snippet) > 220:
95
+ snippet = snippet[:217] + "..."
96
+ return f"{context} failed ({type(exc).__name__}: {snippet})."
97
+
98
+
99
+ def resolve_appinsights_connection_with_reason(
100
+ project_endpoint: str,
101
+ ) -> Tuple[Optional[str], Optional[str]]:
102
+ """Return ``(connection_string, error_reason)`` for *project_endpoint*.
103
+
104
+ On success, ``connection_string`` is the App Insights connection
105
+ string and ``error_reason`` is ``None``. On failure, the
106
+ connection string is ``None`` and ``error_reason`` is a short,
107
+ user-actionable explanation suitable for surfacing in the
108
+ cockpit tile.
109
+
110
+ Successful results are cached in-process for 30 minutes; failure
111
+ results for 60 seconds (so a transient Foundry hiccup does not
112
+ pin the cockpit into the error state for half an hour).
113
+ """
114
+ if not project_endpoint:
115
+ return None, "no AZURE_AI_FOUNDRY_PROJECT_ENDPOINT set"
116
+
117
+ cached = _lookup(project_endpoint)
118
+ if cached is not None:
119
+ return cached
120
+
121
+ try:
122
+ from azure.ai.projects import AIProjectClient
123
+ from azure.identity import DefaultAzureCredential
124
+ except ImportError:
125
+ reason = (
126
+ "azure-ai-projects / azure-identity not installed in the "
127
+ "cockpit's Python environment. Install with "
128
+ "`pip install azure-ai-projects azure-identity`."
129
+ )
130
+ log.debug(reason)
131
+ _store(project_endpoint, None, reason)
132
+ return None, reason
133
+
134
+ try:
135
+ credential = DefaultAzureCredential(exclude_developer_cli_credential=True, process_timeout=30)
136
+ client = AIProjectClient(
137
+ endpoint=project_endpoint,
138
+ credential=credential,
139
+ )
140
+ except Exception as exc: # noqa: BLE001
141
+ reason = _summarize_discovery_exception(
142
+ exc,
143
+ context="Could not build AIProjectClient",
144
+ )
145
+ log.debug(reason)
146
+ _store(project_endpoint, None, reason)
147
+ return None, reason
148
+
149
+ telemetry_attr = getattr(client, "telemetry", None)
150
+ if telemetry_attr is None:
151
+ reason = (
152
+ "AIProjectClient has no .telemetry helper "
153
+ "(azure-ai-projects too old). Set "
154
+ "APPLICATIONINSIGHTS_CONNECTION_STRING manually."
155
+ )
156
+ log.debug(reason)
157
+ _store(project_endpoint, None, reason)
158
+ return None, reason
159
+
160
+ # The exact method name has shifted slightly across SDK versions;
161
+ # try the documented one first, then a couple of known aliases.
162
+ candidate_methods = (
163
+ "get_application_insights_connection_string",
164
+ "get_connection_string",
165
+ "connection_string",
166
+ )
167
+ last_exc: Optional[Exception] = None
168
+ for name in candidate_methods:
169
+ fn = getattr(telemetry_attr, name, None)
170
+ if fn is None:
171
+ continue
172
+ try:
173
+ value = fn() if callable(fn) else fn
174
+ except Exception as exc: # noqa: BLE001
175
+ last_exc = exc
176
+ log.debug(
177
+ "AIProjectClient.telemetry.%s raised %s; trying next.",
178
+ name,
179
+ exc,
180
+ )
181
+ continue
182
+ if isinstance(value, str) and value:
183
+ _store(project_endpoint, value, None)
184
+ return value, None
185
+
186
+ if last_exc is not None:
187
+ reason = _summarize_discovery_exception(
188
+ last_exc,
189
+ context="Foundry telemetry discovery",
190
+ )
191
+ else:
192
+ reason = (
193
+ "Foundry returned no Application Insights connection. Wire "
194
+ "one in: Project details \u2192 Connected resources \u2192 "
195
+ "Add connection \u2192 Application Insights."
196
+ )
197
+ log.debug(reason)
198
+ _store(project_endpoint, None, reason)
199
+ return None, reason
200
+
201
+
202
+ def resolve_appinsights_connection(project_endpoint: str) -> Optional[str]:
203
+ """Return the App Insights connection string for *project_endpoint*.
204
+
205
+ Returns ``None`` on any failure. See
206
+ :func:`resolve_appinsights_connection_with_reason` for the
207
+ diagnostic-aware variant used by the cockpit.
208
+ """
209
+ conn, _ = resolve_appinsights_connection_with_reason(project_endpoint)
210
+ return conn
211
+
212
+
213
+ def resolve_appinsights_connection_from_env() -> Optional[str]:
214
+ """Resolve using ``AZURE_AI_FOUNDRY_PROJECT_ENDPOINT`` if set."""
215
+ endpoint = os.getenv("AZURE_AI_FOUNDRY_PROJECT_ENDPOINT")
216
+ if not endpoint:
217
+ return None
218
+ return resolve_appinsights_connection(endpoint)
219
+
220
+
221
+ def resolve_appinsights_connection_from_env_with_reason() -> Tuple[
222
+ Optional[str], Optional[str]
223
+ ]:
224
+ """Variant of :func:`resolve_appinsights_connection_from_env` that
225
+ also returns the error reason when discovery fails."""
226
+ endpoint = os.getenv("AZURE_AI_FOUNDRY_PROJECT_ENDPOINT")
227
+ if not endpoint:
228
+ return None, "no AZURE_AI_FOUNDRY_PROJECT_ENDPOINT set"
229
+ return resolve_appinsights_connection_with_reason(endpoint)
@@ -0,0 +1,59 @@
1
+ """Logging configuration for AgentOps CLI.
2
+
3
+ No side effects at import time - call setup_logging() explicitly from the
4
+ CLI callback before any command runs.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+
11
+ _LOG_FORMAT = "%(levelname)s: %(message)s"
12
+ _LOG_FORMAT_VERBOSE = "%(asctime)s %(name)s %(levelname)s: %(message)s"
13
+
14
+
15
+ def setup_logging(verbose: bool = False) -> None:
16
+ """Configure root logger.
17
+
18
+ Args:
19
+ verbose: When True, set level to DEBUG and include timestamps.
20
+ When False (default), set level to INFO.
21
+ """
22
+ level = logging.DEBUG if verbose else logging.INFO
23
+ fmt = _LOG_FORMAT_VERBOSE if verbose else _LOG_FORMAT
24
+
25
+ logging.basicConfig(
26
+ level=level,
27
+ format=fmt,
28
+ force=True, # safe to call multiple times (e.g. in tests)
29
+ )
30
+
31
+ # Silence noisy third-party loggers unless we are in DEBUG mode
32
+ if not verbose:
33
+ logging.getLogger("urllib3").setLevel(logging.WARNING)
34
+ logging.getLogger("azure").setLevel(logging.WARNING)
35
+ # azure.identity emits WARNING when individual credential sources
36
+ # in DefaultAzureCredential fail (e.g. the Azure CLI is locked or
37
+ # times out). Those failures are usually transient and the chain
38
+ # still succeeds via another source, so we hide them at the user
39
+ # level. They are still surfaced if the run fails outright.
40
+ logging.getLogger("azure.identity").setLevel(logging.ERROR)
41
+ logging.getLogger("azure.core").setLevel(logging.WARNING)
42
+ logging.getLogger("azure.core.pipeline").setLevel(logging.WARNING)
43
+ logging.getLogger("azure.core.pipeline.policies.http_logging_policy").setLevel(
44
+ logging.WARNING
45
+ )
46
+ logging.getLogger("azure.ai.evaluation").setLevel(logging.CRITICAL)
47
+ logging.getLogger("azure.ai.evaluation._legacy").setLevel(logging.CRITICAL)
48
+ logging.getLogger("httpx").setLevel(logging.WARNING)
49
+ logging.getLogger("openai").setLevel(logging.WARNING)
50
+
51
+
52
+ def get_logger(name: str) -> logging.Logger:
53
+ """Return a module-level logger.
54
+
55
+ Usage:
56
+ log = get_logger(__name__)
57
+ log.debug("...")
58
+ """
59
+ return logging.getLogger(name)