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
agentloop/html_report.py
ADDED
|
@@ -0,0 +1,860 @@
|
|
|
1
|
+
"""Offline HTML analysis artifact with escaped text and no executable trace markup."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import html
|
|
6
|
+
import json
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from agentloop.costs import format_cost_usd
|
|
10
|
+
from agentloop.harness_evidence import METADATA_KEY, HarnessEvidenceError, read_evidence
|
|
11
|
+
from agentloop.timing import event_interval_ms, format_duration_ms
|
|
12
|
+
from agentloop.tracer import AgentTrace
|
|
13
|
+
|
|
14
|
+
_CSS = """
|
|
15
|
+
:root{color-scheme:light;--ink:#172c37;--muted:#526675;--line:#d6e1e6;--accent:#086d79;--paper:#f4f7f8}
|
|
16
|
+
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--paper);color:var(--ink);font:16px/1.55 system-ui,sans-serif}
|
|
17
|
+
main{max-width:1160px;margin:auto;padding:36px 24px 80px}header{border-bottom:3px solid var(--accent);padding-bottom:24px}
|
|
18
|
+
h1{font-size:2rem;line-height:1.2;overflow-wrap:anywhere}h2{margin-top:38px}h3{margin:0 0 12px}p{max-width:90ch}
|
|
19
|
+
a{color:#075b86}a:focus-visible,summary:focus-visible{outline:3px solid #b76308;outline-offset:4px}
|
|
20
|
+
nav{display:flex;flex-wrap:wrap;gap:18px;margin-top:18px}.eyebrow{letter-spacing:.09em;text-transform:uppercase;font-size:.8rem;color:var(--accent);font-weight:700}
|
|
21
|
+
.muted{color:var(--muted)}.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px}
|
|
22
|
+
.metric,article,details.panel{background:white;border:1px solid var(--line);border-radius:9px;padding:18px}.metric strong{display:block;font-size:1.6rem}
|
|
23
|
+
.badge{display:inline-block;background:#e4eef2;padding:2px 8px;border-radius:4px;font-size:.8rem;margin-right:6px}
|
|
24
|
+
.prediction{border-left:4px solid #8a6200}.notice{padding:12px 16px;background:#fff2d8;border-left:4px solid #9c6800}
|
|
25
|
+
.table-wrap{overflow-x:auto}table{width:100%;border-collapse:collapse;background:white}th,td{text-align:left;padding:11px;border-bottom:1px solid var(--line);vertical-align:top}
|
|
26
|
+
th{background:#eaf0f3}caption{text-align:left;color:var(--muted);padding:8px 0}code,pre{font: .88rem/1.5 ui-monospace,monospace}code{overflow-wrap:anywhere}
|
|
27
|
+
pre{white-space:pre-wrap;overflow-wrap:anywhere;background:#edf2f4;padding:14px;border-radius:6px}summary{cursor:pointer;font-weight:600}details{margin:12px 0}
|
|
28
|
+
article{margin:14px 0;scroll-margin-top:20px}tr:target{background:#fff2d8}.track{min-width:180px;background:#e8eff2;height:12px;border-radius:6px}.bar{height:12px;background:var(--accent);border-radius:6px}
|
|
29
|
+
dl{display:grid;grid-template-columns:minmax(140px,1fr) 3fr;gap:7px 16px}dt{color:var(--muted)}dd{margin:0;overflow-wrap:anywhere}
|
|
30
|
+
footer{margin-top:45px;padding-top:16px;border-top:1px solid var(--line);font-size:.85rem;color:var(--muted)}
|
|
31
|
+
@media(max-width:600px){main{padding:20px 12px}h1{font-size:1.65rem}dl{display:block}dd{margin-bottom:10px}}
|
|
32
|
+
@media print{body{background:white}main{max-width:none;padding:0}nav{display:none}article,.metric{break-inside:avoid}a{color:inherit}}
|
|
33
|
+
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _text(value: Any) -> str:
|
|
38
|
+
return html.escape(str(value), quote=True)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _json(value: Any) -> str:
|
|
42
|
+
return (
|
|
43
|
+
"<pre>" + _text(json.dumps(value, indent=2, sort_keys=True, ensure_ascii=False)) + "</pre>"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _definition(items: list[tuple[str, Any]]) -> str:
|
|
48
|
+
return (
|
|
49
|
+
"<dl>"
|
|
50
|
+
+ "".join(f"<dt>{_text(key)}</dt><dd>{_text(value)}</dd>" for key, value in items)
|
|
51
|
+
+ "</dl>"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _table(headers: list[str], rows: list[list[str]], *, caption: str) -> str:
|
|
56
|
+
return (
|
|
57
|
+
'<div class="table-wrap"><table><caption>'
|
|
58
|
+
+ _text(caption)
|
|
59
|
+
+ "</caption><thead><tr>"
|
|
60
|
+
+ "".join(f'<th scope="col">{_text(header)}</th>' for header in headers)
|
|
61
|
+
+ "</tr></thead><tbody>"
|
|
62
|
+
+ "".join("<tr>" + "".join(f"<td>{cell}</td>" for cell in row) + "</tr>" for row in rows)
|
|
63
|
+
+ "</tbody></table></div>"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def cohort_to_html(report: dict[str, Any]) -> str:
|
|
68
|
+
"""Render full-population cohort evidence with the existing local report styles."""
|
|
69
|
+
sections = [
|
|
70
|
+
'<!doctype html><html lang="en"><head><meta charset="utf-8">',
|
|
71
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
72
|
+
"<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'\">",
|
|
73
|
+
f"<title>{_text(report['name'])}</title><style>{_CSS}</style></head><body><main><h1>{_text(report['name'])}</h1>",
|
|
74
|
+
'<p class="notice">External source evidence. Correctness, execution and source coverage are independent gates. No causal harness effect or estimator attribution is invented.</p>',
|
|
75
|
+
]
|
|
76
|
+
if report["synthetic"]:
|
|
77
|
+
sections.append(
|
|
78
|
+
'<p class="notice">Synthetic inputs: these reports demonstrate validation and do not establish empirical performance benefits.</p>'
|
|
79
|
+
)
|
|
80
|
+
sections.append(
|
|
81
|
+
_table(
|
|
82
|
+
["Condition", "Attempts retained", "Accepted", "Rejected", "Indeterminate"],
|
|
83
|
+
[
|
|
84
|
+
[
|
|
85
|
+
_text(condition),
|
|
86
|
+
_text(population["denominator"]),
|
|
87
|
+
_text(population["accepted"]),
|
|
88
|
+
_text(population["rejected"]),
|
|
89
|
+
_text(population["acceptance_indeterminate"]),
|
|
90
|
+
]
|
|
91
|
+
for condition, population in report["conditions"].items()
|
|
92
|
+
],
|
|
93
|
+
caption="Complete observed and planned attempt populations",
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
for condition, comparison in report["comparisons"].items():
|
|
97
|
+
sections.extend(
|
|
98
|
+
[
|
|
99
|
+
f"<h2>Baseline vs {_text(condition)}</h2>",
|
|
100
|
+
f"<p>Comparison: {_text(comparison['comparison_kind'])}; causal harness effect not established.</p>",
|
|
101
|
+
_table(
|
|
102
|
+
["Task", "Outcome", "Runtime improvement"],
|
|
103
|
+
[
|
|
104
|
+
[
|
|
105
|
+
_text(pair["pairing_metadata"]["task_id"]),
|
|
106
|
+
_text(pair["state"]),
|
|
107
|
+
_text(
|
|
108
|
+
pair["runtime_improvement_pct"]
|
|
109
|
+
if pair["runtime_improvement_pct"] is not None
|
|
110
|
+
else "unavailable"
|
|
111
|
+
),
|
|
112
|
+
]
|
|
113
|
+
for pair in comparison["pairs"]
|
|
114
|
+
],
|
|
115
|
+
caption="Independent task-quality and source-evidence gates",
|
|
116
|
+
),
|
|
117
|
+
_definition(
|
|
118
|
+
[
|
|
119
|
+
("Unpaired records", comparison["unpaired_count"]),
|
|
120
|
+
(
|
|
121
|
+
"Planned unidentified candidate attempts",
|
|
122
|
+
comparison["quality_preserving_intervention_rate"][
|
|
123
|
+
"unidentified_planned_attempts"
|
|
124
|
+
],
|
|
125
|
+
),
|
|
126
|
+
(
|
|
127
|
+
"Verified improvements / candidate attempts",
|
|
128
|
+
f"{comparison['quality_preserving_intervention_rate']['numerator']} / {comparison['quality_preserving_intervention_rate']['denominator']}",
|
|
129
|
+
),
|
|
130
|
+
]
|
|
131
|
+
),
|
|
132
|
+
]
|
|
133
|
+
)
|
|
134
|
+
sections.append("</main></body></html>")
|
|
135
|
+
return "\n".join(sections)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def coordination_to_html(report: dict[str, Any]) -> str:
|
|
139
|
+
"""Render source-qualified bundle coordination with the local report styles."""
|
|
140
|
+
sections = [
|
|
141
|
+
'<!doctype html><html lang="en"><head><meta charset="utf-8">',
|
|
142
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
143
|
+
"<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'\">",
|
|
144
|
+
f"<title>AgentLoop coordination</title><style>{_CSS}</style></head><body><main><h1>Recorded coordination</h1>",
|
|
145
|
+
'<p class="notice">External observations. Missing timing is unavailable, child runtime is not caller wait, and overlap does not prove independent work. Reviewer labels do not establish correctness.</p>',
|
|
146
|
+
]
|
|
147
|
+
if report["synthetic"]:
|
|
148
|
+
sections.append(
|
|
149
|
+
'<p class="notice">Synthetic inputs: no empirical performance or quality benefit is established.</p>'
|
|
150
|
+
)
|
|
151
|
+
sections.append(
|
|
152
|
+
_definition(
|
|
153
|
+
[
|
|
154
|
+
("Recorded handoffs", report["handoff_count"]),
|
|
155
|
+
(
|
|
156
|
+
"Observed / unknown children",
|
|
157
|
+
f"{report['observed_child_count']} / {report['unknown_child_count']}",
|
|
158
|
+
),
|
|
159
|
+
("Recorded child failures", report["child_failure_count"]),
|
|
160
|
+
("Caller wait", format_duration_ms(report["handoff_wait_ms"])),
|
|
161
|
+
("Observed overlap", format_duration_ms(report["parallel_overlap_ms"])),
|
|
162
|
+
("Critical path", format_duration_ms(report["critical_path_ms"])),
|
|
163
|
+
(
|
|
164
|
+
"Possible duplicate work",
|
|
165
|
+
report["possible_duplicate_work_count"]
|
|
166
|
+
if report["possible_duplicate_work_count"] is not None
|
|
167
|
+
else "unavailable",
|
|
168
|
+
),
|
|
169
|
+
]
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
sections.append(
|
|
173
|
+
_table(
|
|
174
|
+
["Agent", "Declared role", "Session / document", "Recorded runtime", "Status"],
|
|
175
|
+
[
|
|
176
|
+
[
|
|
177
|
+
_text(actor["agent_name"] or "unknown"),
|
|
178
|
+
_text(actor["declared_role"] or "unknown"),
|
|
179
|
+
_text(
|
|
180
|
+
actor["source_identity"]["trajectory_id"]
|
|
181
|
+
or actor["session_id"]
|
|
182
|
+
or "unknown"
|
|
183
|
+
),
|
|
184
|
+
_text(format_duration_ms(actor["runtime_ms"])),
|
|
185
|
+
_text(actor["execution_status"]),
|
|
186
|
+
]
|
|
187
|
+
for actor in report["actors"]
|
|
188
|
+
],
|
|
189
|
+
caption="Distinct source actors; shared sessions preserve document and trace identities",
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
sections.extend(
|
|
193
|
+
[
|
|
194
|
+
"<h2>Evidence coverage and limitations</h2>",
|
|
195
|
+
_json(report["overlap_coverage"]),
|
|
196
|
+
"<ul>"
|
|
197
|
+
+ "".join("<li>" + _text(item) + "</li>" for item in report["limitations"])
|
|
198
|
+
+ "</ul>",
|
|
199
|
+
"<p>Inclusive usage remains separate from attributed model leaves. Retries, safe reuse, review overhead and review quality effects require additional evidence.</p></main></body></html>",
|
|
200
|
+
]
|
|
201
|
+
)
|
|
202
|
+
return "\n".join(sections)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def analysis_to_html(payload: dict[str, Any], *, include_content: bool = False) -> str:
|
|
206
|
+
"""Render the combined `analyze` payload. All source values enter as escaped text."""
|
|
207
|
+
required = {"trace", "report", "diagnosis", "optimization"}
|
|
208
|
+
if (
|
|
209
|
+
not isinstance(payload, dict)
|
|
210
|
+
or not required <= payload.keys()
|
|
211
|
+
or any(not isinstance(payload[key], dict) for key in required)
|
|
212
|
+
):
|
|
213
|
+
raise ValueError("expected a combined trace, report, diagnosis, and optimization payload")
|
|
214
|
+
trace = AgentTrace.from_dict(payload["trace"])
|
|
215
|
+
report, diagnosis, plan = payload["report"], payload["diagnosis"], payload["optimization"]
|
|
216
|
+
nodes = plan.get("graph", {}).get("nodes", [])
|
|
217
|
+
anchors = {node["node_id"]: f"span-{index}" for index, node in enumerate(nodes)}
|
|
218
|
+
harness_link = (
|
|
219
|
+
'<a href="#harness">Harness decisions</a>' if METADATA_KEY in trace.metadata else ""
|
|
220
|
+
)
|
|
221
|
+
sections = [
|
|
222
|
+
'<!doctype html><html lang="en"><head><meta charset="utf-8">',
|
|
223
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
224
|
+
"<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'\">",
|
|
225
|
+
f"<title>{_text(trace.name)} — AgentLoop analysis</title><style>{_CSS}</style></head><body><main>",
|
|
226
|
+
f'<header><div class="eyebrow">AgentLoop · analysis artifact</div><h1>{_text(trace.name)}</h1>',
|
|
227
|
+
f'<p class="muted">Run <code>{_text(trace.run_id)}</code></p>',
|
|
228
|
+
f'<nav aria-label="Report sections"><a href="#overview">Overview</a><a href="#timeline">Timeline</a><a href="#findings">Findings</a><a href="#comparison">Comparison</a>{harness_link}<a href="#metadata">Metadata</a></nav></header>',
|
|
229
|
+
'<section id="overview"><h2>Recorded execution</h2>',
|
|
230
|
+
]
|
|
231
|
+
if trace.metadata.get("synthetic") is True:
|
|
232
|
+
sections.append(
|
|
233
|
+
'<p class="notice">Synthetic trace: these results demonstrate analysis and are not application performance evidence.</p>'
|
|
234
|
+
)
|
|
235
|
+
if trace.metadata.get("execution_data_present") is False:
|
|
236
|
+
sections.append(
|
|
237
|
+
'<p class="notice">No execution spans were supplied. This artifact contains external evaluation metadata.</p>'
|
|
238
|
+
)
|
|
239
|
+
if report.get("external_evidence") is not None:
|
|
240
|
+
external = report["external_evidence"]
|
|
241
|
+
sections.append(
|
|
242
|
+
'<p class="notice">External execution evidence: source status and usage are reported, not independently verified. Unavailable durations are not measured zero; task correctness requires a separate verifier.</p>'
|
|
243
|
+
+ _definition(
|
|
244
|
+
[
|
|
245
|
+
("Source system", external["source"].get("system", "unknown")),
|
|
246
|
+
("Source format", external["source"].get("format", "unknown")),
|
|
247
|
+
("Source receipt", external["receipt_id"]),
|
|
248
|
+
("Source execution status", external["execution_status"]),
|
|
249
|
+
("Reported model call multiplicity", external["reported_model_call_count"]),
|
|
250
|
+
]
|
|
251
|
+
)
|
|
252
|
+
)
|
|
253
|
+
if report.get("omnigent_observations") is not None:
|
|
254
|
+
observed = report["omnigent_observations"]
|
|
255
|
+
sections.append(
|
|
256
|
+
"<h3>Omnigent observations</h3>"
|
|
257
|
+
+ _definition(
|
|
258
|
+
[
|
|
259
|
+
("Agents", ", ".join(observed["agent_names"]) or "unknown"),
|
|
260
|
+
("Session", observed["source_identity"]["session_id"] or "unknown"),
|
|
261
|
+
("Executor model coverage", observed["model_coverage"]),
|
|
262
|
+
("Policy enforcement", observed["enforcement"]),
|
|
263
|
+
("Task correctness", observed["task_correctness"]),
|
|
264
|
+
]
|
|
265
|
+
)
|
|
266
|
+
+ '<p class="notice">Policy verdicts and tool spans are external observations. A DENY or ASK does not prove prevention or approval. Sessions retain separate trace identities; links do not establish causal dependencies.</p>'
|
|
267
|
+
+ _table(
|
|
268
|
+
["Policy", "Phase", "Decision", "Dispatch prevention"],
|
|
269
|
+
[
|
|
270
|
+
[
|
|
271
|
+
_text(item["name"] or "unknown"),
|
|
272
|
+
_text(item["phase"] or "unknown"),
|
|
273
|
+
_text(item["action"]),
|
|
274
|
+
_text(item["dispatch_prevention"]),
|
|
275
|
+
]
|
|
276
|
+
for item in observed["policy_decisions"]
|
|
277
|
+
],
|
|
278
|
+
caption="Externally reported policy decisions; enforcement remains unverified",
|
|
279
|
+
)
|
|
280
|
+
+ _table(
|
|
281
|
+
["Observed role", "Spans", "Interval union", "Coverage"],
|
|
282
|
+
[
|
|
283
|
+
[
|
|
284
|
+
_text(role),
|
|
285
|
+
_text(value["spans"]),
|
|
286
|
+
_text(format_duration_ms(value["interval_union_ms"])),
|
|
287
|
+
_text(value["coverage"]),
|
|
288
|
+
]
|
|
289
|
+
for role, value in observed["timing_by_role"].items()
|
|
290
|
+
],
|
|
291
|
+
caption="Role intervals are separate observations; cumulative values can overlap",
|
|
292
|
+
)
|
|
293
|
+
)
|
|
294
|
+
if report.get("execution") is not None:
|
|
295
|
+
execution = report["execution"]
|
|
296
|
+
sections.append(
|
|
297
|
+
"<h3>Workflow</h3>"
|
|
298
|
+
+ _definition(
|
|
299
|
+
[
|
|
300
|
+
(key.replace("_", " ").title(), value)
|
|
301
|
+
for key, value in execution.items()
|
|
302
|
+
if value is not None
|
|
303
|
+
]
|
|
304
|
+
)
|
|
305
|
+
)
|
|
306
|
+
sections.append(
|
|
307
|
+
'<p class="notice">Cost and token totals cover recorded model calls. A completed execution or outcome label is not independent task-quality evidence.</p>'
|
|
308
|
+
)
|
|
309
|
+
dependency_evidence = plan.get("graph", {}).get("dependency_evidence")
|
|
310
|
+
if "semantic_waste" in report:
|
|
311
|
+
semantic = report["semantic_waste"]
|
|
312
|
+
sections.append(
|
|
313
|
+
'<section id="semantic-investigations"><h2>Offline semantic investigations</h2>'
|
|
314
|
+
"<p>These investigations use explicit task criteria and source-bound evidence. "
|
|
315
|
+
"Unknowns, disagreement and stale evidence do not produce recommendations. "
|
|
316
|
+
"Any savings are conditional estimates requiring independent replay validation.</p>"
|
|
317
|
+
+ _table(
|
|
318
|
+
["Investigation", "Family", "Status", "Evidence basis"],
|
|
319
|
+
[
|
|
320
|
+
[
|
|
321
|
+
_text(item["definition"]["investigation_id"]),
|
|
322
|
+
_text(item["definition"]["family"]),
|
|
323
|
+
_text(item["status"]),
|
|
324
|
+
_text(item["basis"]),
|
|
325
|
+
]
|
|
326
|
+
for item in semantic["cases"]
|
|
327
|
+
],
|
|
328
|
+
caption="Investigation completeness: " + semantic["status"],
|
|
329
|
+
)
|
|
330
|
+
+ "</section>"
|
|
331
|
+
)
|
|
332
|
+
if "semantic_judgments" in report:
|
|
333
|
+
sections.append(
|
|
334
|
+
'<section id="judgments"><h2>Offline semantic judgments</h2>'
|
|
335
|
+
"<p>Recorded execution facts, deterministic rule inferences, and semantic "
|
|
336
|
+
"judge answers are separate evidence categories. Judge answers do not "
|
|
337
|
+
"establish task quality or calibrated confidence. Judge latency and cost "
|
|
338
|
+
"are analysis overhead, separate from workflow totals.</p>"
|
|
339
|
+
+ _table(
|
|
340
|
+
[
|
|
341
|
+
"Judge / version",
|
|
342
|
+
"Question",
|
|
343
|
+
"Status",
|
|
344
|
+
"Answer",
|
|
345
|
+
"Confidence basis",
|
|
346
|
+
"Incurred cost USD",
|
|
347
|
+
],
|
|
348
|
+
[
|
|
349
|
+
[
|
|
350
|
+
_text(f"{item['judge']['implementation']} / {item['judge']['version']}"),
|
|
351
|
+
_text(item["request"]["spec"]["question"]),
|
|
352
|
+
_text(item["effective_status"]),
|
|
353
|
+
_text(
|
|
354
|
+
"unavailable"
|
|
355
|
+
if item["effective_value"] is None
|
|
356
|
+
else item["effective_value"]
|
|
357
|
+
),
|
|
358
|
+
_text(item["evaluation"]["uncertainty"]["calibration_status"]),
|
|
359
|
+
_text(
|
|
360
|
+
"unavailable"
|
|
361
|
+
if item["invocation"]["usage"]["cost_usd"] is None
|
|
362
|
+
else item["invocation"]["usage"]["cost_usd"]
|
|
363
|
+
),
|
|
364
|
+
]
|
|
365
|
+
for item in report["semantic_judgments"]["records"]
|
|
366
|
+
],
|
|
367
|
+
caption="Saved judgment evidence: " + report["semantic_judgments"]["status"],
|
|
368
|
+
)
|
|
369
|
+
+ "<details><summary>Archived provenance and usage receipts</summary>"
|
|
370
|
+
+ _json(report["semantic_judgments"])
|
|
371
|
+
+ "</details>"
|
|
372
|
+
+ "</section>"
|
|
373
|
+
)
|
|
374
|
+
if dependency_evidence is not None:
|
|
375
|
+
sections.append(
|
|
376
|
+
"<details><summary>Dependency declarations</summary>"
|
|
377
|
+
+ _json(dependency_evidence)
|
|
378
|
+
+ "</details>"
|
|
379
|
+
)
|
|
380
|
+
if not diagnosis.get("analysis_complete", True):
|
|
381
|
+
sections.append(
|
|
382
|
+
'<p class="notice">Analysis incomplete: one or more finding rules failed.</p>'
|
|
383
|
+
+ _json(diagnosis.get("rule_errors", []))
|
|
384
|
+
)
|
|
385
|
+
metrics = [
|
|
386
|
+
("Elapsed runtime", format_duration_ms(report["total_runtime_ms"], precision=3)),
|
|
387
|
+
("Recorded spans", report["event_count"]),
|
|
388
|
+
("Input / output tokens", f"{report['input_tokens']} / {report['output_tokens']}"),
|
|
389
|
+
(
|
|
390
|
+
"Cost from supplied pricing/usage",
|
|
391
|
+
format_cost_usd(
|
|
392
|
+
report.get("estimated_cost_usd"),
|
|
393
|
+
report.get("cost_status"),
|
|
394
|
+
token_status=report.get("token_status"),
|
|
395
|
+
),
|
|
396
|
+
),
|
|
397
|
+
]
|
|
398
|
+
sections.append(
|
|
399
|
+
'<div class="cards">'
|
|
400
|
+
+ "".join(
|
|
401
|
+
f'<div class="metric"><span>{_text(label)}</span><strong>{_text(value)}</strong></div>'
|
|
402
|
+
for label, value in metrics
|
|
403
|
+
)
|
|
404
|
+
+ "</div>"
|
|
405
|
+
)
|
|
406
|
+
sections.append(
|
|
407
|
+
_definition(
|
|
408
|
+
[
|
|
409
|
+
("Token basis", report.get("token_status", "unspecified")),
|
|
410
|
+
("Cost completeness", report.get("cost_status", "unknown")),
|
|
411
|
+
(
|
|
412
|
+
"Cumulative span time",
|
|
413
|
+
format_duration_ms(report["cumulative_span_time_ms"], precision=3)
|
|
414
|
+
+ "; overlapping/nested work may exceed elapsed runtime",
|
|
415
|
+
),
|
|
416
|
+
]
|
|
417
|
+
)
|
|
418
|
+
)
|
|
419
|
+
sections.append("</section>" + _timeline(trace, nodes, anchors))
|
|
420
|
+
bottlenecks = plan.get("graph", {}).get("bottlenecks", [])
|
|
421
|
+
if bottlenecks:
|
|
422
|
+
rows = []
|
|
423
|
+
for node in bottlenecks:
|
|
424
|
+
label = _text(node["name"])
|
|
425
|
+
if node["node_id"] in anchors:
|
|
426
|
+
label = f'<a href="#{anchors[node["node_id"]]}">{label}</a>'
|
|
427
|
+
rows.append(
|
|
428
|
+
[
|
|
429
|
+
label,
|
|
430
|
+
_text(f"{node['duration_ms']:.3f} ms"),
|
|
431
|
+
_text(f"{node['runtime_share']:.1%}"),
|
|
432
|
+
]
|
|
433
|
+
)
|
|
434
|
+
sections.append(
|
|
435
|
+
"<h2>Longest recorded spans</h2>"
|
|
436
|
+
+ _table(
|
|
437
|
+
["Span", "Duration", "Elapsed runtime share"],
|
|
438
|
+
rows,
|
|
439
|
+
caption="Bottleneck candidates from recorded durations; nested spans can overlap.",
|
|
440
|
+
)
|
|
441
|
+
)
|
|
442
|
+
sections.append(
|
|
443
|
+
'<section id="findings"><h2>Predicted improvements</h2><p>Optimizer savings are uncalibrated hypotheses. Validate a candidate run and its quality before accepting a change.</p>'
|
|
444
|
+
)
|
|
445
|
+
after = plan["estimated_after"]
|
|
446
|
+
if (
|
|
447
|
+
plan.get("savings_aggregation", {}).get("latency_estimate_complete") is False
|
|
448
|
+
or plan.get("savings_aggregation", {}).get("cost_estimate_complete") is False
|
|
449
|
+
):
|
|
450
|
+
sections.append(
|
|
451
|
+
'<p class="notice">Some savings are unavailable; totals cover modeled candidates only.</p>'
|
|
452
|
+
)
|
|
453
|
+
sections.append(
|
|
454
|
+
'<article class="prediction"><h3>Predicted outcome</h3>'
|
|
455
|
+
+ _definition(
|
|
456
|
+
[
|
|
457
|
+
("Estimated runtime", format_duration_ms(after["runtime_ms"], precision=3)),
|
|
458
|
+
(
|
|
459
|
+
"Estimated latency reduction",
|
|
460
|
+
"unavailable"
|
|
461
|
+
if after["latency_reduction_pct"] is None
|
|
462
|
+
else f"{after['latency_reduction_pct']:.2f}%",
|
|
463
|
+
),
|
|
464
|
+
(
|
|
465
|
+
"Estimated cost",
|
|
466
|
+
format_cost_usd(after.get("estimated_cost_usd"), after.get("cost_status")),
|
|
467
|
+
),
|
|
468
|
+
]
|
|
469
|
+
)
|
|
470
|
+
+ "<details><summary>Compatible finding selection</summary><p>Exact selection describes the chosen combination; it does not calibrate the savings predictions.</p>"
|
|
471
|
+
+ _json(plan.get("savings_aggregation", {}))
|
|
472
|
+
+ "</details></article>"
|
|
473
|
+
)
|
|
474
|
+
findings = diagnosis.get("findings", [])
|
|
475
|
+
if diagnosis.get("ranking"):
|
|
476
|
+
sections.append(
|
|
477
|
+
"<p>Investigation order: "
|
|
478
|
+
+ _text(diagnosis["ranking"]["sort_by"])
|
|
479
|
+
+ ". Readiness and missing inputs are separate from estimated savings; ranking does not authorize a change.</p>"
|
|
480
|
+
)
|
|
481
|
+
if not findings:
|
|
482
|
+
sections.append("<p>No optimization findings were detected.</p>")
|
|
483
|
+
for index, finding in enumerate(findings):
|
|
484
|
+
sections.append(_finding(finding, index, anchors))
|
|
485
|
+
sections.append(
|
|
486
|
+
'</section><section id="comparison"><h2>Observed baseline / candidate comparison</h2>'
|
|
487
|
+
)
|
|
488
|
+
replay = payload.get("replay")
|
|
489
|
+
if replay:
|
|
490
|
+
sections.append(_comparison(replay))
|
|
491
|
+
else:
|
|
492
|
+
sections.append(
|
|
493
|
+
"<p>No baseline was supplied. Predicted improvements above have not been verified by this report.</p>"
|
|
494
|
+
)
|
|
495
|
+
metadata = dict(trace.metadata)
|
|
496
|
+
harness_section = ""
|
|
497
|
+
if METADATA_KEY in metadata:
|
|
498
|
+
metadata.pop(METADATA_KEY)
|
|
499
|
+
harness_section = _harness_section(trace, anchors, include_content=include_content)
|
|
500
|
+
sections.append(
|
|
501
|
+
"</section>"
|
|
502
|
+
+ harness_section
|
|
503
|
+
+ '<section id="metadata"><h2>Trace and research metadata</h2><p class="notice">Metadata may contain private text or identifiers. Review it before sharing this file.</p>'
|
|
504
|
+
+ _json(metadata)
|
|
505
|
+
)
|
|
506
|
+
if include_content:
|
|
507
|
+
sections.append(
|
|
508
|
+
'<p class="notice">Raw prompts, outputs, errors, and event metadata are included below. Review this content before sharing.</p><details class="panel"><summary>Included event content</summary>'
|
|
509
|
+
+ _json([event.to_dict() for event in trace.events])
|
|
510
|
+
+ "</details>"
|
|
511
|
+
)
|
|
512
|
+
else:
|
|
513
|
+
sections.append(
|
|
514
|
+
"<p>Raw event text and full event metadata are omitted. Finding evidence and trace metadata remain included.</p>"
|
|
515
|
+
)
|
|
516
|
+
sections.append(
|
|
517
|
+
"</section><footer>Generated by AgentLoop. This file contains embedded styles and requires no network connection.</footer></main></body></html>"
|
|
518
|
+
)
|
|
519
|
+
return "\n".join(sections) + "\n"
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def _harness_section(trace: AgentTrace, anchors: dict[str, str], *, include_content: bool) -> str:
|
|
523
|
+
opening = '<section id="harness"><h2>Harness decisions</h2>'
|
|
524
|
+
try:
|
|
525
|
+
evidence = read_evidence(trace)
|
|
526
|
+
except HarnessEvidenceError:
|
|
527
|
+
return (
|
|
528
|
+
opening
|
|
529
|
+
+ '<p class="notice">Harness evidence is invalid or unsupported. Its raw content is omitted.</p></section>'
|
|
530
|
+
)
|
|
531
|
+
if evidence is None:
|
|
532
|
+
return opening + "<p>No decision evidence was retained.</p></section>"
|
|
533
|
+
records = dict(
|
|
534
|
+
sorted(
|
|
535
|
+
evidence["decisions"].items(),
|
|
536
|
+
key=lambda item: (
|
|
537
|
+
item[1]["run_id"],
|
|
538
|
+
-1 if item[1]["hook_sequence"] is None else item[1]["hook_sequence"],
|
|
539
|
+
item[1]["policy_order"],
|
|
540
|
+
item[0],
|
|
541
|
+
),
|
|
542
|
+
)
|
|
543
|
+
)
|
|
544
|
+
links = {identity: f"harness-decision-{index}" for index, identity in enumerate(records)}
|
|
545
|
+
content = [
|
|
546
|
+
opening,
|
|
547
|
+
"<p>Decisions record proposed and applied controls, not proven benefits. Shadow proposals are not executed interventions. Individual policy effects remain unverified; use an intervention comparison with explicit quality gates.</p>",
|
|
548
|
+
]
|
|
549
|
+
if evidence["capture_errors"]:
|
|
550
|
+
content.append(
|
|
551
|
+
'<p class="notice">Decision capture was incomplete.</p>'
|
|
552
|
+
+ _json(evidence["capture_errors"])
|
|
553
|
+
)
|
|
554
|
+
hook_times = {}
|
|
555
|
+
for record in records.values():
|
|
556
|
+
hook_times.setdefault(record["hook_id"], record["timing"]["hook_duration_ms"])
|
|
557
|
+
known = [duration for duration in hook_times.values() if duration is not None]
|
|
558
|
+
content.append(
|
|
559
|
+
_definition(
|
|
560
|
+
[
|
|
561
|
+
("Decision records", len(records)),
|
|
562
|
+
("Distinct evaluated hooks", len(hook_times)),
|
|
563
|
+
(
|
|
564
|
+
"Measured cumulative hook evaluation",
|
|
565
|
+
f"{sum(known):.3f} ms across {len(known)} hooks; includes lock wait, excludes evidence serialization; concurrent hooks may overlap",
|
|
566
|
+
),
|
|
567
|
+
(
|
|
568
|
+
"Model/tool usage",
|
|
569
|
+
"Policy timing is separate from model/tool spans and carries no invented token or cost usage",
|
|
570
|
+
),
|
|
571
|
+
]
|
|
572
|
+
)
|
|
573
|
+
)
|
|
574
|
+
for identity, record in records.items():
|
|
575
|
+
span = record["span_id"]
|
|
576
|
+
span_link = (
|
|
577
|
+
f'<a href="#{anchors[span]}">{_text(span)}</a>'
|
|
578
|
+
if span in anchors
|
|
579
|
+
else _text(span or "not recorded")
|
|
580
|
+
)
|
|
581
|
+
related = ([record["retry_of"]] if record["retry_of"] is not None else []) + record[
|
|
582
|
+
"conflicting_decision_ids"
|
|
583
|
+
]
|
|
584
|
+
related_links = [
|
|
585
|
+
f'<a href="#{links[item]}">{_text(item)}</a>'
|
|
586
|
+
if item in links
|
|
587
|
+
else _text(item) + " (not retained)"
|
|
588
|
+
for item in related
|
|
589
|
+
]
|
|
590
|
+
content.append(
|
|
591
|
+
f'<article id="{links[identity]}"><h3>{_text(record["policy_id"])} · {_text(record["outcome"])}</h3>'
|
|
592
|
+
+ _definition(
|
|
593
|
+
[
|
|
594
|
+
("Decision", identity),
|
|
595
|
+
("Run / branch", f"{record['run_id']} / {record['branch_id']}"),
|
|
596
|
+
("Policy version", record["policy_version"]),
|
|
597
|
+
("Mode", record["mode"]),
|
|
598
|
+
("Boundary", f"{record['boundary']}/{record['phase']}"),
|
|
599
|
+
(
|
|
600
|
+
"Requested / resolved action",
|
|
601
|
+
f"{record['requested_action']} / {record['resolved_action']}",
|
|
602
|
+
),
|
|
603
|
+
("Invocation attempted", record["dispatched"]),
|
|
604
|
+
("Execution status", record["execution_status"]),
|
|
605
|
+
("Reason", record["reason_code"]),
|
|
606
|
+
("Diagnostic feedback", record.get("feedback") or "none"),
|
|
607
|
+
(
|
|
608
|
+
"Budget snapshot",
|
|
609
|
+
"unavailable" if record["budget_snapshot"] is None else "recorded",
|
|
610
|
+
),
|
|
611
|
+
]
|
|
612
|
+
)
|
|
613
|
+
+ f"<p>Parent span: {span_link}</p><p>Retry / conflict links: {', '.join(related_links) or 'none'}</p>"
|
|
614
|
+
+ "<details><summary>Decision provenance and timing</summary>"
|
|
615
|
+
+ _json(record)
|
|
616
|
+
+ "</details></article>"
|
|
617
|
+
)
|
|
618
|
+
policies = evidence["policies"]
|
|
619
|
+
if not include_content:
|
|
620
|
+
for snapshot in policies.values():
|
|
621
|
+
snapshot["configuration"] = None
|
|
622
|
+
snapshot["configuration_capture"] = "redacted"
|
|
623
|
+
content.append(
|
|
624
|
+
"<details><summary>Historical policy declarations</summary><p>Configuration hashes identify snapshots; fingerprints do not anonymize data. Raw configuration requires explicit capture and content inclusion.</p>"
|
|
625
|
+
+ _json(policies)
|
|
626
|
+
+ "</details></section>"
|
|
627
|
+
)
|
|
628
|
+
return "".join(content)
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
def _timeline(trace: AgentTrace, nodes: list[dict[str, Any]], anchors: dict[str, str]) -> str:
|
|
632
|
+
intervals = {event.event_id: event_interval_ms(event) for event in trace.events}
|
|
633
|
+
known = [interval for interval in intervals.values() if interval is not None]
|
|
634
|
+
start = min((interval[0] for interval in known), default=0)
|
|
635
|
+
extent = max((interval[1] for interval in known), default=start) - start
|
|
636
|
+
rows = []
|
|
637
|
+
for node in nodes:
|
|
638
|
+
interval = intervals.get(node["node_id"])
|
|
639
|
+
bar = "Timing unavailable"
|
|
640
|
+
if interval is not None and extent > 0:
|
|
641
|
+
offset = max(0.0, min(100.0, (interval[0] - start) / extent * 100))
|
|
642
|
+
width = max(0.0, min(100 - offset, (interval[1] - interval[0]) / extent * 100))
|
|
643
|
+
bar = f'<div class="track" aria-hidden="true"><div class="bar" style="margin-left:{offset:.4f}%;width:{width:.4f}%"></div></div>'
|
|
644
|
+
parent = node.get("parent_id")
|
|
645
|
+
parent_link = (
|
|
646
|
+
f'<a href="#{anchors[parent]}">{_text(parent)}</a>'
|
|
647
|
+
if parent in anchors
|
|
648
|
+
else _text(parent or "root")
|
|
649
|
+
)
|
|
650
|
+
stage = node.get("stage")
|
|
651
|
+
stage_detail = ""
|
|
652
|
+
if stage is not None:
|
|
653
|
+
stage_detail = (
|
|
654
|
+
"<details><summary>Stage: "
|
|
655
|
+
+ _text(stage.get("stage_id") or stage.get("schema_status"))
|
|
656
|
+
+ "</summary>"
|
|
657
|
+
)
|
|
658
|
+
stage_detail += _definition(
|
|
659
|
+
[
|
|
660
|
+
(key.replace("_", " ").title(), stage.get(key))
|
|
661
|
+
for key in (
|
|
662
|
+
"version",
|
|
663
|
+
"kind",
|
|
664
|
+
"input_schema_ref",
|
|
665
|
+
"output_schema_ref",
|
|
666
|
+
"input_ref",
|
|
667
|
+
"output_ref",
|
|
668
|
+
"outcome",
|
|
669
|
+
)
|
|
670
|
+
if stage.get(key) is not None
|
|
671
|
+
]
|
|
672
|
+
)
|
|
673
|
+
links = [
|
|
674
|
+
f'<a href="#{anchors[source]}">{_text(source)}</a>'
|
|
675
|
+
if source in anchors
|
|
676
|
+
else _text(source) + " (unresolved)"
|
|
677
|
+
for source in stage.get("depends_on", [])
|
|
678
|
+
]
|
|
679
|
+
if links:
|
|
680
|
+
stage_detail += "<p>Depends on: " + ", ".join(links) + "</p>"
|
|
681
|
+
stage_detail += "</details>"
|
|
682
|
+
rows.append(
|
|
683
|
+
f'<tr id="{anchors[node["node_id"]]}"><td>{_text(node["name"])}<br><code>{_text(node["node_id"])}</code>{stage_detail}</td><td>{_text(node.get("operation_kind", node["event_type"]))}</td><td>{_text(format_duration_ms(node["duration_ms"], unit="ms", precision=3))}</td><td>{bar}</td><td>{parent_link}</td></tr>'
|
|
684
|
+
)
|
|
685
|
+
return (
|
|
686
|
+
'<section id="timeline"><h2>Execution timeline</h2><div class="table-wrap"><table><caption>Recorded span timing and parent structure. Bars show relative timestamps, not predicted savings.</caption><thead><tr><th scope="col">Span</th><th scope="col">Operation</th><th scope="col">Duration</th><th scope="col">Relative timing</th><th scope="col">Parent</th></tr></thead><tbody>'
|
|
687
|
+
+ "".join(rows)
|
|
688
|
+
+ "</tbody></table></div>"
|
|
689
|
+
+ ("<p>No execution spans.</p>" if not rows else "")
|
|
690
|
+
+ "</section>"
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
def _finding(finding: dict[str, Any], index: int, anchors: dict[str, str]) -> str:
|
|
695
|
+
savings = finding["savings"]
|
|
696
|
+
evidence = finding.get("evidence_level", "inferred")
|
|
697
|
+
result = f'<article class="prediction" id="finding-{index}"><span class="badge">{_text(evidence)} evidence</span><span class="badge">{_text(finding["confidence"])} confidence</span><h3>{_text(finding["title"])}</h3>'
|
|
698
|
+
result += f"<p>{_text(finding.get('metadata', {}).get('why', ''))}</p>"
|
|
699
|
+
if finding.get("ranking"):
|
|
700
|
+
ranking = finding["ranking"]
|
|
701
|
+
result += _definition(
|
|
702
|
+
[
|
|
703
|
+
("Investigation priority", ranking["priority_rank"]),
|
|
704
|
+
("Test readiness", ranking["status"].replace("_", " ")),
|
|
705
|
+
(
|
|
706
|
+
"Why",
|
|
707
|
+
"; ".join(reason.replace("_", " ") for reason in ranking["reasons"])
|
|
708
|
+
or "Required inputs are complete; compare the declared ranking components.",
|
|
709
|
+
),
|
|
710
|
+
]
|
|
711
|
+
)
|
|
712
|
+
result += (
|
|
713
|
+
"<details><summary>Ranking components, input references and ordering</summary>"
|
|
714
|
+
+ _json(
|
|
715
|
+
{
|
|
716
|
+
key: ranking[key]
|
|
717
|
+
for key in (
|
|
718
|
+
"method",
|
|
719
|
+
"order",
|
|
720
|
+
"components",
|
|
721
|
+
"required_inputs",
|
|
722
|
+
"reasons",
|
|
723
|
+
"invalid_inputs",
|
|
724
|
+
"automatic_application_allowed",
|
|
725
|
+
)
|
|
726
|
+
}
|
|
727
|
+
)
|
|
728
|
+
+ "</details>"
|
|
729
|
+
)
|
|
730
|
+
result += _definition(
|
|
731
|
+
[
|
|
732
|
+
("Finding ID", finding["finding_id"]),
|
|
733
|
+
(
|
|
734
|
+
"Estimated latency savings",
|
|
735
|
+
format_duration_ms(savings["estimated_latency_savings_ms"], unit="ms", precision=3),
|
|
736
|
+
),
|
|
737
|
+
("Estimated cost savings", format_cost_usd(savings.get("estimated_cost_savings_usd"))),
|
|
738
|
+
("Proposed change", finding["rewrite"]["hint"]),
|
|
739
|
+
("Validation", finding["validation"]["acceptance_criteria"]),
|
|
740
|
+
]
|
|
741
|
+
)
|
|
742
|
+
links = [
|
|
743
|
+
f'<a href="#{anchors[span]}">{_text(span)}</a>' if span in anchors else _text(span)
|
|
744
|
+
for span in finding.get("affected_spans", [])
|
|
745
|
+
]
|
|
746
|
+
result += "<p>Evidence spans: " + (", ".join(links) or "none") + "</p>"
|
|
747
|
+
if finding.get("observations", {}).get("investigation_id"):
|
|
748
|
+
result += (
|
|
749
|
+
"<details><summary>Semantic investigation and judge provenance</summary>"
|
|
750
|
+
+ _json(finding["observations"])
|
|
751
|
+
+ "</details>"
|
|
752
|
+
)
|
|
753
|
+
estimate = finding.get("estimate")
|
|
754
|
+
if estimate:
|
|
755
|
+
result += (
|
|
756
|
+
"<details><summary>Estimator, assumptions, and observed inputs</summary>"
|
|
757
|
+
+ _json(estimate)
|
|
758
|
+
+ "</details>"
|
|
759
|
+
)
|
|
760
|
+
else:
|
|
761
|
+
result += (
|
|
762
|
+
"<details><summary>Assumptions and formula</summary>"
|
|
763
|
+
+ _json(
|
|
764
|
+
{"assumptions": finding.get("assumptions", []), "formula": savings.get("formula")}
|
|
765
|
+
)
|
|
766
|
+
+ "</details>"
|
|
767
|
+
)
|
|
768
|
+
result += (
|
|
769
|
+
"<details><summary>Recorded finding evidence</summary>"
|
|
770
|
+
+ _json(finding.get("evidence", []))
|
|
771
|
+
+ "</details></article>"
|
|
772
|
+
)
|
|
773
|
+
return result
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
def _comparison(replay: dict[str, Any]) -> str:
|
|
777
|
+
rows = []
|
|
778
|
+
for label, key in (
|
|
779
|
+
("Run", "run_id"),
|
|
780
|
+
("Elapsed runtime (ms)", "runtime_ms"),
|
|
781
|
+
("Cost", "estimated_cost_usd"),
|
|
782
|
+
("Token basis", "token_status"),
|
|
783
|
+
("Quality score", "quality_score"),
|
|
784
|
+
):
|
|
785
|
+
values = []
|
|
786
|
+
for side in ("baseline", "candidate"):
|
|
787
|
+
run = replay[side]
|
|
788
|
+
value = run.get(key)
|
|
789
|
+
if key == "estimated_cost_usd":
|
|
790
|
+
value = format_cost_usd(
|
|
791
|
+
value, run.get("cost_status"), token_status=run.get("token_status")
|
|
792
|
+
)
|
|
793
|
+
values.append(_text("unavailable" if value is None else value))
|
|
794
|
+
rows.append([_text(label), *values])
|
|
795
|
+
if "decision_count_delta" in replay["deltas"]:
|
|
796
|
+
for label, key in (
|
|
797
|
+
("Recorded model calls", "model_call_count"),
|
|
798
|
+
("Recorded tool calls", "tool_call_count"),
|
|
799
|
+
("Recorded decision spans", "decision_count"),
|
|
800
|
+
("Recorded error spans", "error_span_count"),
|
|
801
|
+
):
|
|
802
|
+
rows.append(
|
|
803
|
+
[
|
|
804
|
+
_text(label),
|
|
805
|
+
*[_text(replay[side].get(key)) for side in ("baseline", "candidate")],
|
|
806
|
+
]
|
|
807
|
+
)
|
|
808
|
+
result = _table(
|
|
809
|
+
["Recorded metric", "Baseline", "Candidate"],
|
|
810
|
+
rows,
|
|
811
|
+
caption="Observed trace comparison; costs retain their recorded pricing and token basis.",
|
|
812
|
+
)
|
|
813
|
+
deltas = replay["deltas"]
|
|
814
|
+
result += "<h3>Observed deltas</h3>" + _table(
|
|
815
|
+
["Metric", "Candidate minus baseline"],
|
|
816
|
+
[
|
|
817
|
+
[_text(label), _text("unavailable" if deltas.get(key) is None else deltas[key])]
|
|
818
|
+
for label, key in (
|
|
819
|
+
("Runtime (ms)", "runtime_ms_delta"),
|
|
820
|
+
("Cost (USD)", "cost_usd_delta"),
|
|
821
|
+
("Input tokens", "input_tokens_delta"),
|
|
822
|
+
("Output tokens", "output_tokens_delta"),
|
|
823
|
+
)
|
|
824
|
+
],
|
|
825
|
+
caption="Negative deltas mean lower recorded values.",
|
|
826
|
+
)
|
|
827
|
+
result += (
|
|
828
|
+
"<p>Configured gates: <strong>"
|
|
829
|
+
+ ("passed" if replay["gates"]["passed"] else "failed")
|
|
830
|
+
+ "</strong>.</p>"
|
|
831
|
+
)
|
|
832
|
+
result += _table(
|
|
833
|
+
["Gate", "Result", "Detail"],
|
|
834
|
+
[
|
|
835
|
+
[
|
|
836
|
+
_text(gate["name"]),
|
|
837
|
+
"indeterminate"
|
|
838
|
+
if gate.get("indeterminate")
|
|
839
|
+
else ("pass" if gate["passed"] else "fail"),
|
|
840
|
+
_text(gate["detail"]),
|
|
841
|
+
]
|
|
842
|
+
for gate in replay["gates"]["results"]
|
|
843
|
+
],
|
|
844
|
+
caption="Only configured checks determine this gate result.",
|
|
845
|
+
)
|
|
846
|
+
result += (
|
|
847
|
+
"<details><summary>Comparison configuration and provenance</summary>"
|
|
848
|
+
+ _json({"gates": replay["gates"], "deltas": deltas})
|
|
849
|
+
+ "</details>"
|
|
850
|
+
)
|
|
851
|
+
result += (
|
|
852
|
+
"<details><summary>Supplied quality evidence</summary><p>Quality evidence may contain raw task inputs and outputs; review it before sharing.</p>"
|
|
853
|
+
+ (
|
|
854
|
+
_json(replay["quality"])
|
|
855
|
+
if replay.get("quality") is not None
|
|
856
|
+
else "<p>No quality checks were supplied.</p>"
|
|
857
|
+
)
|
|
858
|
+
+ "</details>"
|
|
859
|
+
)
|
|
860
|
+
return result
|