@tangle-network/agent-eval 0.138.0 → 0.139.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.
Files changed (164) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -1
  3. package/dist/analyst/index.d.ts +41 -94
  4. package/dist/analyst/index.d.ts.map +1 -1
  5. package/dist/analyst/index.js +9 -24
  6. package/dist/analyst/index.js.map +1 -1
  7. package/dist/{benchmark-D8dkki-J.js → benchmark-CYtcIF2V.js} +2 -2
  8. package/dist/{benchmark-D8dkki-J.js.map → benchmark-CYtcIF2V.js.map} +1 -1
  9. package/dist/{benchmark-DlQgU_XI.d.ts → benchmark-DDVdWcwA.d.ts} +3 -3
  10. package/dist/{benchmark-DlQgU_XI.d.ts.map → benchmark-DDVdWcwA.d.ts.map} +1 -1
  11. package/dist/{benchmark-command-CMqVqReF.js → benchmark-command-BKfjOBJ5.js} +243 -38
  12. package/dist/benchmark-command-BKfjOBJ5.js.map +1 -0
  13. package/dist/benchmarks/index.d.ts +1 -1
  14. package/dist/benchmarks/index.js +1 -1
  15. package/dist/{benchmarks-BJ_xK5rQ.js → benchmarks-zxhy1QV3.js} +4 -4
  16. package/dist/{benchmarks-BJ_xK5rQ.js.map → benchmarks-zxhy1QV3.js.map} +1 -1
  17. package/dist/campaign/index.d.ts +5 -5
  18. package/dist/campaign/index.js +4 -3
  19. package/dist/{campaign-BIBS-NHV.js → campaign-DrS6_hLd.js} +10 -9
  20. package/dist/campaign-DrS6_hLd.js.map +1 -0
  21. package/dist/canonical-D011XM8r.js +86 -0
  22. package/dist/canonical-D011XM8r.js.map +1 -0
  23. package/dist/cli.js +3 -3
  24. package/dist/{client-BwPKohkJ.d.ts → client-BohnDFBq.d.ts} +4 -4
  25. package/dist/{client-BwPKohkJ.d.ts.map → client-BohnDFBq.d.ts.map} +1 -1
  26. package/dist/{completion-verifier-B4-IMYcS.d.ts → completion-verifier-IPoP4fQO.d.ts} +178 -4
  27. package/dist/completion-verifier-IPoP4fQO.d.ts.map +1 -0
  28. package/dist/contract/index.d.ts +10 -10
  29. package/dist/contract/index.js +8 -7
  30. package/dist/contract/index.js.map +1 -1
  31. package/dist/control.d.ts +2 -2
  32. package/dist/{cost-ledger-CHDLA0Ss.js → cost-ledger-CZ9diLxY.js} +7 -7
  33. package/dist/cost-ledger-CZ9diLxY.js.map +1 -0
  34. package/dist/{cost-ledger-B1D3COAc.d.ts → cost-ledger-DKgyIWRj.d.ts} +5 -2
  35. package/dist/cost-ledger-DKgyIWRj.d.ts.map +1 -0
  36. package/dist/default-registry-B8vf7Rmf.d.ts +118 -0
  37. package/dist/default-registry-B8vf7Rmf.d.ts.map +1 -0
  38. package/dist/{default-registry-lp5R0lve.js → default-registry-BgJJItGr.js} +57 -1532
  39. package/dist/default-registry-BgJJItGr.js.map +1 -0
  40. package/dist/dspy-rlm-engine-DTkVyDX-.js +344 -0
  41. package/dist/dspy-rlm-engine-DTkVyDX-.js.map +1 -0
  42. package/dist/{eval-campaign-9MozgKL7.js → eval-campaign-BmptJj50.js} +2 -2
  43. package/dist/{eval-campaign-9MozgKL7.js.map → eval-campaign-BmptJj50.js.map} +1 -1
  44. package/dist/{exact-types-Dpw2LeHA.d.ts → exact-types-MaaFcllV.d.ts} +2 -2
  45. package/dist/{exact-types-Dpw2LeHA.d.ts.map → exact-types-MaaFcllV.d.ts.map} +1 -1
  46. package/dist/external-optimizer-contracts-BrxY2Sli.d.ts +32 -0
  47. package/dist/external-optimizer-contracts-BrxY2Sli.d.ts.map +1 -0
  48. package/dist/{extract-usage-CS391dOE.js → extract-usage-DZs601Va.js} +2 -2
  49. package/dist/{extract-usage-CS391dOE.js.map → extract-usage-DZs601Va.js.map} +1 -1
  50. package/dist/{feedback-trajectory-CoNep7rl.d.ts → feedback-trajectory-BJUWOkJM.d.ts} +3 -3
  51. package/dist/{feedback-trajectory-CoNep7rl.d.ts.map → feedback-trajectory-BJUWOkJM.d.ts.map} +1 -1
  52. package/dist/fuzz.d.ts +1 -1
  53. package/dist/fuzz.js +1 -1
  54. package/dist/{hf-dataset-DBJXXoY1.js → hf-dataset-XggBupCr.js} +2 -2
  55. package/dist/{hf-dataset-DBJXXoY1.js.map → hf-dataset-XggBupCr.js.map} +1 -1
  56. package/dist/hosted/index.d.ts +3 -3
  57. package/dist/{index-D0cxAdaV.d.ts → index-BTm_P9aC.d.ts} +11 -11
  58. package/dist/{index-D0cxAdaV.d.ts.map → index-BTm_P9aC.d.ts.map} +1 -1
  59. package/dist/{index-B2-IxCMB.d.ts → index-CWOPCJiw.d.ts} +2 -2
  60. package/dist/{index-B2-IxCMB.d.ts.map → index-CWOPCJiw.d.ts.map} +1 -1
  61. package/dist/{index-sMN_hI4E.d.ts → index-CtR1xh4V.d.ts} +3 -3
  62. package/dist/{index-sMN_hI4E.d.ts.map → index-CtR1xh4V.d.ts.map} +1 -1
  63. package/dist/{index-CjVYlVBK.d.ts → index-_66rVpwN.d.ts} +5 -5
  64. package/dist/{index-CjVYlVBK.d.ts.map → index-_66rVpwN.d.ts.map} +1 -1
  65. package/dist/index.d.ts +35 -56
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +51 -176
  68. package/dist/index.js.map +1 -1
  69. package/dist/{insight-report-CXd8VBDR.d.ts → insight-report-Bu5Wi9tG.d.ts} +4 -4
  70. package/dist/{insight-report-CXd8VBDR.d.ts.map → insight-report-Bu5Wi9tG.d.ts.map} +1 -1
  71. package/dist/{integrity-B-MLFz0I.d.ts → integrity-COTh3DTH.d.ts} +2 -2
  72. package/dist/{integrity-B-MLFz0I.d.ts.map → integrity-COTh3DTH.d.ts.map} +1 -1
  73. package/dist/kind-factory-CFxA0JQX.js +2133 -0
  74. package/dist/kind-factory-CFxA0JQX.js.map +1 -0
  75. package/dist/ledger-core/index.js +2 -1
  76. package/dist/{ledger-core-C0Yx1I14.js → ledger-core-Dxz0Rkwa.js} +3 -85
  77. package/dist/ledger-core-Dxz0Rkwa.js.map +1 -0
  78. package/dist/{llm-client-Cj3c7PEm.js → llm-client-bkztEfIx.js} +2 -2
  79. package/dist/{llm-client-Cj3c7PEm.js.map → llm-client-bkztEfIx.js.map} +1 -1
  80. package/dist/meta-eval/index.d.ts +2 -2
  81. package/dist/multishot/index.d.ts +2 -2
  82. package/dist/openapi.json +1 -1
  83. package/dist/{release-report-CoyvyLBs.d.ts → release-report-fZarvIm-.d.ts} +3 -3
  84. package/dist/{release-report-CoyvyLBs.d.ts.map → release-report-fZarvIm-.d.ts.map} +1 -1
  85. package/dist/{replay-DbIYwso6.d.ts → replay-DjG4IG60.d.ts} +34 -143
  86. package/dist/replay-DjG4IG60.d.ts.map +1 -0
  87. package/dist/{replay-Cb-4Vf0k.js → replay-SA4OB7O7.js} +48 -137
  88. package/dist/replay-SA4OB7O7.js.map +1 -0
  89. package/dist/reporting.d.ts +4 -4
  90. package/dist/{researcher-BCeOEjtR.d.ts → researcher-BxhtGfKa.d.ts} +5 -5
  91. package/dist/{researcher-BCeOEjtR.d.ts.map → researcher-BxhtGfKa.d.ts.map} +1 -1
  92. package/dist/{reward-hacking-sE2l_NV6.d.ts → reward-hacking-CqSLiV51.d.ts} +2 -2
  93. package/dist/{reward-hacking-sE2l_NV6.d.ts.map → reward-hacking-CqSLiV51.d.ts.map} +1 -1
  94. package/dist/rl.d.ts +5 -5
  95. package/dist/rl.js +1 -1
  96. package/dist/rollout/index.d.ts +1 -1
  97. package/dist/rollout/index.js +2 -2
  98. package/dist/{rollout-DQFl0UXA.js → rollout-8nj3mYvx.js} +2 -2
  99. package/dist/{rollout-DQFl0UXA.js.map → rollout-8nj3mYvx.js.map} +1 -1
  100. package/dist/{rubric-predictive-validity-w2klGv1u.d.ts → rubric-predictive-validity-DQBQj6uV.d.ts} +2 -2
  101. package/dist/{rubric-predictive-validity-w2klGv1u.d.ts.map → rubric-predictive-validity-DQBQj6uV.d.ts.map} +1 -1
  102. package/dist/{run-evidence-CbE0A8Xg.d.ts → run-evidence-C4RcRQT5.d.ts} +3 -3
  103. package/dist/{run-evidence-CbE0A8Xg.d.ts.map → run-evidence-C4RcRQT5.d.ts.map} +1 -1
  104. package/dist/{run-record-DwHMk1Ai.d.ts → run-record-CztDMXVF.d.ts} +2 -2
  105. package/dist/{run-record-DwHMk1Ai.d.ts.map → run-record-CztDMXVF.d.ts.map} +1 -1
  106. package/dist/{semantic-concept-judge-DYXDPZW0.js → semantic-concept-judge-BuIJ9IfB.js} +43 -6
  107. package/dist/semantic-concept-judge-BuIJ9IfB.js.map +1 -0
  108. package/dist/{server-DLEvyW2z.js → server-DaCpLfi0.js} +3 -3
  109. package/dist/{server-DLEvyW2z.js.map → server-DaCpLfi0.js.map} +1 -1
  110. package/dist/single-run-lock-BTTtPZ9N.js +989 -0
  111. package/dist/single-run-lock-BTTtPZ9N.js.map +1 -0
  112. package/dist/{skill-usage-Bv3G4VkA.d.ts → skill-usage-B-BFS8M2.d.ts} +54 -39
  113. package/dist/skill-usage-B-BFS8M2.d.ts.map +1 -0
  114. package/dist/{skillopt-optimization-method-CjKMZy0d.js → skillopt-optimization-method-BbGnCC53.js} +18 -802
  115. package/dist/skillopt-optimization-method-BbGnCC53.js.map +1 -0
  116. package/dist/{skillopt-optimization-method-CzfnA8O-.d.ts → skillopt-optimization-method-_s0Tub7Y.d.ts} +11 -39
  117. package/dist/skillopt-optimization-method-_s0Tub7Y.d.ts.map +1 -0
  118. package/dist/{statistics-mf70aXKp.d.ts → statistics-B5d0Zd-z.d.ts} +2 -2
  119. package/dist/{statistics-mf70aXKp.d.ts.map → statistics-B5d0Zd-z.d.ts.map} +1 -1
  120. package/dist/store-otlp-DX4fGIcf.js +757 -0
  121. package/dist/store-otlp-DX4fGIcf.js.map +1 -0
  122. package/dist/{summary-report-BKinV4yD.d.ts → summary-report-Cg7BifAM.d.ts} +3 -3
  123. package/dist/{summary-report-BKinV4yD.d.ts.map → summary-report-Cg7BifAM.d.ts.map} +1 -1
  124. package/dist/tool-groups-CdYq22lX.d.ts +258 -0
  125. package/dist/tool-groups-CdYq22lX.d.ts.map +1 -0
  126. package/dist/traces.d.ts +7 -6
  127. package/dist/traces.js +5 -5
  128. package/dist/{types-zFYez3PK.d.ts → types-BBFNHxSK.d.ts} +5 -5
  129. package/dist/{types-zFYez3PK.d.ts.map → types-BBFNHxSK.d.ts.map} +1 -1
  130. package/dist/{types-BtJhn8v6.d.ts → types-DoEYskCd.d.ts} +5 -5
  131. package/dist/{types-BtJhn8v6.d.ts.map → types-DoEYskCd.d.ts.map} +1 -1
  132. package/dist/{types-5q2T25iW.d.ts → types-uPrS6mD-.d.ts} +2 -2
  133. package/dist/{types-5q2T25iW.d.ts.map → types-uPrS6mD-.d.ts.map} +1 -1
  134. package/dist/usage-receipt-CgxMEBZq.js +134 -0
  135. package/dist/usage-receipt-CgxMEBZq.js.map +1 -0
  136. package/dist/wire/index.d.ts +3 -3
  137. package/dist/wire/index.js +1 -1
  138. package/docs/trace-analysis.md +170 -484
  139. package/package.json +1 -2
  140. package/dist/analyze-runs-CPYxfPWT.d.ts +0 -72
  141. package/dist/analyze-runs-CPYxfPWT.d.ts.map +0 -1
  142. package/dist/benchmark-command-CMqVqReF.js.map +0 -1
  143. package/dist/campaign-BIBS-NHV.js.map +0 -1
  144. package/dist/completion-verifier-B4-IMYcS.d.ts.map +0 -1
  145. package/dist/cost-ledger-B1D3COAc.d.ts.map +0 -1
  146. package/dist/cost-ledger-CHDLA0Ss.js.map +0 -1
  147. package/dist/default-registry-PUhIVRWz.d.ts +0 -215
  148. package/dist/default-registry-PUhIVRWz.d.ts.map +0 -1
  149. package/dist/default-registry-lp5R0lve.js.map +0 -1
  150. package/dist/ledger-core-C0Yx1I14.js.map +0 -1
  151. package/dist/registry-C4yJTza7.d.ts +0 -178
  152. package/dist/registry-C4yJTza7.d.ts.map +0 -1
  153. package/dist/replay-Cb-4Vf0k.js.map +0 -1
  154. package/dist/replay-DbIYwso6.d.ts.map +0 -1
  155. package/dist/semantic-concept-judge-DYXDPZW0.js.map +0 -1
  156. package/dist/single-run-lock-D_bS5xhj.js +0 -318
  157. package/dist/single-run-lock-D_bS5xhj.js.map +0 -1
  158. package/dist/skill-usage-Bv3G4VkA.d.ts.map +0 -1
  159. package/dist/skillopt-optimization-method-CjKMZy0d.js.map +0 -1
  160. package/dist/skillopt-optimization-method-CzfnA8O-.d.ts.map +0 -1
  161. package/dist/store-otlp-BenKynPE.js +0 -1688
  162. package/dist/store-otlp-BenKynPE.js.map +0 -1
  163. package/dist/tools-DZGdROtG.js +0 -255
  164. package/dist/tools-DZGdROtG.js.map +0 -1
