@tangle-network/agent-eval 0.143.0 → 0.144.0
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 +22 -0
- package/README.md +21 -8
- package/dist/analyst/index.d.ts +4 -4
- package/dist/analyst/index.d.ts.map +1 -1
- package/dist/analyst/index.js +3 -3
- package/dist/{benchmark-command-CSddvlq7.js → benchmark-command-4c7N_rlw.js} +7 -6
- package/dist/benchmark-command-4c7N_rlw.js.map +1 -0
- package/dist/benchmarks/index.d.ts +1 -1
- package/dist/benchmarks/index.js +1 -1
- package/dist/{benchmarks-Dg0B56tK.js → benchmarks-05UGZ8sZ.js} +4 -4
- package/dist/{benchmarks-Dg0B56tK.js.map → benchmarks-05UGZ8sZ.js.map} +1 -1
- package/dist/campaign/index.d.ts +4 -3
- package/dist/campaign/index.js +4 -4
- package/dist/{campaign-C7ZGiZYG.js → campaign-BKOtvRAB.js} +11 -9
- package/dist/campaign-BKOtvRAB.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.js +3 -3
- package/dist/{default-registry-BupFSXSN.js → default-registry-DfHJEwYh.js} +2 -2
- package/dist/{default-registry-BupFSXSN.js.map → default-registry-DfHJEwYh.js.map} +1 -1
- package/dist/{dspy-rlm-engine-CJ4sN8Wx.js → dspy-rlm-engine-CBFwlyaY.js} +89 -7
- package/dist/dspy-rlm-engine-CBFwlyaY.js.map +1 -0
- package/dist/external-optimizer-contracts-iK0yu4AR.d.ts +128 -0
- package/dist/external-optimizer-contracts-iK0yu4AR.d.ts.map +1 -0
- package/dist/{index-BKjcUH13.d.ts → index-BZUe-ODI.d.ts} +41 -5
- package/dist/index-BZUe-ODI.d.ts.map +1 -0
- package/dist/{index-DY83M1WL.d.ts → index-DgbFl4cv.d.ts} +9 -8
- package/dist/{index-DY83M1WL.d.ts.map → index-DgbFl4cv.d.ts.map} +1 -1
- package/dist/{index-CaOjqCli.d.ts → index-DtMpBKVF.d.ts} +3 -3
- package/dist/{index-CaOjqCli.d.ts.map → index-DtMpBKVF.d.ts.map} +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/{integrity-hruKe6oe.js → integrity-DY6tIbl0.js} +48 -18
- package/dist/integrity-DY6tIbl0.js.map +1 -0
- package/dist/openapi.json +1 -1
- package/dist/{single-run-lock-Do-8vBIJ.js → single-run-lock-t1si1ob7.js} +370 -152
- package/dist/single-run-lock-t1si1ob7.js.map +1 -0
- package/dist/{skill-usage-CRqaHi0R.d.ts → skill-usage-BiVEU0QY.d.ts} +3 -3
- package/dist/{skill-usage-CRqaHi0R.d.ts.map → skill-usage-BiVEU0QY.d.ts.map} +1 -1
- package/dist/{skillopt-optimization-method-CwRvi-rL.d.ts → skillopt-optimization-method-B7o01OdX.d.ts} +43 -9
- package/dist/skillopt-optimization-method-B7o01OdX.d.ts.map +1 -0
- package/dist/{skillopt-optimization-method-Di8Xkalt.js → skillopt-optimization-method-Ds8J1_K8.js} +289 -222
- package/dist/skillopt-optimization-method-Ds8J1_K8.js.map +1 -0
- package/dist/supervisor-run/index.d.ts +3 -3
- package/dist/supervisor-run/index.js +3 -3
- package/dist/{supervisor-run-BEns49Nx.js → supervisor-run-DiyQVczd.js} +301 -25
- package/dist/supervisor-run-DiyQVczd.js.map +1 -0
- package/dist/{types-Dea6tiVI.d.ts → types-yLK8gXE9.d.ts} +15 -2
- package/dist/types-yLK8gXE9.d.ts.map +1 -0
- package/docs/campaign-proposers.md +11 -7
- package/package.json +1 -1
- package/dist/benchmark-command-CSddvlq7.js.map +0 -1
- package/dist/campaign-C7ZGiZYG.js.map +0 -1
- package/dist/dspy-rlm-engine-CJ4sN8Wx.js.map +0 -1
- package/dist/external-optimizer-contracts-nb7c_WAR.d.ts +0 -42
- package/dist/external-optimizer-contracts-nb7c_WAR.d.ts.map +0 -1
- package/dist/index-BKjcUH13.d.ts.map +0 -1
- package/dist/integrity-hruKe6oe.js.map +0 -1
- package/dist/single-run-lock-Do-8vBIJ.js.map +0 -1
- package/dist/skillopt-optimization-method-CwRvi-rL.d.ts.map +0 -1
- package/dist/skillopt-optimization-method-Di8Xkalt.js.map +0 -1
- package/dist/supervisor-run-BEns49Nx.js.map +0 -1
- package/dist/types-Dea6tiVI.d.ts.map +0 -1
package/dist/{skillopt-optimization-method-Di8Xkalt.js → skillopt-optimization-method-Ds8J1_K8.js}
RENAMED
|
@@ -2,13 +2,13 @@ import { c as ValidationError, i as JudgeError, t as AgentEvalError } from "./er
|
|
|
2
2
|
import { i as CostLedger, t as CostAccountingIncompleteError } from "./cost-ledger-DMFxsLKr.js";
|
|
3
3
|
import { f as maximumChargeForLlmRequest, l as costReceiptFromLlm, m as stripFencedJson, u as costReceiptFromLlmError } from "./llm-client-B3WXSH5Y.js";
|
|
4
4
|
import { a as clamp01, o as combineAbortSignals, t as assertProposalFindings } from "./proposal-findings-2GIUo1et.js";
|
|
5
|
-
import { C as
|
|
5
|
+
import { C as assertNoCredentialValues, D as removeCredentialEnvironment, E as isRecord, O as safePathComponent, S as assertJsonValue, T as isExternalTextCandidate, _ as canonicalJson, d as runWithCleanup, f as startExternalOptimizerModelProxy, h as sendJson, l as runExternalOptimizerProcess, m as listenLocal, n as createRunCostLedger, p as closeServer, r as fsCampaignStorage, t as acquireSingleRunLock, u as closeExternalOptimizerResources, v as contentHash, w as isCandidateText, x as assertExternalOptimizerModelBudget } from "./single-run-lock-t1si1ob7.js";
|
|
6
6
|
import { p as mapConcurrent } from "./ledger-core-Dxz0Rkwa.js";
|
|
7
7
|
import { E as pairedBootstrap, H as weightedComposite, M as pairedRiskDifferenceScore, N as pairedSignTest, O as pairedDeltaTieFraction, T as pairedBinaryScale, d as confidenceInterval, j as pairedRiskDifferenceExact } from "./statistics-ByxzSiOM.js";
|
|
8
8
|
import { t as DEFAULT_REDACTION_RULES } from "./redact-7Aq1ukl-.js";
|
|
9
9
|
import { a as campaignCellCostProvenance, o as campaignCellExecutionEvidence, t as detectRewardHacking, u as projectCampaignCellQuality } from "./reward-hacking-DjTi9HLb.js";
|
|
10
10
|
import { z } from "zod";
|
|
11
|
-
import {
|
|
11
|
+
import { writeFileSync } from "node:fs";
|
|
12
12
|
import { basename, isAbsolute, join } from "node:path";
|
|
13
13
|
import { createHash, randomBytes } from "node:crypto";
|
|
14
14
|
import { createServer } from "node:http";
|
|
@@ -656,160 +656,6 @@ function paretoFrontierWithCrowding(candidates, objectives) {
|
|
|
656
656
|
return crowdingDistance(frontier, objectives).sort((a, b) => b.distance - a.distance);
|
|
657
657
|
}
|
|
658
658
|
//#endregion
|
|
659
|
-
//#region src/verdict-cache.ts
|
|
660
|
-
/**
|
|
661
|
-
* Content-addressed judge-verdict caching.
|
|
662
|
-
*
|
|
663
|
-
* LAW: cache JUDGE VERDICTS only — judging the same artifact with the same
|
|
664
|
-
* judge+rubric is pure. NEVER cache agent rollouts. (A router that cached
|
|
665
|
-
* identical fanout prompts silently destroyed best-of-N diversity; rollout
|
|
666
|
-
* caching reintroduces that failure class. Judging has no diversity to
|
|
667
|
-
* destroy — same artifact + same rubric ⇒ same verdict is the desired
|
|
668
|
-
* property, not a bug.)
|
|
669
|
-
*
|
|
670
|
-
* The cache key is a sha-256 over the canonical JSON of everything that can
|
|
671
|
-
* change a verdict: the artifact content, the scenario id, the judge name,
|
|
672
|
-
* the full dimension list (key + description — the description IS the rubric
|
|
673
|
-
* text shown to the judge), and a caller-supplied `judgeVersion`.
|
|
674
|
-
* `judgeVersion` is REQUIRED: a judge whose prompt/model/ensemble changes
|
|
675
|
-
* without a version bump would otherwise silently serve stale verdicts.
|
|
676
|
-
*
|
|
677
|
-
* Strict canonicalization (`canonicalJson`) throws on undefined / function /
|
|
678
|
-
* symbol / non-finite numbers — an artifact that cannot be unambiguously
|
|
679
|
-
* serialized cannot be content-addressed, and coercing it would let two
|
|
680
|
-
* different artifacts collide on one key.
|
|
681
|
-
*/
|
|
682
|
-
function canonicalizeAt(value, path) {
|
|
683
|
-
if (value === null) return "null";
|
|
684
|
-
switch (typeof value) {
|
|
685
|
-
case "boolean": return value ? "true" : "false";
|
|
686
|
-
case "number":
|
|
687
|
-
if (!Number.isFinite(value)) throw new Error(`canonicalJson: non-finite number (${value}) at ${path} — ambiguity is an error, not a coercion`);
|
|
688
|
-
return JSON.stringify(value);
|
|
689
|
-
case "string": return JSON.stringify(value);
|
|
690
|
-
case "undefined":
|
|
691
|
-
case "function":
|
|
692
|
-
case "symbol": throw new Error(`canonicalJson: ${typeof value} at ${path} — ambiguity is an error, not a coercion`);
|
|
693
|
-
case "bigint": throw new Error(`canonicalJson: bigint at ${path} — not representable in JSON`);
|
|
694
|
-
case "object": break;
|
|
695
|
-
}
|
|
696
|
-
const obj = value;
|
|
697
|
-
if (typeof obj.toJSON === "function") return canonicalizeAt(obj.toJSON(), path);
|
|
698
|
-
if (Array.isArray(obj)) return `[${obj.map((item, i) => canonicalizeAt(item, `${path}[${i}]`)).join(",")}]`;
|
|
699
|
-
if (obj instanceof Map || obj instanceof Set) throw new Error(`canonicalJson: ${obj instanceof Map ? "Map" : "Set"} at ${path} — would serialize as '{}'; convert to a plain object/array first`);
|
|
700
|
-
return `{${Object.keys(obj).sort().map((k) => `${JSON.stringify(k)}:${canonicalizeAt(obj[k], `${path}.${k}`)}`).join(",")}}`;
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* Stable JSON stringify: object keys sorted recursively, so two semantically
|
|
704
|
-
* equal values produce byte-identical output regardless of key insertion
|
|
705
|
-
* order. Throws on undefined / function / symbol / NaN / ±Infinity / bigint /
|
|
706
|
-
* Map / Set — anything JSON.stringify would coerce or drop silently.
|
|
707
|
-
*
|
|
708
|
-
* Distinct from `pre-registration.ts`'s `canonicalize`/`hashJson`, which are
|
|
709
|
-
* permissive (coercion allowed) and async (web-crypto). Use THIS pair when a
|
|
710
|
-
* hash collision or silent coercion would corrupt a cache key or attestation.
|
|
711
|
-
*/
|
|
712
|
-
function canonicalJson(value) {
|
|
713
|
-
return canonicalizeAt(value, "$");
|
|
714
|
-
}
|
|
715
|
-
/** Hex sha-256 over `canonicalJson(value)`. The content address used by the
|
|
716
|
-
* verdict cache and report attestation. */
|
|
717
|
-
function contentHash(value) {
|
|
718
|
-
return createHash("sha256").update(canonicalJson(value)).digest("hex");
|
|
719
|
-
}
|
|
720
|
-
/** Process-local Map-backed store. */
|
|
721
|
-
function inMemoryVerdictCache() {
|
|
722
|
-
const entries = /* @__PURE__ */ new Map();
|
|
723
|
-
return {
|
|
724
|
-
get: (key) => entries.get(key),
|
|
725
|
-
set: (key, score) => {
|
|
726
|
-
entries.set(key, score);
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
function parseCacheLine(line, path, lineNo) {
|
|
731
|
-
let parsed;
|
|
732
|
-
try {
|
|
733
|
-
parsed = JSON.parse(line);
|
|
734
|
-
} catch (err) {
|
|
735
|
-
throw new Error(`fileVerdictCache: corrupt JSONL at ${path}:${lineNo} — ${err instanceof Error ? err.message : String(err)}`);
|
|
736
|
-
}
|
|
737
|
-
const rec = parsed;
|
|
738
|
-
if (typeof rec !== "object" || rec === null || typeof rec.key !== "string" || typeof rec.score !== "object" || rec.score === null || typeof rec.score.composite !== "number" || typeof rec.score.dimensions !== "object") throw new Error(`fileVerdictCache: invalid record shape at ${path}:${lineNo} — expected {key, score:{dimensions, composite, notes}}`);
|
|
739
|
-
return rec;
|
|
740
|
-
}
|
|
741
|
-
/**
|
|
742
|
-
* JSONL-file-backed store: the full file is loaded into an in-memory index at
|
|
743
|
-
* construction; every `set` appends one line synchronously (durable before
|
|
744
|
-
* the verdict is returned). A corrupt or malformed line throws at load with
|
|
745
|
-
* file:line — a skipped line would silently re-judge (cost) or, worse, mask
|
|
746
|
-
* a half-written file that needs operator attention.
|
|
747
|
-
*/
|
|
748
|
-
function fileVerdictCache(path) {
|
|
749
|
-
const entries = /* @__PURE__ */ new Map();
|
|
750
|
-
if (existsSync(path)) {
|
|
751
|
-
const lines = readFileSync(path, "utf8").split("\n");
|
|
752
|
-
for (let i = 0; i < lines.length; i++) {
|
|
753
|
-
const line = lines[i];
|
|
754
|
-
if (line === void 0 || line.trim() === "") continue;
|
|
755
|
-
const rec = parseCacheLine(line, path, i + 1);
|
|
756
|
-
entries.set(rec.key, rec.score);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
return {
|
|
760
|
-
get: (key) => entries.get(key),
|
|
761
|
-
set: (key, score) => {
|
|
762
|
-
appendFileSync(path, `${JSON.stringify({
|
|
763
|
-
key,
|
|
764
|
-
score
|
|
765
|
-
})}\n`, "utf8");
|
|
766
|
-
entries.set(key, score);
|
|
767
|
-
}
|
|
768
|
-
};
|
|
769
|
-
}
|
|
770
|
-
/**
|
|
771
|
-
* Wrap a `JudgeConfig` so repeat judgments of the same artifact are served
|
|
772
|
-
* from the store instead of re-invoking `score()`. The wrapper is generic
|
|
773
|
-
* over the judge's own type parameters and preserves `appliesTo` — it is a
|
|
774
|
-
* drop-in replacement anywhere a `JudgeConfig` is accepted.
|
|
775
|
-
*
|
|
776
|
-
* A judge that throws is NOT cached: the error propagates and the next
|
|
777
|
-
* attempt re-judges (caching a failure would pin a transient outage forever).
|
|
778
|
-
*/
|
|
779
|
-
function cachedJudge(judge, store, options) {
|
|
780
|
-
if (typeof options.judgeVersion !== "string" || options.judgeVersion.trim() === "") throw new Error("cachedJudge: judgeVersion is required and must be a non-empty string");
|
|
781
|
-
const stats = {
|
|
782
|
-
hits: 0,
|
|
783
|
-
misses: 0
|
|
784
|
-
};
|
|
785
|
-
const wrapped = {
|
|
786
|
-
name: judge.name,
|
|
787
|
-
dimensions: judge.dimensions,
|
|
788
|
-
judgeVersion: options.judgeVersion,
|
|
789
|
-
async score(input) {
|
|
790
|
-
const key = contentHash({
|
|
791
|
-
artifact: canonicalJson(input.artifact),
|
|
792
|
-
scenarioId: input.scenario.id,
|
|
793
|
-
judgeName: judge.name,
|
|
794
|
-
dimensions: judge.dimensions,
|
|
795
|
-
judgeVersion: options.judgeVersion
|
|
796
|
-
});
|
|
797
|
-
const cached = await store.get(key);
|
|
798
|
-
if (cached !== void 0) {
|
|
799
|
-
stats.hits += 1;
|
|
800
|
-
return cached;
|
|
801
|
-
}
|
|
802
|
-
const score = await judge.score(input);
|
|
803
|
-
await store.set(key, score);
|
|
804
|
-
stats.misses += 1;
|
|
805
|
-
return score;
|
|
806
|
-
},
|
|
807
|
-
stats: () => ({ ...stats })
|
|
808
|
-
};
|
|
809
|
-
if (judge.appliesTo) wrapped.appliesTo = judge.appliesTo;
|
|
810
|
-
return wrapped;
|
|
811
|
-
}
|
|
812
|
-
//#endregion
|
|
813
659
|
//#region src/llm-judge.ts
|
|
814
660
|
/**
|
|
815
661
|
* `llmJudge` — the single-LLM-call bridge that turns a rubric prompt into a
|
|
@@ -1813,6 +1659,8 @@ async function startExternalOptimizerCallback(args) {
|
|
|
1813
1659
|
let closePromise;
|
|
1814
1660
|
const activeControllers = /* @__PURE__ */ new Set();
|
|
1815
1661
|
const activeHandlers = /* @__PURE__ */ new Set();
|
|
1662
|
+
const proposedCandidateHashes = /* @__PURE__ */ new Set();
|
|
1663
|
+
let observationSequence = 0;
|
|
1816
1664
|
const server = createServer((request, response) => {
|
|
1817
1665
|
if (!accepting) {
|
|
1818
1666
|
sendJsonIfOpen(response, 503, { error: "external optimizer callback is closing" });
|
|
@@ -1833,7 +1681,13 @@ async function startExternalOptimizerCallback(args) {
|
|
|
1833
1681
|
if (accepted > args.maxEvaluations) return void 0;
|
|
1834
1682
|
evaluations += 1;
|
|
1835
1683
|
return accepted;
|
|
1836
|
-
}
|
|
1684
|
+
}, (observation) => {
|
|
1685
|
+
if (!args.observe) return;
|
|
1686
|
+
args.observe({
|
|
1687
|
+
...observation,
|
|
1688
|
+
sequence: ++observationSequence
|
|
1689
|
+
});
|
|
1690
|
+
}, proposedCandidateHashes).finally(() => {
|
|
1837
1691
|
controller.signal.removeEventListener("abort", abortRequest);
|
|
1838
1692
|
activeControllers.delete(controller);
|
|
1839
1693
|
activeHandlers.delete(handler);
|
|
@@ -1868,7 +1722,7 @@ async function startExternalOptimizerCallback(args) {
|
|
|
1868
1722
|
if (serverResult?.status === "rejected") throw serverResult.reason;
|
|
1869
1723
|
}
|
|
1870
1724
|
}
|
|
1871
|
-
async function handleCallback(request, response, signal, args, nextEvaluation) {
|
|
1725
|
+
async function handleCallback(request, response, signal, args, nextEvaluation, observe, proposedCandidateHashes) {
|
|
1872
1726
|
try {
|
|
1873
1727
|
if (request.method !== "POST" || request.url !== "/evaluate") {
|
|
1874
1728
|
sendJsonIfOpen(response, 404, { error: "not found" });
|
|
@@ -1878,19 +1732,76 @@ async function handleCallback(request, response, signal, args, nextEvaluation) {
|
|
|
1878
1732
|
sendJsonIfOpen(response, 401, { error: "unauthorized" });
|
|
1879
1733
|
return;
|
|
1880
1734
|
}
|
|
1881
|
-
|
|
1735
|
+
let body;
|
|
1736
|
+
try {
|
|
1737
|
+
body = await readJson(request);
|
|
1738
|
+
} catch {
|
|
1739
|
+
observe({
|
|
1740
|
+
kind: "refusal",
|
|
1741
|
+
reason: "invalid-request"
|
|
1742
|
+
});
|
|
1743
|
+
sendJsonIfOpen(response, 400, { error: "request body must be bounded valid JSON" });
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1882
1746
|
if (!isRecord(body) || !isExternalTextCandidate(body.candidate) || typeof body.exampleId !== "string") {
|
|
1747
|
+
observe({
|
|
1748
|
+
kind: "refusal",
|
|
1749
|
+
reason: "invalid-request"
|
|
1750
|
+
});
|
|
1883
1751
|
sendJsonIfOpen(response, 400, { error: "candidate and exampleId are required strings" });
|
|
1884
1752
|
return;
|
|
1885
1753
|
}
|
|
1886
|
-
|
|
1754
|
+
const candidate = cloneCandidate(body.candidate);
|
|
1755
|
+
const candidateHash = contentHash({
|
|
1756
|
+
kind: "external-text-candidate",
|
|
1757
|
+
candidate
|
|
1758
|
+
});
|
|
1759
|
+
if (!proposedCandidateHashes.has(candidateHash)) {
|
|
1760
|
+
observe({
|
|
1761
|
+
kind: "proposal",
|
|
1762
|
+
candidate,
|
|
1763
|
+
candidateHash
|
|
1764
|
+
});
|
|
1765
|
+
proposedCandidateHashes.add(candidateHash);
|
|
1766
|
+
}
|
|
1767
|
+
const count = nextEvaluation();
|
|
1768
|
+
if (count === void 0) {
|
|
1769
|
+
observe({
|
|
1770
|
+
kind: "refusal",
|
|
1771
|
+
reason: "evaluation-limit",
|
|
1772
|
+
candidate,
|
|
1773
|
+
candidateHash,
|
|
1774
|
+
exampleId: body.exampleId
|
|
1775
|
+
});
|
|
1887
1776
|
sendJsonIfOpen(response, 429, { error: "evaluation limit reached" });
|
|
1888
1777
|
return;
|
|
1889
1778
|
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1779
|
+
let result;
|
|
1780
|
+
try {
|
|
1781
|
+
result = await args.evaluate({
|
|
1782
|
+
candidate,
|
|
1783
|
+
exampleId: body.exampleId
|
|
1784
|
+
}, signal);
|
|
1785
|
+
} catch {
|
|
1786
|
+
observe({
|
|
1787
|
+
kind: "refusal",
|
|
1788
|
+
reason: "evaluation-failed",
|
|
1789
|
+
candidate,
|
|
1790
|
+
candidateHash,
|
|
1791
|
+
exampleId: body.exampleId
|
|
1792
|
+
});
|
|
1793
|
+
sendJsonIfOpen(response, 500, { error: "evaluation failed" });
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
observe({
|
|
1797
|
+
kind: "evaluation",
|
|
1798
|
+
candidate,
|
|
1799
|
+
candidateHash,
|
|
1800
|
+
exampleId: body.exampleId,
|
|
1801
|
+
evaluationNumber: count,
|
|
1802
|
+
response: structuredClone(result)
|
|
1803
|
+
});
|
|
1804
|
+
sendJsonIfOpen(response, 200, result);
|
|
1894
1805
|
} catch {
|
|
1895
1806
|
sendJsonIfOpen(response, 500, { error: "evaluation failed" });
|
|
1896
1807
|
}
|
|
@@ -1930,6 +1841,10 @@ function assertCallbackConfig(args) {
|
|
|
1930
1841
|
if (!Number.isSafeInteger(args.maxEvaluations) || args.maxEvaluations <= 0) throw new Error("external optimizer callback: maxEvaluations must be a positive safe integer");
|
|
1931
1842
|
if (args.acceptEvaluation !== void 0 && typeof args.acceptEvaluation !== "function") throw new Error("external optimizer callback: acceptEvaluation must be a function");
|
|
1932
1843
|
if (typeof args.evaluate !== "function") throw new Error("external optimizer callback: evaluate must be a function");
|
|
1844
|
+
if (args.observe !== void 0 && typeof args.observe !== "function") throw new Error("external optimizer callback: observe must be a function");
|
|
1845
|
+
}
|
|
1846
|
+
function cloneCandidate(candidate) {
|
|
1847
|
+
return typeof candidate === "string" ? candidate : { ...candidate };
|
|
1933
1848
|
}
|
|
1934
1849
|
//#endregion
|
|
1935
1850
|
//#region src/campaign/external-optimizer-run-budget.ts
|
|
@@ -3492,7 +3407,7 @@ async function compareOptimizationMethods(opts) {
|
|
|
3492
3407
|
throw error;
|
|
3493
3408
|
}
|
|
3494
3409
|
});
|
|
3495
|
-
assertReportedCostWithinCeiling(
|
|
3410
|
+
assertReportedCostWithinCeiling(combineComparisonCosts(optimized.map((result) => ({
|
|
3496
3411
|
label: `method '${result.name}'`,
|
|
3497
3412
|
cost: result.cost
|
|
3498
3413
|
}))).totalCostUsd, opts.costCeiling, "optimization");
|
|
@@ -3577,12 +3492,12 @@ async function compareOptimizationMethods(opts) {
|
|
|
3577
3492
|
favored
|
|
3578
3493
|
};
|
|
3579
3494
|
});
|
|
3580
|
-
const optimizationCost =
|
|
3495
|
+
const optimizationCost = combineComparisonCosts(scores.map((score) => ({
|
|
3581
3496
|
label: `method '${score.name}'`,
|
|
3582
3497
|
cost: score.optimizationCost
|
|
3583
3498
|
})));
|
|
3584
3499
|
const testCost = costFromLedgerSummary(costLedger.summary({ phase: testCostPhase }));
|
|
3585
|
-
const totalCost =
|
|
3500
|
+
const totalCost = combineComparisonCosts([{
|
|
3586
3501
|
label: "optimization",
|
|
3587
3502
|
cost: optimizationCost
|
|
3588
3503
|
}, {
|
|
@@ -3645,6 +3560,7 @@ function assertOptimizationProvenance(methodName, value) {
|
|
|
3645
3560
|
for (const [field, entry] of [["sourceUrl", value.source.sourceUrl], ["revision", value.source.revision]]) if (entry !== void 0 && (typeof entry !== "string" || !entry.trim())) fail(`source.${field}`);
|
|
3646
3561
|
if (typeof value.runId !== "string" || !value.runId.trim()) fail("runId");
|
|
3647
3562
|
if (value.optimizerModel !== void 0 && (typeof value.optimizerModel !== "string" || !value.optimizerModel.trim() || value.optimizerModel.trim() !== value.optimizerModel)) fail("optimizerModel");
|
|
3563
|
+
if (value.optimizerCallRef !== void 0 && (typeof value.optimizerCallRef !== "string" || !value.optimizerCallRef.trim() || value.optimizerCallRef.trim() !== value.optimizerCallRef)) fail("optimizerCallRef");
|
|
3648
3564
|
if (typeof value.resumed !== "boolean") fail("resumed");
|
|
3649
3565
|
if (!Number.isSafeInteger(value.evaluationCount) || value.evaluationCount < 0) fail("evaluationCount");
|
|
3650
3566
|
if (typeof value.artifactDir !== "string" || !value.artifactDir.trim()) fail("artifactDir");
|
|
@@ -3667,6 +3583,24 @@ function assertOptimizationProvenance(methodName, value) {
|
|
|
3667
3583
|
if (value.tokenUsage.reasoningTokens !== void 0 && value.tokenUsage.reasoningTokens > value.tokenUsage.outputTokens) fail("tokenUsage.reasoningTokens");
|
|
3668
3584
|
if (value.tokenUsage.totalTokens !== value.tokenUsage.inputTokens + value.tokenUsage.outputTokens) fail("tokenUsage.totalTokens");
|
|
3669
3585
|
}
|
|
3586
|
+
if (value.observations !== void 0) {
|
|
3587
|
+
if (value.observations.scope !== "callback-submitted-candidates" || typeof value.observations.path !== "string" || !value.observations.path.trim() || typeof value.observations.sha256 !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.observations.sha256)) fail("observations");
|
|
3588
|
+
for (const field of [
|
|
3589
|
+
"submittedCandidates",
|
|
3590
|
+
"evaluations",
|
|
3591
|
+
"refusals"
|
|
3592
|
+
]) if (!Number.isSafeInteger(value.observations[field]) || value.observations[field] < 0) fail(`observations.${field}`);
|
|
3593
|
+
}
|
|
3594
|
+
if (value.modelExecutions !== void 0) {
|
|
3595
|
+
if (value.modelExecutions.scope !== "runtime-model-calls" || typeof value.modelExecutions.path !== "string" || !value.modelExecutions.path.trim() || typeof value.modelExecutions.sha256 !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value.modelExecutions.sha256)) fail("modelExecutions");
|
|
3596
|
+
for (const field of [
|
|
3597
|
+
"calls",
|
|
3598
|
+
"succeeded",
|
|
3599
|
+
"failed"
|
|
3600
|
+
]) if (!Number.isSafeInteger(value.modelExecutions[field]) || value.modelExecutions[field] < 0) fail(`modelExecutions.${field}`);
|
|
3601
|
+
if (value.modelExecutions.calls !== value.modelExecutions.succeeded + value.modelExecutions.failed) fail("modelExecutions.calls");
|
|
3602
|
+
}
|
|
3603
|
+
if (value.optimizerModel === void 0 !== (value.optimizerCallRef === void 0) || value.optimizerModel === void 0 !== (value.modelExecutions === void 0)) fail("optimizerModel execution provenance");
|
|
3670
3604
|
}
|
|
3671
3605
|
function assertComparisonControls(opts, seed, resamples, confidence) {
|
|
3672
3606
|
if (opts.optimizationRunOptions && "costCeiling" in opts.optimizationRunOptions) throw new Error("compareOptimizationMethods: optimizationRunOptions.costCeiling is not supported; costCeiling covers optimization and final scoring");
|
|
@@ -3810,6 +3744,7 @@ function callerDispatchRef(opts) {
|
|
|
3810
3744
|
function costFromLedgerSummary(summary) {
|
|
3811
3745
|
const cost = {
|
|
3812
3746
|
totalCostUsd: summary.totalCostUsd,
|
|
3747
|
+
costProvenance: structuredClone(summary.costProvenance),
|
|
3813
3748
|
accountingComplete: summary.accountingComplete,
|
|
3814
3749
|
incompleteReasons: [...summary.incompleteReasons]
|
|
3815
3750
|
};
|
|
@@ -3836,19 +3771,37 @@ function optimizationTokenUsageFromSummary(summary, receipts) {
|
|
|
3836
3771
|
calls: summary.totalCalls
|
|
3837
3772
|
};
|
|
3838
3773
|
}
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3774
|
+
/** Combine method costs without turning one unknown bill into a known total. */
|
|
3775
|
+
function combineComparisonCosts(entries) {
|
|
3776
|
+
const totalCostUsd = entries.reduce((total, entry) => total + entry.cost.totalCostUsd, 0);
|
|
3777
|
+
const cost = {
|
|
3778
|
+
totalCostUsd,
|
|
3779
|
+
costProvenance: entries.some((entry) => entry.cost.costProvenance.kind === "uncaptured") ? {
|
|
3780
|
+
kind: "uncaptured",
|
|
3781
|
+
usd: null
|
|
3782
|
+
} : entries.every((entry) => entry.cost.costProvenance.kind === "observed") ? {
|
|
3783
|
+
kind: "observed",
|
|
3784
|
+
usd: totalCostUsd
|
|
3785
|
+
} : {
|
|
3786
|
+
kind: "estimated",
|
|
3787
|
+
usd: totalCostUsd
|
|
3788
|
+
},
|
|
3842
3789
|
accountingComplete: entries.every((entry) => entry.cost.accountingComplete),
|
|
3843
3790
|
incompleteReasons: entries.flatMap((entry) => entry.cost.incompleteReasons.map((reason) => `${entry.label}: ${reason}`))
|
|
3844
3791
|
};
|
|
3792
|
+
assertComparisonCost(cost, "combined cost");
|
|
3793
|
+
return cost;
|
|
3845
3794
|
}
|
|
3846
3795
|
function assertComparisonCost(cost, label) {
|
|
3847
3796
|
if (!cost || typeof cost !== "object") throw new Error(`compareOptimizationMethods: ${label} returned no cost`);
|
|
3848
3797
|
if (!Number.isFinite(cost.totalCostUsd) || cost.totalCostUsd < 0) throw new Error(`compareOptimizationMethods: ${label} returned an invalid totalCostUsd`);
|
|
3798
|
+
const provenance = cost.costProvenance;
|
|
3799
|
+
if (!provenance || typeof provenance !== "object" || provenance.kind !== "observed" && provenance.kind !== "estimated" && provenance.kind !== "uncaptured" || (provenance.kind === "uncaptured" ? provenance.usd !== null : !Number.isFinite(provenance.usd) || provenance.usd < 0)) throw new Error(`compareOptimizationMethods: ${label} returned invalid costProvenance`);
|
|
3800
|
+
if (provenance.kind !== "uncaptured" && provenance.usd !== cost.totalCostUsd) throw new Error(`compareOptimizationMethods: ${label} returned costProvenance inconsistent with totalCostUsd`);
|
|
3849
3801
|
if (typeof cost.accountingComplete !== "boolean") throw new Error(`compareOptimizationMethods: ${label} returned invalid accountingComplete`);
|
|
3850
3802
|
if (!Array.isArray(cost.incompleteReasons) || cost.incompleteReasons.some((reason) => typeof reason !== "string" || reason.trim().length === 0)) throw new Error(`compareOptimizationMethods: ${label} returned invalid incompleteReasons`);
|
|
3851
3803
|
if (cost.accountingComplete !== (cost.incompleteReasons.length === 0)) throw new Error(`compareOptimizationMethods: ${label} returned inconsistent cost completeness and reasons`);
|
|
3804
|
+
if (cost.accountingComplete && provenance.kind === "uncaptured") throw new Error(`compareOptimizationMethods: ${label} cannot mark uncaptured cost as complete`);
|
|
3852
3805
|
}
|
|
3853
3806
|
//#endregion
|
|
3854
3807
|
//#region src/campaign/external-text-optimization.ts
|
|
@@ -4097,16 +4050,23 @@ function externalTextOptimizationMethod(config) {
|
|
|
4097
4050
|
status: "completed"
|
|
4098
4051
|
}
|
|
4099
4052
|
});
|
|
4053
|
+
const measuredCost = combineComparisonCosts([{
|
|
4054
|
+
label: "evaluation",
|
|
4055
|
+
cost: evaluationCost
|
|
4056
|
+
}, {
|
|
4057
|
+
label: "optimizer",
|
|
4058
|
+
cost: optimizerCost
|
|
4059
|
+
}]);
|
|
4100
4060
|
return {
|
|
4101
4061
|
winnerSurface: decodeExternalTextCandidate(result.bestCandidate),
|
|
4102
4062
|
cost: {
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
]
|
|
4063
|
+
...measuredCost,
|
|
4064
|
+
...externalCostReason ? { costProvenance: {
|
|
4065
|
+
kind: "uncaptured",
|
|
4066
|
+
usd: null
|
|
4067
|
+
} } : {},
|
|
4068
|
+
accountingComplete: measuredCost.accountingComplete && externalCostReason === void 0,
|
|
4069
|
+
incompleteReasons: [...measuredCost.incompleteReasons, ...externalCostReason ? [`optimizer: external spend is not observed: ${externalCostReason}`] : []]
|
|
4110
4070
|
},
|
|
4111
4071
|
durationMs: Date.now() - started,
|
|
4112
4072
|
provenance: {
|
|
@@ -5339,8 +5299,8 @@ const TOKEN_USAGE_FIELDS = [
|
|
|
5339
5299
|
"calls"
|
|
5340
5300
|
];
|
|
5341
5301
|
function assertPriorExternalOptimizerUsage(summary, budget, name) {
|
|
5342
|
-
if (!summary.
|
|
5343
|
-
if (summary.totalCalls > budget.maxRequests || summary.totalCostUsd > budget.maxCostUsd + Number.EPSILON) throw new Error(`${name}: prior optimizer-model usage exceeds the configured budget`);
|
|
5302
|
+
if (!summary.usageComplete || budget.maxCostUsd !== void 0 && !summary.accountingComplete) throw new Error(`${name}: cannot resume optimizer-model work with incomplete bounded usage`);
|
|
5303
|
+
if (summary.totalCalls > budget.maxRequests || budget.maxCostUsd !== void 0 && summary.totalCostUsd > budget.maxCostUsd + Number.EPSILON) throw new Error(`${name}: prior optimizer-model usage exceeds the configured budget`);
|
|
5344
5304
|
}
|
|
5345
5305
|
function assertExternalOptimizerTokenUsage(usage, name, optimizer) {
|
|
5346
5306
|
if (usage === void 0) return;
|
|
@@ -5355,6 +5315,78 @@ function assertExternalOptimizerCompletionCount(upstream, requestAttempts, succe
|
|
|
5355
5315
|
if (upstream.requestAttempts !== void 0 && upstream.requestAttempts !== requestAttempts) throw new Error(`${name}: ${optimizer} reported ${upstream.requestAttempts} model attempts but the proxy received ${requestAttempts}`);
|
|
5356
5316
|
}
|
|
5357
5317
|
//#endregion
|
|
5318
|
+
//#region src/campaign/external-optimizer-observations.ts
|
|
5319
|
+
/** Append-only observation log for one external-optimizer attempt. */
|
|
5320
|
+
function openExternalOptimizerObservationLog(input) {
|
|
5321
|
+
if (input.storage.read(input.path) !== void 0 || input.storage.exists(input.path)) throw new Error(`external optimizer observation log already exists at '${input.path}'`);
|
|
5322
|
+
input.storage.write(input.path, "");
|
|
5323
|
+
let revision = 0;
|
|
5324
|
+
const counts = {
|
|
5325
|
+
submittedCandidates: 0,
|
|
5326
|
+
evaluations: 0,
|
|
5327
|
+
refusals: 0
|
|
5328
|
+
};
|
|
5329
|
+
return {
|
|
5330
|
+
observe(observation) {
|
|
5331
|
+
const expectedSequence = counts.submittedCandidates + counts.evaluations + counts.refusals + 1;
|
|
5332
|
+
if (observation.sequence !== expectedSequence) throw new Error(`external optimizer observation log expected sequence ${expectedSequence}, got ${observation.sequence}`);
|
|
5333
|
+
const line = `${canonicalJson(observation)}\n`;
|
|
5334
|
+
const next = input.storage.append(input.path, line, revision);
|
|
5335
|
+
if (next === void 0) throw new Error(`external optimizer observation log changed concurrently at '${input.path}'`);
|
|
5336
|
+
revision = next;
|
|
5337
|
+
if (observation.kind === "proposal") counts.submittedCandidates += 1;
|
|
5338
|
+
else if (observation.kind === "evaluation") counts.evaluations += 1;
|
|
5339
|
+
else counts.refusals += 1;
|
|
5340
|
+
},
|
|
5341
|
+
summary() {
|
|
5342
|
+
const contents = input.storage.read(input.path) ?? "";
|
|
5343
|
+
const bytes = new TextEncoder().encode(contents);
|
|
5344
|
+
if (bytes.byteLength !== revision) throw new Error(`external optimizer observation log revision changed at '${input.path}'`);
|
|
5345
|
+
return {
|
|
5346
|
+
scope: "callback-submitted-candidates",
|
|
5347
|
+
path: input.path,
|
|
5348
|
+
sha256: `sha256:${createHash("sha256").update(bytes).digest("hex")}`,
|
|
5349
|
+
...counts
|
|
5350
|
+
};
|
|
5351
|
+
}
|
|
5352
|
+
};
|
|
5353
|
+
}
|
|
5354
|
+
/** Append-only opaque Runtime execution records for one optimizer attempt. */
|
|
5355
|
+
function openExternalOptimizerExecutionLog(input) {
|
|
5356
|
+
if (input.storage.read(input.path) !== void 0 || input.storage.exists(input.path)) throw new Error(`external optimizer execution log already exists at '${input.path}'`);
|
|
5357
|
+
input.storage.write(input.path, "");
|
|
5358
|
+
let revision = 0;
|
|
5359
|
+
const counts = {
|
|
5360
|
+
calls: 0,
|
|
5361
|
+
succeeded: 0,
|
|
5362
|
+
failed: 0
|
|
5363
|
+
};
|
|
5364
|
+
return {
|
|
5365
|
+
observe(observation) {
|
|
5366
|
+
if (observation.sequence !== counts.calls + 1) throw new Error(`external optimizer execution log expected sequence ${counts.calls + 1}, got ${observation.sequence}`);
|
|
5367
|
+
const line = `${canonicalJson(observation)}\n`;
|
|
5368
|
+
const next = input.storage.append(input.path, line, revision);
|
|
5369
|
+
if (next === void 0) throw new Error(`external optimizer execution log changed concurrently at '${input.path}'`);
|
|
5370
|
+
revision = next;
|
|
5371
|
+
counts.calls += 1;
|
|
5372
|
+
if (observation.succeeded) counts.succeeded += 1;
|
|
5373
|
+
else counts.failed += 1;
|
|
5374
|
+
},
|
|
5375
|
+
summary() {
|
|
5376
|
+
const contents = input.storage.read(input.path) ?? "";
|
|
5377
|
+
const bytes = new TextEncoder().encode(contents);
|
|
5378
|
+
if (bytes.byteLength !== revision) throw new Error(`external optimizer execution log revision changed at '${input.path}'`);
|
|
5379
|
+
if (counts.calls !== counts.succeeded + counts.failed) throw new Error(`external optimizer execution log counts disagree at '${input.path}'`);
|
|
5380
|
+
return {
|
|
5381
|
+
scope: "runtime-model-calls",
|
|
5382
|
+
path: input.path,
|
|
5383
|
+
sha256: `sha256:${createHash("sha256").update(bytes).digest("hex")}`,
|
|
5384
|
+
...counts
|
|
5385
|
+
};
|
|
5386
|
+
}
|
|
5387
|
+
};
|
|
5388
|
+
}
|
|
5389
|
+
//#endregion
|
|
5358
5390
|
//#region src/campaign/external-optimizer-run-config.ts
|
|
5359
5391
|
function externalOptimizerRunnerIdentity(runner, module) {
|
|
5360
5392
|
return {
|
|
@@ -5446,27 +5478,16 @@ function assertExternalOptimizerRuntimeIdentity(value, expectedPackage, label) {
|
|
|
5446
5478
|
//#region src/campaign/optimizer-model.ts
|
|
5447
5479
|
function assertOptimizerModel(value, label) {
|
|
5448
5480
|
if (!value || typeof value !== "object") throw new Error(`${label} is required`);
|
|
5449
|
-
for (const field of [
|
|
5450
|
-
|
|
5451
|
-
"baseUrl",
|
|
5452
|
-
"apiKey"
|
|
5453
|
-
]) {
|
|
5454
|
-
const item = value[field];
|
|
5455
|
-
if (typeof item !== "string" || !item.trim() || item.trim() !== item) throw new Error(`${label}.${field} must be trimmed and non-empty`);
|
|
5456
|
-
}
|
|
5457
|
-
let url;
|
|
5458
|
-
try {
|
|
5459
|
-
url = new URL(value.baseUrl);
|
|
5460
|
-
} catch {
|
|
5461
|
-
throw new Error(`${label}.baseUrl must be an absolute HTTP URL`);
|
|
5462
|
-
}
|
|
5463
|
-
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw new Error(`${label}.baseUrl must use HTTP or HTTPS without credentials, query, or fragment`);
|
|
5481
|
+
for (const [field, item] of [["model", value.model], ["callRef", value.callRef]]) if (typeof item !== "string" || !item.trim() || item.trim() !== item) throw new Error(`${label}.${field} must be trimmed and non-empty`);
|
|
5482
|
+
if (typeof value.call !== "function") throw new Error(`${label}.call must be a function`);
|
|
5464
5483
|
assertExternalOptimizerModelBudget(value.budget, `${label}.budget`);
|
|
5465
5484
|
}
|
|
5466
5485
|
function snapshotOptimizerModel(value) {
|
|
5467
5486
|
return {
|
|
5468
|
-
|
|
5469
|
-
budget: structuredClone(value.budget)
|
|
5487
|
+
model: value.model,
|
|
5488
|
+
budget: structuredClone(value.budget),
|
|
5489
|
+
call: value.call,
|
|
5490
|
+
callRef: value.callRef
|
|
5470
5491
|
};
|
|
5471
5492
|
}
|
|
5472
5493
|
const MAX_TIMER_DELAY_MS$1 = 2147483647;
|
|
@@ -5581,7 +5602,7 @@ function assertEngineRun(run, label) {
|
|
|
5581
5602
|
function assertEngineOptions(run, label) {
|
|
5582
5603
|
if (!run || typeof run !== "object") throw new Error(`gepaOptimizationMethod: ${label} is required`);
|
|
5583
5604
|
if (typeof run.engine !== "string" || !run.engine.trim() || run.engine.trim() !== run.engine) throw new Error(`gepaOptimizationMethod: ${label}.engine must be a trimmed non-empty string`);
|
|
5584
|
-
if (!Number.isFinite(run.maxProposerCostUsd) || run.maxProposerCostUsd <= 0) throw new Error(`gepaOptimizationMethod: ${label}.maxProposerCostUsd must be a positive finite number`);
|
|
5605
|
+
if (run.maxProposerCostUsd !== void 0 && (!Number.isFinite(run.maxProposerCostUsd) || run.maxProposerCostUsd <= 0)) throw new Error(`gepaOptimizationMethod: ${label}.maxProposerCostUsd must be a positive finite number when supplied`);
|
|
5585
5606
|
if (run.maxConcurrency !== void 0) assertPositiveSafeInteger$1(run.maxConcurrency, `${label}.maxConcurrency`);
|
|
5586
5607
|
if (run.stopAtScore !== void 0 && !Number.isFinite(run.stopAtScore)) throw new Error(`gepaOptimizationMethod: ${label}.stopAtScore must be a finite number`);
|
|
5587
5608
|
if (run.sandbox !== void 0 && typeof run.sandbox !== "boolean") throw new Error(`gepaOptimizationMethod: ${label}.sandbox must be a boolean`);
|
|
@@ -5708,7 +5729,7 @@ function gepaOptimizationMethod(config) {
|
|
|
5708
5729
|
maxEvidenceChars,
|
|
5709
5730
|
optimizerModel: config.optimizer ? {
|
|
5710
5731
|
model: config.optimizer.model,
|
|
5711
|
-
|
|
5732
|
+
callRef: config.optimizer.callRef,
|
|
5712
5733
|
budget: config.optimizer.budget
|
|
5713
5734
|
} : null,
|
|
5714
5735
|
runner: externalOptimizerRunnerIdentity(bridgeRunner, "agent_eval_rpc.gepa_bridge"),
|
|
@@ -5727,6 +5748,14 @@ function gepaOptimizationMethod(config) {
|
|
|
5727
5748
|
attemptId,
|
|
5728
5749
|
maxEvaluations: evaluationLimit
|
|
5729
5750
|
});
|
|
5751
|
+
const observationLog = openExternalOptimizerObservationLog({
|
|
5752
|
+
storage,
|
|
5753
|
+
path: `${runDir}/observations-${attemptId}.jsonl`
|
|
5754
|
+
});
|
|
5755
|
+
const executionLog = config.optimizer ? openExternalOptimizerExecutionLog({
|
|
5756
|
+
storage,
|
|
5757
|
+
path: `${runDir}/model-executions-${attemptId}.jsonl`
|
|
5758
|
+
}) : void 0;
|
|
5730
5759
|
const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, "GEPA bridge");
|
|
5731
5760
|
const evaluate = createExternalTextEvaluator({
|
|
5732
5761
|
input,
|
|
@@ -5746,6 +5775,7 @@ function gepaOptimizationMethod(config) {
|
|
|
5746
5775
|
maxEvaluations: evaluationLimit,
|
|
5747
5776
|
acceptEvaluation: () => runBudget.acceptEvaluation(),
|
|
5748
5777
|
evaluate,
|
|
5778
|
+
observe: observationLog.observe,
|
|
5749
5779
|
...signal ? { signal } : {}
|
|
5750
5780
|
});
|
|
5751
5781
|
const runnerEnv = bridgeRunner?.env ?? {};
|
|
@@ -5765,8 +5795,9 @@ function gepaOptimizationMethod(config) {
|
|
|
5765
5795
|
});
|
|
5766
5796
|
assertPriorExternalOptimizerUsage(priorOptimizerUsage, config.optimizer.budget, name);
|
|
5767
5797
|
modelProxy = await startExternalOptimizerModelProxy({
|
|
5768
|
-
|
|
5769
|
-
|
|
5798
|
+
call: config.optimizer.call,
|
|
5799
|
+
callRef: config.optimizer.callRef,
|
|
5800
|
+
recordExecution: executionLog.observe,
|
|
5770
5801
|
model: config.optimizer.model,
|
|
5771
5802
|
budget: config.optimizer.budget,
|
|
5772
5803
|
costLedger,
|
|
@@ -5775,7 +5806,7 @@ function gepaOptimizationMethod(config) {
|
|
|
5775
5806
|
tags: { ...runBudget.attemptTags },
|
|
5776
5807
|
initialUsage: {
|
|
5777
5808
|
requests: priorOptimizerUsage.totalCalls,
|
|
5778
|
-
costUsd: priorOptimizerUsage.totalCostUsd
|
|
5809
|
+
...priorOptimizerUsage.costProvenance.kind === "uncaptured" ? {} : { costUsd: priorOptimizerUsage.totalCostUsd }
|
|
5779
5810
|
},
|
|
5780
5811
|
...signal ? { signal } : {}
|
|
5781
5812
|
});
|
|
@@ -5854,17 +5885,31 @@ function gepaOptimizationMethod(config) {
|
|
|
5854
5885
|
});
|
|
5855
5886
|
const optimizerCost = costFromLedgerSummary(optimizerSummary);
|
|
5856
5887
|
const reportedProposerCost = result.proposerCostUsd ?? 0;
|
|
5857
|
-
if (modelProxy)
|
|
5888
|
+
if (modelProxy) {
|
|
5889
|
+
modelProxy.assertExecutionComplete();
|
|
5890
|
+
assertExternalOptimizerCompletionCount(result.tokenUsage, modelProxy.requestAttempts(), modelProxy.successfulCompletions(), name, "GEPA");
|
|
5891
|
+
}
|
|
5858
5892
|
const tokenUsage = modelProxy ? optimizationTokenUsageFromSummary(optimizerSummary, optimizerReceipts) : void 0;
|
|
5859
5893
|
const runtime = observedExternalOptimizerRuntime(runtimeIdentity);
|
|
5894
|
+
const meteredCost = modelProxy ? combineComparisonCosts([{
|
|
5895
|
+
label: "evaluation",
|
|
5896
|
+
cost: evaluationCost
|
|
5897
|
+
}, {
|
|
5898
|
+
label: "optimizer model",
|
|
5899
|
+
cost: optimizerCost
|
|
5900
|
+
}]) : void 0;
|
|
5901
|
+
const externalTotalCostUsd = evaluationCost.totalCostUsd + reportedProposerCost;
|
|
5860
5902
|
return {
|
|
5861
5903
|
winnerSurface: decodeExternalTextCandidate(result.bestCandidate),
|
|
5862
|
-
cost: modelProxy ? {
|
|
5863
|
-
totalCostUsd:
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5904
|
+
cost: modelProxy ? meteredCost : {
|
|
5905
|
+
totalCostUsd: externalTotalCostUsd,
|
|
5906
|
+
costProvenance: result.proposerCostAccounting === "reported" && evaluationCost.costProvenance.kind !== "uncaptured" ? {
|
|
5907
|
+
kind: "estimated",
|
|
5908
|
+
usd: externalTotalCostUsd
|
|
5909
|
+
} : {
|
|
5910
|
+
kind: "uncaptured",
|
|
5911
|
+
usd: null
|
|
5912
|
+
},
|
|
5868
5913
|
accountingComplete: false,
|
|
5869
5914
|
incompleteReasons: [
|
|
5870
5915
|
...evaluationCost.incompleteReasons,
|
|
@@ -5875,13 +5920,18 @@ function gepaOptimizationMethod(config) {
|
|
|
5875
5920
|
durationMs: Date.now() - started,
|
|
5876
5921
|
provenance: {
|
|
5877
5922
|
...runtime,
|
|
5878
|
-
...config.optimizer ? {
|
|
5923
|
+
...config.optimizer ? {
|
|
5924
|
+
optimizerModel: config.optimizer.model,
|
|
5925
|
+
optimizerCallRef: config.optimizer.callRef
|
|
5926
|
+
} : {},
|
|
5879
5927
|
compatibleRunId,
|
|
5880
5928
|
runId,
|
|
5881
5929
|
resumed: result.resumed,
|
|
5882
5930
|
evaluationCount: runBudget.acceptedEvaluations(),
|
|
5883
5931
|
artifactDir: outputDir,
|
|
5884
|
-
...tokenUsage ? { tokenUsage } : {}
|
|
5932
|
+
...tokenUsage ? { tokenUsage } : {},
|
|
5933
|
+
observations: observationLog.summary(),
|
|
5934
|
+
...executionLog ? { modelExecutions: executionLog.summary() } : {}
|
|
5885
5935
|
}
|
|
5886
5936
|
};
|
|
5887
5937
|
}
|
|
@@ -7076,7 +7126,7 @@ function skillOptOptimizationMethod(config) {
|
|
|
7076
7126
|
background: config.background ?? "",
|
|
7077
7127
|
optimizerModel: {
|
|
7078
7128
|
model: config.optimizer.model,
|
|
7079
|
-
|
|
7129
|
+
callRef: config.optimizer.callRef,
|
|
7080
7130
|
budget: config.optimizer.budget
|
|
7081
7131
|
},
|
|
7082
7132
|
seedCandidate: input.baselineSurface,
|
|
@@ -7101,6 +7151,14 @@ function skillOptOptimizationMethod(config) {
|
|
|
7101
7151
|
attemptId,
|
|
7102
7152
|
maxEvaluations: config.maxEvaluations
|
|
7103
7153
|
});
|
|
7154
|
+
const observationLog = openExternalOptimizerObservationLog({
|
|
7155
|
+
storage,
|
|
7156
|
+
path: `${runDir}/observations-${attemptId}.jsonl`
|
|
7157
|
+
});
|
|
7158
|
+
const executionLog = openExternalOptimizerExecutionLog({
|
|
7159
|
+
storage,
|
|
7160
|
+
path: `${runDir}/model-executions-${attemptId}.jsonl`
|
|
7161
|
+
});
|
|
7104
7162
|
const scenarioById = mapExternalScenarios(input.trainScenarios, input.selectionScenarios, "SkillOpt bridge");
|
|
7105
7163
|
const evaluate = createExternalTextEvaluator({
|
|
7106
7164
|
input,
|
|
@@ -7120,6 +7178,7 @@ function skillOptOptimizationMethod(config) {
|
|
|
7120
7178
|
maxEvaluations: config.maxEvaluations,
|
|
7121
7179
|
acceptEvaluation: () => runBudget.acceptEvaluation(),
|
|
7122
7180
|
evaluate,
|
|
7181
|
+
observe: observationLog.observe,
|
|
7123
7182
|
...signal ? { signal } : {}
|
|
7124
7183
|
});
|
|
7125
7184
|
const runnerEnv = bridgeRunner?.env ?? {};
|
|
@@ -7138,8 +7197,9 @@ function skillOptOptimizationMethod(config) {
|
|
|
7138
7197
|
});
|
|
7139
7198
|
assertPriorExternalOptimizerUsage(priorOptimizerUsage, config.optimizer.budget, name);
|
|
7140
7199
|
const modelProxy = await startExternalOptimizerModelProxy({
|
|
7141
|
-
|
|
7142
|
-
|
|
7200
|
+
call: config.optimizer.call,
|
|
7201
|
+
callRef: config.optimizer.callRef,
|
|
7202
|
+
recordExecution: executionLog.observe,
|
|
7143
7203
|
model: config.optimizer.model,
|
|
7144
7204
|
budget: config.optimizer.budget,
|
|
7145
7205
|
costLedger,
|
|
@@ -7148,7 +7208,7 @@ function skillOptOptimizationMethod(config) {
|
|
|
7148
7208
|
tags: { ...runBudget.attemptTags },
|
|
7149
7209
|
initialUsage: {
|
|
7150
7210
|
requests: priorOptimizerUsage.totalCalls,
|
|
7151
|
-
costUsd: priorOptimizerUsage.totalCostUsd
|
|
7211
|
+
...priorOptimizerUsage.costProvenance.kind === "uncaptured" ? {} : { costUsd: priorOptimizerUsage.totalCostUsd }
|
|
7152
7212
|
},
|
|
7153
7213
|
...signal ? { signal } : {}
|
|
7154
7214
|
});
|
|
@@ -7237,32 +7297,39 @@ function skillOptOptimizationMethod(config) {
|
|
|
7237
7297
|
tags: runBudget.runTags
|
|
7238
7298
|
});
|
|
7239
7299
|
const optimizerCost = costFromLedgerSummary(optimizerUsage);
|
|
7300
|
+
modelProxy.assertExecutionComplete();
|
|
7240
7301
|
assertExternalOptimizerCompletionCount(result.tokenUsage, modelProxy.requestAttempts(), modelProxy.successfulCompletions(), name, "SkillOpt");
|
|
7241
7302
|
const tokenUsage = optimizationTokenUsageFromSummary(optimizerUsage, optimizerReceipts);
|
|
7242
7303
|
const runtime = observedExternalOptimizerRuntime(runtimeIdentity);
|
|
7304
|
+
const combinedCost = combineComparisonCosts([{
|
|
7305
|
+
label: "evaluation",
|
|
7306
|
+
cost: evaluationCost
|
|
7307
|
+
}, {
|
|
7308
|
+
label: "optimizer model",
|
|
7309
|
+
cost: optimizerCost
|
|
7310
|
+
}]);
|
|
7243
7311
|
return {
|
|
7244
7312
|
winnerSurface: result.bestCandidate,
|
|
7245
|
-
cost:
|
|
7246
|
-
totalCostUsd: evaluationCost.totalCostUsd + optimizerCost.totalCostUsd,
|
|
7247
|
-
accountingComplete: evaluationCost.accountingComplete && optimizerCost.accountingComplete,
|
|
7248
|
-
incompleteReasons: [...evaluationCost.incompleteReasons.map((reason) => `evaluation: ${reason}`), ...optimizerCost.incompleteReasons.map((reason) => `optimizer model: ${reason}`)]
|
|
7249
|
-
},
|
|
7313
|
+
cost: combinedCost,
|
|
7250
7314
|
durationMs: Date.now() - started,
|
|
7251
7315
|
provenance: {
|
|
7252
7316
|
...runtime,
|
|
7253
7317
|
optimizerModel: config.optimizer.model,
|
|
7318
|
+
optimizerCallRef: config.optimizer.callRef,
|
|
7254
7319
|
compatibleRunId,
|
|
7255
7320
|
runId,
|
|
7256
7321
|
resumed: result.resumed,
|
|
7257
7322
|
evaluationCount: runBudget.acceptedEvaluations(),
|
|
7258
7323
|
artifactDir: outputDir,
|
|
7259
|
-
...tokenUsage ? { tokenUsage } : {}
|
|
7324
|
+
...tokenUsage ? { tokenUsage } : {},
|
|
7325
|
+
observations: observationLog.summary(),
|
|
7326
|
+
modelExecutions: executionLog.summary()
|
|
7260
7327
|
}
|
|
7261
7328
|
};
|
|
7262
7329
|
}
|
|
7263
7330
|
};
|
|
7264
7331
|
}
|
|
7265
7332
|
//#endregion
|
|
7266
|
-
export {
|
|
7333
|
+
export { assertCampaignSplitIdentity as $, assertOptimizationResult as A, summarizeAgentReceiptIntegrity as At, surfaceContentHash as B, detectScale as C, decidePairedPromotion as Ct, runCanaries as D, BackendIntegrityError as Dt, pairHoldout as E, pairedDeltaTest as Et, assertCodeSurfaceIdentity as F, DEFAULT_MUTATION_PRIMITIVES as G, campaignBreakdown as H, assertComponentSurface as I, planCampaignRun as J, buildReflectionPrompt as K, codeSurfaceIdentityMaterial as L, compareOptimizationMethods as M, JudgeParseError as Mt, costFromLedgerSummary as N, composeGate as O, assertRealAgentReceipts as Ot, optimizationTokenUsageFromSummary as P, assertCampaignDesign as Q, componentSurfaceIdentityMaterial as R, defaultProductionGate as S, recoverTruncatedJson as St, heldoutSignificance as T, minimumPairsForPairedDeltaTest as Tt, campaignMeanComposite as U, surfaceHash as V, compareRankKeys as W, resolveRunDir as X, runCampaign as Y, tangleTracesRoot as Z, buildEvidenceVector as _, crowdingDistance as _t, emitLoopProvenance as a, REFERENCE_EQUIVALENCE_JUDGE_VERSION as at, powerPreflight as b, paretoFrontierWithCrowding as bt, provenanceRecordPath as c, DEFAULT_RED_TEAM_CORPUS as ct, runImprovementLoop as d, scoreRedTeamOutput as dt, campaignScenarioIdentity as et, runOptimization as f, toolNamesForRun as ft, gepaOptimizationMethod as g, llmJudge as gt, labelTrustRank as h, hashScenarios as ht, canonicalDigest as i, REFERENCE_EQUIVALENCE_INPUT_LIMITS as it, combineComparisonCosts as j, summarizeBackendIntegrity as jt, externalTextOptimizationMethod as k, assertRealBackend as kt, provenanceSpansPath as l, redTeamDataset as lt, isProposedCandidate as m, HoldoutLockedError as mt, buildLoopProvenanceRecord as n, campaignSplitDigestFromIdentities as nt, loopProvenanceArgsFromResult as o, createReferenceEquivalenceJudge as ot, runEval as p, Dataset as pt, parseReflectionResponse as q, campaignMeasurementDigest as r, openAutoPr as rt, loopProvenanceSpans as s, runReferenceEquivalenceJudge as st, skillOptOptimizationMethod as t, campaignSplitDigest as tt, verifyLoopProvenanceRecord as u, redTeamReport as ut, paretoPolicy as v, dominates as vt, dimensionRegressions as w, pairedDecisionShape as wt, heldOutGate as x, scalarScore as xt, paretoSignificanceGate as y, paretoFrontier as yt, renderSurfaceDiff as z };
|
|
7267
7334
|
|
|
7268
|
-
//# sourceMappingURL=skillopt-optimization-method-
|
|
7335
|
+
//# sourceMappingURL=skillopt-optimization-method-Ds8J1_K8.js.map
|