@dailephd/my-dev-kit-lab 0.9.2 → 0.9.3
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.
- package/CHANGELOG.md +6 -1
- package/README.md +7 -5
- package/dist/src/agents/adapters/codexAdapter.js +4 -1
- package/dist/src/cli/help.js +38 -2
- package/dist/src/cli/runLabCli.js +9 -1
- package/dist/src/commands/buildGalleryCommand.js +16 -3
- package/dist/src/commands/runComparePromptsCommand.js +109 -0
- package/dist/src/commands/runExperimentRunCommand.js +47 -2
- package/dist/src/core/processTree.js +41 -17
- package/dist/src/core/runMeasuredCommand.js +14 -8
- package/dist/src/experiments/plugins/agentSuccessRate/campaignCheckpointStore.js +23 -1
- package/dist/src/experiments/plugins/agentSuccessRate/campaignExecution.js +7 -2
- package/dist/src/experiments/plugins/agentSuccessRate/campaignIdentity.js +29 -4
- package/dist/src/experiments/plugins/agentSuccessRate/campaignResumableExecution.js +1 -1
- package/dist/src/experiments/plugins/agentSuccessRate/config.js +47 -2
- package/dist/src/experiments/plugins/agentSuccessRate/plugin.js +4 -2
- package/dist/src/experiments/plugins/agentSuccessRate/promptContract.js +121 -0
- package/dist/src/experiments/plugins/agentSuccessRate/realAgentExecution.js +32 -2
- package/dist/src/experiments/plugins/agentSuccessRate/realAgentPrompt.js +105 -11
- package/dist/src/experiments/plugins/agentSuccessRate/strictDiffResponse.js +312 -0
- package/dist/src/gallery/galleryPathSafety.js +111 -0
- package/dist/src/gallery/readGallerySources.js +542 -0
- package/dist/src/gallery/writeGalleryManifest.js +57 -3
- package/dist/src/report/experiments/buildPluginExperimentReport.js +4 -16
- package/dist/src/report/experiments/htmlSafety.js +32 -0
- package/dist/src/report/experiments/metricEvidence.js +389 -0
- package/dist/src/report/experiments/metricGlossary.js +227 -0
- package/dist/src/report/experiments/metricGlossaryCatalog.js +199 -0
- package/dist/src/report/experiments/promptTemplateComparisonEvidence.js +377 -0
- package/dist/src/report/experiments/promptTemplateComparisonModel.js +436 -0
- package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +158 -64
- package/dist/src/report/experiments/renderPluginExperimentReportText.js +22 -677
- package/dist/src/report/experiments/renderPromptTemplateComparison.js +192 -0
- package/dist/src/report/experiments/renderSpecializedTextSections.js +633 -0
- package/dist/src/report/experiments/reportSectionRegistry.js +79 -0
- package/dist/src/report/experiments/specializedReportSections.js +142 -0
- package/dist/src/report/experiments/writePluginExperimentReports.js +4 -2
- package/dist/src/securityValidation/attackScenarios/scenarios/secretLeakageScenario.js +146 -133
- package/dist/src/securityValidation/attackScenarios/scenarios/subprocessInjectionScenario.js +54 -36
- package/dist/src/securityValidation/commandRunner.js +13 -6
- package/docs/METRICS.md +11 -1
- package/package.json +1 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { escapeHtml } from "./htmlSafety.js";
|
|
2
|
+
// Deterministic JSON/text/HTML renderers. Output is a pure function of the report model: no clock, no
|
|
3
|
+
// machine-local path, no raw provider response. All HTML text is escaped; the document has no links to
|
|
4
|
+
// external resources and no scripts.
|
|
5
|
+
export function renderPromptTemplateComparisonJson(report) {
|
|
6
|
+
return `${JSON.stringify(report, null, 2)}\n`;
|
|
7
|
+
}
|
|
8
|
+
function pct(value) {
|
|
9
|
+
return value === null ? "unavailable" : `${value.toFixed(2)}%`;
|
|
10
|
+
}
|
|
11
|
+
function pp(value) {
|
|
12
|
+
return value === null ? "unavailable" : `${value >= 0 ? "+" : ""}${value.toFixed(2)} percentage points`;
|
|
13
|
+
}
|
|
14
|
+
function rateText(rate) {
|
|
15
|
+
return rate.availability === "available" ? `${rate.numerator}/${rate.denominator} = ${pct(rate.ratePercent)}` : `${rate.numerator}/${rate.denominator} = UNAVAILABLE (${rate.reason})`;
|
|
16
|
+
}
|
|
17
|
+
function reasons(record) {
|
|
18
|
+
const entries = Object.entries(record);
|
|
19
|
+
return entries.length === 0 ? "none" : entries.map(([key, count]) => `${key}=${count}`).join(", ");
|
|
20
|
+
}
|
|
21
|
+
function successText(basis) {
|
|
22
|
+
return `baseline ${basis.baselineSuccessCount}/${basis.denominator}, candidate ${basis.candidateSuccessCount}/${basis.denominator} (both ${basis.bothSucceeded}, only baseline ${basis.onlyBaselineSucceeded}, only candidate ${basis.onlyCandidateSucceeded}, neither ${basis.neitherSucceeded})`;
|
|
23
|
+
}
|
|
24
|
+
export function renderPromptTemplateComparisonText(report) {
|
|
25
|
+
const lines = [];
|
|
26
|
+
lines.push("Prompt Template Comparison");
|
|
27
|
+
lines.push(`Schema: ${report.schemaVersion}`);
|
|
28
|
+
lines.push(`Comparison status: ${report.comparison.status}`);
|
|
29
|
+
lines.push(`Winner: none declared`);
|
|
30
|
+
lines.push(`Behavioral improvement: ${report.behavioralImprovement.status} - ${report.behavioralImprovement.reason}`);
|
|
31
|
+
lines.push("");
|
|
32
|
+
lines.push("Runs");
|
|
33
|
+
for (const [name, side] of [["Baseline", report.baseline], ["Candidate", report.candidate]]) {
|
|
34
|
+
lines.push(`- ${name}: run=${side.runId ?? "unavailable"} provider=${side.providerId ?? "unavailable"} template=${side.templateId ?? "unverified"} basis=${side.promptBasis} contractDigest=${side.promptContractDigest ?? "n/a"} identity=${side.identityDigest ?? "unverified"}`);
|
|
35
|
+
}
|
|
36
|
+
lines.push("");
|
|
37
|
+
lines.push("Comparability criteria");
|
|
38
|
+
if (report.criteria.length === 0)
|
|
39
|
+
lines.push("- (not evaluated)");
|
|
40
|
+
for (const criterion of report.criteria)
|
|
41
|
+
lines.push(`- ${criterion.id}: ${criterion.status} - ${criterion.detail}`);
|
|
42
|
+
if (report.comparison.incomparabilityReasons.length > 0) {
|
|
43
|
+
lines.push("");
|
|
44
|
+
lines.push("Incomparability reasons");
|
|
45
|
+
for (const item of report.comparison.incomparabilityReasons)
|
|
46
|
+
lines.push(`- ${item}`);
|
|
47
|
+
}
|
|
48
|
+
lines.push("");
|
|
49
|
+
lines.push("Matched cohort");
|
|
50
|
+
lines.push(`- Provider: ${report.cohort.provider ?? "unavailable"}`);
|
|
51
|
+
lines.push(`- Matched units: ${report.cohort.matchedUnitCount}`);
|
|
52
|
+
lines.push(`- Eligible matched units: ${report.cohort.eligibleMatchedUnitCount}`);
|
|
53
|
+
lines.push(`- Excluded units: ${report.cohort.excludedUnitCount} (${reasons(report.cohort.exclusionReasonCounts)})`);
|
|
54
|
+
lines.push(`- Unknown or unavailable units: ${report.cohort.unknownOrUnavailableUnitCount}`);
|
|
55
|
+
for (const unmatched of report.cohort.unmatchedCases)
|
|
56
|
+
lines.push(`- Unmatched case ${unmatched.caseId}: ${unmatched.reason}`);
|
|
57
|
+
lines.push("");
|
|
58
|
+
lines.push(`Invalid-output rate (${report.invalidOutput.basis}): ${report.invalidOutput.metric}`);
|
|
59
|
+
const printStratum = (stratum) => {
|
|
60
|
+
lines.push(`- ${stratum.stratum}: eligible units ${stratum.eligibleUnitCount}`);
|
|
61
|
+
lines.push(` baseline ${rateText(stratum.baseline)}; invalid by reason: ${reasons(stratum.baseline.invalidByReason)}`);
|
|
62
|
+
lines.push(` candidate ${rateText(stratum.candidate)}; invalid by reason: ${reasons(stratum.candidate.invalidByReason)}`);
|
|
63
|
+
lines.push(` difference (baseline minus candidate): ${pp(stratum.percentagePointDifference)}`);
|
|
64
|
+
};
|
|
65
|
+
if (report.invalidOutput.strata.length === 0)
|
|
66
|
+
lines.push("- unavailable: no comparable cohort");
|
|
67
|
+
for (const stratum of report.invalidOutput.strata)
|
|
68
|
+
printStratum(stratum);
|
|
69
|
+
if (report.invalidOutput.overall)
|
|
70
|
+
printStratum(report.invalidOutput.overall);
|
|
71
|
+
for (const repair of report.invalidOutput.repairAttemptSummary) {
|
|
72
|
+
lines.push(`- repair attempt ${repair.attemptNumber} (allowance ${repair.repairAllowance ?? "unknown"}): baseline ${repair.baselineInvalid}/${repair.baselineEligible}, candidate ${repair.candidateInvalid}/${repair.candidateEligible}; ${repair.note}`);
|
|
73
|
+
}
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push("Task success (reported separately from response validity)");
|
|
76
|
+
if (report.taskSuccess.strata.length === 0)
|
|
77
|
+
lines.push("- unavailable: no comparable cohort");
|
|
78
|
+
const printTask = (stratum) => {
|
|
79
|
+
lines.push(`- ${stratum.stratum}: matched units ${stratum.matchedUnitCount}, verdict unavailable ${stratum.unavailableUnitCount}`);
|
|
80
|
+
lines.push(` initial attempt: ${successText(stratum.initial)}`);
|
|
81
|
+
lines.push(` final outcome: ${successText(stratum.final)}`);
|
|
82
|
+
};
|
|
83
|
+
for (const stratum of report.taskSuccess.strata)
|
|
84
|
+
printTask(stratum);
|
|
85
|
+
if (report.taskSuccess.overall)
|
|
86
|
+
printTask(report.taskSuccess.overall);
|
|
87
|
+
lines.push("");
|
|
88
|
+
lines.push("Limitations");
|
|
89
|
+
for (const item of report.limitations)
|
|
90
|
+
lines.push(`- ${item}`);
|
|
91
|
+
if (report.warnings.length > 0) {
|
|
92
|
+
lines.push("");
|
|
93
|
+
lines.push("Warnings");
|
|
94
|
+
for (const item of report.warnings)
|
|
95
|
+
lines.push(`- ${item}`);
|
|
96
|
+
}
|
|
97
|
+
return `${lines.join("\n")}\n`;
|
|
98
|
+
}
|
|
99
|
+
function row(cells) {
|
|
100
|
+
return `<tr>${cells.map((cell) => `<td>${escapeHtml(cell)}</td>`).join("")}</tr>`;
|
|
101
|
+
}
|
|
102
|
+
function table(caption, headers, rows) {
|
|
103
|
+
return `<div class="table-wrap" role="region" aria-label="${escapeHtml(caption)}" tabindex="0"><table><caption>${escapeHtml(caption)}</caption><thead><tr>${headers
|
|
104
|
+
.map((header) => `<th scope="col">${escapeHtml(header)}</th>`)
|
|
105
|
+
.join("")}</tr></thead><tbody>${rows.map(row).join("")}</tbody></table></div>`;
|
|
106
|
+
}
|
|
107
|
+
export function renderPromptTemplateComparisonHtml(report) {
|
|
108
|
+
const strataRows = [...report.invalidOutput.strata, ...(report.invalidOutput.overall ? [report.invalidOutput.overall] : [])].map((stratum) => [
|
|
109
|
+
stratum.stratum,
|
|
110
|
+
String(stratum.eligibleUnitCount),
|
|
111
|
+
rateText(stratum.baseline),
|
|
112
|
+
rateText(stratum.candidate),
|
|
113
|
+
pp(stratum.percentagePointDifference)
|
|
114
|
+
]);
|
|
115
|
+
const taskRows = [...report.taskSuccess.strata, ...(report.taskSuccess.overall ? [report.taskSuccess.overall] : [])].map((stratum) => [
|
|
116
|
+
stratum.stratum,
|
|
117
|
+
String(stratum.matchedUnitCount),
|
|
118
|
+
String(stratum.unavailableUnitCount),
|
|
119
|
+
successText(stratum.initial),
|
|
120
|
+
successText(stratum.final)
|
|
121
|
+
]);
|
|
122
|
+
const list = (items) => (items.length === 0 ? "<p>None.</p>" : `<ul>${items.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>`);
|
|
123
|
+
return `<!DOCTYPE html>
|
|
124
|
+
<html lang="en">
|
|
125
|
+
<head>
|
|
126
|
+
<meta charset="utf-8" />
|
|
127
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
128
|
+
<title>Prompt Template Comparison</title>
|
|
129
|
+
<style>
|
|
130
|
+
:root { color-scheme: light; font-family: Arial, Helvetica, sans-serif; }
|
|
131
|
+
body { margin: 0; color: #18212b; background: #f6f8fb; }
|
|
132
|
+
main { max-width: 1120px; margin: 0 auto; padding: 28px; }
|
|
133
|
+
section { background: #fff; border: 1px solid #d7e0ea; border-radius: 8px; padding: 18px; margin-bottom: 16px; }
|
|
134
|
+
.table-wrap { overflow-x: auto; }
|
|
135
|
+
table { width: 100%; border-collapse: collapse; }
|
|
136
|
+
th, td { border: 1px solid #d9e1ea; padding: 8px 10px; text-align: left; vertical-align: top; }
|
|
137
|
+
th { background: #edf2f7; }
|
|
138
|
+
caption { text-align: left; font-weight: 700; padding: 4px 0; }
|
|
139
|
+
.badge { display: inline-block; border-radius: 999px; padding: 3px 9px; font-weight: 700; background: #e8eef7; }
|
|
140
|
+
.notice { border-left: 4px solid #a06a00; padding-left: 10px; }
|
|
141
|
+
</style>
|
|
142
|
+
</head>
|
|
143
|
+
<body>
|
|
144
|
+
<main>
|
|
145
|
+
<h1>Prompt Template Comparison</h1>
|
|
146
|
+
<p>Schema <code>${escapeHtml(report.schemaVersion)}</code>. Comparison status: <span class="badge">${escapeHtml(report.comparison.status)}</span>. No winner is declared.</p>
|
|
147
|
+
<p class="notice">Behavioral improvement: <strong>${escapeHtml(report.behavioralImprovement.status)}</strong>. ${escapeHtml(report.behavioralImprovement.reason)}</p>
|
|
148
|
+
<section>
|
|
149
|
+
<h2>Runs</h2>
|
|
150
|
+
${table("Baseline and candidate", ["Role", "Run", "Provider", "Template", "Identity basis", "Contract digest"], [
|
|
151
|
+
["baseline", report.baseline.runId ?? "unavailable", report.baseline.providerId ?? "unavailable", report.baseline.templateId ?? "unverified", report.baseline.promptBasis, report.baseline.promptContractDigest ?? "n/a"],
|
|
152
|
+
["candidate", report.candidate.runId ?? "unavailable", report.candidate.providerId ?? "unavailable", report.candidate.templateId ?? "unverified", report.candidate.promptBasis, report.candidate.promptContractDigest ?? "n/a"]
|
|
153
|
+
])}
|
|
154
|
+
</section>
|
|
155
|
+
<section>
|
|
156
|
+
<h2>Comparability</h2>
|
|
157
|
+
${report.criteria.length ? table("Comparability criteria", ["Criterion", "Status", "Detail"], report.criteria.map((c) => [c.id, c.status, c.detail])) : "<p>Not evaluated.</p>"}
|
|
158
|
+
${report.comparison.incomparabilityReasons.length ? `<h3>Incomparability reasons</h3>${list(report.comparison.incomparabilityReasons)}` : ""}
|
|
159
|
+
</section>
|
|
160
|
+
<section>
|
|
161
|
+
<h2>Matched cohort</h2>
|
|
162
|
+
${table("Cohort counts", ["Measure", "Value"], [
|
|
163
|
+
["Provider", report.cohort.provider ?? "unavailable"],
|
|
164
|
+
["Matched units", String(report.cohort.matchedUnitCount)],
|
|
165
|
+
["Eligible matched units", String(report.cohort.eligibleMatchedUnitCount)],
|
|
166
|
+
["Excluded units", String(report.cohort.excludedUnitCount)],
|
|
167
|
+
["Exclusion reasons", reasons(report.cohort.exclusionReasonCounts)],
|
|
168
|
+
["Unknown or unavailable units", String(report.cohort.unknownOrUnavailableUnitCount)]
|
|
169
|
+
])}
|
|
170
|
+
${report.cohort.unmatchedCases.length ? list(report.cohort.unmatchedCases.map((u) => `${u.caseId}: ${u.reason}`)) : ""}
|
|
171
|
+
</section>
|
|
172
|
+
<section>
|
|
173
|
+
<h2>Invalid-output rate</h2>
|
|
174
|
+
<p>${escapeHtml(report.invalidOutput.metric)} (${escapeHtml(report.invalidOutput.basis)}). Difference is baseline minus candidate; positive means the candidate has a lower observed rate.</p>
|
|
175
|
+
${strataRows.length ? table("Invalid-output rates", ["Stratum", "Eligible units", "Baseline", "Candidate", "Difference"], strataRows) : "<p>Unavailable: no comparable cohort.</p>"}
|
|
176
|
+
${report.invalidOutput.repairAttemptSummary.length ? list(report.invalidOutput.repairAttemptSummary.map((r) => `Repair attempt ${r.attemptNumber}: baseline ${r.baselineInvalid}/${r.baselineEligible}, candidate ${r.candidateInvalid}/${r.candidateEligible}. ${r.note}`)) : ""}
|
|
177
|
+
</section>
|
|
178
|
+
<section>
|
|
179
|
+
<h2>Task success</h2>
|
|
180
|
+
<p>Reported separately from response validity and read from persisted verdicts.</p>
|
|
181
|
+
${taskRows.length ? table("Task success", ["Stratum", "Matched units", "Verdict unavailable", "Initial attempt", "Final outcome"], taskRows) : "<p>Unavailable: no comparable cohort.</p>"}
|
|
182
|
+
</section>
|
|
183
|
+
<section>
|
|
184
|
+
<h2>Limitations</h2>
|
|
185
|
+
${list(report.limitations)}
|
|
186
|
+
${report.warnings.length ? `<h3>Warnings</h3>${list(report.warnings)}` : ""}
|
|
187
|
+
</section>
|
|
188
|
+
</main>
|
|
189
|
+
</body>
|
|
190
|
+
</html>
|
|
191
|
+
`;
|
|
192
|
+
}
|