@@ -1,9 +1,9 @@
1
1
  import { c as ValidationError, i as JudgeError, t as AgentEvalError } from "./errors-D-LKuDhb.js";
2
- import { c as costForTokenPricing, i as CostLedger, t as CostAccountingIncompleteError } from "./cost-ledger-CHDLA0Ss.js";
3
- import { f as maximumChargeForLlmRequest, l as costReceiptFromLlm, m as stripFencedJson, u as costReceiptFromLlmError } from "./llm-client-Cj3c7PEm.js";
4
- import { n as createRunCostLedger, r as fsCampaignStorage, t as acquireSingleRunLock } from "./single-run-lock-D_bS5xhj.js";
5
- import { p as mapConcurrent } from "./ledger-core-C0Yx1I14.js";
2
+ import { i as CostLedger, t as CostAccountingIncompleteError } from "./cost-ledger-CZ9diLxY.js";
3
+ import { f as maximumChargeForLlmRequest, l as costReceiptFromLlm, m as stripFencedJson, u as costReceiptFromLlmError } from "./llm-client-bkztEfIx.js";
6
4
  import { a as clamp01, o as combineAbortSignals, t as assertProposalFindings } from "./proposal-findings-2GIUo1et.js";
5
+ import { C as safePathComponent, S as removeCredentialEnvironment, _ as assertJsonValue, b as isExternalTextCandidate, d as runWithCleanup, f as startExternalOptimizerModelProxy, g as assertExternalOptimizerModelBudget, 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 assertNoCredentialValues, x as isRecord, y as isCandidateText } from "./single-run-lock-BTTtPZ9N.js";
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 campaignCellExecutionEvidence, l as projectCampaignCellQuality, t as detectRewardHacking } from "./reward-hacking-GyN0kMd8.js";
@@ -11,10 +11,10 @@ import { z } from "zod";
11
11
  import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
