@crowandraven/evalkeeper 0.0.0-stage → 0.1.1

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 (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -2
  3. package/bin/evalkeeper.mjs +9 -0
  4. package/dist/attention.d.ts +49 -0
  5. package/dist/attention.js +48 -0
  6. package/dist/attention.js.map +1 -0
  7. package/dist/board.d.ts +55 -0
  8. package/dist/board.js +2 -0
  9. package/dist/board.js.map +1 -0
  10. package/dist/cli/addPages.d.ts +79 -0
  11. package/dist/cli/addPages.js +181 -0
  12. package/dist/cli/addPages.js.map +1 -0
  13. package/dist/cli/main.d.ts +18 -0
  14. package/dist/cli/main.js +115 -0
  15. package/dist/cli/main.js.map +1 -0
  16. package/dist/common.d.ts +72 -0
  17. package/dist/common.js +276 -0
  18. package/dist/common.js.map +1 -0
  19. package/dist/compare.d.ts +85 -0
  20. package/dist/compare.js +185 -0
  21. package/dist/compare.js.map +1 -0
  22. package/dist/decisions.d.ts +84 -0
  23. package/dist/decisions.js +146 -0
  24. package/dist/decisions.js.map +1 -0
  25. package/dist/feedback.d.ts +114 -0
  26. package/dist/feedback.js +116 -0
  27. package/dist/feedback.js.map +1 -0
  28. package/dist/format.d.ts +6 -0
  29. package/dist/format.js +22 -0
  30. package/dist/format.js.map +1 -0
  31. package/dist/glossary.d.ts +46 -0
  32. package/dist/glossary.js +45 -0
  33. package/dist/glossary.js.map +1 -0
  34. package/dist/health.d.ts +40 -0
  35. package/dist/health.js +101 -0
  36. package/dist/health.js.map +1 -0
  37. package/dist/index.d.ts +31 -0
  38. package/dist/index.js +34 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/labels.d.ts +8 -0
  41. package/dist/labels.js +15 -0
  42. package/dist/labels.js.map +1 -0
  43. package/dist/legs.d.ts +23 -0
  44. package/dist/legs.js +22 -0
  45. package/dist/legs.js.map +1 -0
  46. package/dist/memoryStore.d.ts +21 -0
  47. package/dist/memoryStore.js +228 -0
  48. package/dist/memoryStore.js.map +1 -0
  49. package/dist/models.d.ts +50 -0
  50. package/dist/models.js +39 -0
  51. package/dist/models.js.map +1 -0
  52. package/dist/prune.d.ts +48 -0
  53. package/dist/prune.js +77 -0
  54. package/dist/prune.js.map +1 -0
  55. package/dist/quickSet.d.ts +26 -0
  56. package/dist/quickSet.js +44 -0
  57. package/dist/quickSet.js.map +1 -0
  58. package/dist/runner.d.ts +193 -0
  59. package/dist/runner.js +706 -0
  60. package/dist/runner.js.map +1 -0
  61. package/dist/settings.d.ts +157 -0
  62. package/dist/settings.js +183 -0
  63. package/dist/settings.js.map +1 -0
  64. package/dist/stableJson.d.ts +11 -0
  65. package/dist/stableJson.js +15 -0
  66. package/dist/stableJson.js.map +1 -0
  67. package/dist/stats.d.ts +98 -0
  68. package/dist/stats.js +119 -0
  69. package/dist/stats.js.map +1 -0
  70. package/dist/store.d.ts +146 -0
  71. package/dist/store.js +3 -0
  72. package/dist/store.js.map +1 -0
  73. package/dist/suggest.d.ts +75 -0
  74. package/dist/suggest.js +150 -0
  75. package/dist/suggest.js.map +1 -0
  76. package/dist/summary.d.ts +51 -0
  77. package/dist/summary.js +61 -0
  78. package/dist/summary.js.map +1 -0
  79. package/dist/testing.d.ts +26 -0
  80. package/dist/testing.js +341 -0
  81. package/dist/testing.js.map +1 -0
  82. package/dist/timeout.d.ts +2 -0
  83. package/dist/timeout.js +15 -0
  84. package/dist/timeout.js.map +1 -0
  85. package/dist/types.d.ts +219 -0
  86. package/dist/types.js +46 -0
  87. package/dist/types.js.map +1 -0
  88. package/dist/upkeepRules.d.ts +28 -0
  89. package/dist/upkeepRules.js +40 -0
  90. package/dist/upkeepRules.js.map +1 -0
  91. package/dist/util.d.ts +8 -0
  92. package/dist/util.js +18 -0
  93. package/dist/util.js.map +1 -0
  94. package/dist/weekly.d.ts +80 -0
  95. package/dist/weekly.js +111 -0
  96. package/dist/weekly.js.map +1 -0
  97. package/package.json +81 -4
  98. package/src/attention.ts +88 -0
  99. package/src/board.ts +56 -0
  100. package/src/cli/addPages.ts +256 -0
  101. package/src/cli/main.ts +125 -0
  102. package/src/common.ts +338 -0
  103. package/src/compare.ts +261 -0
  104. package/src/decisions.ts +230 -0
  105. package/src/feedback.ts +225 -0
  106. package/src/format.ts +19 -0
  107. package/src/glossary.ts +75 -0
  108. package/src/health.ts +147 -0
  109. package/src/index.ts +33 -0
  110. package/src/labels.ts +18 -0
  111. package/src/legs.ts +38 -0
  112. package/src/memoryStore.ts +268 -0
  113. package/src/models.ts +82 -0
  114. package/src/prune.ts +95 -0
  115. package/src/quickSet.ts +55 -0
  116. package/src/runner.ts +971 -0
  117. package/src/settings.ts +331 -0
  118. package/src/stableJson.ts +24 -0
  119. package/src/stats.ts +215 -0
  120. package/src/store.ts +167 -0
  121. package/src/suggest.ts +245 -0
  122. package/src/summary.ts +109 -0
  123. package/src/testing.ts +392 -0
  124. package/src/timeout.ts +14 -0
  125. package/src/types.ts +252 -0
  126. package/src/upkeepRules.ts +46 -0
  127. package/src/util.ts +17 -0
  128. package/src/weekly.ts +167 -0
  129. package/starter/index.ts +86 -0
  130. package/templates/app/api/cron/evals-weekly/route.ts +24 -0
  131. package/templates/app/evals/[suite]/page.tsx +449 -0
  132. package/templates/app/evals/[suite]/runs/[runId]/page.tsx +95 -0
  133. package/templates/app/evals/feedback/page.tsx +219 -0
  134. package/templates/app/evals/page.tsx +313 -0
  135. package/templates/components/evalkeeper/AddCase.tsx +62 -0
  136. package/templates/components/evalkeeper/AnswerKey.tsx +360 -0
  137. package/templates/components/evalkeeper/CaseMenu.tsx +122 -0
  138. package/templates/components/evalkeeper/Fields.tsx +110 -0
  139. package/templates/components/evalkeeper/RefreshWhile.tsx +25 -0
  140. package/templates/components/evalkeeper/SettingsHistory.tsx +191 -0
  141. package/templates/components/evalkeeper/Submit.tsx +58 -0
  142. package/templates/components/evalkeeper/Thumbs.tsx +117 -0
  143. package/templates/components/evalkeeper/Tip.tsx +98 -0
  144. package/templates/components/evalkeeper/WeeklyCheck.tsx +124 -0
  145. package/templates/components/evalkeeper/evalkeeper.css +71 -0
  146. package/templates/components/evalkeeper/ui.tsx +103 -0
  147. package/templates/lib/evalkeeper/actions.ts +263 -0
  148. package/templates/lib/evalkeeper/cronAuth.ts +18 -0
  149. package/templates/lib/evalkeeper/paths.ts +11 -0
  150. package/templates/lib/evalkeeper/time.ts +4 -0
  151. package/templates/lib/evalkeeper/weekly.ts +51 -0
@@ -0,0 +1,40 @@
1
+ import type { BoardRow } from "./board.js";
2
+ import type { ModelCatalog } from "./models.js";
3
+ import { type CheckDef, type SuitePriority } from "./types.js";
4
+ /**
5
+ * Where a suite stands, for its card on the evals hub: one status and the
6
+ * reasons, from the same board and suggestion its own page shows. Pure.
7
+ */
8
+ /** Where a suite stands, from not tested to good. */
9
+ export type HealthStatus = "untested" | "stale" | "few" | "improve" | "fair" | "good";
10
+ /**
11
+ * A suite's status for its card, with the live model's score and the reasons, most important first.
12
+ */
13
+ export type Health = {
14
+ status: HealthStatus;
15
+ title: string;
16
+ /** The live model, its score, and how many models were tested. */
17
+ live: {
18
+ label: string;
19
+ rate: number;
20
+ } | null;
21
+ testedModels: number;
22
+ /** What to do or watch, most important first. */
23
+ details: string[];
24
+ };
25
+ /**
26
+ * Where a suite stands, for its card on the hub, from the same board and suggestion its
27
+ * page shows.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const board = await runner.board("ticket_triage");
32
+ * const h = suiteHealth(board.rows, suite.checks, suite.priority, board.cases, board.provisional, MODELS);
33
+ * // h.status: "good" | "fair" | "improve" | "few" | "stale" | "untested"
34
+ * ```
35
+ */
36
+ export declare function suiteHealth(rows: BoardRow[], checks: CheckDef[], priority: SuitePriority, cases: number,
37
+ /** Cases in use on unreviewed answers. */
38
+ provisional?: number,
39
+ /** Your model catalog, for retirements and the fallback's provider. */
40
+ models?: ModelCatalog): Health;
package/dist/health.js ADDED
@@ -0,0 +1,101 @@
1
+ import { confidenceFor, TARGET_CASES } from "./summary.js";
2
+ import { suggest } from "./suggest.js";
3
+ import { checkBar } from "./types.js";
4
+ const pct = (x) => `${Math.round(x * 100)}%`;
5
+ /**
6
+ * Where a suite stands, for its card on the hub, from the same board and suggestion its
7
+ * page shows.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const board = await runner.board("ticket_triage");
12
+ * const h = suiteHealth(board.rows, suite.checks, suite.priority, board.cases, board.provisional, MODELS);
13
+ * // h.status: "good" | "fair" | "improve" | "few" | "stale" | "untested"
14
+ * ```
15
+ */
16
+ export function suiteHealth(rows, checks, priority, cases,
17
+ /** Cases in use on unreviewed answers. */
18
+ provisional = 0,
19
+ /** Your model catalog, for retirements and the fallback's provider. */
20
+ models = {}) {
21
+ const liveRow = rows.find((r) => r.live) ?? null;
22
+ const testedModels = rows.filter((r) => r.test && !r.test.stale).length;
23
+ const t = liveRow?.test;
24
+ const live = liveRow && t ? { label: liveRow.label, rate: t.right / t.total } : null;
25
+ const base = { live, testedModels };
26
+ const fewer = cases < TARGET_CASES ? `${cases} of ${TARGET_CASES} cases` : "";
27
+ if (!t)
28
+ return {
29
+ ...base,
30
+ status: "untested",
31
+ title: "Not tested yet",
32
+ details: [
33
+ `Test the models to see how ${liveRow?.label ?? "the live model"} does.`,
34
+ ],
35
+ };
36
+ if (t.stale)
37
+ return {
38
+ ...base,
39
+ status: "stale",
40
+ title: "Test again",
41
+ details: ["Cases, answers, or instructions changed since the last test."],
42
+ };
43
+ const details = [];
44
+ if (provisional)
45
+ details.push(`${provisional} of ${cases} answers are provisional: review them before trusting these scores.`);
46
+ // Live checks under their bars, serious first.
47
+ const below = checks
48
+ .map((c) => ({ c, rate: t.byCheck[c.key]?.rate ?? null }))
49
+ .filter((x) => x.rate !== null && x.rate < checkBar(x.c))
50
+ .sort((a, b) => Number(b.c.severity === "serious") -
51
+ Number(a.c.severity === "serious") || a.rate - b.rate);
52
+ for (const { c, rate } of below.slice(0, 3))
53
+ details.push(`${c.label}: ${pct(rate)}, under the ${pct(checkBar(c))} bar${c.severity === "serious" ? " (serious)" : ""}.`);
54
+ if (below.length > 3)
55
+ details.push(`${below.length - 3} more under the bar.`);
56
+ const s = suggest(rows, checks, priority, models);
57
+ const change = s && !s.same;
58
+ if (change)
59
+ details.push(s.keepLive
60
+ ? `A better fallback is suggested: ${s.fallback?.label}.`
61
+ : `${s.live.label} is suggested over ${liveRow.label}.`);
62
+ if (testedModels < 2)
63
+ details.push("Only one model tested: test others to compare.");
64
+ const confidence = confidenceFor(cases, live?.rate ?? 0.5);
65
+ if (confidence.level === "too-few")
66
+ return {
67
+ ...base,
68
+ status: "few",
69
+ title: "Too few cases to trust",
70
+ details: [
71
+ `${fewer}: a score could be off by about ${confidence.margin} points.`,
72
+ ...details,
73
+ ],
74
+ };
75
+ if (below.length || change)
76
+ return {
77
+ ...base,
78
+ status: "improve",
79
+ title: "Room to improve",
80
+ details: fewer
81
+ ? [...details, `${fewer}: add more to firm it up.`]
82
+ : details,
83
+ };
84
+ if (confidence.level === "rough")
85
+ return {
86
+ ...base,
87
+ status: "fair",
88
+ title: "Good so far",
89
+ details: [
90
+ `Meets every bar, but with ${fewer} a score could be off by about ${confidence.margin} points.`,
91
+ ...details,
92
+ ],
93
+ };
94
+ return {
95
+ ...base,
96
+ status: "good",
97
+ title: "In good shape",
98
+ details: details.length ? details : ["Meets every bar on enough cases."],
99
+ };
100
+ }
101
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAqC,MAAM,YAAY,CAAC;AAwBzE,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,IAAgB,EAChB,MAAkB,EAClB,QAAuB,EACvB,KAAa;AACb,0CAA0C;AAC1C,WAAW,GAAG,CAAC;AACf,uEAAuE;AACvE,SAAuB,EAAE;IAEzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACjD,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;IACxE,MAAM,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC;IACxB,MAAM,IAAI,GACR,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,YAAY,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9E,IAAI,CAAC,CAAC;QACJ,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,UAAU;YAClB,KAAK,EAAE,gBAAgB;YACvB,OAAO,EAAE;gBACP,8BAA8B,OAAO,EAAE,KAAK,IAAI,gBAAgB,QAAQ;aACzE;SACF,CAAC;IACJ,IAAI,CAAC,CAAC,KAAK;QACT,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,CAAC,8DAA8D,CAAC;SAC1E,CAAC;IAEJ,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,WAAW;QACb,OAAO,CAAC,IAAI,CACV,GAAG,WAAW,OAAO,KAAK,qEAAqE,CAChG,CAAC;IACJ,+CAA+C;IAC/C,MAAM,KAAK,GAAG,MAAM;SACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;SACzD,MAAM,CACL,CAAC,CAAC,EAAsC,EAAE,CACxC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAC5C;SACA,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAC1D,CAAC;IACJ,KAAK,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CACV,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,CAC9G,CAAC;IACJ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAE9E,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5B,IAAI,MAAM;QACR,OAAO,CAAC,IAAI,CACV,CAAC,CAAC,QAAQ;YACR,CAAC,CAAC,mCAAmC,CAAC,CAAC,QAAQ,EAAE,KAAK,GAAG;YACzD,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,sBAAsB,OAAO,CAAC,KAAK,GAAG,CAC1D,CAAC;IACJ,IAAI,YAAY,GAAG,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;IAEjE,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC;IAC3D,IAAI,UAAU,CAAC,KAAK,KAAK,SAAS;QAChC,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,wBAAwB;YAC/B,OAAO,EAAE;gBACP,GAAG,KAAK,mCAAmC,UAAU,CAAC,MAAM,UAAU;gBACtE,GAAG,OAAO;aACX;SACF,CAAC;IACJ,IAAI,KAAK,CAAC,MAAM,IAAI,MAAM;QACxB,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,SAAS;YACjB,KAAK,EAAE,iBAAiB;YACxB,OAAO,EAAE,KAAK;gBACZ,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,KAAK,2BAA2B,CAAC;gBACnD,CAAC,CAAC,OAAO;SACZ,CAAC;IACJ,IAAI,UAAU,CAAC,KAAK,KAAK,OAAO;QAC9B,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE;gBACP,6BAA6B,KAAK,kCAAkC,UAAU,CAAC,MAAM,UAAU;gBAC/F,GAAG,OAAO;aACX;SACF,CAAC;IACJ,OAAO;QACL,GAAG,IAAI;QACP,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,eAAe;QACtB,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,kCAAkC,CAAC;KACzE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The core: suites, checks, stats, comparisons, suggestions, health, feedback,
3
+ * versioned settings, and the store interfaces. Pure: no database,
4
+ * framework, or provider.
5
+ *
6
+ * @module evalkeeper
7
+ */
8
+ export * from "./types.js";
9
+ export * from "./models.js";
10
+ export * from "./board.js";
11
+ export * from "./stats.js";
12
+ export * from "./compare.js";
13
+ export * from "./summary.js";
14
+ export * from "./suggest.js";
15
+ export * from "./health.js";
16
+ export * from "./attention.js";
17
+ export * from "./common.js";
18
+ export * from "./legs.js";
19
+ export * from "./timeout.js";
20
+ export * from "./prune.js";
21
+ export * from "./quickSet.js";
22
+ export * from "./stableJson.js";
23
+ export * from "./upkeepRules.js";
24
+ export * from "./format.js";
25
+ export * from "./glossary.js";
26
+ export * from "./feedback.js";
27
+ export * from "./weekly.js";
28
+ export * from "./settings.js";
29
+ export * from "./decisions.js";
30
+ export * from "./store.js";
31
+ export * from "./labels.js";
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The core: suites, checks, stats, comparisons, suggestions, health, feedback,
3
+ * versioned settings, and the store interfaces. Pure: no database,
4
+ * framework, or provider.
5
+ *
6
+ * @module evalkeeper
7
+ */
8
+ export * from "./types.js";
9
+ export * from "./models.js";
10
+ export * from "./board.js";
11
+ export * from "./stats.js";
12
+ export * from "./compare.js";
13
+ export * from "./summary.js";
14
+ export * from "./suggest.js";
15
+ export * from "./health.js";
16
+ export * from "./attention.js";
17
+ export * from "./common.js";
18
+ export * from "./legs.js";
19
+ export * from "./timeout.js";
20
+ export * from "./prune.js";
21
+ export * from "./quickSet.js";
22
+ export * from "./stableJson.js";
23
+ export * from "./upkeepRules.js";
24
+ export * from "./format.js";
25
+ export * from "./glossary.js";
26
+ export * from "./feedback.js";
27
+ export * from "./weekly.js";
28
+ export * from "./settings.js";
29
+ export * from "./decisions.js";
30
+ export * from "./store.js";
31
+ export * from "./labels.js";
32
+ // Server-only (node:crypto): import from "@crowandraven/evalkeeper/runner".
33
+ // In-memory store for tests and demos: "@crowandraven/evalkeeper/memory".
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,4EAA4E;AAC5E,0EAA0E"}
@@ -0,0 +1,8 @@
1
+ import type { LabelRecord } from "./store.js";
2
+ /**
3
+ * The EXPECTED answer tests use: the newest confirmed one, or failing that a
4
+ * provisional one (put to use before review). Pending answers never count.
5
+ */
6
+ export declare function confirmedLabel(labels: LabelRecord[]): LabelRecord | null;
7
+ /** In use on an answer nobody has reviewed yet. */
8
+ export declare function isProvisional(labels: LabelRecord[]): boolean;
package/dist/labels.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The EXPECTED answer tests use: the newest confirmed one, or failing that a
3
+ * provisional one (put to use before review). Pending answers never count.
4
+ */
5
+ export function confirmedLabel(labels) {
6
+ const newest = (status) => labels
7
+ .filter((l) => l.status === status)
8
+ .sort((a, b) => +b.updatedAt - +a.updatedAt)[0] ?? null;
9
+ return newest("CONFIRMED") ?? newest("PROVISIONAL");
10
+ }
11
+ /** In use on an answer nobody has reviewed yet. */
12
+ export function isProvisional(labels) {
13
+ return confirmedLabel(labels)?.status === "PROVISIONAL";
14
+ }
15
+ //# sourceMappingURL=labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.js","sourceRoot":"","sources":["../src/labels.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,MAAM,MAAM,GAAG,CAAC,MAA6B,EAAE,EAAE,CAC/C,MAAM;SACH,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;SAClC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAC5D,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,MAAM,CAAC,aAAa,CAAC,CAAC;AACtD,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,OAAO,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,aAAa,CAAC;AAC1D,CAAC"}
package/dist/legs.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * A test longer than one request's time limit runs in legs: each leg
3
+ * answers what it can, then hands the rest to a fresh request. Pure.
4
+ */
5
+ /** At most this many legs (about half an hour) before a test gives up. */
6
+ export declare const MAX_LEGS = 6;
7
+ /**
8
+ * Whether a leg that ran out of time should hand off: only when it made
9
+ * progress (so a stuck case can't loop) and legs remain.
10
+ */
11
+ export declare function shouldContinue(opts: {
12
+ /** Answers left for a later leg. */
13
+ left: number;
14
+ /** Answers this leg gave. */
15
+ done: number;
16
+ leg: number;
17
+ outOfCredits: boolean;
18
+ }): boolean;
19
+ /**
20
+ * Whether a test still marked running was stopped by the server: nothing
21
+ * started or answered within `stuckMs`. Legs keep it alive.
22
+ */
23
+ export declare function isStuck(startedAt: Date, lastAnswerAt: Date | null, now: number, stuckMs: number): boolean;
package/dist/legs.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A test longer than one request's time limit runs in legs: each leg
3
+ * answers what it can, then hands the rest to a fresh request. Pure.
4
+ */
5
+ /** At most this many legs (about half an hour) before a test gives up. */
6
+ export const MAX_LEGS = 6;
7
+ /**
8
+ * Whether a leg that ran out of time should hand off: only when it made
9
+ * progress (so a stuck case can't loop) and legs remain.
10
+ */
11
+ export function shouldContinue(opts) {
12
+ return (opts.left > 0 && opts.done > 0 && !opts.outOfCredits && opts.leg < MAX_LEGS);
13
+ }
14
+ /**
15
+ * Whether a test still marked running was stopped by the server: nothing
16
+ * started or answered within `stuckMs`. Legs keep it alive.
17
+ */
18
+ export function isStuck(startedAt, lastAnswerAt, now, stuckMs) {
19
+ const last = Math.max(+startedAt, lastAnswerAt ? +lastAnswerAt : 0);
20
+ return now - last > stuckMs;
21
+ }
22
+ //# sourceMappingURL=legs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legs.js","sourceRoot":"","sources":["../src/legs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC;AAE1B;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAO9B;IACC,OAAO,CACL,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,GAAG,GAAG,QAAQ,CAC5E,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CACrB,SAAe,EACf,YAAyB,EACzB,GAAW,EACX,OAAe;IAEf,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,OAAO,GAAG,GAAG,IAAI,GAAG,OAAO,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * An in-memory store, for tests, demos, and trying Evalkeeper before adding
3
+ * tables.
4
+ *
5
+ * @module evalkeeper/memory
6
+ */
7
+ import type { FeedbackRecord, FeedbackStore } from "./feedback.js";
8
+ import { type SettingsChange, type SettingsStore, type SettingsVersion } from "./settings.js";
9
+ import type { CaseRecord, EvalStore, OutputRecord, RunRecord } from "./store.js";
10
+ /**
11
+ * An EvalStore in memory: for tests, demos, and trying Evalkeeper before
12
+ * adding tables. Everything is gone when the process ends.
13
+ */
14
+ export declare function memoryStore(): EvalStore & FeedbackStore & SettingsStore & {
15
+ cases: CaseRecord[];
16
+ runs: RunRecord[];
17
+ outputs: OutputRecord[];
18
+ feedback: FeedbackRecord[];
19
+ versions: SettingsVersion[];
20
+ changes: SettingsChange[];
21
+ };
@@ -0,0 +1,228 @@
1
+ import { cleanRating } from "./feedback.js";
2
+ import { SettingsConflict, } from "./settings.js";
3
+ /**
4
+ * An EvalStore in memory: for tests, demos, and trying Evalkeeper before
5
+ * adding tables. Everything is gone when the process ends.
6
+ */
7
+ export function memoryStore() {
8
+ const cases = [];
9
+ const runs = [];
10
+ const outputs = [];
11
+ const feedback = [];
12
+ const versions = [];
13
+ const changes = [];
14
+ const live = new Map();
15
+ let n = 0;
16
+ const id = (prefix) => `${prefix}_${(++n).toString(36)}`;
17
+ const now = () => new Date();
18
+ return {
19
+ cases,
20
+ runs,
21
+ outputs,
22
+ feedback,
23
+ versions,
24
+ changes,
25
+ async liveVersion(operation) {
26
+ const id = live.get(operation);
27
+ return versions.find((v) => v.id === id) ?? null;
28
+ },
29
+ async listVersions(operation) {
30
+ return versions
31
+ .filter((v) => v.operation === operation)
32
+ .sort((a, b) => b.number - a.number);
33
+ },
34
+ async listChanges(operation, opts = {}) {
35
+ // Kept in the order they happened, so newest first is the reverse.
36
+ return changes
37
+ .filter((c) => c.operation === operation)
38
+ .reverse()
39
+ .slice(0, opts.limit ?? Infinity);
40
+ },
41
+ async switchTo(operation, sw) {
42
+ // Synchronous from here on, so it's atomic in memory.
43
+ const fromId = live.get(operation) ?? null;
44
+ if (fromId !== sw.expectLive)
45
+ throw new SettingsConflict(operation);
46
+ let to;
47
+ if (sw.create) {
48
+ const last = versions
49
+ .filter((v) => v.operation === operation)
50
+ .reduce((n, v) => Math.max(n, v.number), 0);
51
+ to = {
52
+ ...sw.create.settings,
53
+ id: id("ver"),
54
+ operation,
55
+ number: last + 1,
56
+ promptVersion: sw.create.promptVersion,
57
+ createdAt: now(),
58
+ };
59
+ versions.push(to);
60
+ }
61
+ else {
62
+ to = versions.find((v) => v.id === sw.versionId && v.operation === operation);
63
+ if (!to)
64
+ throw new Error("No such version for this feature");
65
+ }
66
+ live.set(operation, to.id);
67
+ changes.push({
68
+ id: id("chg"),
69
+ operation,
70
+ kind: sw.kind,
71
+ fromVersionId: fromId,
72
+ toVersionId: to.id,
73
+ reason: sw.reason,
74
+ by: sw.by,
75
+ evidence: sw.evidence ?? null,
76
+ createdAt: now(),
77
+ });
78
+ return to;
79
+ },
80
+ async rate(r) {
81
+ const c = cleanRating(r);
82
+ const at = now();
83
+ const prior = feedback.find((f) => f.raterId === c.raterId &&
84
+ f.operation === c.operation &&
85
+ f.targetId === c.targetId);
86
+ if (prior) {
87
+ // A changed rating needs a fresh look.
88
+ if (prior.rating !== c.rating) {
89
+ prior.status = "OPEN";
90
+ prior.caseId = null;
91
+ }
92
+ Object.assign(prior, c, { updatedAt: at });
93
+ return prior;
94
+ }
95
+ const f = {
96
+ ...c,
97
+ id: id("fb"),
98
+ status: "OPEN",
99
+ caseId: null,
100
+ createdAt: at,
101
+ updatedAt: at,
102
+ };
103
+ feedback.push(f);
104
+ return f;
105
+ },
106
+ async clearRating(raterId, operation, targetId) {
107
+ const i = feedback.findIndex((f) => f.raterId === raterId &&
108
+ f.operation === operation &&
109
+ f.targetId === targetId);
110
+ if (i >= 0)
111
+ feedback.splice(i, 1);
112
+ },
113
+ async listFeedback(opts = {}) {
114
+ return feedback
115
+ .filter((f) => (!opts.operation || f.operation === opts.operation) &&
116
+ (!opts.rating || f.rating === opts.rating) &&
117
+ (!opts.status || f.status === opts.status) &&
118
+ (!opts.since || f.updatedAt >= opts.since))
119
+ .sort((a, b) => +b.updatedAt - +a.updatedAt)
120
+ .slice(0, opts.limit ?? Infinity);
121
+ },
122
+ async setFeedbackStatus(feedbackId, status, caseId = null) {
123
+ const f = feedback.find((x) => x.id === feedbackId);
124
+ if (f) {
125
+ f.status = status;
126
+ f.caseId = caseId;
127
+ f.updatedAt = now();
128
+ }
129
+ },
130
+ async listCases(suite) {
131
+ return cases
132
+ .filter((c) => c.suite === suite && c.status !== "RETIRED")
133
+ .sort((a, b) => +a.createdAt - +b.createdAt);
134
+ },
135
+ async createCase({ labels = [], ...data }) {
136
+ const at = now();
137
+ const c = {
138
+ ...data,
139
+ id: id("case"),
140
+ createdAt: at,
141
+ updatedAt: at,
142
+ labels: labels.map((l) => ({
143
+ ...l,
144
+ id: id("label"),
145
+ createdAt: at,
146
+ updatedAt: at,
147
+ })),
148
+ };
149
+ cases.push(c);
150
+ return c;
151
+ },
152
+ async addLabel(caseId, data) {
153
+ const c = cases.find((x) => x.id === caseId);
154
+ if (!c)
155
+ throw new Error(`Unknown case ${caseId}`);
156
+ const at = now();
157
+ const l = { ...data, id: id("label"), createdAt: at, updatedAt: at };
158
+ c.labels.push(l);
159
+ c.updatedAt = at;
160
+ return l;
161
+ },
162
+ async setLabelStatus(labelId, status) {
163
+ for (const c of cases)
164
+ for (const l of c.labels)
165
+ if (l.id === labelId) {
166
+ l.status = status;
167
+ l.updatedAt = now();
168
+ }
169
+ },
170
+ async setCaseStatus(caseId, status) {
171
+ const c = cases.find((x) => x.id === caseId);
172
+ if (c) {
173
+ c.status = status;
174
+ c.updatedAt = now();
175
+ }
176
+ },
177
+ async getRun(runId) {
178
+ return runs.find((r) => r.id === runId) ?? null;
179
+ },
180
+ async listRuns(suite, opts = {}) {
181
+ return runs
182
+ .filter((r) => r.suite === suite && (!opts.status || r.status === opts.status))
183
+ .sort((a, b) => +b.startedAt - +a.startedAt)
184
+ .slice(0, opts.limit ?? Infinity);
185
+ },
186
+ async createRun(data) {
187
+ const r = {
188
+ ...data,
189
+ id: id("run"),
190
+ status: "RUNNING",
191
+ metrics: null,
192
+ error: null,
193
+ startedAt: now(),
194
+ finishedAt: null,
195
+ };
196
+ runs.push(r);
197
+ return r;
198
+ },
199
+ async updateRun(runId, patch, onlyIf) {
200
+ const r = runs.find((x) => x.id === runId);
201
+ if (!r || (onlyIf && r.status !== onlyIf.status))
202
+ return;
203
+ Object.assign(r, patch);
204
+ },
205
+ async listOutputs(runId) {
206
+ return outputs.filter((o) => o.runId === runId);
207
+ },
208
+ async findReusableOutput(requestHash, since) {
209
+ return (outputs
210
+ .filter((o) => o.requestHash === requestHash &&
211
+ !o.reused &&
212
+ !o.error &&
213
+ o.createdAt >= since)
214
+ .sort((a, b) => +b.createdAt - +a.createdAt)[0] ?? null);
215
+ },
216
+ async createOutput(data) {
217
+ const o = { ...data, id: id("out"), createdAt: now() };
218
+ outputs.push(o);
219
+ return o;
220
+ },
221
+ async setOutputScores(outputId, scores) {
222
+ const o = outputs.find((x) => x.id === outputId);
223
+ if (o)
224
+ o.scores = scores;
225
+ },
226
+ };
227
+ }
228
+ //# sourceMappingURL=memoryStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryStore.js","sourceRoot":"","sources":["../src/memoryStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * What Evalkeeper needs to know about the models your app can use. You
3
+ * pass a catalog in; Evalkeeper never picks a provider itself. Pure.
4
+ */
5
+ /** How hard a reasoning model thinks, where the model takes a setting. */
6
+ export declare const REASONING_EFFORTS: readonly ["none", "low", "medium", "high"];
7
+ /** A reasoning setting a model may accept. */
8
+ export type ReasoningEffort = (typeof REASONING_EFFORTS)[number];
9
+ /**
10
+ * What Evalkeeper needs to know about one model: its label, provider, prices, reasoning
11
+ * settings, and retirement date.
12
+ */
13
+ export type ModelInfo = {
14
+ label: string;
15
+ /** Who serves it ("anthropic", "openai", …): the fallback must differ. */
16
+ provider: string;
17
+ /** USD per 1M tokens, for estimates and the cost of each answer. */
18
+ inputPer1M?: number;
19
+ outputPer1M?: number;
20
+ /** Reasoning efforts it accepts, lowest first. */
21
+ efforts?: ReasoningEffort[];
22
+ /**
23
+ * When the provider retires it, as "YYYY-MM" or "YYYY-MM-DD". A retiring
24
+ * model is never suggested, and a retiring live model gets replaced.
25
+ */
26
+ retiring?: string;
27
+ /** Where the price came from, so it can be checked. */
28
+ source?: string;
29
+ /**
30
+ * As a decision model: "native" probabilities come from the model itself
31
+ * (a full distribution for choices and scales); "prompted" ones are the
32
+ * model's own estimate written out, with no distribution for choices.
33
+ */
34
+ decisions?: "native" | "prompted";
35
+ };
36
+ /** Your app's models, by id. */
37
+ export type ModelCatalog = Record<string, ModelInfo>;
38
+ /** "January 2027" for a retiring model; null when it isn't retiring. */
39
+ export declare function retiresLabel(models: ModelCatalog, model: string): string | null;
40
+ /** The cost of a call from its token counts; null when the price is unknown. */
41
+ export declare function priceCall(models: ModelCatalog, model: string, tokens: {
42
+ input: number;
43
+ output: number;
44
+ }): number | null;
45
+ /**
46
+ * The effort a model actually gets for a requested one: the same if it
47
+ * takes it; for "none" on a model without it, its lowest; otherwise its own
48
+ * default. Undefined: send nothing.
49
+ */
50
+ export declare function effortFor(models: ModelCatalog, model: string, requested: ReasoningEffort | null | undefined): ReasoningEffort | undefined;
package/dist/models.js ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * What Evalkeeper needs to know about the models your app can use. You
3
+ * pass a catalog in; Evalkeeper never picks a provider itself. Pure.
4
+ */
5
+ /** How hard a reasoning model thinks, where the model takes a setting. */
6
+ export const REASONING_EFFORTS = ["none", "low", "medium", "high"];
7
+ /** "January 2027" for a retiring model; null when it isn't retiring. */
8
+ export function retiresLabel(models, model) {
9
+ const when = models[model]?.retiring;
10
+ if (!when)
11
+ return null;
12
+ const [y = 1970, m = 1] = when.split("-").map(Number);
13
+ return new Date(Date.UTC(y, (m || 1) - 1, 1)).toLocaleDateString("en-US", {
14
+ month: "long",
15
+ year: "numeric",
16
+ timeZone: "UTC",
17
+ });
18
+ }
19
+ /** The cost of a call from its token counts; null when the price is unknown. */
20
+ export function priceCall(models, model, tokens) {
21
+ const m = models[model];
22
+ if (m?.inputPer1M === undefined || m.outputPer1M === undefined)
23
+ return null;
24
+ return (tokens.input * m.inputPer1M + tokens.output * m.outputPer1M) / 1e6;
25
+ }
26
+ /**
27
+ * The effort a model actually gets for a requested one: the same if it
28
+ * takes it; for "none" on a model without it, its lowest; otherwise its own
29
+ * default. Undefined: send nothing.
30
+ */
31
+ export function effortFor(models, model, requested) {
32
+ const efforts = models[model]?.efforts;
33
+ if (!requested || !efforts)
34
+ return undefined;
35
+ if (efforts.includes(requested))
36
+ return requested;
37
+ return requested === "none" ? efforts[0] : undefined;
38
+ }
39
+ //# sourceMappingURL=models.js.map