agentloop-profiler 0.1.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.
- agentloop/__init__.py +136 -0
- agentloop/ablation_protocol.py +229 -0
- agentloop/ablations.py +564 -0
- agentloop/aggregate_cli.py +88 -0
- agentloop/aggregate_stats.py +175 -0
- agentloop/aggregates.py +532 -0
- agentloop/audit.py +39 -0
- agentloop/autoinstrument.py +145 -0
- agentloop/batch_experiments.py +295 -0
- agentloop/batching.py +95 -0
- agentloop/budget_types.py +335 -0
- agentloop/budgets.py +539 -0
- agentloop/calibration.py +872 -0
- agentloop/checkpoint_state.py +306 -0
- agentloop/checkpoint_store.py +86 -0
- agentloop/ci.py +202 -0
- agentloop/cli.py +1314 -0
- agentloop/client.py +228 -0
- agentloop/completion.py +345 -0
- agentloop/completion_types.py +199 -0
- agentloop/config.py +50 -0
- agentloop/context_controls.py +443 -0
- agentloop/context_experiments.py +337 -0
- agentloop/context_types.py +216 -0
- agentloop/costs.py +667 -0
- agentloop/cursor_validation.py +48 -0
- agentloop/decorators.py +445 -0
- agentloop/demo.py +300 -0
- agentloop/doctor.py +341 -0
- agentloop/drift.py +361 -0
- agentloop/drift_cli.py +147 -0
- agentloop/drift_types.py +110 -0
- agentloop/drift_windows.py +340 -0
- agentloop/entrypoint.py +201 -0
- agentloop/estimates.py +133 -0
- agentloop/events.py +75 -0
- agentloop/experiment_artifacts.py +80 -0
- agentloop/experiment_observations.py +169 -0
- agentloop/experiment_reports.py +545 -0
- agentloop/experiment_types.py +355 -0
- agentloop/experiments.py +392 -0
- agentloop/exporters.py +117 -0
- agentloop/finding_benchmark_types.py +131 -0
- agentloop/finding_benchmarks.py +424 -0
- agentloop/findings.py +419 -0
- agentloop/graph.py +464 -0
- agentloop/harness.py +825 -0
- agentloop/harness_bench/__init__.py +1 -0
- agentloop/harness_bench/cli.py +77 -0
- agentloop/harness_bench/drivers.py +96 -0
- agentloop/harness_bench/offline.py +507 -0
- agentloop/harness_evidence.py +585 -0
- agentloop/harness_usage.py +91 -0
- agentloop/html_report.py +860 -0
- agentloop/integrations/__init__.py +1 -0
- agentloop/integrations/crewai.py +144 -0
- agentloop/integrations/harbor/__init__.py +1 -0
- agentloop/integrations/harbor/atif.py +982 -0
- agentloop/integrations/harbor/atif_validation.py +329 -0
- agentloop/integrations/harbor/cli.py +207 -0
- agentloop/integrations/harbor/manifest.py +86 -0
- agentloop/integrations/harbor/trial_evidence.py +196 -0
- agentloop/integrations/harbor/trials.py +1109 -0
- agentloop/integrations/harbor/verifier.py +118 -0
- agentloop/integrations/langgraph.py +150 -0
- agentloop/integrations/langgraph_harness.py +466 -0
- agentloop/integrations/langgraph_recovery.py +366 -0
- agentloop/integrations/omnigent/__init__.py +1 -0
- agentloop/integrations/omnigent/cli.py +78 -0
- agentloop/integrations/omnigent/evidence.py +93 -0
- agentloop/integrations/omnigent/telemetry.py +422 -0
- agentloop/integrations/openai.py +415 -0
- agentloop/integrations/openai_agents.py +291 -0
- agentloop/integrations/sdk.py +82 -0
- agentloop/integrations/vercel_ai.py +83 -0
- agentloop/interoperability/__init__.py +5 -0
- agentloop/interoperability/artifacts.py +112 -0
- agentloop/interoperability/cli.py +59 -0
- agentloop/interoperability/cohort_evidence.py +175 -0
- agentloop/interoperability/cohorts.py +681 -0
- agentloop/interoperability/contracts.py +427 -0
- agentloop/interoperability/coordination.py +554 -0
- agentloop/interoperability/evidence.py +215 -0
- agentloop/interoperability/otlp_jsonl.py +775 -0
- agentloop/interoperability/otlp_validation.py +496 -0
- agentloop/interoperability/registry.py +561 -0
- agentloop/interoperability/validation.py +333 -0
- agentloop/intervention_service.py +110 -0
- agentloop/intervention_store.py +118 -0
- agentloop/interventions.py +190 -0
- agentloop/issues.py +90 -0
- agentloop/judgment_adapters.py +125 -0
- agentloop/judgment_benchmark_types.py +98 -0
- agentloop/judgment_benchmarks.py +606 -0
- agentloop/judgment_types.py +241 -0
- agentloop/judgment_views.py +38 -0
- agentloop/judgments.py +342 -0
- agentloop/loop_guards.py +274 -0
- agentloop/loop_types.py +66 -0
- agentloop/markdown.py +102 -0
- agentloop/metrics.py +342 -0
- agentloop/migrations.py +303 -0
- agentloop/model_routing.py +470 -0
- agentloop/onboarding.py +315 -0
- agentloop/operations.py +44 -0
- agentloop/optimizer.py +199 -0
- agentloop/otel.py +715 -0
- agentloop/otel_ids.py +81 -0
- agentloop/otel_semantics.py +134 -0
- agentloop/parallelism.py +141 -0
- agentloop/patches.py +603 -0
- agentloop/plan_export.py +126 -0
- agentloop/policy_promotion.py +325 -0
- agentloop/promotion_evidence.py +304 -0
- agentloop/promotion_types.py +209 -0
- agentloop/quality.py +446 -0
- agentloop/ranking.py +529 -0
- agentloop/recovery_evidence.py +96 -0
- agentloop/replay.py +753 -0
- agentloop/retention.py +375 -0
- agentloop/retention_types.py +113 -0
- agentloop/reuse_experiments.py +247 -0
- agentloop/routing_checks.py +116 -0
- agentloop/routing_types.py +241 -0
- agentloop/rules.py +396 -0
- agentloop/runtime.py +286 -0
- agentloop/savings.py +158 -0
- agentloop/scheduling_plan.py +99 -0
- agentloop/scheduling_types.py +169 -0
- agentloop/schema.py +257 -0
- agentloop/semantic_rules.py +200 -0
- agentloop/semantic_waste.py +345 -0
- agentloop/semantic_waste_types.py +88 -0
- agentloop/server.py +494 -0
- agentloop/store.py +1429 -0
- agentloop/structural_experiments.py +431 -0
- agentloop/structural_types.py +113 -0
- agentloop/structured_quality.py +1020 -0
- agentloop/studies.py +629 -0
- agentloop/study_statistics.py +58 -0
- agentloop/substitution_evidence.py +199 -0
- agentloop/substitution_export.py +190 -0
- agentloop/substitution_reports.py +407 -0
- agentloop/substitution_types.py +284 -0
- agentloop/substitutions.py +267 -0
- agentloop/timing.py +142 -0
- agentloop/tokens.py +188 -0
- agentloop/tool_scheduling.py +410 -0
- agentloop/trace_sources.py +31 -0
- agentloop/tracer.py +494 -0
- agentloop/value.py +306 -0
- agentloop/version.py +3 -0
- agentloop/workflow_types.py +264 -0
- agentloop/workflows.py +284 -0
- agentloop_profiler-0.1.0.dist-info/METADATA +513 -0
- agentloop_profiler-0.1.0.dist-info/RECORD +166 -0
- agentloop_profiler-0.1.0.dist-info/WHEEL +5 -0
- agentloop_profiler-0.1.0.dist-info/entry_points.txt +2 -0
- agentloop_profiler-0.1.0.dist-info/licenses/LICENSE +201 -0
- agentloop_profiler-0.1.0.dist-info/licenses/THIRD_PARTY_LICENSES.md +101 -0
- agentloop_profiler-0.1.0.dist-info/top_level.txt +2 -0
- dashboard/__init__.py +5 -0
- dashboard/app.py +922 -0
- dashboard/streamlit_compat.py +63 -0
- dashboard/trace_upload.py +57 -0
- dashboard/value_view.py +105 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""Measurement qualifications for native projections of external evidence.
|
|
2
|
+
|
|
3
|
+
Native event schema requires numeric durations and two statuses. Missing source
|
|
4
|
+
measurements use compatibility placeholders, qualified here before analysis.
|
|
5
|
+
This namespace is not an authenticity guarantee or an executable adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import math
|
|
11
|
+
from collections.abc import Mapping
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from agentloop.interoperability.validation import ImportValidationError, validate_json_tree
|
|
15
|
+
|
|
16
|
+
EXTERNAL_KEY = "agentloop.external"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def read_external(trace: Any) -> dict[str, Any] | None:
|
|
20
|
+
metadata = getattr(trace, "metadata", {})
|
|
21
|
+
metadata = metadata if isinstance(metadata, Mapping) else {}
|
|
22
|
+
if "agentloop.harbor_trial" in metadata:
|
|
23
|
+
from agentloop.integrations.harbor.trial_evidence import read_trial
|
|
24
|
+
|
|
25
|
+
trial = read_trial(trace)
|
|
26
|
+
measurement = trial["measurement"]
|
|
27
|
+
return {
|
|
28
|
+
"schema_version": "1.0",
|
|
29
|
+
"source": {"system": "harbor", "format": "harbor_trial"},
|
|
30
|
+
"receipt_id": trial["receipt_id"],
|
|
31
|
+
"runtime_ms": measurement["runtime_ms"],
|
|
32
|
+
"event_timing_complete": measurement["runtime_ms"] is not None,
|
|
33
|
+
"execution_status": trial["outcome"]["execution_status"],
|
|
34
|
+
"usage_complete": measurement["input_tokens"] is not None
|
|
35
|
+
and measurement["output_tokens"] is not None,
|
|
36
|
+
"reported_model_call_count": None,
|
|
37
|
+
"comparison_eligible": True,
|
|
38
|
+
}
|
|
39
|
+
if EXTERNAL_KEY not in metadata:
|
|
40
|
+
if metadata.get("external_evidence_schema") == "1.0" or any(
|
|
41
|
+
isinstance(event.metadata, Mapping)
|
|
42
|
+
and event.metadata.get("external_evidence_schema") == "1.0"
|
|
43
|
+
for event in trace.events
|
|
44
|
+
):
|
|
45
|
+
raise ImportValidationError(
|
|
46
|
+
"invalid_external_evidence", EXTERNAL_KEY, "source event qualification is missing"
|
|
47
|
+
)
|
|
48
|
+
return None
|
|
49
|
+
value = metadata[EXTERNAL_KEY]
|
|
50
|
+
validate_json_tree(value)
|
|
51
|
+
if not isinstance(value, dict) or set(value) != {
|
|
52
|
+
"schema_version",
|
|
53
|
+
"source",
|
|
54
|
+
"receipt_id",
|
|
55
|
+
"runtime_ms",
|
|
56
|
+
"event_timing_complete",
|
|
57
|
+
"execution_status",
|
|
58
|
+
"usage_complete",
|
|
59
|
+
"reported_model_call_count",
|
|
60
|
+
"comparison_eligible",
|
|
61
|
+
}:
|
|
62
|
+
raise ImportValidationError(
|
|
63
|
+
"invalid_external_evidence", EXTERNAL_KEY, "invalid measurement qualification"
|
|
64
|
+
)
|
|
65
|
+
if value["schema_version"] != "1.0" or not isinstance(value["source"], dict):
|
|
66
|
+
raise ImportValidationError(
|
|
67
|
+
"invalid_external_evidence", EXTERNAL_KEY, "unsupported qualification schema"
|
|
68
|
+
)
|
|
69
|
+
if not isinstance(value["receipt_id"], str) or not value["receipt_id"].startswith("receipt_"):
|
|
70
|
+
raise ImportValidationError(
|
|
71
|
+
"invalid_external_evidence", EXTERNAL_KEY, "missing source receipt reference"
|
|
72
|
+
)
|
|
73
|
+
for key in ("event_timing_complete", "usage_complete", "comparison_eligible"):
|
|
74
|
+
if type(value[key]) is not bool:
|
|
75
|
+
raise ImportValidationError(
|
|
76
|
+
"invalid_external_evidence", EXTERNAL_KEY, "qualification flags must be boolean"
|
|
77
|
+
)
|
|
78
|
+
runtime = value["runtime_ms"]
|
|
79
|
+
if runtime is not None and (
|
|
80
|
+
type(runtime) not in {int, float} or not math.isfinite(runtime) or runtime < 0
|
|
81
|
+
):
|
|
82
|
+
raise ImportValidationError(
|
|
83
|
+
"invalid_external_evidence",
|
|
84
|
+
EXTERNAL_KEY,
|
|
85
|
+
"runtime must be finite and nonnegative or null",
|
|
86
|
+
)
|
|
87
|
+
count = value["reported_model_call_count"]
|
|
88
|
+
if count is not None and (type(count) is not int or count < 0):
|
|
89
|
+
raise ImportValidationError(
|
|
90
|
+
"invalid_external_evidence", EXTERNAL_KEY, "invalid reported call count"
|
|
91
|
+
)
|
|
92
|
+
if not isinstance(value["execution_status"], str) or value["execution_status"] not in {
|
|
93
|
+
"completed",
|
|
94
|
+
"failed",
|
|
95
|
+
"timed_out",
|
|
96
|
+
"cancelled",
|
|
97
|
+
"partial",
|
|
98
|
+
"missing",
|
|
99
|
+
"unknown",
|
|
100
|
+
}:
|
|
101
|
+
raise ImportValidationError(
|
|
102
|
+
"invalid_external_evidence", EXTERNAL_KEY, "invalid execution status"
|
|
103
|
+
)
|
|
104
|
+
if value["event_timing_complete"] and any(
|
|
105
|
+
event.metadata.get("timing_available") is not True for event in trace.events
|
|
106
|
+
):
|
|
107
|
+
raise ImportValidationError(
|
|
108
|
+
"invalid_external_evidence",
|
|
109
|
+
EXTERNAL_KEY,
|
|
110
|
+
"event timing qualification contradicts events",
|
|
111
|
+
)
|
|
112
|
+
return value
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def require_external_comparison(trace: Any, operation: str) -> None:
|
|
116
|
+
if "agentloop.harbor_trial" in getattr(trace, "metadata", {}):
|
|
117
|
+
from agentloop.integrations.harbor.trial_evidence import read_trial
|
|
118
|
+
|
|
119
|
+
trial = read_trial(trace)
|
|
120
|
+
# Studies already support missing per-metric values. A captured trial
|
|
121
|
+
# record is complete evidence even when a measurement is unavailable.
|
|
122
|
+
if operation == "study":
|
|
123
|
+
return
|
|
124
|
+
if trial["measurement"]["runtime_ms"] is None:
|
|
125
|
+
raise ValueError(
|
|
126
|
+
f"{operation} requires an externally recorded agent execution interval"
|
|
127
|
+
)
|
|
128
|
+
if operation == "value estimates":
|
|
129
|
+
raise ValueError(
|
|
130
|
+
"value estimates require finding-level timing; a trial phase is not a model/tool profile"
|
|
131
|
+
)
|
|
132
|
+
return
|
|
133
|
+
evidence = read_external(trace)
|
|
134
|
+
if evidence is not None and (
|
|
135
|
+
not evidence["comparison_eligible"]
|
|
136
|
+
or evidence["runtime_ms"] is None
|
|
137
|
+
or evidence["execution_status"] == "unknown"
|
|
138
|
+
or not evidence["event_timing_complete"]
|
|
139
|
+
or not evidence["usage_complete"]
|
|
140
|
+
):
|
|
141
|
+
raise ValueError(
|
|
142
|
+
f"{operation} requires complete external trial measurements and independent quality evidence"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def qualify_report(trace: Any, report: dict[str, Any]) -> None:
|
|
147
|
+
evidence = read_external(trace)
|
|
148
|
+
if evidence is None:
|
|
149
|
+
return
|
|
150
|
+
report["external_evidence"] = evidence
|
|
151
|
+
report["total_runtime_ms"] = evidence["runtime_ms"]
|
|
152
|
+
report["timing_status"] = "complete" if evidence["event_timing_complete"] else "unavailable"
|
|
153
|
+
report["reported_model_call_count"] = evidence["reported_model_call_count"]
|
|
154
|
+
report["model_call_count_basis"] = "recorded blocks; multiplicity is external reported"
|
|
155
|
+
report["repeated_context_tokens"] = report["repeated_context_ratio"] = None
|
|
156
|
+
report["retry_count"] = None
|
|
157
|
+
report["rule_abstentions"] = [
|
|
158
|
+
{
|
|
159
|
+
"rule_id": "cache_context",
|
|
160
|
+
"reason": "ATIF does not provide the actual provider input context"
|
|
161
|
+
if evidence["source"].get("format") == "atif"
|
|
162
|
+
else "Imported telemetry does not establish the complete provider input context",
|
|
163
|
+
},
|
|
164
|
+
]
|
|
165
|
+
models = [event for event in trace.events if event.event_type == "model_call"]
|
|
166
|
+
for direction in ("input", "output"):
|
|
167
|
+
key = direction + "_tokens"
|
|
168
|
+
report["known_" + key] = report[key]
|
|
169
|
+
if any(event.metadata.get(key + "_available") is not True for event in models) or (
|
|
170
|
+
not models and not evidence["usage_complete"]
|
|
171
|
+
):
|
|
172
|
+
report[key] = None
|
|
173
|
+
for item in report["events"]:
|
|
174
|
+
if item["metadata"].get("timing_available") is False:
|
|
175
|
+
item["duration_ms"] = None
|
|
176
|
+
if item["metadata"].get("source_status_available") is False:
|
|
177
|
+
item["status"] = "unknown"
|
|
178
|
+
if item["event_type"] == "model_call":
|
|
179
|
+
for key in ("input_tokens", "output_tokens"):
|
|
180
|
+
if item["metadata"].get(key + "_available") is False:
|
|
181
|
+
item[key] = None
|
|
182
|
+
if not evidence["event_timing_complete"]:
|
|
183
|
+
report["parallelism_opportunities"] = []
|
|
184
|
+
for key in ("cumulative_span_time_ms", "model_time_ms", "tool_time_ms", "retry_time_ms"):
|
|
185
|
+
report[key] = None
|
|
186
|
+
report["token_status"] = "external_reported" if evidence["usage_complete"] else "partial"
|
|
187
|
+
# Retained source cost lives in receipts. It is not provider accounting or a
|
|
188
|
+
# rate calculated from independently verified provider usage.
|
|
189
|
+
report["cost_status"] = "unknown"
|
|
190
|
+
report["estimated_cost_usd"] = None
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def qualify_candidates(report: dict[str, Any], candidates: list[Any]) -> None:
|
|
194
|
+
evidence = report.get("external_evidence")
|
|
195
|
+
if evidence is None:
|
|
196
|
+
return
|
|
197
|
+
for candidate in candidates:
|
|
198
|
+
candidate.estimated_cost_savings_usd = None
|
|
199
|
+
if not evidence["event_timing_complete"]:
|
|
200
|
+
candidate.estimated_latency_savings_ms = None
|
|
201
|
+
if candidate.estimate:
|
|
202
|
+
inputs = candidate.estimate.get("inputs", {})
|
|
203
|
+
inputs["sum_duration_ms"] = inputs["max_duration_ms"] = None
|
|
204
|
+
candidate.estimate["unmodeled_metrics"] = ["latency", "cost"]
|
|
205
|
+
candidate.observations = {
|
|
206
|
+
**(candidate.observations or {}),
|
|
207
|
+
"external_source": evidence["source"],
|
|
208
|
+
"source_receipt_id": evidence["receipt_id"],
|
|
209
|
+
"source_execution_status": evidence["execution_status"],
|
|
210
|
+
}
|
|
211
|
+
candidate.evidence_level = "external_reported"
|
|
212
|
+
candidate.assumptions = [
|
|
213
|
+
*(candidate.assumptions or []),
|
|
214
|
+
"Source artifacts are externally reported; execution completeness and task correctness require independent verification.",
|
|
215
|
+
]
|