12
12
  import { basename, isAbsolute, join } from "node:path";
13
13
  import { createHash, randomBytes } from "node:crypto";
14
- import { lstat, mkdir, mkdtemp, open, rm, writeFile } from "node:fs/promises";
15
- import { homedir, tmpdir } from "node:os";
16
- import { execSync, spawn } from "node:child_process";
17
14
  import { createServer } from "node:http";
15
+ import { execSync } from "node:child_process";
16
+ import { mkdir } from "node:fs/promises";
17
+ import { homedir, tmpdir } from "node:os";
18
18
  import { isDeepStrictEqual } from "node:util";
19
19
  //#region src/judges.ts
20
20
  /**
@@ -1803,115 +1803,6 @@ function designedCellIds(scenarios, reps) {
1803
1803
  return ids;
1804
1804
  }
1805
1805
  //#endregion
1806
- //#region src/campaign/external-optimizer-contracts.ts
1807
- const MAX_TIMER_DELAY_MS$5 = 2147483647;
1808
- function isCandidateText(value, maxChars) {
1809
- return typeof value === "string" && value.trim().length > 0 && value.length <= maxChars;
1810
- }
1811
- function isExternalTextCandidate(value) {
1812
- if (typeof value === "string") return value.trim().length > 0;
1813
- if (!isRecord(value)) return false;
1814
- const entries = Object.entries(value);
1815
- return entries.length > 0 && entries.every(([name, content]) => name.trim().length > 0 && name.trim() === name && typeof content === "string");
1816
- }
1817
- function assertJsonValue(value, label, seen = /* @__PURE__ */ new Set()) {
1818
- if (value === null || typeof value === "string" || typeof value === "boolean") return;
1819
- if (typeof value === "number" && Number.isFinite(value)) return;
1820
- if (Array.isArray(value)) {
1821
- if (seen.has(value)) throw new Error(`${label} must be JSON-serializable`);
1822
- seen.add(value);
1823
- for (const item of value) assertJsonValue(item, label, seen);
1824
- seen.delete(value);
1825
- return;
1826
- }
1827
- if (typeof value === "object") {
1828
- if (seen.has(value)) throw new Error(`${label} must be JSON-serializable`);
1829
- const prototype = Object.getPrototypeOf(value);
1830
- if (prototype !== Object.prototype && prototype !== null) throw new Error(`${label} must be JSON-serializable`);
1831
- seen.add(value);
1832
- for (const item of Object.values(value)) assertJsonValue(item, label, seen);
1833
- seen.delete(value);
1834
- return;
1835
- }
1836
- throw new Error(`${label} must be JSON-serializable`);
1837
- }
1838
- function assertNoCredentialValues(value, path, credentialLocation = "runner.env") {
1839
- if (Array.isArray(value)) {
1840
- for (const [index, item] of value.entries()) assertNoCredentialValues(item, `${path}[${index}]`, credentialLocation);
1841
- return;
1842
- }
1843
- if (!isRecord(value)) return;
1844
- for (const [key, item] of Object.entries(value)) {
1845
- if (isCredentialKey(key)) throw new Error(`${path}.${key} must be supplied through ${credentialLocation}`);
1846
- assertNoCredentialValues(item, `${path}.${key}`, credentialLocation);
1847
- }
1848
- }
1849
- function removeCredentialEnvironment(environment) {
1850
- const sanitized = {};
1851
- for (const [key, value] of Object.entries(environment)) if (value !== void 0 && !isCredentialKey(key)) sanitized[key] = value;
1852
- return sanitized;
1853
- }
1854
- function assertExternalOptimizerModelBudget(value, label) {
1855
- if (!value || typeof value !== "object") throw new Error(`${label} is required`);
1856
- for (const [field, entry] of [
1857
- ["maxRequests", value.maxRequests],
1858
- ["maxRequestBytes", value.maxRequestBytes],
1859
- ["maxResponseBytes", value.maxResponseBytes],
1860
- ["maxOutputTokensPerRequest", value.maxOutputTokensPerRequest]
1861
- ]) if (!Number.isSafeInteger(entry) || entry <= 0) throw new Error(`${label}.${field} must be a positive safe integer`);
1862
- if (!Number.isFinite(value.maxCostUsd) || value.maxCostUsd <= 0) throw new Error(`${label}.maxCostUsd must be positive and finite`);
1863
- if (value.requestTimeoutMs !== void 0 && (!Number.isSafeInteger(value.requestTimeoutMs) || value.requestTimeoutMs <= 0 || value.requestTimeoutMs > MAX_TIMER_DELAY_MS$5)) throw new Error(`${label}.requestTimeoutMs must be between 1 and ${MAX_TIMER_DELAY_MS$5}`);
1864
- costForTokenPricing(value.pricing, {
1865
- inputTokens: 1,
1866
- outputTokens: 1
1867
- });
1868
- }
1869
- function safePathComponent(value) {
1870
- return value.replace(/[^a-zA-Z0-9._-]/g, "_");
1871
- }
1872
- function isCredentialKey(key) {
1873
- return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/-/g, "_").toLowerCase().split("_").some((segment) => [
1874
- "auth",
1875
- "authorization",
1876
- "cookie",
1877
- "credential",
1878
- "credentials",
1879
- "key",
1880
- "password",
1881
- "secret",
1882
- "session",
1883
- "token"
1884
- ].includes(segment));
1885
- }
1886
- function isRecord(value) {
1887
- return typeof value === "object" && value !== null && !Array.isArray(value);
1888
- }
1889
- //#endregion
1890
- //#region src/campaign/external-optimizer-http.ts
1891
- function listenLocal(server) {
1892
- return new Promise((resolvePromise, reject) => {
1893
- server.once("error", reject);
1894
- server.listen(0, "127.0.0.1", () => {
1895
- server.off("error", reject);
1896
- const address = server.address();
1897
- if (!address || typeof address === "string") {
1898
- reject(/* @__PURE__ */ new Error("external optimizer callback did not bind a TCP port"));
1899
- return;
1900
- }
1901
- resolvePromise(address.port);
1902
- });
1903
- });
1904
- }
1905
- function closeServer(server) {
1906
- return new Promise((resolvePromise, reject) => {
1907
- server.close((error) => error ? reject(error) : resolvePromise());
1908
- });
1909
- }
1910
- function sendJson(response, status, body) {
1911
- response.writeHead(status, { "content-type": "application/json; charset=utf-8" });
1912
- response.end(JSON.stringify(body));
1913
- }
1914
- //#endregion
1915
1806
  //#region src/campaign/external-optimizer-callback.ts
1916
1807
  const MAX_CALLBACK_BODY_BYTES = 1e6;
