@cursor/july 0.1.15 → 0.1.17

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 (243) hide show
  1. package/README.md +9 -4
  2. package/dist/bin/agent-serve.js +60 -2
  3. package/dist/channels/slack/api.d.ts.map +1 -1
  4. package/dist/channels/slack/api.js +13 -3
  5. package/dist/channels/slack/auth.d.ts +7 -1
  6. package/dist/channels/slack/auth.d.ts.map +1 -1
  7. package/dist/channels/slack/auth.js +14 -0
  8. package/dist/channels/slack/blocks.d.ts +61 -0
  9. package/dist/channels/slack/blocks.d.ts.map +1 -0
  10. package/dist/channels/slack/blocks.js +90 -0
  11. package/dist/channels/slack/defaults.d.ts +2 -0
  12. package/dist/channels/slack/defaults.d.ts.map +1 -1
  13. package/dist/channels/slack/defaults.js +29 -3
  14. package/dist/channels/slack/dispatch.d.ts +3 -17
  15. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  16. package/dist/channels/slack/index.d.ts +1 -0
  17. package/dist/channels/slack/index.d.ts.map +1 -1
  18. package/dist/channels/slack/index.js +1 -0
  19. package/dist/channels/slack/interactive.d.ts +39 -3
  20. package/dist/channels/slack/interactive.d.ts.map +1 -1
  21. package/dist/channels/slack/interactive.js +152 -7
  22. package/dist/channels/slack/manifest.d.ts +3 -0
  23. package/dist/channels/slack/manifest.d.ts.map +1 -1
  24. package/dist/channels/slack/manifest.js +3 -0
  25. package/dist/channels/slack/setup.d.ts +4 -1
  26. package/dist/channels/slack/setup.d.ts.map +1 -1
  27. package/dist/channels/slack/setup.js +16 -2
  28. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  29. package/dist/channels/slack/slack-channel.js +24 -3
  30. package/dist/channels/slack/types.d.ts +77 -0
  31. package/dist/channels/slack/types.d.ts.map +1 -1
  32. package/dist/connections.d.ts +4 -1
  33. package/dist/connections.d.ts.map +1 -1
  34. package/dist/connections.js +4 -1
  35. package/dist/docs/404.html +2 -2
  36. package/dist/docs/ab.html +3 -3
  37. package/dist/docs/assets/{app.DpdGZTLe.js → app.BbEXr2KO.js} +1 -1
  38. package/dist/docs/assets/chunks/@localSearchIndexroot.DCBsrfwP.js +1 -0
  39. package/dist/docs/assets/chunks/{VPLocalSearchBox.IB-0QqIT.js → VPLocalSearchBox.DBEi4HDp.js} +1 -1
  40. package/dist/docs/assets/chunks/{theme.-fYBoNtR.js → theme.DGfptcHw.js} +2 -2
  41. package/dist/docs/assets/{example-agents_index.md.BPXjUtRB.js → example-agents_index.md.D2PEVSXl.js} +2 -2
  42. package/dist/docs/assets/{example-agents_index.md.BPXjUtRB.lean.js → example-agents_index.md.D2PEVSXl.lean.js} +1 -1
  43. package/dist/docs/assets/example-agents_security-reviewer.md.BZSNycMf.js +19 -0
  44. package/dist/docs/assets/{example-agents_security-reviewer.md.CE9v-aKm.lean.js → example-agents_security-reviewer.md.BZSNycMf.lean.js} +1 -1
  45. package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.js → guides_mcp-oauth.md.Dd8EgSem.js} +3 -2
  46. package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.lean.js → guides_mcp-oauth.md.Dd8EgSem.lean.js} +1 -1
  47. package/dist/docs/assets/{guides_slack.md.FWale6Ip.js → guides_slack.md.D_xFKlnF.js} +1 -1
  48. package/dist/docs/assets/{reference_connections.md.CsSr3rDz.js → reference_connections.md.B9Q3TOve.js} +12 -5
  49. package/dist/docs/assets/{reference_connections.md.CsSr3rDz.lean.js → reference_connections.md.B9Q3TOve.lean.js} +1 -1
  50. package/dist/docs/building-with-agents.html +3 -3
  51. package/dist/docs/concepts.html +3 -3
  52. package/dist/docs/deployment.html +3 -3
  53. package/dist/docs/evals.html +3 -3
  54. package/dist/docs/example-agents/approval-buddy.html +3 -3
  55. package/dist/docs/example-agents/benny.html +3 -3
  56. package/dist/docs/example-agents/bugbot.html +3 -3
  57. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  58. package/dist/docs/example-agents/codeowners-review.html +3 -3
  59. package/dist/docs/example-agents/concierge.html +3 -3
  60. package/dist/docs/example-agents/fsd.html +3 -3
  61. package/dist/docs/example-agents/index.html +5 -5
  62. package/dist/docs/example-agents/knowledge-base.html +3 -3
  63. package/dist/docs/example-agents/oncall.html +3 -3
  64. package/dist/docs/example-agents/security-reviewer.html +14 -14
  65. package/dist/docs/example-agents/slack-agent.html +3 -3
  66. package/dist/docs/example-agents/weather-agent.html +3 -3
  67. package/dist/docs/guides/agent-to-agent.html +3 -3
  68. package/dist/docs/guides/cloud-runtime.html +3 -3
  69. package/dist/docs/guides/github.html +3 -3
  70. package/dist/docs/guides/human-in-the-loop.html +3 -3
  71. package/dist/docs/guides/mcp-oauth.html +6 -5
  72. package/dist/docs/guides/slack.html +5 -5
  73. package/dist/docs/guides/webhooks.html +3 -3
  74. package/dist/docs/hashmap.json +1 -1
  75. package/dist/docs/hillclimbing.html +3 -3
  76. package/dist/docs/index.html +3 -3
  77. package/dist/docs/quickstart.html +3 -3
  78. package/dist/docs/reference/agent-config.html +3 -3
  79. package/dist/docs/reference/channels.html +3 -3
  80. package/dist/docs/reference/cli.html +3 -3
  81. package/dist/docs/reference/connections.html +14 -7
  82. package/dist/docs/reference/hooks.html +3 -3
  83. package/dist/docs/reference/http-api.html +3 -3
  84. package/dist/docs/reference/instructions.html +3 -3
  85. package/dist/docs/reference/playground.html +3 -3
  86. package/dist/docs/reference/project-layout.html +3 -3
  87. package/dist/docs/reference/prompt.html +3 -3
  88. package/dist/docs/reference/schedules.html +3 -3
  89. package/dist/docs/reference/sessions.html +3 -3
  90. package/dist/docs/reference/skills.html +3 -3
  91. package/dist/docs/reference/subagents.html +3 -3
  92. package/dist/docs/reference/tools.html +3 -3
  93. package/dist/docs/scaffolding-agents.html +3 -3
  94. package/dist/docs/storage.html +3 -3
  95. package/dist/docs/troubleshooting.html +3 -3
  96. package/dist/evals/assertions.d.ts +190 -0
  97. package/dist/evals/assertions.d.ts.map +1 -0
  98. package/dist/evals/assertions.js +461 -0
  99. package/dist/evals/expect.d.ts +95 -0
  100. package/dist/evals/expect.d.ts.map +1 -0
  101. package/dist/evals/expect.js +194 -0
  102. package/dist/evals/judge.d.ts +133 -0
  103. package/dist/evals/judge.d.ts.map +1 -0
  104. package/dist/evals/judge.js +228 -0
  105. package/dist/evals/loaders.d.ts +51 -0
  106. package/dist/evals/loaders.d.ts.map +1 -0
  107. package/dist/evals/loaders.js +124 -0
  108. package/dist/evals/matchers.d.ts +95 -0
  109. package/dist/evals/matchers.d.ts.map +1 -0
  110. package/dist/evals/matchers.js +145 -0
  111. package/dist/evals/reporters.d.ts +70 -0
  112. package/dist/evals/reporters.d.ts.map +1 -0
  113. package/dist/evals/reporters.js +221 -0
  114. package/dist/evals/results.d.ts +103 -0
  115. package/dist/evals/results.d.ts.map +1 -0
  116. package/dist/evals/results.js +28 -0
  117. package/dist/evals/run-facts.d.ts +77 -0
  118. package/dist/evals/run-facts.d.ts.map +1 -0
  119. package/dist/evals/run-facts.js +187 -0
  120. package/dist/evals.d.ts +136 -31
  121. package/dist/evals.d.ts.map +1 -1
  122. package/dist/evals.js +76 -12
  123. package/dist/index.d.ts +1 -1
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +1 -1
  126. package/dist/internal/cli-ax.d.ts +27 -0
  127. package/dist/internal/cli-ax.d.ts.map +1 -1
  128. package/dist/internal/cli-ax.js +90 -12
  129. package/dist/internal/cli-mcp.d.ts +8 -0
  130. package/dist/internal/cli-mcp.d.ts.map +1 -1
  131. package/dist/internal/cli-mcp.js +98 -0
  132. package/dist/internal/cli-slack.d.ts +29 -1
  133. package/dist/internal/cli-slack.d.ts.map +1 -1
  134. package/dist/internal/cli-slack.js +777 -12
  135. package/dist/internal/deploy-client.d.ts +7 -0
  136. package/dist/internal/deploy-client.d.ts.map +1 -1
  137. package/dist/internal/deploy-client.js +9 -0
  138. package/dist/internal/discovery.d.ts.map +1 -1
  139. package/dist/internal/discovery.js +29 -9
  140. package/dist/internal/distribution.d.ts.map +1 -1
  141. package/dist/internal/distribution.js +2 -0
  142. package/dist/internal/eval-judge-model.d.ts +59 -0
  143. package/dist/internal/eval-judge-model.d.ts.map +1 -0
  144. package/dist/internal/eval-judge-model.js +131 -0
  145. package/dist/internal/eval-run-store.d.ts.map +1 -1
  146. package/dist/internal/eval-run-store.js +12 -20
  147. package/dist/internal/eval-runner.d.ts +31 -25
  148. package/dist/internal/eval-runner.d.ts.map +1 -1
  149. package/dist/internal/eval-runner.js +332 -128
  150. package/dist/internal/evals-client.d.ts.map +1 -1
  151. package/dist/internal/evals-client.js +7 -3
  152. package/dist/internal/local-env.d.ts +8 -0
  153. package/dist/internal/local-env.d.ts.map +1 -0
  154. package/dist/internal/local-env.js +47 -0
  155. package/dist/internal/playground/static.d.ts +3 -0
  156. package/dist/internal/playground/static.d.ts.map +1 -1
  157. package/dist/internal/playground/static.js +3 -0
  158. package/dist/internal/run-client.d.ts +15 -0
  159. package/dist/internal/run-client.d.ts.map +1 -1
  160. package/dist/internal/run-client.js +3 -2
  161. package/dist/internal/sdk-runner.d.ts +36 -1
  162. package/dist/internal/sdk-runner.d.ts.map +1 -1
  163. package/dist/internal/sdk-runner.js +65 -25
  164. package/dist/internal/server.d.ts.map +1 -1
  165. package/dist/internal/server.js +10 -1
  166. package/dist/internal/session-engine.d.ts +18 -5
  167. package/dist/internal/session-engine.d.ts.map +1 -1
  168. package/dist/internal/session-engine.js +72 -19
  169. package/dist/internal/slack-provision-client.d.ts +130 -0
  170. package/dist/internal/slack-provision-client.d.ts.map +1 -0
  171. package/dist/internal/slack-provision-client.js +284 -0
  172. package/dist/playground/assets/cursor-icons-16-f_W_ogc-.woff2 +0 -0
  173. package/dist/playground/assets/index-CidizGZv.css +1 -0
  174. package/dist/playground/assets/index-DNqirsrK.js +85 -0
  175. package/dist/playground/index.html +2 -2
  176. package/dist/types.d.ts +70 -4
  177. package/dist/types.d.ts.map +1 -1
  178. package/dist/types.js +26 -0
  179. package/docs/example-agents/index.md +1 -1
  180. package/docs/example-agents/security-reviewer.md +23 -21
  181. package/docs/guides/mcp-oauth.md +10 -5
  182. package/docs/guides/slack.md +3 -2
  183. package/docs/reference/connections.md +28 -18
  184. package/package.json +20 -2
  185. package/skills/create-agent/SKILL.md +15 -7
  186. package/skills/debug/SKILL.md +3 -1
  187. package/skills/mcp-auth/SKILL.md +1 -1
  188. package/skills/setup-slack/SKILL.md +173 -11
  189. package/src/bin/agent-serve.ts +63 -2
  190. package/src/channels/slack/api.ts +16 -3
  191. package/src/channels/slack/auth.ts +16 -1
  192. package/src/channels/slack/blocks.ts +139 -0
  193. package/src/channels/slack/defaults.ts +32 -4
  194. package/src/channels/slack/dispatch.ts +3 -18
  195. package/src/channels/slack/index.ts +1 -0
  196. package/src/channels/slack/interactive.ts +183 -19
  197. package/src/channels/slack/manifest.ts +3 -0
  198. package/src/channels/slack/setup.ts +16 -2
  199. package/src/channels/slack/slack-channel.ts +37 -6
  200. package/src/channels/slack/types.ts +89 -0
  201. package/src/connections.ts +4 -1
  202. package/src/evals/assertions.ts +704 -0
  203. package/src/evals/expect.ts +272 -0
  204. package/src/evals/judge.ts +346 -0
  205. package/src/evals/loaders.ts +113 -0
  206. package/src/evals/matchers.ts +246 -0
  207. package/src/evals/reporters.ts +274 -0
  208. package/src/evals/results.ts +132 -0
  209. package/src/evals/run-facts.ts +274 -0
  210. package/src/evals.ts +249 -42
  211. package/src/index.ts +2 -0
  212. package/src/internal/cli-ax.ts +134 -15
  213. package/src/internal/cli-mcp.ts +118 -5
  214. package/src/internal/cli-slack.ts +993 -15
  215. package/src/internal/deploy-client.ts +10 -0
  216. package/src/internal/discovery.ts +31 -5
  217. package/src/internal/distribution.ts +2 -0
  218. package/src/internal/eval-judge-model.ts +148 -0
  219. package/src/internal/eval-run-store.ts +10 -14
  220. package/src/internal/eval-runner.ts +466 -215
  221. package/src/internal/evals-client.ts +14 -2
  222. package/src/internal/local-env.ts +53 -0
  223. package/src/internal/playground/static.ts +3 -0
  224. package/src/internal/run-client.ts +17 -1
  225. package/src/internal/sdk-runner.ts +103 -22
  226. package/src/internal/server.ts +10 -0
  227. package/src/internal/session-engine.ts +89 -21
  228. package/src/internal/slack-provision-client.ts +438 -0
  229. package/src/types.ts +92 -4
  230. package/dist/channels/slack/post-update-delivery.d.ts +0 -85
  231. package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
  232. package/dist/docs/assets/chunks/@localSearchIndexroot.D2d8CfFS.js +0 -1
  233. package/dist/docs/assets/example-agents_security-reviewer.md.CE9v-aKm.js +0 -19
  234. package/dist/internal/json-dir-store.d.ts +0 -32
  235. package/dist/internal/json-dir-store.d.ts.map +0 -1
  236. package/dist/internal/persistence-coordinator.d.ts +0 -127
  237. package/dist/internal/persistence-coordinator.d.ts.map +0 -1
  238. package/dist/persistence.d.ts +0 -184
  239. package/dist/persistence.d.ts.map +0 -1
  240. package/dist/playground/assets/cursor-icons-16-CQ50JpfO.woff2 +0 -0
  241. package/dist/playground/assets/index-BVMOoiek.js +0 -86
  242. package/dist/playground/assets/index-DYmP4b--.css +0 -1
  243. /package/dist/docs/assets/{guides_slack.md.FWale6Ip.lean.js → guides_slack.md.D_xFKlnF.lean.js} +0 -0
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Built-in eval reporters.
3
+ *
4
+ * The CLI already prints a console summary; reporters add destinations on top.
5
+ * Attach them in `evals/evals.config.ts` to observe every case in the run, or
6
+ * on a single `defineEval({ reporters })` to scope a destination to that case.
7
+ *
8
+ * ```ts
9
+ * // evals/evals.config.ts
10
+ * import { defineEvalConfig } from "@cursor/july/evals";
11
+ * import { JUnit } from "@cursor/july/evals/reporters";
12
+ *
13
+ * export default defineEvalConfig({
14
+ * maxConcurrency: 20,
15
+ * reporters: [JUnit({ filePath: ".agent-serve/junit.xml" })],
16
+ * });
17
+ * ```
18
+ *
19
+ * `agentkit eval --junit <path>` and `--artifacts <dir>` attach these same two
20
+ * reporters without touching the eval files, which is usually the better fit:
21
+ * CI owns the output paths, not the eval author.
22
+ */
23
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
24
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
25
+ return new (P || (P = Promise))(function (resolve, reject) {
26
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
27
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
28
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
29
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
30
+ });
31
+ };
32
+ var __rest = (this && this.__rest) || function (s, e) {
33
+ var t = {};
34
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
35
+ t[p] = s[p];
36
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
37
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
38
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
39
+ t[p[i]] = s[p[i]];
40
+ }
41
+ return t;
42
+ };
43
+ import { mkdir, writeFile } from "node:fs/promises";
44
+ import { dirname, join, resolve } from "node:path";
45
+ /**
46
+ * Write JUnit XML so CI shows per-case annotations.
47
+ *
48
+ * Each case becomes one `<testcase>` named by its path-derived id. Failed gates
49
+ * and execution errors become `<failure>`, `t.skip(reason)` becomes `<skipped>`,
50
+ * and a soft threshold miss becomes a `<failure>` only under `--strict` (it is
51
+ * reported as a `<system-out>` score line otherwise).
52
+ */
53
+ export function JUnit(options) {
54
+ return {
55
+ onRunComplete(summary) {
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ var _a;
58
+ const xml = renderJUnitXml(summary, (_a = options.suiteName) !== null && _a !== void 0 ? _a : "agentkit-evals");
59
+ const target = resolve(options.filePath);
60
+ yield mkdir(dirname(target), { recursive: true });
61
+ yield writeFile(target, xml, "utf8");
62
+ });
63
+ },
64
+ };
65
+ }
66
+ /** Render a {@link EvalRunSummary} as JUnit XML. Exported for tests. */
67
+ export function renderJUnitXml(summary, suiteName) {
68
+ var _a, _b, _c, _d;
69
+ const lines = [
70
+ '<?xml version="1.0" encoding="UTF-8"?>',
71
+ `<testsuites name="${escapeXml(suiteName)}" tests="${summary.total}" failures="${summary.failed + (summary.strict ? summary.scored : 0)}" skipped="${summary.skipped}" time="${(summary.durationMs / 1000).toFixed(3)}">`,
72
+ ` <testsuite name="${escapeXml(suiteName)}" tests="${summary.total}" failures="${summary.failed + (summary.strict ? summary.scored : 0)}" skipped="${summary.skipped}" time="${(summary.durationMs / 1000).toFixed(3)}">`,
73
+ ];
74
+ for (const result of summary.results) {
75
+ const verdict = (_a = result.verdict) !== null && _a !== void 0 ? _a : (result.ok ? "passed" : "failed");
76
+ const time = (result.durationMs / 1000).toFixed(3);
77
+ lines.push(` <testcase name="${escapeXml(result.id)}" classname="${escapeXml(suiteName)}" time="${time}">`);
78
+ if (verdict === "skipped") {
79
+ lines.push(` <skipped message="${escapeXml((_b = result.skipReason) !== null && _b !== void 0 ? _b : "skipped")}"/>`);
80
+ }
81
+ else if (verdict === "failed" ||
82
+ (verdict === "scored" && summary.strict)) {
83
+ const failures = result.assertions.filter((a) => !a.passed);
84
+ const message = (_d = (_c = result.error) !== null && _c !== void 0 ? _c : failures
85
+ .map((a) => `${a.name}${a.detail === undefined ? "" : ` (${a.detail})`}`)
86
+ .join("; ")) !== null && _d !== void 0 ? _d : verdict;
87
+ lines.push(` <failure message="${escapeXml(message === "" ? verdict : message)}" type="${escapeXml(verdict)}"/>`);
88
+ }
89
+ const systemOut = renderSystemOut(result);
90
+ if (systemOut !== "") {
91
+ lines.push(` <system-out>${escapeXml(systemOut)}</system-out>`);
92
+ }
93
+ lines.push(" </testcase>");
94
+ }
95
+ lines.push(" </testsuite>", "</testsuites>", "");
96
+ return lines.join("\n");
97
+ }
98
+ function renderSystemOut(result) {
99
+ const parts = [];
100
+ for (const assertion of result.assertions) {
101
+ if (assertion.score === undefined) {
102
+ continue;
103
+ }
104
+ const bar = assertion.threshold === undefined ? "" : ` (>= ${assertion.threshold})`;
105
+ parts.push(`${assertion.name}=${assertion.score.toFixed(3)}${bar}`);
106
+ }
107
+ for (const [name, value] of Object.entries(result.metrics)) {
108
+ parts.push(`${name}=${String(value)}`);
109
+ }
110
+ parts.push(...result.logs);
111
+ return parts.join("\n");
112
+ }
113
+ function escapeXml(text) {
114
+ return stripIllegalXmlChars(text)
115
+ .replace(/&/g, "&amp;")
116
+ .replace(/</g, "&lt;")
117
+ .replace(/>/g, "&gt;")
118
+ .replace(/"/g, "&quot;")
119
+ .replace(/'/g, "&apos;");
120
+ }
121
+ /**
122
+ * Drop characters XML 1.0 forbids outright.
123
+ *
124
+ * Tool output routinely carries stray control bytes, and they are illegal in
125
+ * XML even when escaped — a CI provider would reject the whole report. Tab,
126
+ * newline, and carriage return are the only legal ones below 0x20.
127
+ */
128
+ function stripIllegalXmlChars(text) {
129
+ let out = "";
130
+ for (const char of text) {
131
+ const code = char.codePointAt(0);
132
+ if (code >= 0x20 || code === 0x09 || code === 0x0a || code === 0x0d) {
133
+ out += char;
134
+ }
135
+ }
136
+ return out;
137
+ }
138
+ /**
139
+ * Persist the full story of a run to disk.
140
+ *
141
+ * Console output stays tight on purpose; when a case fails, the artifact has
142
+ * everything — every assertion with its score, the captured event stream, the
143
+ * tool calls, and `t.log` lines.
144
+ *
145
+ * ```text
146
+ * <dir>/summary.json run totals + config
147
+ * <dir>/results.jsonl one line per case, in completion order
148
+ * <dir>/evals/<case-id>.json per-case detail
149
+ * ```
150
+ */
151
+ export function Artifacts(options) {
152
+ const root = resolve(options.dir);
153
+ const jsonlPath = join(root, "results.jsonl");
154
+ const lines = [];
155
+ let target;
156
+ let discovered = [];
157
+ return {
158
+ onRunStart(evals, runTarget) {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ discovered = evals;
161
+ target = runTarget;
162
+ yield mkdir(join(root, "evals"), { recursive: true });
163
+ });
164
+ },
165
+ onEvalComplete(result) {
166
+ return __awaiter(this, void 0, void 0, function* () {
167
+ var _a;
168
+ lines.push(JSON.stringify({
169
+ id: result.id,
170
+ verdict: (_a = result.verdict) !== null && _a !== void 0 ? _a : (result.ok ? "passed" : "failed"),
171
+ ok: result.ok,
172
+ durationMs: result.durationMs,
173
+ }));
174
+ const file = join(root, "evals", `${sanitizeCaseId(result.id)}.json`);
175
+ yield mkdir(dirname(file), { recursive: true });
176
+ yield writeFile(file, `${JSON.stringify(result, null, 2)}\n`, "utf8");
177
+ yield writeFile(jsonlPath, `${lines.join("\n")}\n`, "utf8");
178
+ });
179
+ },
180
+ onRunComplete(summary) {
181
+ return __awaiter(this, void 0, void 0, function* () {
182
+ yield mkdir(root, { recursive: true });
183
+ const { results } = summary, totals = __rest(summary, ["results"]);
184
+ yield writeFile(join(root, "summary.json"), `${JSON.stringify(Object.assign(Object.assign({}, totals), { caseCount: results.length, target, discovered: discovered.map((e) => e.id) }), null, 2)}\n`, "utf8");
185
+ });
186
+ },
187
+ };
188
+ }
189
+ /**
190
+ * Turn a case id into a safe relative path.
191
+ *
192
+ * Ids are already path-shaped (`weather/nyc`), and `defineEval` rejects `..` in
193
+ * case ids, but the artifact writer sanitizes anyway so a hand-built result can
194
+ * never escape the run directory.
195
+ */
196
+ export function sanitizeCaseId(id) {
197
+ return id
198
+ .split("/")
199
+ .map((segment) => segment.replace(/[^A-Za-z0-9._-]/g, "_"))
200
+ .filter((segment) => segment !== "" && segment !== "." && segment !== "..")
201
+ .join("/");
202
+ }
203
+ /** Fan one lifecycle call out to several reporters, isolating failures. */
204
+ export function combineReporters(reporters, onError) {
205
+ const forEach = (run) => __awaiter(this, void 0, void 0, function* () {
206
+ for (const reporter of reporters) {
207
+ try {
208
+ yield run(reporter);
209
+ }
210
+ catch (error) {
211
+ // A broken destination must not fail the eval run itself.
212
+ onError === null || onError === void 0 ? void 0 : onError(error);
213
+ }
214
+ }
215
+ });
216
+ return {
217
+ onRunStart: (evals, target) => forEach((r) => { var _a; return (_a = r.onRunStart) === null || _a === void 0 ? void 0 : _a.call(r, evals, target); }),
218
+ onEvalComplete: (result) => forEach((r) => { var _a; return (_a = r.onEvalComplete) === null || _a === void 0 ? void 0 : _a.call(r, result); }),
219
+ onRunComplete: (summary) => forEach((r) => { var _a; return (_a = r.onRunComplete) === null || _a === void 0 ? void 0 : _a.call(r, summary); }),
220
+ };
221
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Result and reporter types shared by the runner, the CLI, and reporters.
3
+ *
4
+ * Pure types only: reporters that touch the filesystem live in
5
+ * `@cursor/july/evals/reporters`, so the authoring surface stays importable
6
+ * from anywhere.
7
+ */
8
+ import type { EvalAssertionResult, EvalVerdict } from "./assertions.js";
9
+ /** One finished eval case. */
10
+ export interface EvalRunResult {
11
+ id: string;
12
+ path: string;
13
+ description?: string;
14
+ /**
15
+ * No hard gate failed. Unchanged from before severity existed: a soft
16
+ * threshold miss (`verdict: "scored"`) leaves this `true` and is fatal only
17
+ * under `--strict`.
18
+ */
19
+ ok: boolean;
20
+ /** Full grade, including `scored` and `skipped`. */
21
+ verdict?: EvalVerdict;
22
+ /** Reason passed to `t.skip(...)`. */
23
+ skipReason?: string;
24
+ assertions: EvalAssertionResult[];
25
+ sessionId?: string;
26
+ /** Messages passed to `t.send` (eval inputs). */
27
+ inputs: string[];
28
+ finalText?: string;
29
+ tools?: string[];
30
+ /** Tool calls with args/results from the trajectory. */
31
+ toolCalls?: Array<{
32
+ toolName: string;
33
+ args?: unknown;
34
+ output?: unknown;
35
+ isError: boolean;
36
+ }>;
37
+ error?: string;
38
+ logs: string[];
39
+ /** Structured scores from `t.metric(...)`. */
40
+ metrics: Record<string, string | number>;
41
+ /** Author-supplied metadata from `defineEval({ metadata })`. */
42
+ metadata?: Record<string, unknown>;
43
+ tags?: string[];
44
+ durationMs: number;
45
+ }
46
+ /** Aggregate outcome of one `eval` invocation. */
47
+ export interface EvalRunSummary {
48
+ total: number;
49
+ passed: number;
50
+ failed: number;
51
+ /** Cases that only missed a soft threshold. */
52
+ scored: number;
53
+ skipped: number;
54
+ /** Whether soft threshold misses were treated as failures. */
55
+ strict: boolean;
56
+ startedAt: string;
57
+ finishedAt: string;
58
+ durationMs: number;
59
+ results: readonly EvalRunResult[];
60
+ }
61
+ /** One discovered case, as handed to {@link EvalReporter.onRunStart}. */
62
+ export interface EvalReporterEvalInfo {
63
+ id: string;
64
+ fileId: string;
65
+ description?: string;
66
+ tags?: string[];
67
+ }
68
+ /** Where the run executed. */
69
+ export interface EvalReporterTarget {
70
+ baseUrl: string;
71
+ /** `local` boots an ephemeral server; the others target a running one. */
72
+ mode: "local" | "url" | "prod";
73
+ }
74
+ /**
75
+ * A destination for eval results.
76
+ *
77
+ * The runner grades everything itself; a reporter only ships results out. All
78
+ * three hooks are optional and may return a promise for async work such as an
79
+ * upload or a file write.
80
+ *
81
+ * ```ts
82
+ * // evals/evals.config.ts
83
+ * export default defineEvalConfig({
84
+ * maxConcurrency: 20,
85
+ * reporters: [JUnit({ filePath: ".agent-serve/junit.xml" })],
86
+ * });
87
+ * ```
88
+ */
89
+ export interface EvalReporter {
90
+ /** Fires once before any case runs. */
91
+ onRunStart?(evals: readonly EvalReporterEvalInfo[], target: EvalReporterTarget): void | Promise<void>;
92
+ /** Fires after each observed case, with its assertions and verdict. */
93
+ onEvalComplete?(result: EvalRunResult): void | Promise<void>;
94
+ /** Fires once with the aggregated summary. */
95
+ onRunComplete?(summary: EvalRunSummary): void | Promise<void>;
96
+ }
97
+ /** Tally verdicts for {@link EvalRunSummary}. */
98
+ export declare function summarizeEvalResults(results: readonly EvalRunResult[], options: {
99
+ strict: boolean;
100
+ startedAt: string;
101
+ finishedAt: string;
102
+ }): EvalRunSummary;
103
+ //# sourceMappingURL=results.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../src/evals/results.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Result and reporter types shared by the runner, the CLI, and reporters.
3
+ *
4
+ * Pure types only: reporters that touch the filesystem live in
5
+ * `@cursor/july/evals/reporters`, so the authoring surface stays importable
6
+ * from anywhere.
7
+ */
8
+ /** Tally verdicts for {@link EvalRunSummary}. */
9
+ export function summarizeEvalResults(results, options) {
10
+ const verdictOf = (result) => { var _a; return (_a = result.verdict) !== null && _a !== void 0 ? _a : (result.ok ? "passed" : "failed"); };
11
+ const counts = { passed: 0, failed: 0, scored: 0, skipped: 0 };
12
+ for (const result of results) {
13
+ counts[verdictOf(result)]++;
14
+ }
15
+ return {
16
+ total: results.length,
17
+ passed: counts.passed,
18
+ failed: counts.failed,
19
+ scored: counts.scored,
20
+ skipped: counts.skipped,
21
+ strict: options.strict,
22
+ startedAt: options.startedAt,
23
+ finishedAt: options.finishedAt,
24
+ durationMs: new Date(options.finishedAt).getTime() -
25
+ new Date(options.startedAt).getTime(),
26
+ results,
27
+ };
28
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Typed facts derived from a captured session event stream.
3
+ *
4
+ * Assertions never walk raw events: they read this normalized view, which
5
+ * tracks each tool call's lifecycle (requested → result / approval decision),
6
+ * subagent delegations, and unanswered human-in-the-loop (HITL) approvals.
7
+ */
8
+ import type { SessionEvent } from "../types.js";
9
+ import type { EvalToolCallStatus } from "./matchers.js";
10
+ /** One tool call, in request order, with its resolved lifecycle state. */
11
+ export interface EvalToolCallFact {
12
+ callId: string;
13
+ toolName: string;
14
+ /** Arguments from `actions.requested` (absent for result-only calls). */
15
+ input?: unknown;
16
+ /** Payload from `action.result`. */
17
+ output?: unknown;
18
+ status: EvalToolCallStatus;
19
+ /** Approval outcome when the tool required a human decision. */
20
+ approvalDecision?: "approve" | "deny";
21
+ /** Set when the call ran inside a subagent. */
22
+ parentCallId?: string;
23
+ turnId?: string;
24
+ /** 0-based position in request order across the whole run. */
25
+ index: number;
26
+ }
27
+ /** One subagent delegation (`task`). */
28
+ export interface EvalSubagentFact {
29
+ callId: string;
30
+ name?: string;
31
+ description?: string;
32
+ /** The delegating `task` tool call's result payload, once it settled. */
33
+ output?: unknown;
34
+ status: "completed" | "pending";
35
+ turnId?: string;
36
+ index: number;
37
+ }
38
+ /** One human approval request raised by a `needsApproval` tool. */
39
+ export interface EvalInputRequestFact {
40
+ callId: string;
41
+ toolName: string;
42
+ args?: unknown;
43
+ resolved: boolean;
44
+ decision?: "approve" | "deny";
45
+ }
46
+ export interface EvalRunFacts {
47
+ /** Every tool call in request order, including nested subagent calls. */
48
+ toolCalls: EvalToolCallFact[];
49
+ subagents: EvalSubagentFact[];
50
+ inputRequests: EvalInputRequestFact[];
51
+ /** Approval requests still awaiting a human decision. */
52
+ pendingInputRequests: EvalInputRequestFact[];
53
+ /** True when the run stopped on an unanswered approval request. */
54
+ parked: boolean;
55
+ turns: number;
56
+ turnsFailed: number;
57
+ /** First failure message from `turn.failed` / `session.failed`. */
58
+ failureMessage?: string;
59
+ /** No failed turn and at least one turn. */
60
+ ok: boolean;
61
+ /** Every finished assistant message, in order (excludes subagent text). */
62
+ assistantMessages: string[];
63
+ /** All assistant text joined with newlines. */
64
+ assistantText: string;
65
+ /** Tool calls that reported `isError`. */
66
+ failedToolCalls: EvalToolCallFact[];
67
+ }
68
+ /**
69
+ * Collapse a session event list into {@link EvalRunFacts}.
70
+ *
71
+ * Tool calls are keyed by `callId`, so a result event updates the call that
72
+ * `actions.requested` created rather than appending a duplicate. Result-only
73
+ * calls (no matching request) are still recorded, which keeps assertions honest
74
+ * against transports that drop the request event.
75
+ */
76
+ export declare function deriveRunFacts(events: readonly SessionEvent[]): EvalRunFacts;
77
+ //# sourceMappingURL=run-facts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-facts.d.ts","sourceRoot":"","sources":["../../src/evals/run-facts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,0EAA0E;AAC1E,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oCAAoC;IACpC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACtC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,mEAAmE;AACnE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,yDAAyD;IACzD,oBAAoB,EAAE,oBAAoB,EAAE,CAAC;IAC7C,mEAAmE;IACnE,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,EAAE,EAAE,OAAO,CAAC;IACZ,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,+CAA+C;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,eAAe,EAAE,gBAAgB,EAAE,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,YAAY,CAgM5E"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Typed facts derived from a captured session event stream.
3
+ *
4
+ * Assertions never walk raw events: they read this normalized view, which
5
+ * tracks each tool call's lifecycle (requested → result / approval decision),
6
+ * subagent delegations, and unanswered human-in-the-loop (HITL) approvals.
7
+ */
8
+ /**
9
+ * Collapse a session event list into {@link EvalRunFacts}.
10
+ *
11
+ * Tool calls are keyed by `callId`, so a result event updates the call that
12
+ * `actions.requested` created rather than appending a duplicate. Result-only
13
+ * calls (no matching request) are still recorded, which keeps assertions honest
14
+ * against transports that drop the request event.
15
+ */
16
+ export function deriveRunFacts(events) {
17
+ var _a, _b, _c, _d;
18
+ const toolCalls = [];
19
+ const byCallId = new Map();
20
+ const subagents = [];
21
+ const subagentsByCallId = new Map();
22
+ const inputRequests = [];
23
+ const inputRequestsByCallId = new Map();
24
+ const assistantMessages = [];
25
+ const turnIds = new Set();
26
+ const failedTurnIds = new Set();
27
+ let failureMessage;
28
+ let sessionFailed = false;
29
+ const ensureCall = (callId, toolName, turnId, parentCallId) => {
30
+ const existing = byCallId.get(callId);
31
+ if (existing !== undefined) {
32
+ return existing;
33
+ }
34
+ const fact = {
35
+ callId,
36
+ toolName,
37
+ status: "pending",
38
+ parentCallId,
39
+ turnId,
40
+ index: toolCalls.length,
41
+ };
42
+ toolCalls.push(fact);
43
+ byCallId.set(callId, fact);
44
+ return fact;
45
+ };
46
+ for (const event of events) {
47
+ if (event.turnId !== undefined) {
48
+ turnIds.add(event.turnId);
49
+ }
50
+ switch (event.type) {
51
+ case "actions.requested": {
52
+ for (const call of event.data.calls) {
53
+ const fact = ensureCall(call.callId, call.toolName, event.turnId, (_a = call.parentCallId) !== null && _a !== void 0 ? _a : event.data.parentCallId);
54
+ fact.input = call.args;
55
+ }
56
+ break;
57
+ }
58
+ case "action.result": {
59
+ const fact = ensureCall(event.data.callId, event.data.toolName, event.turnId, event.data.parentCallId);
60
+ fact.toolName = event.data.toolName;
61
+ fact.output = event.data.output;
62
+ // A denied approval is a distinct outcome from a tool that ran and
63
+ // errored, so do not let the synthetic error result overwrite it.
64
+ if (fact.status !== "rejected") {
65
+ fact.status = event.data.isError ? "failed" : "completed";
66
+ }
67
+ const subagent = subagentsByCallId.get(event.data.callId);
68
+ if (subagent !== undefined) {
69
+ subagent.output = event.data.output;
70
+ subagent.status = "completed";
71
+ }
72
+ break;
73
+ }
74
+ case "action.approval_requested": {
75
+ const request = {
76
+ callId: event.data.callId,
77
+ toolName: event.data.toolName,
78
+ args: event.data.args,
79
+ resolved: false,
80
+ };
81
+ inputRequests.push(request);
82
+ inputRequestsByCallId.set(event.data.callId, request);
83
+ break;
84
+ }
85
+ case "action.approval_resolved": {
86
+ const request = inputRequestsByCallId.get(event.data.callId);
87
+ if (request !== undefined) {
88
+ request.resolved = true;
89
+ request.decision = event.data.decision;
90
+ }
91
+ const fact = ensureCall(event.data.callId, event.data.toolName, event.turnId, event.data.parentCallId);
92
+ fact.approvalDecision = event.data.decision;
93
+ if (event.data.decision === "deny") {
94
+ fact.status = "rejected";
95
+ }
96
+ break;
97
+ }
98
+ case "subagent.called": {
99
+ const existing = subagentsByCallId.get(event.data.callId);
100
+ if (existing === undefined) {
101
+ const fact = {
102
+ callId: event.data.callId,
103
+ name: event.data.name,
104
+ description: event.data.description,
105
+ status: "pending",
106
+ turnId: event.turnId,
107
+ index: subagents.length,
108
+ };
109
+ subagents.push(fact);
110
+ subagentsByCallId.set(event.data.callId, fact);
111
+ }
112
+ else {
113
+ existing.name = (_b = event.data.name) !== null && _b !== void 0 ? _b : existing.name;
114
+ existing.description = (_c = event.data.description) !== null && _c !== void 0 ? _c : existing.description;
115
+ }
116
+ break;
117
+ }
118
+ case "subagent.completed": {
119
+ const fact = subagentsByCallId.get(event.data.callId);
120
+ if (fact === undefined) {
121
+ const created = {
122
+ callId: event.data.callId,
123
+ name: event.data.name,
124
+ status: "completed",
125
+ turnId: event.turnId,
126
+ index: subagents.length,
127
+ };
128
+ subagents.push(created);
129
+ subagentsByCallId.set(event.data.callId, created);
130
+ }
131
+ else {
132
+ fact.status = "completed";
133
+ fact.name = (_d = fact.name) !== null && _d !== void 0 ? _d : event.data.name;
134
+ }
135
+ break;
136
+ }
137
+ case "message.completed": {
138
+ // Nested subagent chatter is not part of the agent's reply.
139
+ if (event.data.parentCallId === undefined && event.data.text !== "") {
140
+ assistantMessages.push(event.data.text);
141
+ }
142
+ break;
143
+ }
144
+ case "turn.completed": {
145
+ if (event.data.result !== undefined &&
146
+ event.data.result !== "" &&
147
+ !assistantMessages.includes(event.data.result)) {
148
+ assistantMessages.push(event.data.result);
149
+ }
150
+ break;
151
+ }
152
+ case "turn.failed":
153
+ case "session.failed": {
154
+ if (event.turnId !== undefined) {
155
+ failedTurnIds.add(event.turnId);
156
+ }
157
+ else {
158
+ // A session-scoped failure carries no turn id, so it would otherwise
159
+ // leave `turnsFailed` at 0 and read as a healthy run.
160
+ sessionFailed = true;
161
+ }
162
+ failureMessage = failureMessage !== null && failureMessage !== void 0 ? failureMessage : event.data.message;
163
+ break;
164
+ }
165
+ default:
166
+ break;
167
+ }
168
+ }
169
+ const pendingInputRequests = inputRequests.filter((r) => !r.resolved);
170
+ // `turn.*` events all carry a turnId; session-scoped events do not, so the
171
+ // turn count is the number of distinct turn ids seen.
172
+ const turns = turnIds.size;
173
+ return {
174
+ toolCalls,
175
+ subagents,
176
+ inputRequests,
177
+ pendingInputRequests,
178
+ parked: pendingInputRequests.length > 0,
179
+ turns,
180
+ turnsFailed: failedTurnIds.size,
181
+ failureMessage,
182
+ ok: failedTurnIds.size === 0 && !sessionFailed && turns > 0,
183
+ assistantMessages,
184
+ assistantText: assistantMessages.join("\n"),
185
+ failedToolCalls: toolCalls.filter((c) => c.status === "failed"),
186
+ };
187
+ }