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,196 @@
|
|
|
1
|
+
"""Frozen trial measurements separate from ATIF model/tool projections."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import math
|
|
7
|
+
from hashlib import sha256
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from agentloop.interoperability.contracts import _validate_quality
|
|
11
|
+
from agentloop.interoperability.validation import (
|
|
12
|
+
ImportValidationError,
|
|
13
|
+
relative_reference,
|
|
14
|
+
validate_json_tree,
|
|
15
|
+
)
|
|
16
|
+
from agentloop.interventions import canonical_json
|
|
17
|
+
|
|
18
|
+
TRIAL_KEY = "agentloop.harbor_trial"
|
|
19
|
+
PAIRING_KEYS = (
|
|
20
|
+
"task_digest",
|
|
21
|
+
"scorer_config_hash",
|
|
22
|
+
"environment_hash",
|
|
23
|
+
"protocol_id",
|
|
24
|
+
"repetition",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _fail(reason: str) -> None:
|
|
29
|
+
raise ImportValidationError("invalid_trial_evidence", TRIAL_KEY, reason)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _binding(trace: Any) -> str:
|
|
33
|
+
value = trace.to_dict()
|
|
34
|
+
value["metadata"] = {key: item for key, item in value["metadata"].items() if key != TRIAL_KEY}
|
|
35
|
+
return sha256(canonical_json(value).encode()).hexdigest()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def attach_trial(trace: Any, record: dict) -> None:
|
|
39
|
+
if TRIAL_KEY in trace.metadata:
|
|
40
|
+
_fail("trial evidence cannot replace an existing receipt")
|
|
41
|
+
snapshot = {
|
|
42
|
+
**record,
|
|
43
|
+
"schema_version": "1.0",
|
|
44
|
+
"run_id": trace.run_id,
|
|
45
|
+
"trace_binding_sha256": _binding(trace),
|
|
46
|
+
}
|
|
47
|
+
snapshot["sha256"] = sha256(canonical_json(snapshot).encode()).hexdigest()
|
|
48
|
+
trace.metadata[TRIAL_KEY] = json.loads(canonical_json(snapshot))
|
|
49
|
+
read_trial(trace)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def read_trial(trace: Any) -> dict | None:
|
|
53
|
+
if TRIAL_KEY not in trace.metadata:
|
|
54
|
+
return None
|
|
55
|
+
value = trace.metadata[TRIAL_KEY]
|
|
56
|
+
validate_json_tree(value)
|
|
57
|
+
if (
|
|
58
|
+
not isinstance(value, dict)
|
|
59
|
+
or set(value)
|
|
60
|
+
!= {
|
|
61
|
+
"schema_version",
|
|
62
|
+
"run_id",
|
|
63
|
+
"receipt_id",
|
|
64
|
+
"source_result",
|
|
65
|
+
"measurement",
|
|
66
|
+
"outcome",
|
|
67
|
+
"pairing",
|
|
68
|
+
"trace_binding_sha256",
|
|
69
|
+
"sha256",
|
|
70
|
+
}
|
|
71
|
+
or value["schema_version"] != "1.0"
|
|
72
|
+
):
|
|
73
|
+
_fail("unsupported trial measurement schema")
|
|
74
|
+
content = {key: item for key, item in value.items() if key != "sha256"}
|
|
75
|
+
if (
|
|
76
|
+
value["sha256"] != sha256(canonical_json(content).encode()).hexdigest()
|
|
77
|
+
or value["trace_binding_sha256"] != _binding(trace)
|
|
78
|
+
or value["run_id"] != trace.run_id
|
|
79
|
+
):
|
|
80
|
+
_fail("trial measurements no longer match their captured trace")
|
|
81
|
+
_validate_quality(value["outcome"])
|
|
82
|
+
source = value["source_result"]
|
|
83
|
+
if not isinstance(source, dict) or set(source) != {"reference", "sha256"}:
|
|
84
|
+
_fail("invalid source result reference")
|
|
85
|
+
relative_reference(source["reference"])
|
|
86
|
+
if (
|
|
87
|
+
not isinstance(source["sha256"], str)
|
|
88
|
+
or len(source["sha256"]) != 64
|
|
89
|
+
or any(char not in "0123456789abcdef" for char in source["sha256"])
|
|
90
|
+
):
|
|
91
|
+
_fail("source result hash must be SHA-256")
|
|
92
|
+
if not isinstance(value["receipt_id"], str) or not value["receipt_id"].startswith("receipt_"):
|
|
93
|
+
_fail("source receipt reference is missing")
|
|
94
|
+
measurement = value["measurement"]
|
|
95
|
+
if not isinstance(measurement, dict) or set(measurement) != {
|
|
96
|
+
"runtime_ms",
|
|
97
|
+
"scope",
|
|
98
|
+
"input_tokens",
|
|
99
|
+
"output_tokens",
|
|
100
|
+
"cached_input_tokens",
|
|
101
|
+
"cost_usd",
|
|
102
|
+
"usage_provenance",
|
|
103
|
+
"cost_scope",
|
|
104
|
+
}:
|
|
105
|
+
_fail("invalid measurement fields")
|
|
106
|
+
if (
|
|
107
|
+
measurement["scope"] != "agent_execution"
|
|
108
|
+
or measurement["usage_provenance"] != "external_reported"
|
|
109
|
+
or measurement["cost_scope"] != "agent_context"
|
|
110
|
+
):
|
|
111
|
+
_fail("unsupported measurement scope/provenance")
|
|
112
|
+
for key in ("runtime_ms", "cost_usd"):
|
|
113
|
+
number = measurement[key]
|
|
114
|
+
if number is not None and (
|
|
115
|
+
type(number) not in {int, float} or not math.isfinite(number) or number < 0
|
|
116
|
+
):
|
|
117
|
+
_fail("measurement must be finite nonnegative or null")
|
|
118
|
+
for key in ("input_tokens", "output_tokens", "cached_input_tokens"):
|
|
119
|
+
number = measurement[key]
|
|
120
|
+
if number is not None and (type(number) is not int or number < 0):
|
|
121
|
+
_fail("usage must be a nonnegative integer or null")
|
|
122
|
+
prompt, cache = measurement["input_tokens"], measurement["cached_input_tokens"]
|
|
123
|
+
if prompt is not None and cache is not None and cache > prompt:
|
|
124
|
+
_fail("cache usage is not a prompt subset")
|
|
125
|
+
if not isinstance(value["pairing"], dict) or set(value["pairing"]) != set(PAIRING_KEYS):
|
|
126
|
+
_fail("invalid pairing metadata")
|
|
127
|
+
for key, item in value["pairing"].items():
|
|
128
|
+
if trace.metadata.get(key) != item:
|
|
129
|
+
_fail("pairing metadata differs from its captured source")
|
|
130
|
+
if item is not None and type(item) not in {str, int, float, bool}:
|
|
131
|
+
_fail("pairing keys must be scalar or absent")
|
|
132
|
+
return json.loads(canonical_json(value))
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def qualify_trial_report(trace: Any, report: dict) -> None:
|
|
136
|
+
evidence = read_trial(trace)
|
|
137
|
+
if evidence is None:
|
|
138
|
+
return
|
|
139
|
+
measurement = evidence["measurement"]
|
|
140
|
+
report["external_trial"] = evidence
|
|
141
|
+
report["total_runtime_ms"] = measurement["runtime_ms"]
|
|
142
|
+
report["input_tokens"], report["output_tokens"] = (
|
|
143
|
+
measurement["input_tokens"],
|
|
144
|
+
measurement["output_tokens"],
|
|
145
|
+
)
|
|
146
|
+
report["token_status"] = (
|
|
147
|
+
"external_reported"
|
|
148
|
+
if measurement["input_tokens"] is not None and measurement["output_tokens"] is not None
|
|
149
|
+
else "partial"
|
|
150
|
+
)
|
|
151
|
+
report["estimated_cost_usd"] = measurement["cost_usd"]
|
|
152
|
+
report["cost_status"] = "complete" if measurement["cost_usd"] is not None else "unknown"
|
|
153
|
+
report["cost_measurement_basis"] = "external_reported_agent_context"
|
|
154
|
+
report["timing_status"] = "complete" if measurement["runtime_ms"] is not None else "unavailable"
|
|
155
|
+
report["model_call_count_basis"] = "no model inference is manufactured from a trial phase"
|
|
156
|
+
for key in (
|
|
157
|
+
"model_call_count",
|
|
158
|
+
"tool_call_count",
|
|
159
|
+
"model_time_ms",
|
|
160
|
+
"tool_time_ms",
|
|
161
|
+
"retry_time_ms",
|
|
162
|
+
):
|
|
163
|
+
report[key] = None
|
|
164
|
+
report["repeated_context_tokens"] = report["repeated_context_ratio"] = None
|
|
165
|
+
report["retry_count"] = None
|
|
166
|
+
if measurement["runtime_ms"] is None:
|
|
167
|
+
for key in ("cumulative_span_time_ms", "model_time_ms", "tool_time_ms", "retry_time_ms"):
|
|
168
|
+
report[key] = None
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def trial_study_values(evidence: dict) -> tuple[float | None, bool | None]:
|
|
172
|
+
outcome = evidence["outcome"]
|
|
173
|
+
status = outcome["execution_status"]
|
|
174
|
+
passed = outcome["quality_pass"]
|
|
175
|
+
success = (
|
|
176
|
+
False
|
|
177
|
+
if status in {"failed", "timed_out", "cancelled"} or passed is False
|
|
178
|
+
else passed
|
|
179
|
+
if status == "completed"
|
|
180
|
+
else None
|
|
181
|
+
)
|
|
182
|
+
# This is a configured binary acceptance indicator, not a normalized reward.
|
|
183
|
+
score = float(passed) if passed is not None and status == "completed" else None
|
|
184
|
+
return score, success
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def require_trial_pair(baseline: Any, candidate: Any) -> None:
|
|
188
|
+
left, right = read_trial(baseline), read_trial(candidate)
|
|
189
|
+
if left is None and right is None:
|
|
190
|
+
return
|
|
191
|
+
if left is None or right is None:
|
|
192
|
+
_fail("external trial comparisons require two compatible trial records")
|
|
193
|
+
for key in PAIRING_KEYS:
|
|
194
|
+
a, b = left["pairing"][key], right["pairing"][key]
|
|
195
|
+
if a is None or b is None or type(a) is not type(b) or a != b:
|
|
196
|
+
_fail("task/scorer/environment/protocol/repetition identity is missing or incompatible")
|