1917
1808
  async function startExternalOptimizerCallback(args) {
@@ -1924,7 +1815,7 @@ async function startExternalOptimizerCallback(args) {
1924
1815
  const activeHandlers = /* @__PURE__ */ new Set();
1925
1816
  const server = createServer((request, response) => {
1926
1817
  if (!accepting) {
1927
- sendJsonIfOpen$1(response, 503, { error: "external optimizer callback is closing" });
1818
+ sendJsonIfOpen(response, 503, { error: "external optimizer callback is closing" });
1928
1819
  return;
1929
1820
  }
1930
1821
  const controller = new AbortController();
@@ -1972,7 +1863,7 @@ async function startExternalOptimizerCallback(args) {
1972
1863
  const closingServer = closeServer(server);
1973
1864
  server.closeIdleConnections?.();
1974
1865
  for (const controller of activeControllers) controller.abort();
1975
- const [serverResult] = await Promise.allSettled([closingServer, waitForActiveHandlers$1(activeHandlers)]);
1866
+ const [serverResult] = await Promise.allSettled([closingServer, waitForActiveHandlers(activeHandlers)]);
1976
1867
  if (activeControllers.size !== 0 || activeHandlers.size !== 0) throw new Error("external optimizer callback closed with active request work");
1977
1868
  if (serverResult?.status === "rejected") throw serverResult.reason;
1978
1869
  }
@@ -1980,34 +1871,34 @@ async function startExternalOptimizerCallback(args) {
1980
1871
  async function handleCallback(request, response, signal, args, nextEvaluation) {
1981
1872
  try {
1982
1873
  if (request.method !== "POST" || request.url !== "/evaluate") {
1983
- sendJsonIfOpen$1(response, 404, { error: "not found" });
1874
+ sendJsonIfOpen(response, 404, { error: "not found" });
1984
1875
  return;
1985
1876
  }
1986
1877
  if (request.headers.authorization !== `Bearer ${args.token}`) {
1987
- sendJsonIfOpen$1(response, 401, { error: "unauthorized" });
1878
+ sendJsonIfOpen(response, 401, { error: "unauthorized" });
1988
1879
  return;
1989
1880
  }
1990
1881
  const body = await readJson(request);
1991
1882
  if (!isRecord(body) || !isExternalTextCandidate(body.candidate) || typeof body.exampleId !== "string") {
1992
- sendJsonIfOpen$1(response, 400, { error: "candidate and exampleId are required strings" });
1883
+ sendJsonIfOpen(response, 400, { error: "candidate and exampleId are required strings" });
1993
1884
  return;
1994
1885
  }
1995
1886
  if (nextEvaluation() === void 0) {
1996
- sendJsonIfOpen$1(response, 429, { error: "evaluation limit reached" });
1887
+ sendJsonIfOpen(response, 429, { error: "evaluation limit reached" });
1997
1888
  return;
1998
1889
  }
1999
- sendJsonIfOpen$1(response, 200, await args.evaluate({
1890
+ sendJsonIfOpen(response, 200, await args.evaluate({
2000
1891
  candidate: body.candidate,
2001
1892
  exampleId: body.exampleId
2002
1893
  }, signal));
2003
1894
  } catch {
2004
- sendJsonIfOpen$1(response, 500, { error: "evaluation failed" });
1895
+ sendJsonIfOpen(response, 500, { error: "evaluation failed" });
2005
1896
  }
2006
1897
  }
2007
- async function waitForActiveHandlers$1(activeHandlers) {
1898
+ async function waitForActiveHandlers(activeHandlers) {
2008
1899
  while (activeHandlers.size > 0) await Promise.allSettled([...activeHandlers]);
2009
1900
  }
2010
- function sendJsonIfOpen$1(response, status, body) {
1901
+ function sendJsonIfOpen(response, status, body) {
2011
1902
  if (response.destroyed || response.writableEnded) return;
2012
1903
  sendJson(response, status, body);
2013
1904
  }
@@ -2041,681 +1932,6 @@ function assertCallbackConfig(args) {
2041
1932
  if (typeof args.evaluate !== "function") throw new Error("external optimizer callback: evaluate must be a function");
2042
1933
  }
2043
1934
  //#endregion
2044
- //#region src/campaign/external-optimizer-model-proxy.ts
2045
- const MODEL_PROXY_PATHS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
2046
- /**
2047
- * Put an OpenAI-compatible optimizer behind the shared cost ledger.
2048
- *
2049
- * The child process receives only a loopback URL and an ephemeral token.
2050
- * Provider credentials stay in this process. Every request reserves its
2051
- * conservative byte-count input bound plus the provider-enforced output cap
2052
- * before it leaves the machine.
2053
- */
2054
- async function startExternalOptimizerModelProxy(args) {
2055
- assertModelProxyConfig(args);
2056
- args.signal?.throwIfAborted();
2057
- const token = randomLocalToken();
2058
- const fetchImpl = args.fetchImpl ?? fetch;
2059
- let requestCount = 0;
2060
- let successfulCompletionCount = 0;
2061
- let totalRequestCount = args.initialUsage?.requests ?? 0;
2062
- let committedForBudget = args.initialUsage?.costUsd ?? 0;
2063
- let reservedForBudget = 0;
2064
- let accepting = true;
2065
- let closePromise;
2066
- const activeControllers = /* @__PURE__ */ new Set();
2067
- const activeHandlers = /* @__PURE__ */ new Set();
2068
- const server = createServer((request, response) => {
2069
- if (!accepting) {
2070
- sendJsonIfOpen(response, 503, { error: "external optimizer model proxy is closing" });
2071
- return;
2072
- }
2073
- const controller = new AbortController();
2074
- const abortRequest = () => {
2075
- request.destroy();
2076
- response.destroy();
2077
- };
2078
- activeControllers.add(controller);
2079
- controller.signal.addEventListener("abort", abortRequest, { once: true });
2080
- let handler;
2081
- handler = handleModelProxyRequest({
2082
- request,
2083
- response,
2084
- controller,
2085
- token,
2086
- args,
2087
- fetchImpl,
2088
- nextReservation: (maximumCostUsd) => {
2089
- if (totalRequestCount >= args.budget.maxRequests) return {
2090
- accepted: false,
2091
- reason: "optimizer model request limit reached"
2092
- };
2093
- if (committedForBudget + reservedForBudget + maximumCostUsd > args.budget.maxCostUsd + Number.EPSILON) return {
2094
- accepted: false,
2095
- reason: "optimizer model cost limit reached"
2096
- };
2097
- requestCount += 1;
2098
- totalRequestCount += 1;
2099
- reservedForBudget += maximumCostUsd;
2100
- return { accepted: true };
2101
- },
2102
- settleReservation: (maximumCostUsd, chargedCostUsd) => {
2103
- reservedForBudget = Math.max(0, reservedForBudget - maximumCostUsd);
2104
- committedForBudget += chargedCostUsd;
2105
- },
2106
- recordSuccessfulCompletion: () => {
2107
- successfulCompletionCount += 1;
2108
- }
2109
- }).finally(() => {
2110
- controller.signal.removeEventListener("abort", abortRequest);
2111
- activeControllers.delete(controller);
2112
- activeHandlers.delete(handler);
2113
- });
2114
- activeHandlers.add(handler);
2115
- handler.catch(() => void 0);
2116
- });
2117
- const port = await listenLocal(server);
2118
- const close = () => {
2119
- closePromise ??= closeModelProxy();
2120
- return closePromise;
2121
- };
2122
- const onAbort = () => {
2123
- close().catch(() => void 0);
2124
- };
2125
- args.signal?.addEventListener("abort", onAbort, { once: true });
2126
- if (args.signal?.aborted) onAbort();
2127
- return {
2128
- baseUrl: `http://127.0.0.1:${port}/v1`,
2129
- apiKey: token,
2130
- requestAttempts: () => requestCount,
2131
- successfulCompletions: () => successfulCompletionCount,
2132
- close
2133
- };
2134
- async function closeModelProxy() {
2135
- args.signal?.removeEventListener("abort", onAbort);
2136
- accepting = false;
2137
- const closingServer = closeServer(server);
2138
- server.closeIdleConnections?.();
2139
- for (const controller of activeControllers) controller.abort();
2140
- const [serverResult] = await Promise.allSettled([closingServer, waitForActiveHandlers(activeHandlers)]);
2141
- if (activeControllers.size !== 0 || activeHandlers.size !== 0) throw new Error("external optimizer model proxy closed with active request work");
2142
- if (serverResult?.status === "rejected") throw serverResult.reason;
2143
- }
2144
- }
2145
- async function handleModelProxyRequest(args) {
2146
- const { controller, request, response } = args;
2147
- try {
2148
- const path = request.url ? new URL(request.url, "http://127.0.0.1").pathname : "";
2149
- if (request.method !== "POST" || !MODEL_PROXY_PATHS.has(path)) {
2150
- sendJsonIfOpen(response, 404, { error: "not found" });
2151
- return;
2152
- }
2153
- if (request.headers.authorization !== `Bearer ${args.token}`) {
2154
- sendJsonIfOpen(response, 401, { error: "unauthorized" });
2155
- return;
2156
- }
2157
- const body = await readBody(request, args.args.budget.maxRequestBytes);
2158
- const parsed = parseModelProxyRequest(body, args.args.model, args.args.budget);
2159
- const maximumUsage = conservativeMaximumUsage(body.byteLength, parsed.maxOutputTokens, args.args.budget.pricing);
2160
- const maximumCostUsd = costForTokenPricing(args.args.budget.pricing, maximumUsage);
2161
- const reservation = args.nextReservation(maximumCostUsd);
2162
- if (!reservation.accepted) {
2163
- sendJsonIfOpen(response, 429, { error: reservation.reason });
2164
- return;
2165
- }
2166
- const timeout = setTimeout(() => controller.abort(), args.args.budget.requestTimeoutMs ?? 3e5);
2167
- let chargedForBudget = maximumCostUsd;
2168
- try {
2169
- const paid = await args.args.costLedger.runPaidCall({
2170
- channel: "optimizer",
2171
- phase: args.args.phase,
2172
- actor: args.args.actor,
2173
- ...args.args.tags ? { tags: args.args.tags } : {},
2174
- model: args.args.model,
2175
- maximumCharge: {
2176
- customTokenPricing: args.args.budget.pricing,
2177
- ...maximumUsage
2178
- },
2179
- execute: async () => forwardModelProxyRequest({
2180
- fetchImpl: args.fetchImpl,
2181
- upstreamBaseUrl: args.args.upstreamBaseUrl,
2182
- upstreamApiKey: args.args.upstreamApiKey,
2183
- path,
2184
- body,
2185
- model: args.args.model,
2186
- pricing: args.args.budget.pricing,
2187
- maxResponseBytes: args.args.budget.maxResponseBytes,
2188
- signal: controller.signal
2189
- }),
2190
- receipt: (result) => result.receipt,
2191
- receiptFromError: () => ({
2192
- model: args.args.model,
2193
- inputTokens: 0,
2194
- outputTokens: 0,
2195
- costUnknown: true,
2196
- usageUnknown: true
2197
- })
2198
- });
2199
- if (!paid.succeeded) {
2200
- chargedForBudget = paid.receipt ? paid.receipt.usageUnknown || paid.receipt.costUnknown ? maximumCostUsd : paid.receipt.costUsd : 0;
2201
- sendJsonIfOpen(response, isAbortError(paid.error) ? 504 : paid.error instanceof ProviderResponseTooLargeError ? 502 : 429, { error: paid.error.message });
2202
- return;
2203
- }
2204
- chargedForBudget = paid.value.usageComplete ? paid.receipt.costUsd : maximumCostUsd;
2205
- if (!paid.value.usageComplete) {
2206
- sendJsonIfOpen(response, 502, { error: "optimizer model response omitted complete token usage" });
2207
- return;
2208
- }
2209
- if (paid.value.status >= 200 && paid.value.status < 300) args.recordSuccessfulCompletion();
2210
- if (response.destroyed || response.writableEnded) return;
2211
- response.writeHead(paid.value.status, {
2212
- "content-type": paid.value.contentType,
2213
- "content-length": String(paid.value.body.byteLength)
2214
- });
2215
- response.end(paid.value.body);
2216
- } finally {
2217
- clearTimeout(timeout);
2218
- args.settleReservation(maximumCostUsd, chargedForBudget);
2219
- }
2220
- } catch (error) {
2221
- sendJsonIfOpen(response, error instanceof RequestBodyTooLargeError ? 413 : error instanceof Error && isAbortError(error) ? 503 : 400, { error: toErrorMessage(error) });
2222
- }
2223
- }
2224
- async function waitForActiveHandlers(activeHandlers) {
2225
- while (activeHandlers.size > 0) await Promise.allSettled([...activeHandlers]);
2226
- }
2227
- function sendJsonIfOpen(response, status, body) {
2228
- if (response.destroyed || response.writableEnded) return;
2229
- sendJson(response, status, body);
2230
- }
2231
- async function forwardModelProxyRequest(args) {
2232
- const upstream = modelProxyUpstreamUrl(args.upstreamBaseUrl, args.path);
2233
- const response = await args.fetchImpl(upstream, {
2234
- method: "POST",
2235
- headers: {
2236
- authorization: `Bearer ${args.upstreamApiKey}`,
2237
- "content-type": "application/json"
2238
- },
2239
- body: args.body.buffer.slice(args.body.byteOffset, args.body.byteOffset + args.body.byteLength),
2240
- signal: args.signal,
2241
- redirect: "error"
2242
- });
2243
- const body = await readProviderResponseBody(response, args.maxResponseBytes);
2244
- const usage = parseProviderUsage(body);
2245
- return {
2246
- status: response.status,
2247
- contentType: response.headers.get("content-type") ?? "application/json",
2248
- body,
2249
- receipt: usage ? {
2250
- model: args.model,
2251
- ...usage,
2252
- ...usage.actualCostUsd === void 0 ? { customTokenPricing: args.pricing } : {}
2253
- } : {
2254
- model: args.model,
2255
- inputTokens: 0,
2256
- outputTokens: 0,
2257
- costUnknown: true,
2258
- usageUnknown: true
2259
- },
2260
- usageComplete: usage !== void 0
2261
- };
2262
- }
2263
- function parseModelProxyRequest(body, expectedModel, budget) {
2264
- let value;
2265
- try {
2266
- value = JSON.parse(Buffer.from(body).toString("utf8"));
2267
- } catch {
2268
- throw new Error("optimizer model request must be valid JSON");
2269
- }
2270
- if (!isRecord(value)) throw new Error("optimizer model request must be a JSON object");
2271
- if (value.model !== expectedModel) throw new Error(`optimizer model request must use configured model '${expectedModel}'`);
2272
- if (value.stream !== void 0 && value.stream !== false) throw new Error("streaming optimizer model requests are not supported");
2273
- for (const field of [
2274
- "n",
2275
- "best_of",
2276
- "candidate_count",
2277
- "num_candidates"
2278
- ]) if (value[field] !== void 0 && value[field] !== 1) throw new Error(`optimizer model request ${field} must be 1 when supplied`);
2279
- const suppliedMaximums = [
2280
- value.max_output_tokens,
2281
- value.max_completion_tokens,
2282
- value.max_tokens
2283
- ].filter((maximum) => maximum !== void 0);
2284
- if (suppliedMaximums.length === 0 || suppliedMaximums.some((maximum) => !Number.isSafeInteger(maximum) || maximum <= 0)) throw new Error("optimizer model request requires a positive output-token limit");
2285
- const maxOutputTokens = Math.max(...suppliedMaximums);
2286
- if (maxOutputTokens > budget.maxOutputTokensPerRequest) throw new Error("optimizer model request exceeds maxOutputTokensPerRequest");
2287
- return { maxOutputTokens };
2288
- }
2289
- function modelProxyUpstreamUrl(baseUrl, requestPath) {
2290
- const upstream = new URL(baseUrl);
2291
- const basePath = upstream.pathname.replace(/\/+$/, "");
2292
- upstream.pathname = `${basePath}${basePath.endsWith("/v1") ? requestPath.replace(/^\/v1/, "") : requestPath}`;
2293
- return upstream.toString();
2294
- }
2295
- function parseProviderUsage(body) {
2296
- let value;
2297
- try {
2298
- value = JSON.parse(Buffer.from(body).toString("utf8"));
2299
- } catch {
2300
- return;
2301
- }
2302
- if (!isRecord(value) || !isRecord(value.usage)) return void 0;
2303
- const usage = value.usage;
2304
- const totalInputTokens = usage.input_tokens ?? usage.prompt_tokens;
2305
- const outputTokens = usage.output_tokens ?? usage.completion_tokens;
2306
- if (!Number.isSafeInteger(totalInputTokens) || totalInputTokens < 0 || !Number.isSafeInteger(outputTokens) || outputTokens < 0) return;
2307
- const inputDetails = isRecord(usage.input_tokens_details) ? usage.input_tokens_details : isRecord(usage.prompt_tokens_details) ? usage.prompt_tokens_details : {};
2308
- const outputDetails = isRecord(usage.output_tokens_details) ? usage.output_tokens_details : isRecord(usage.completion_tokens_details) ? usage.completion_tokens_details : {};
2309
- const cachedTokens = optionalTokenCount(inputDetails, [
2310
- "cached_tokens",
2311
- "cache_read_tokens",
2312
- "cache_read_input_tokens"
2313
- ]);
2314
- const cacheWriteTokens = optionalTokenCount(inputDetails, [
2315
- "cache_write_tokens",
2316
- "cache_creation_tokens",
2317
- "cache_creation_input_tokens"
2318
- ]);
2319
- const reasoningTokens = optionalTokenCount(outputDetails, ["reasoning_tokens"]);
2320
- const actualCostUsd = typeof usage.cost === "number" && Number.isFinite(usage.cost) && usage.cost >= 0 ? usage.cost : void 0;
2321
- if (cachedTokens === INVALID_TOKEN_COUNT || cacheWriteTokens === INVALID_TOKEN_COUNT || reasoningTokens === INVALID_TOKEN_COUNT) return;
2322
- const classifiedInputTokens = (cachedTokens ?? 0) + (cacheWriteTokens ?? 0);
2323
- if (classifiedInputTokens > totalInputTokens || (reasoningTokens ?? 0) > outputTokens) return;
2324
- return {
2325
- inputTokens: totalInputTokens - classifiedInputTokens,
2326
- outputTokens,
2327
- ...cachedTokens === void 0 ? {} : { cachedTokens },
2328
- ...cacheWriteTokens === void 0 ? {} : { cacheWriteTokens },
2329
- ...reasoningTokens === void 0 ? {} : { reasoningTokens },
2330
- ...actualCostUsd === void 0 ? {} : { actualCostUsd }
2331
- };
2332
- }
2333
- const INVALID_TOKEN_COUNT = Symbol("invalid-token-count");
2334
- function optionalTokenCount(details, fields) {
2335
- let found;
2336
- for (const field of fields) {
2337
- const value = details[field];
2338
- if (value === void 0 || value === null) continue;
2339
- if (!Number.isSafeInteger(value) || value < 0) return INVALID_TOKEN_COUNT;
2340
- if (found !== void 0 && found !== value) return INVALID_TOKEN_COUNT;
2341
- found = value;
2342
- }
2343
- return found;
2344
- }
2345
- function conservativeMaximumUsage(inputTokenUpperBound, outputTokenUpperBound, pricing) {
2346
- const inputRates = [
2347
- pricing.inputUsdPerMillion,
2348
- pricing.cachedInputUsdPerMillion ?? pricing.inputUsdPerMillion,
2349
- pricing.cacheWriteUsdPerMillion ?? pricing.inputUsdPerMillion
2350
- ];
2351
- const mostExpensiveInputClass = inputRates.indexOf(Math.max(...inputRates));
2352
- return {
2353
- inputTokens: mostExpensiveInputClass === 0 ? inputTokenUpperBound : 0,
2354
- ...mostExpensiveInputClass === 1 ? { cachedTokens: inputTokenUpperBound } : {},
2355
- ...mostExpensiveInputClass === 2 ? { cacheWriteTokens: inputTokenUpperBound } : {},
2356
- outputTokens: outputTokenUpperBound
2357
- };
2358
- }
2359
- async function readProviderResponseBody(response, maxBytes) {
2360
- const declaredLength = response.headers.get("content-length");
2361
- if (declaredLength !== null) {
2362
- const parsedLength = Number(declaredLength);
2363
- if (Number.isFinite(parsedLength) && parsedLength > maxBytes) throw new ProviderResponseTooLargeError();
2364
- }
2365
- if (!response.body) return /* @__PURE__ */ new Uint8Array();
2366
- const reader = response.body.getReader();
2367
- const chunks = [];
2368
- let totalBytes = 0;
2369
- try {
2370
- while (true) {
2371
- const next = await reader.read();
2372
- if (next.done) break;
2373
- totalBytes += next.value.byteLength;
2374
- if (totalBytes > maxBytes) {
2375
- await reader.cancel();
2376
- throw new ProviderResponseTooLargeError();
2377
- }
2378
- chunks.push(next.value);
2379
- }
2380
- } finally {
2381
- reader.releaseLock();
2382
- }
2383
- const body = new Uint8Array(totalBytes);
2384
- let offset = 0;
2385
- for (const chunk of chunks) {
2386
- body.set(chunk, offset);
2387
- offset += chunk.byteLength;
2388
- }
2389
- return body;
2390
- }
2391
- function assertModelProxyConfig(args) {
2392
- for (const [label, value] of [
2393
- ["upstreamBaseUrl", args.upstreamBaseUrl],
2394
- ["upstreamApiKey", args.upstreamApiKey],
2395
- ["model", args.model],
2396
- ["phase", args.phase],
2397
- ["actor", args.actor]
2398
- ]) if (typeof value !== "string" || !value.trim() || value.trim() !== value) throw new Error(`external optimizer model proxy: ${label} must be trimmed and non-empty`);
2399
- let parsed;
2400
- try {
2401
- parsed = new URL(args.upstreamBaseUrl);
2402
- } catch {
2403
- throw new Error("external optimizer model proxy: upstreamBaseUrl must be an HTTP(S) URL");
2404
- }
2405
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.search || parsed.hash) throw new Error("external optimizer model proxy: upstreamBaseUrl must be an HTTP(S) URL without credentials, query, or fragment");
2406
- assertExternalOptimizerModelBudget(args.budget, "external optimizer model proxy: budget");
2407
- if (args.tags !== void 0) {
2408
- for (const [key, value] of Object.entries(args.tags)) if (!key.trim() || key.trim() !== key || !value.trim() || value.trim() !== value) throw new Error("external optimizer model proxy: tags must be trimmed and non-empty");
2409
- }
2410
- if (args.initialUsage !== void 0) {
2411
- if (!Number.isSafeInteger(args.initialUsage.requests) || args.initialUsage.requests < 0 || !Number.isFinite(args.initialUsage.costUsd) || args.initialUsage.costUsd < 0) throw new Error("external optimizer model proxy: initialUsage must contain non-negative requests and cost");
2412
- if (args.initialUsage.requests > args.budget.maxRequests || args.initialUsage.costUsd > args.budget.maxCostUsd + Number.EPSILON) throw new Error("external optimizer model proxy: initialUsage exceeds the configured budget");
2413
- }
2414
- }
2415
- var RequestBodyTooLargeError = class extends Error {};
2416
- var ProviderResponseTooLargeError = class extends Error {
2417
- constructor() {
2418
- super("optimizer model response exceeds maxResponseBytes");
2419
- }
2420
- };
2421
- function readBody(request, maximumBytes) {
2422
- return new Promise((resolvePromise, reject) => {
2423
- let size = 0;
2424
- let tooLarge = false;
2425
- const chunks = [];
2426
- request.on("data", (chunk) => {
2427
- if (tooLarge) return;
2428
- size += chunk.byteLength;
2429
- if (size > maximumBytes) {
2430
- tooLarge = true;
2431
- chunks.length = 0;
2432
- return;
2433
- }
2434
- chunks.push(chunk);
2435
- });
2436
- request.on("error", reject);
2437
- request.on("end", () => {
2438
- if (tooLarge) {
2439
- reject(new RequestBodyTooLargeError("optimizer model request body too large"));
2440
- return;
2441
- }
2442
- resolvePromise(new Uint8Array(Buffer.concat(chunks)));
2443
- });
2444
- });
2445
- }
2446
- function randomLocalToken() {
2447
- return randomBytes(32).toString("hex");
2448
- }
2449
- function isAbortError(error) {
2450
- return error.name === "AbortError" || error.message.toLowerCase().includes("abort");
2451
- }
2452
- function toErrorMessage(error) {
2453
- return error instanceof Error ? error.message : String(error);
2454
- }
2455
- //#endregion
2456
- //#region src/campaign/external-optimizer-resources.ts
2457
- async function runWithCleanup(args) {
2458
- let value;
2459
- let operationError;
2460
- try {
2461
- value = await args.run();
2462
- } catch (cause) {
2463
- operationError = toError(cause);
2464
- }
2465
- let cleanupError;
2466
- try {
2467
- await args.cleanup();
2468
- } catch (cause) {
2469
- cleanupError = toError(cause);
2470
- }
2471
- if (operationError && cleanupError) throw new AggregateError([operationError, cleanupError], `${operationError.message}; ${args.label} cleanup failed: ${cleanupError.message}`);
2472
- if (operationError) throw operationError;
2473
- if (cleanupError) throw new Error(`${args.label} cleanup failed: ${cleanupError.message}`, { cause: cleanupError });
2474
- return value;
2475
- }
2476
- async function closeExternalOptimizerResources(args) {
2477
- const errors = (await Promise.allSettled([...args.modelProxy ? [args.modelProxy.close()] : [], args.callback.close()])).flatMap((result) => result.status === "rejected" ? [result.reason] : []);
2478
- if (errors.length > 0) throw new AggregateError(errors, `${args.label}: failed to close optimizer resources`);
2479
- }
2480
- function toError(cause) {
2481
- return cause instanceof Error ? cause : new Error(String(cause));
2482
- }
2483
- //#endregion
2484
- //#region src/campaign/external-optimizer-subprocess.ts
2485
- const MAX_PROCESS_OUTPUT_CHARS = 64e3;
2486
- const MAX_PROCESS_INPUT_BYTES = 64 * 1024 * 1024;
2487
- const MAX_PROCESS_RESULT_BYTES = 4 * 1024 * 1024;
2488
- const PROCESS_TERMINATION_GRACE_MS = 5e3;
2489
- const PROCESS_TERMINATION_POLL_MS = 25;
2490
- const PROCESS_KILL_WAIT_MS = 1e3;
2491
- const MAX_TIMER_DELAY_MS$4 = 2147483647;
2492
- const PROCESS_OUTPUT_HEAD_CHARS = MAX_PROCESS_OUTPUT_CHARS / 2;
2493
- async function runExternalOptimizerProcess(args) {
2494
- if (!Number.isSafeInteger(args.timeoutMs) || args.timeoutMs <= 0 || args.timeoutMs > MAX_TIMER_DELAY_MS$4) throw new Error(`${args.label} timeoutMs must be between 1 and ${MAX_TIMER_DELAY_MS$4}`);
2495
- if (process.platform === "win32") throw new Error(`${args.label} requires POSIX process-group cleanup; run the optimizer through WSL or Linux`);
2496
- throwIfAborted(args.signal, args.label);
2497
- const dir = await mkdtemp(join(tmpdir(), args.tempPrefix));
2498
- const inputPath = join(dir, "input.json");
2499
- const outputPath = join(dir, "output.json");
2500
- return runWithCleanup({
2501
- label: `${args.label} temporary directory`,
2502
- run: async () => {
2503
- const serializedInput = JSON.stringify(args.input);
2504
- if (serializedInput === void 0) throw new Error(`${args.label} input must be JSON-serializable`);
2505
- const inputJson = `${serializedInput}\n`;
2506
- const inputBytes = Buffer.byteLength(inputJson);
2507
- if (inputBytes > MAX_PROCESS_INPUT_BYTES) throw new Error(`${args.label} input exceeds ${MAX_PROCESS_INPUT_BYTES} bytes (${inputBytes})`);
2508
- await writeFile(inputPath, inputJson);
2509
- const command = args.runner?.command ?? "python";
2510
- const commandArgs = [
2511
- ...args.runner?.args ?? ["-m", args.module],
2512
- "--input",
2513
- inputPath,
2514
- "--output",
2515
- outputPath
2516
- ];
2517
- await runProcess({
2518
- label: args.label,
2519
- command,
2520
- args: commandArgs,
2521
- cwd: dir,
2522
- env: args.runner?.env,
2523
- timeoutMs: args.timeoutMs,
2524
- signal: args.signal
2525
- });
2526
- throwIfAborted(args.signal, args.label);
2527
- const raw = JSON.parse(await readBoundedTextFile(outputPath, MAX_PROCESS_RESULT_BYTES, `${args.label} output`));
2528
- throwIfAborted(args.signal, args.label);
2529
- if (!isRecord(raw)) throw new Error(`${args.label} output must be a JSON object`);
2530
- return raw;
2531
- },
2532
- cleanup: () => rm(dir, {
2533
- recursive: true,
2534
- force: true
2535
- })
2536
- });
2537
- }
2538
- async function readBoundedTextFile(path, maxBytes, label) {
2539
- if (!(await lstat(path)).isFile()) throw new Error(`${label} must be a regular file`);
2540
- const file = await open(path, "r");
2541
- try {
2542
- const buffer = Buffer.allocUnsafe(maxBytes + 1);
2543
- let bytesRead = 0;
2544
- while (bytesRead < buffer.byteLength) {
2545
- const chunk = await file.read(buffer, bytesRead, buffer.byteLength - bytesRead, bytesRead);
2546
- if (chunk.bytesRead === 0) break;
2547
- bytesRead += chunk.bytesRead;
2548
- }
2549
- if (bytesRead > maxBytes) throw new Error(`${label} exceeds ${maxBytes} bytes`);
2550
- return buffer.subarray(0, bytesRead).toString("utf8");
2551
- } finally {
2552
- await file.close();
2553
- }
2554
- }
2555
- function runProcess(args) {
2556
- throwIfAborted(args.signal, args.label);
2557
- return new Promise((resolvePromise, reject) => {
2558
- const child = spawn(args.command, args.args, {
2559
- cwd: args.cwd,
2560
- env: {
2561
- ...safeProcessEnvironment(),
2562
- ...args.env
2563
- },
2564
- stdio: [
2565
- "ignore",
2566
- "pipe",
2567
- "pipe"
2568
- ],
2569
- detached: process.platform !== "win32",
2570
- windowsHide: true
2571
- });
2572
- const stdout = createProcessOutputCapture();
2573
- const stderr = createProcessOutputCapture();
2574
- let settled = false;
2575
- let timeout;
2576
- const onAbort = () => finish(abortReason(args.signal, args.label));
2577
- const finish = (error) => {
2578
- if (settled) return;
2579
- settled = true;
2580
- if (timeout) clearTimeout(timeout);
2581
- args.signal?.removeEventListener("abort", onAbort);
2582
- terminateProcessTree(child).then(() => {
2583
- if (error) reject(error);
2584
- else resolvePromise();
2585
- }, (cleanupError) => {
2586
- if (error) {
2587
- const cleanup = cleanupError instanceof Error ? cleanupError : new Error(String(cleanupError));
2588
- reject(new AggregateError([error, cleanup], `${error.message}; ${args.label} process cleanup failed: ${cleanup.message}`));
2589
- return;
2590
- }
2591
- reject(/* @__PURE__ */ new Error(`${args.label} process cleanup failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`));
2592
- });
2593
- };
2594
- timeout = setTimeout(() => {
2595
- finish(/* @__PURE__ */ new Error(`${args.label} exceeded ${args.timeoutMs}ms`));
2596
- }, args.timeoutMs);
2597
- args.signal?.addEventListener("abort", onAbort, { once: true });
2598
- if (args.signal?.aborted) onAbort();
2599
- child.stdout.on("data", (chunk) => {
2600
- appendProcessOutput(stdout, chunk);
2601
- });
2602
- child.stderr.on("data", (chunk) => {
2603
- appendProcessOutput(stderr, chunk);
2604
- });
2605
- child.on("error", (error) => {
2606
- finish(/* @__PURE__ */ new Error(`${args.label} could not start: ${error.message}`));
2607
- });
2608
- child.on("close", (code) => {
2609
- if (code === 0) {
2610
- finish();
2611
- return;
2612
- }
2613
- finish(/* @__PURE__ */ new Error(`${args.label} exited ${String(code)}. stderr=${summarizeProcessOutput(stderr)} stdout=${summarizeProcessOutput(stdout)}`));
2614
- });
2615
- });
2616
- }
2617
- function throwIfAborted(signal, label) {
2618
- if (signal?.aborted) throw abortReason(signal, label);
2619
- }
2620
- function abortReason(signal, label) {
2621
- return signal.reason instanceof Error ? signal.reason : new Error(`${label} aborted`, { cause: signal.reason });
2622
- }
2623
- function safeProcessEnvironment() {
2624
- return Object.fromEntries([
2625
- "PATH",
2626
- "HOME",
2627
- "USER",
2628
- "LOGNAME",
2629
- "SHELL",
2630
- "TMPDIR",
2631
- "TMP",
2632
- "TEMP",
2633
- "LANG",
2634
- "LANGUAGE",
2635
- "LC_ALL",
2636
- "VIRTUAL_ENV",
2637
- "PYTHONPATH",
2638
- "SYSTEMROOT",
2639
- "COMSPEC",
2640
- "PATHEXT",
2641
- "WINDIR"
2642
- ].flatMap((name) => {
2643
- const value = process.env[name];
2644
- return value === void 0 ? [] : [[name, value]];
2645
- }));
2646
- }
2647
- async function terminateProcessTree(child) {
2648
- const pid = child.pid;
2649
- if (!pid) return;
2650
- if (process.platform === "win32") throw new Error("native Windows process-tree cleanup is unsupported");
2651
- if (!signalProcessGroup(pid, "SIGTERM")) return;
2652
- if (await waitForProcessGroupExit(pid, PROCESS_TERMINATION_GRACE_MS)) return;
2653
- if (!signalProcessGroup(pid, "SIGKILL")) return;
2654
- if (await waitForProcessGroupExit(pid, PROCESS_KILL_WAIT_MS)) return;
2655
- throw new Error(`process group ${pid} remained alive after SIGKILL`);
2656
- }
2657
- function signalProcessGroup(pid, signal) {
2658
- try {
2659
- process.kill(-pid, signal);
2660
- return true;
2661
- } catch (error) {
2662
- if (isMissingProcessError(error)) return false;
2663
- throw error;
2664
- }
2665
- }
2666
- async function waitForProcessGroupExit(pid, timeoutMs) {
2667
- const deadline = Date.now() + timeoutMs;
2668
- while (processGroupExists(pid)) {
2669
- const remainingMs = deadline - Date.now();
2670
- if (remainingMs <= 0) return false;
2671
- await new Promise((resolve) => setTimeout(resolve, Math.min(PROCESS_TERMINATION_POLL_MS, remainingMs)));
2672
- }
2673
- return true;
2674
- }
2675
- function processGroupExists(pid) {
2676
- try {
2677
- process.kill(-pid, 0);
2678
- return true;
2679
- } catch (error) {
2680
- if (isMissingProcessError(error)) return false;
2681
- throw error;
2682
- }
2683
- }
2684
- function isMissingProcessError(error) {
2685
- return typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH";
2686
- }
2687
- function createProcessOutputCapture() {
2688
- return {
2689
- full: "",
2690
- head: "",
2691
- tail: "",
2692
- totalChars: 0
2693
- };
2694
- }
2695
- function appendProcessOutput(capture, chunk) {
2696
- const text = chunk.toString();
2697
- capture.totalChars += text.length;
2698
- if (capture.full !== void 0) {
2699
- const combined = `${capture.full}${text}`;
2700
- if (combined.length <= MAX_PROCESS_OUTPUT_CHARS) {
2701
- capture.full = combined;
2702
- return;
2703
- }
2704
- capture.head = combined.slice(0, PROCESS_OUTPUT_HEAD_CHARS);
2705
- capture.tail = combined.slice(-32e3);
2706
- capture.full = void 0;
2707
- return;
2708
- }
2709
- capture.tail = `${capture.tail}${text}`.slice(-32e3);
2710
- }
2711
- function summarizeProcessOutput(capture, max = 4e3) {
2712
- const compact = (capture.full ?? `${capture.head}\n...[${capture.totalChars - capture.head.length - capture.tail.length} chars omitted]...\n${capture.tail}`).trim().replace(/\s+/g, " ");
2713
- if (compact.length <= max) return compact;
2714
- const headChars = Math.floor(max / 3);
2715
- const tailChars = max - headChars;
2716
- return `${compact.slice(0, headChars)}...[${compact.length - max} chars omitted]...${compact.slice(-tailChars)}`;
2717
- }
2718
- //#endregion
2719
1935
  //#region src/campaign/external-optimizer-run-budget.ts
2720
1936
  function externalOptimizerRunKey(input) {
2721
1937
  if (!input.attemptId.trim() || input.attemptId.trim() !== input.attemptId) throw new Error("external optimizer attemptId must be trimmed and non-empty");
@@ -7946,4 +7162,4 @@ function skillOptOptimizationMethod(config) {
7946
7162
  //#endregion
7947
7163
  export { campaignScenarioIdentity as $, assertOptimizationResult as A, pairedDeltaTest as At, surfaceHash as B, detectScale as C, paretoFrontier as Ct, runCanaries as D, decidePairedPromotion as Dt, pairHoldout as E, recoverTruncatedJson as Et, assertComponentSurface as F, summarizeBackendIntegrity as Ft, buildReflectionPrompt as G, campaignMeanComposite as H, codeSurfaceIdentityMaterial as I, JudgeParseError as It, runCampaign as J, parseReflectionResponse as K, componentSurfaceIdentityMaterial as L, costFromLedgerSummary as M, assertRealAgentReceipts as Mt, optimizationTokenUsageFromSummary as N, assertRealBackend as Nt, composeGate as O, pairedDecisionShape as Ot, assertCodeSurfaceIdentity as P, summarizeAgentReceiptIntegrity as Pt, assertCampaignSplitIdentity as Q, renderSurfaceDiff as R, defaultProductionGate as S, dominates as St, heldoutSignificance as T, scalarScore as Tt, compareRankKeys as U, campaignBreakdown as V, DEFAULT_MUTATION_PRIMITIVES as W, tangleTracesRoot as X, resolveRunDir as Y, assertCampaignDesign as Z, buildEvidenceVector as _, canonicalJson as _t, emitLoopProvenance as a, createReferenceEquivalenceJudge as at, powerPreflight as b, inMemoryVerdictCache as bt, provenanceRecordPath as c, redTeamDataset as ct, runImprovementLoop as d, toolNamesForRun as dt, campaignSplitDigest as et, runOptimization as f, Dataset as ft, gepaOptimizationMethod as g, cachedJudge as gt, labelTrustRank as h, llmJudge as ht, canonicalDigest as i, REFERENCE_EQUIVALENCE_JUDGE_VERSION as it, compareOptimizationMethods as j, BackendIntegrityError as jt, externalTextOptimizationMethod as k, minimumPairsForPairedDeltaTest as kt, provenanceSpansPath as l, redTeamReport as lt, isProposedCandidate as m, hashScenarios as mt, buildLoopProvenanceRecord as n, openAutoPr as nt, loopProvenanceArgsFromResult as o, runReferenceEquivalenceJudge as ot, runEval as p, HoldoutLockedError as pt, planCampaignRun as q, campaignMeasurementDigest as r, REFERENCE_EQUIVALENCE_INPUT_LIMITS as rt, loopProvenanceSpans as s, DEFAULT_RED_TEAM_CORPUS as st, skillOptOptimizationMethod as t, campaignSplitDigestFromIdentities as tt, verifyLoopProvenanceRecord as u, scoreRedTeamOutput as ut, paretoPolicy as v, contentHash as vt, dimensionRegressions as w, paretoFrontierWithCrowding as wt, heldOutGate as x, crowdingDistance as xt, paretoSignificanceGate as y, fileVerdictCache as yt, surfaceContentHash as z };
7948
7164
 
7949
- //# sourceMappingURL=skillopt-optimization-method-CjKMZy0d.js.map
7165
+ //# sourceMappingURL=skillopt-optimization-method-BbGnCC53.js.map