@archmax-ai/harness 0.0.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 (351) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +219 -0
  3. package/dist/agent.d.ts +174 -0
  4. package/dist/agent.js +140 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/assembly/compose.d.ts +170 -0
  7. package/dist/assembly/compose.js +391 -0
  8. package/dist/assembly/compose.js.map +1 -0
  9. package/dist/assembly/delegation-registry.d.ts +5 -0
  10. package/dist/assembly/delegation-registry.js +118 -0
  11. package/dist/assembly/delegation-registry.js.map +1 -0
  12. package/dist/assembly/index.d.ts +192 -0
  13. package/dist/assembly/index.js +265 -0
  14. package/dist/assembly/index.js.map +1 -0
  15. package/dist/assembly/plain.d.ts +7 -0
  16. package/dist/assembly/plain.js +41 -0
  17. package/dist/assembly/plain.js.map +1 -0
  18. package/dist/authoring-skill/archmax-harness/README.md +76 -0
  19. package/dist/authoring-skill/archmax-harness/SKILL.md +241 -0
  20. package/dist/authoring-skill/archmax-harness/references/backend-integration.md +626 -0
  21. package/dist/authoring-skill/archmax-harness/references/cases.md +41 -0
  22. package/dist/authoring-skill/archmax-harness/references/diagnostics.md +51 -0
  23. package/dist/authoring-skill/archmax-harness/references/hook-and-test-scripts.md +1070 -0
  24. package/dist/authoring-skill/archmax-harness/references/hooks-and-scripts.md +82 -0
  25. package/dist/authoring-skill/archmax-harness/references/wiring.md +101 -0
  26. package/dist/authoring-skill/archmax-harness/references/workflow-schema.md +1631 -0
  27. package/dist/authoring-skill/archmax-harness/references/workflow-yaml.md +241 -0
  28. package/dist/behaviour/support.d.ts +232 -0
  29. package/dist/behaviour/support.js +339 -0
  30. package/dist/behaviour/support.js.map +1 -0
  31. package/dist/cli/banner.d.ts +11 -0
  32. package/dist/cli/banner.js +29 -0
  33. package/dist/cli/banner.js.map +1 -0
  34. package/dist/cli/bootstrap.d.ts +33 -0
  35. package/dist/cli/bootstrap.js +153 -0
  36. package/dist/cli/bootstrap.js.map +1 -0
  37. package/dist/cli/command.d.ts +39 -0
  38. package/dist/cli/command.js +97 -0
  39. package/dist/cli/command.js.map +1 -0
  40. package/dist/cli/state-flow.d.ts +46 -0
  41. package/dist/cli/state-flow.js +268 -0
  42. package/dist/cli/state-flow.js.map +1 -0
  43. package/dist/cli/style.d.ts +41 -0
  44. package/dist/cli/style.js +64 -0
  45. package/dist/cli/style.js.map +1 -0
  46. package/dist/cli/turn.d.ts +41 -0
  47. package/dist/cli/turn.js +161 -0
  48. package/dist/cli/turn.js.map +1 -0
  49. package/dist/cli.d.ts +10 -0
  50. package/dist/cli.js +426 -0
  51. package/dist/cli.js.map +1 -0
  52. package/dist/core/code-description.d.ts +22 -0
  53. package/dist/core/code-description.js +38 -0
  54. package/dist/core/code-description.js.map +1 -0
  55. package/dist/core/deepagents.d.ts +183 -0
  56. package/dist/core/deepagents.js +128 -0
  57. package/dist/core/deepagents.js.map +1 -0
  58. package/dist/core/events.d.ts +350 -0
  59. package/dist/core/events.js +205 -0
  60. package/dist/core/events.js.map +1 -0
  61. package/dist/core/frontmatter.d.ts +15 -0
  62. package/dist/core/frontmatter.js +32 -0
  63. package/dist/core/frontmatter.js.map +1 -0
  64. package/dist/core/listing-redact.d.ts +37 -0
  65. package/dist/core/listing-redact.js +88 -0
  66. package/dist/core/listing-redact.js.map +1 -0
  67. package/dist/core/match.d.ts +26 -0
  68. package/dist/core/match.js +75 -0
  69. package/dist/core/match.js.map +1 -0
  70. package/dist/core/message-readers.d.ts +84 -0
  71. package/dist/core/message-readers.js +159 -0
  72. package/dist/core/message-readers.js.map +1 -0
  73. package/dist/core/messages.d.ts +49 -0
  74. package/dist/core/messages.js +85 -0
  75. package/dist/core/messages.js.map +1 -0
  76. package/dist/core/mount-prompt.d.ts +28 -0
  77. package/dist/core/mount-prompt.js +55 -0
  78. package/dist/core/mount-prompt.js.map +1 -0
  79. package/dist/core/mount-redact.d.ts +28 -0
  80. package/dist/core/mount-redact.js +32 -0
  81. package/dist/core/mount-redact.js.map +1 -0
  82. package/dist/core/mounts.d.ts +88 -0
  83. package/dist/core/mounts.js +147 -0
  84. package/dist/core/mounts.js.map +1 -0
  85. package/dist/core/path-mapping.d.ts +52 -0
  86. package/dist/core/path-mapping.js +113 -0
  87. package/dist/core/path-mapping.js.map +1 -0
  88. package/dist/core/platform-prompt.generated.d.ts +2 -0
  89. package/dist/core/platform-prompt.generated.js +4 -0
  90. package/dist/core/platform-prompt.generated.js.map +1 -0
  91. package/dist/core/prompt.d.ts +42 -0
  92. package/dist/core/prompt.js +75 -0
  93. package/dist/core/prompt.js.map +1 -0
  94. package/dist/core/session-id.d.ts +38 -0
  95. package/dist/core/session-id.js +61 -0
  96. package/dist/core/session-id.js.map +1 -0
  97. package/dist/core/session-store.d.ts +85 -0
  98. package/dist/core/session-store.js +149 -0
  99. package/dist/core/session-store.js.map +1 -0
  100. package/dist/core/session-zone.d.ts +54 -0
  101. package/dist/core/session-zone.js +82 -0
  102. package/dist/core/session-zone.js.map +1 -0
  103. package/dist/core/skill-prompt.d.ts +31 -0
  104. package/dist/core/skill-prompt.js +54 -0
  105. package/dist/core/skill-prompt.js.map +1 -0
  106. package/dist/core/skill-redact.d.ts +15 -0
  107. package/dist/core/skill-redact.js +27 -0
  108. package/dist/core/skill-redact.js.map +1 -0
  109. package/dist/core/skills.d.ts +172 -0
  110. package/dist/core/skills.js +214 -0
  111. package/dist/core/skills.js.map +1 -0
  112. package/dist/core/tool-mocks.d.ts +23 -0
  113. package/dist/core/tool-mocks.js +39 -0
  114. package/dist/core/tool-mocks.js.map +1 -0
  115. package/dist/core/tool-telemetry.d.ts +16 -0
  116. package/dist/core/tool-telemetry.js +40 -0
  117. package/dist/core/tool-telemetry.js.map +1 -0
  118. package/dist/core/usage.d.ts +114 -0
  119. package/dist/core/usage.js +226 -0
  120. package/dist/core/usage.js.map +1 -0
  121. package/dist/core/workspace-context.d.ts +136 -0
  122. package/dist/core/workspace-context.js +178 -0
  123. package/dist/core/workspace-context.js.map +1 -0
  124. package/dist/core/workspace-prompt.d.ts +7 -0
  125. package/dist/core/workspace-prompt.js +102 -0
  126. package/dist/core/workspace-prompt.js.map +1 -0
  127. package/dist/core/workspace-router.d.ts +61 -0
  128. package/dist/core/workspace-router.js +145 -0
  129. package/dist/core/workspace-router.js.map +1 -0
  130. package/dist/core/workspace.d.ts +85 -0
  131. package/dist/core/workspace.js +193 -0
  132. package/dist/core/workspace.js.map +1 -0
  133. package/dist/core/zones.d.ts +181 -0
  134. package/dist/core/zones.js +202 -0
  135. package/dist/core/zones.js.map +1 -0
  136. package/dist/env.d.ts +99 -0
  137. package/dist/env.js +271 -0
  138. package/dist/env.js.map +1 -0
  139. package/dist/index.d.ts +265 -0
  140. package/dist/index.js +197 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/kernel/kernel.d.ts +192 -0
  143. package/dist/kernel/kernel.js +751 -0
  144. package/dist/kernel/kernel.js.map +1 -0
  145. package/dist/lifecycle/hook-shape.d.ts +44 -0
  146. package/dist/lifecycle/hook-shape.js +66 -0
  147. package/dist/lifecycle/hook-shape.js.map +1 -0
  148. package/dist/lifecycle/runner.d.ts +177 -0
  149. package/dist/lifecycle/runner.js +372 -0
  150. package/dist/lifecycle/runner.js.map +1 -0
  151. package/dist/lifecycle/transcript.d.ts +27 -0
  152. package/dist/lifecycle/transcript.js +43 -0
  153. package/dist/lifecycle/transcript.js.map +1 -0
  154. package/dist/machine/allow.d.ts +65 -0
  155. package/dist/machine/allow.js +107 -0
  156. package/dist/machine/allow.js.map +1 -0
  157. package/dist/machine/delegation.d.ts +9 -0
  158. package/dist/machine/delegation.js +10 -0
  159. package/dist/machine/delegation.js.map +1 -0
  160. package/dist/machine/diagnostic.d.ts +14 -0
  161. package/dist/machine/diagnostic.js +2 -0
  162. package/dist/machine/diagnostic.js.map +1 -0
  163. package/dist/machine/lint-spec.d.ts +4 -0
  164. package/dist/machine/lint-spec.js +266 -0
  165. package/dist/machine/lint-spec.js.map +1 -0
  166. package/dist/machine/load-spec.d.ts +90 -0
  167. package/dist/machine/load-spec.js +120 -0
  168. package/dist/machine/load-spec.js.map +1 -0
  169. package/dist/machine/machine.d.ts +273 -0
  170. package/dist/machine/machine.js +551 -0
  171. package/dist/machine/machine.js.map +1 -0
  172. package/dist/machine/mount-grants.d.ts +25 -0
  173. package/dist/machine/mount-grants.js +24 -0
  174. package/dist/machine/mount-grants.js.map +1 -0
  175. package/dist/machine/slug.d.ts +14 -0
  176. package/dist/machine/slug.js +17 -0
  177. package/dist/machine/slug.js.map +1 -0
  178. package/dist/machine/spec-schema.d.ts +662 -0
  179. package/dist/machine/spec-schema.js +717 -0
  180. package/dist/machine/spec-schema.js.map +1 -0
  181. package/dist/machine/tool-names.d.ts +98 -0
  182. package/dist/machine/tool-names.js +144 -0
  183. package/dist/machine/tool-names.js.map +1 -0
  184. package/dist/machine/triggers.d.ts +114 -0
  185. package/dist/machine/triggers.js +165 -0
  186. package/dist/machine/triggers.js.map +1 -0
  187. package/dist/machine/types.d.ts +186 -0
  188. package/dist/machine/types.js +12 -0
  189. package/dist/machine/types.js.map +1 -0
  190. package/dist/machine/validate-spec.d.ts +42 -0
  191. package/dist/machine/validate-spec.js +29 -0
  192. package/dist/machine/validate-spec.js.map +1 -0
  193. package/dist/machine/variables.d.ts +196 -0
  194. package/dist/machine/variables.js +415 -0
  195. package/dist/machine/variables.js.map +1 -0
  196. package/dist/public/cli.d.ts +15 -0
  197. package/dist/public/cli.js +14 -0
  198. package/dist/public/cli.js.map +1 -0
  199. package/dist/public/messages.d.ts +33 -0
  200. package/dist/public/messages.js +33 -0
  201. package/dist/public/messages.js.map +1 -0
  202. package/dist/public/sandbox.d.ts +99 -0
  203. package/dist/public/sandbox.js +32 -0
  204. package/dist/public/sandbox.js.map +1 -0
  205. package/dist/public/spec.d.ts +147 -0
  206. package/dist/public/spec.js +149 -0
  207. package/dist/public/spec.js.map +1 -0
  208. package/dist/public/testing.d.ts +71 -0
  209. package/dist/public/testing.js +39 -0
  210. package/dist/public/testing.js.map +1 -0
  211. package/dist/rubrics/rubrics.d.ts +135 -0
  212. package/dist/rubrics/rubrics.js +145 -0
  213. package/dist/rubrics/rubrics.js.map +1 -0
  214. package/dist/runtime/contract.d.ts +73 -0
  215. package/dist/runtime/contract.js +96 -0
  216. package/dist/runtime/contract.js.map +1 -0
  217. package/dist/sandbox/assets/parts/core.js +22 -0
  218. package/dist/sandbox/assets/parts/lifecycle-hook.js +47 -0
  219. package/dist/sandbox/bridge.d.ts +16 -0
  220. package/dist/sandbox/bridge.js +95 -0
  221. package/dist/sandbox/bridge.js.map +1 -0
  222. package/dist/sandbox/executor.d.ts +46 -0
  223. package/dist/sandbox/executor.js +119 -0
  224. package/dist/sandbox/executor.js.map +1 -0
  225. package/dist/sandbox/imports.d.ts +33 -0
  226. package/dist/sandbox/imports.js +67 -0
  227. package/dist/sandbox/imports.js.map +1 -0
  228. package/dist/sandbox/prelude.d.ts +12 -0
  229. package/dist/sandbox/prelude.js +51 -0
  230. package/dist/sandbox/prelude.js.map +1 -0
  231. package/dist/sandbox/ptc-gateway.d.ts +104 -0
  232. package/dist/sandbox/ptc-gateway.js +167 -0
  233. package/dist/sandbox/ptc-gateway.js.map +1 -0
  234. package/dist/sandbox/runtime.d.ts +59 -0
  235. package/dist/sandbox/runtime.js +51 -0
  236. package/dist/sandbox/runtime.js.map +1 -0
  237. package/dist/sandbox/tools.d.ts +34 -0
  238. package/dist/sandbox/tools.js +147 -0
  239. package/dist/sandbox/tools.js.map +1 -0
  240. package/dist/sessions/operations.d.ts +79 -0
  241. package/dist/sessions/operations.js +121 -0
  242. package/dist/sessions/operations.js.map +1 -0
  243. package/dist/sessions/resolve.d.ts +97 -0
  244. package/dist/sessions/resolve.js +145 -0
  245. package/dist/sessions/resolve.js.map +1 -0
  246. package/dist/sessions/resume.d.ts +242 -0
  247. package/dist/sessions/resume.js +288 -0
  248. package/dist/sessions/resume.js.map +1 -0
  249. package/dist/sessions/scope.d.ts +99 -0
  250. package/dist/sessions/scope.js +145 -0
  251. package/dist/sessions/scope.js.map +1 -0
  252. package/dist/sessions/summary.d.ts +65 -0
  253. package/dist/sessions/summary.js +56 -0
  254. package/dist/sessions/summary.js.map +1 -0
  255. package/dist/testing/assertions.d.ts +30 -0
  256. package/dist/testing/assertions.js +231 -0
  257. package/dist/testing/assertions.js.map +1 -0
  258. package/dist/testing/case-document.d.ts +141 -0
  259. package/dist/testing/case-document.js +51 -0
  260. package/dist/testing/case-document.js.map +1 -0
  261. package/dist/testing/case-schema.d.ts +29 -0
  262. package/dist/testing/case-schema.js +519 -0
  263. package/dist/testing/case-schema.js.map +1 -0
  264. package/dist/testing/discovery.d.ts +10 -0
  265. package/dist/testing/discovery.js +24 -0
  266. package/dist/testing/discovery.js.map +1 -0
  267. package/dist/testing/driver.d.ts +78 -0
  268. package/dist/testing/driver.js +117 -0
  269. package/dist/testing/driver.js.map +1 -0
  270. package/dist/testing/grade.d.ts +116 -0
  271. package/dist/testing/grade.js +261 -0
  272. package/dist/testing/grade.js.map +1 -0
  273. package/dist/testing/interpreter.d.ts +55 -0
  274. package/dist/testing/interpreter.js +103 -0
  275. package/dist/testing/interpreter.js.map +1 -0
  276. package/dist/testing/mock-middleware.d.ts +5 -0
  277. package/dist/testing/mock-middleware.js +33 -0
  278. package/dist/testing/mock-middleware.js.map +1 -0
  279. package/dist/testing/runner.d.ts +205 -0
  280. package/dist/testing/runner.js +266 -0
  281. package/dist/testing/runner.js.map +1 -0
  282. package/dist/testing/target.d.ts +27 -0
  283. package/dist/testing/target.js +21 -0
  284. package/dist/testing/target.js.map +1 -0
  285. package/dist/validate/validate.d.ts +41 -0
  286. package/dist/validate/validate.js +669 -0
  287. package/dist/validate/validate.js.map +1 -0
  288. package/dist/workflow/agent-tools.d.ts +10 -0
  289. package/dist/workflow/agent-tools.js +10 -0
  290. package/dist/workflow/agent-tools.js.map +1 -0
  291. package/dist/workflow/checkpointer.d.ts +52 -0
  292. package/dist/workflow/checkpointer.js +200 -0
  293. package/dist/workflow/checkpointer.js.map +1 -0
  294. package/dist/workflow/control-tools.d.ts +174 -0
  295. package/dist/workflow/control-tools.js +468 -0
  296. package/dist/workflow/control-tools.js.map +1 -0
  297. package/dist/workflow/governance.d.ts +104 -0
  298. package/dist/workflow/governance.js +546 -0
  299. package/dist/workflow/governance.js.map +1 -0
  300. package/dist/workflow/middleware.d.ts +85 -0
  301. package/dist/workflow/middleware.js +283 -0
  302. package/dist/workflow/middleware.js.map +1 -0
  303. package/dist/workflow/on-error.d.ts +25 -0
  304. package/dist/workflow/on-error.js +58 -0
  305. package/dist/workflow/on-error.js.map +1 -0
  306. package/dist/workflow/parks.d.ts +46 -0
  307. package/dist/workflow/parks.js +513 -0
  308. package/dist/workflow/parks.js.map +1 -0
  309. package/dist/workflow/paths.d.ts +67 -0
  310. package/dist/workflow/paths.js +108 -0
  311. package/dist/workflow/paths.js.map +1 -0
  312. package/dist/workflow/prompt-cache.d.ts +70 -0
  313. package/dist/workflow/prompt-cache.js +103 -0
  314. package/dist/workflow/prompt-cache.js.map +1 -0
  315. package/dist/workflow/prompt-pruning.d.ts +20 -0
  316. package/dist/workflow/prompt-pruning.js +83 -0
  317. package/dist/workflow/prompt-pruning.js.map +1 -0
  318. package/dist/workflow/render-prompt.d.ts +45 -0
  319. package/dist/workflow/render-prompt.js +140 -0
  320. package/dist/workflow/render-prompt.js.map +1 -0
  321. package/dist/workflow/runtime-config.d.ts +7 -0
  322. package/dist/workflow/runtime-config.js +9 -0
  323. package/dist/workflow/runtime-config.js.map +1 -0
  324. package/dist/workflow/session-artifacts.d.ts +90 -0
  325. package/dist/workflow/session-artifacts.js +134 -0
  326. package/dist/workflow/session-artifacts.js.map +1 -0
  327. package/dist/workflow/session-view.d.ts +31 -0
  328. package/dist/workflow/session-view.js +94 -0
  329. package/dist/workflow/session-view.js.map +1 -0
  330. package/dist/workflow/snapshot.d.ts +14 -0
  331. package/dist/workflow/snapshot.js +97 -0
  332. package/dist/workflow/snapshot.js.map +1 -0
  333. package/dist/workflow/state.d.ts +347 -0
  334. package/dist/workflow/state.js +322 -0
  335. package/dist/workflow/state.js.map +1 -0
  336. package/dist/workflow/sub-workflow.d.ts +174 -0
  337. package/dist/workflow/sub-workflow.js +392 -0
  338. package/dist/workflow/sub-workflow.js.map +1 -0
  339. package/dist/workflow/tool-service.d.ts +48 -0
  340. package/dist/workflow/tool-service.js +291 -0
  341. package/dist/workflow/tool-service.js.map +1 -0
  342. package/dist/workflow/turn-boundary.d.ts +39 -0
  343. package/dist/workflow/turn-boundary.js +128 -0
  344. package/dist/workflow/turn-boundary.js.map +1 -0
  345. package/dist/workflow/turn-runner.d.ts +40 -0
  346. package/dist/workflow/turn-runner.js +122 -0
  347. package/dist/workflow/turn-runner.js.map +1 -0
  348. package/dist/workflow/workflow-tools.d.ts +46 -0
  349. package/dist/workflow/workflow-tools.js +90 -0
  350. package/dist/workflow/workflow-tools.js.map +1 -0
  351. package/package.json +119 -0
@@ -0,0 +1,103 @@
1
+ import { isWorkflowToolName } from "../machine/tool-names.js";
2
+ import { evaluateExpectations, haltsCaseOnFailure, notExecutedRecord, } from "./assertions.js";
3
+ import { DEFAULT_SESSION_ID, createSessionEngine, unDelegatableMocksMessage, unInterceptableMocksMessage, } from "./driver.js";
4
+ /**
5
+ * Describe every assertion step a case did not account for, as `not-executed`
6
+ * records. The one place un-run steps are built, so the three ways a case can
7
+ * stop early — a structural halt, a thrown action, and the runner's wall-clock
8
+ * timeout — cannot drift apart in what they report.
9
+ */
10
+ export function notExecutedRecords(doc, alreadyAccountedFor) {
11
+ const out = [];
12
+ for (const [index, step] of doc.steps.entries()) {
13
+ if (step.kind !== "assert" || alreadyAccountedFor(index))
14
+ continue;
15
+ out.push(notExecutedRecord(step.expect, index));
16
+ }
17
+ return out;
18
+ }
19
+ /**
20
+ * Why a case's declared mocks cannot be honoured by this target, or `null`.
21
+ * Checked once, before anything runs: a mock-declaring case never executes
22
+ * with partial interception — and never seeds or drives first.
23
+ */
24
+ function mockRefusal(doc, agent) {
25
+ if (doc.mocks.length === 0)
26
+ return null;
27
+ // Without the tool-mock middleware, declared mocks would intercept only
28
+ // scripts' PTC calls while the agent's own calls hit real tools. Absence of
29
+ // the capability field (a hand-rolled runtime) counts as "cannot intercept".
30
+ if (agent.toolMocks !== true)
31
+ return unInterceptableMocksMessage(doc.mocks.length);
32
+ // A delegation mock stands in for a whole other governed machine: without a
33
+ // governed assembly to dispatch one, the mock is inert.
34
+ if (doc.mocks.some((mock) => isWorkflowToolName(mock.name)) && !agent.workflow) {
35
+ return unDelegatableMocksMessage();
36
+ }
37
+ return null;
38
+ }
39
+ /** Execute one case document against the agent under test. */
40
+ export async function executeCase(opts) {
41
+ const { doc, seeds, agent, sessionId, grade, onRecord } = opts;
42
+ const engine = createSessionEngine({
43
+ agent,
44
+ defaultSessionId: sessionId,
45
+ ...(opts.signal ? { signal: opts.signal } : {}),
46
+ });
47
+ const records = [];
48
+ const collect = (produced) => {
49
+ for (const record of produced) {
50
+ records.push(record);
51
+ onRecord?.(record);
52
+ }
53
+ };
54
+ const notExecutedFrom = (from) => notExecutedRecords(doc, (step) => step < from);
55
+ const refused = mockRefusal(doc, agent);
56
+ if (refused)
57
+ return { records, error: refused };
58
+ // The step the loop is currently attempting, so the catch below knows where
59
+ // execution stopped. -1 until the first step: a throw from `engine.open`
60
+ // leaves every assertion step un-run.
61
+ let attemptedStep = -1;
62
+ try {
63
+ // Start conditions apply before any step: a bad trigger declaration or a
64
+ // failed workspace seed fails the case even when it has no steps.
65
+ await engine.open(DEFAULT_SESSION_ID, {
66
+ ...(doc.trigger !== undefined ? { trigger: doc.trigger } : {}),
67
+ ...(doc.variables !== undefined ? { variables: doc.variables } : {}),
68
+ files: seeds,
69
+ });
70
+ // The schema guarantees every assertion follows an action, so `view` is
71
+ // always set by the time an assertion evaluates.
72
+ let view = null;
73
+ for (const [index, step] of doc.steps.entries()) {
74
+ attemptedStep = index;
75
+ if (step.kind === "action") {
76
+ view = await runAction(step.action);
77
+ continue;
78
+ }
79
+ const produced = await evaluateExpectations([step.expect], view, index, grade);
80
+ collect(produced);
81
+ // A failed structural assertion means the session is no longer the one
82
+ // this case describes, so driving it further grades the wrong session.
83
+ // Stop, and account for the steps that will not run.
84
+ if (haltsCaseOnFailure(step.expect.assert) && produced.some((r) => r.status === "failed")) {
85
+ collect(notExecutedFrom(index + 1));
86
+ break;
87
+ }
88
+ }
89
+ }
90
+ catch (err) {
91
+ collect(notExecutedFrom(attemptedStep + 1));
92
+ return { records, error: err.message };
93
+ }
94
+ return { records };
95
+ async function runAction(action) {
96
+ if (action.action === "send")
97
+ return engine.send(DEFAULT_SESSION_ID, action.message, doc.mocks);
98
+ if (action.action === "deliver")
99
+ return engine.deliver(DEFAULT_SESSION_ID, action.trigger, action.variables);
100
+ return engine.decide(DEFAULT_SESSION_ID, action.to, action.comment);
101
+ }
102
+ }
103
+ //# sourceMappingURL=interpreter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpreter.js","sourceRoot":"","sources":["../../src/testing/interpreter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { AgentMiddleware } from "langchain";
2
+ import { type ToolMockSpec } from "../core/tool-mocks.js";
3
+ export type { ToolMockSpec };
4
+ /** Short-circuit governed tool calls with declarative mock results (test cases only). */
5
+ export declare function createToolMockMiddleware(): AgentMiddleware;
@@ -0,0 +1,33 @@
1
+ import { ToolMessage } from "@langchain/core/messages";
2
+ import { createMiddleware } from "langchain";
3
+ import { isWorkflowToolName } from "../machine/tool-names.js";
4
+ import { findMock, mockPayload, readMocks, TOOL_MOCK_MIDDLEWARE_NAME, } from "../core/tool-mocks.js";
5
+ /** Short-circuit governed tool calls with declarative mock results (test cases only). */
6
+ export function createToolMockMiddleware() {
7
+ return createMiddleware({
8
+ // The name is the assembly-time detection handle for `capabilities.toolMocks`.
9
+ name: TOOL_MOCK_MIDDLEWARE_NAME,
10
+ wrapToolCall: async (request, handler) => {
11
+ const toolName = request.toolCall?.name ?? "";
12
+ const args = (request.toolCall?.args ?? {});
13
+ const configurable = request.runtime?.configurable ?? request.config?.configurable ?? {};
14
+ // A delegation mock is served by the **dispatcher**, not here. Short-
15
+ // circuiting it at this seam would skip the dispatch entirely — no
16
+ // sub-workflow event, no trail step, no check that the answer matches what
17
+ // the target declares it returns — leaving a case asserting against a
18
+ // delegation the run has no record of making.
19
+ const mock = isWorkflowToolName(toolName)
20
+ ? undefined
21
+ : findMock(readMocks(configurable), toolName, args);
22
+ if (mock) {
23
+ return new ToolMessage({
24
+ content: mockPayload(mock),
25
+ tool_call_id: request.toolCall?.id ?? "",
26
+ name: toolName,
27
+ });
28
+ }
29
+ return handler(request);
30
+ },
31
+ });
32
+ }
33
+ //# sourceMappingURL=mock-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-middleware.js","sourceRoot":"","sources":["../../src/testing/mock-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,QAAQ,EACR,WAAW,EACX,SAAS,EACT,yBAAyB,GAE1B,MAAM,uBAAuB,CAAC;AAI/B,yFAAyF;AACzF,MAAM,UAAU,wBAAwB;IACtC,OAAO,gBAAgB,CAAC;QACtB,+EAA+E;QAC/E,IAAI,EAAE,yBAAyB;QAC/B,YAAY,EAAE,KAAK,EAAE,OAA2B,EAAE,OAA2B,EAAE,EAAE;YAC/E,MAAM,QAAQ,GAAW,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC;YACtD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAA4B,CAAC;YACvE,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE,CAAC;YAEzF,sEAAsE;YACtE,mEAAmE;YACnE,2EAA2E;YAC3E,sEAAsE;YACtE,8CAA8C;YAC9C,MAAM,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC;gBACvC,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YACtD,IAAI,IAAI,EAAE,CAAC;gBACT,OAAO,IAAI,WAAW,CAAC;oBACrB,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC;oBAC1B,YAAY,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE;oBACxC,IAAI,EAAE,QAAQ;iBACf,CAAC,CAAC;YACL,CAAC;YAED,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Running a suite of cases.
3
+ *
4
+ * Three steps, each its own exported function: {@link discoverCases} finds and
5
+ * parses the case files, {@link runCase} drives one against the agent under
6
+ * test, and {@link runTests} wires the two together with suite configuration.
7
+ * The **verdict** a case settles to and the **contract** a target must satisfy
8
+ * live here too, because nothing else reads them.
9
+ *
10
+ * The runner returns data and prints nothing: the CLI's test view is the
11
+ * renderer, and a host reporter reads the same `CaseResult`s.
12
+ *
13
+ * What is deliberately *not* here is `createCaseTarget` — see `target.ts`. The
14
+ * runner reaches its target through that builder and a host replaces it, so
15
+ * folding it in would make the seam unreplaceable in fact rather than in type.
16
+ */
17
+ import type { BackendProtocolV2 } from "deepagents";
18
+ import type { Agent, GovernedAgent } from "../agent.js";
19
+ import type { WorkflowEventHandler } from "../core/events.js";
20
+ import type { SandboxRuntime } from "../sandbox/runtime.js";
21
+ import { type ModelFactory } from "../env.js";
22
+ import { Workspace } from "../core/workspace.js";
23
+ import { type CaseDocument } from "./case-schema.js";
24
+ import type { GradeFn } from "./assertions.js";
25
+ /**
26
+ * The outcome of one assertion. `not-executed` is a first-class case, not an
27
+ * absence: a case that stopped early still accounts for the assertion steps it
28
+ * never reached.
29
+ */
30
+ export type AssertionStatus = "passed" | "failed" | "not-executed";
31
+ export interface AssertionRecord {
32
+ kind: string;
33
+ /** @deprecated Derived: `status === "passed"`. Kept for one release; read `status`. */
34
+ pass: boolean;
35
+ /**
36
+ * The `atLeast` bar a `grade` assertion had to clear, `null` for every other
37
+ * kind. Descriptive only — it is rendered beside the score; whether the
38
+ * record failed is already decided in `status`.
39
+ */
40
+ threshold: number | null;
41
+ /**
42
+ * The assertion's outcome — the single authoritative one, computed by the
43
+ * engine and the field verdict reduction keys off. A `grade` record takes its
44
+ * status from the case's declared `atLeast` threshold, so it can never
45
+ * contradict the verdict computed from the same score.
46
+ */
47
+ status: AssertionStatus;
48
+ /** A `grade` record's score; absent for deterministic assertions. */
49
+ score?: number;
50
+ detail?: string;
51
+ /**
52
+ * Zero-based index, in the case document's flat `steps` list, of the
53
+ * assertion step that produced this record — the same index the case schema
54
+ * uses in its `steps[i]` error locations. Values are sparse with respect to
55
+ * `steps`: action steps produce no records.
56
+ */
57
+ step: number;
58
+ }
59
+ export type CaseStatus = "passed" | "failed" | "skipped";
60
+ export interface CaseVerdict {
61
+ status: CaseStatus;
62
+ failures: string[];
63
+ }
64
+ /**
65
+ * Reduce recorded assertions to a verdict. Every failed record fails its case —
66
+ * there is no severity tier that records a failure without failing. A `grade`
67
+ * miss reads as a failure like any other, with its score beside the bar it
68
+ * missed. Every branch keys off `status`: with `not-executed` records present,
69
+ * "did not pass" and "failed" are different things.
70
+ */
71
+ export declare function reduceVerdict(records: AssertionRecord[]): CaseVerdict;
72
+ /** Map a verdict to a process exit code. */
73
+ export declare function exitCodeForVerdict(verdict: CaseVerdict): number;
74
+ /**
75
+ * The one contract a case target must satisfy, wherever it came from. Cases
76
+ * drive the agent through the workflow graph (and may resume human states), so
77
+ * the target must be workflow-governed. Both the default target builder and
78
+ * `runTests` enforce this, so a caller-supplied target is refused on the same
79
+ * terms as one the SDK built.
80
+ */
81
+ export declare function assertWorkflowGovernedTarget(agent: Agent, workflow: string): asserts agent is GovernedAgent;
82
+ export interface RunTestsOptions {
83
+ workflow: string;
84
+ rootDir?: string;
85
+ /**
86
+ * Backend serving the **authored governance plane** this suite reads — the
87
+ * machine spec, the case documents under `workflows/<slug>/tests/`, and the
88
+ * fixtures their `from:` entries name. The same option `createAgent` takes,
89
+ * and for the same reason: a host whose authored tree lives in a store rather
90
+ * than on local disk has nothing under `<rootDir>/workflows/`, so discovery
91
+ * over a filesystem root would find no cases at all and report an empty suite
92
+ * rather than a missing one.
93
+ *
94
+ * Defaults to a filesystem backend over the resolved root — what `archmax test`
95
+ * uses, and what a host keeps when its cases really are files on disk. A host
96
+ * that supplies this also supplies its own `createTarget`: the two describe
97
+ * the same authored content, one to read the suite from and one to run it.
98
+ */
99
+ authoring?: BackendProtocolV2;
100
+ /** Only run case files whose workspace-relative path contains this substring. */
101
+ filter?: string;
102
+ /** Forwarded to the workflow agent under test for lifecycle diagnostics. */
103
+ onEvent?: WorkflowEventHandler;
104
+ /**
105
+ * Reporter callback invoked before each case file runs, with the session id
106
+ * the case will drive — so a live renderer can show only that session's events.
107
+ */
108
+ onCaseStart?: (file: string, sessionId: string) => void;
109
+ /** Reporter callback invoked with each case result as it completes. */
110
+ onCaseResult?: (result: CaseResult) => void;
111
+ /**
112
+ * Script-execution backend forwarded to the agent under test (its lifecycle
113
+ * hooks and `archmax_run` sources). Case documents themselves are YAML
114
+ * interpreted on the host — no sandbox is involved in running them.
115
+ */
116
+ sandboxRuntime?: SandboxRuntime;
117
+ /** Model factory forwarded to the agent under test and the grading model. */
118
+ modelFactory?: ModelFactory;
119
+ /**
120
+ * The agent under test — an already-built workflow-governed runtime, or a
121
+ * factory that builds one. Defaults to `createCaseTarget({ workflow,
122
+ * rootDir, onEvent, sandboxRuntime, modelFactory })`.
123
+ *
124
+ * A host that assembles its own workflow agent supplies it here rather than
125
+ * describing it through options; the case protocol stays the runtime's, the
126
+ * agent stays the caller's. A supplied target owns its whole assembly, which
127
+ * includes the mocks: a case that declares `mocks:` against a target without
128
+ * the tool-mock middleware is refused before the agent runs (see
129
+ * `toolMocks`). In the factory form, `rootDir` is the
130
+ * *resolved* workspace root.
131
+ */
132
+ createTarget?: GovernedAgent | ((ctx: {
133
+ workflow: string;
134
+ rootDir: string;
135
+ onEvent?: WorkflowEventHandler;
136
+ }) => Promise<GovernedAgent>);
137
+ /**
138
+ * Names the agent session a case runs on, given the case file's
139
+ * workspace-relative path. Defaults to `test-default-<runId>-<file>`. A case
140
+ * is one conversation on one session, which is what lets a host correlate a
141
+ * case's checkpoints, artifacts, and token usage with its own records — the
142
+ * chosen id is reported back on `CaseResult.sessionId`.
143
+ */
144
+ sessionIdForCase?: (file: string) => string;
145
+ }
146
+ export interface CaseResult {
147
+ id: string;
148
+ /** The case's short label — what reporters print beside the verdict. */
149
+ title?: string;
150
+ description?: string;
151
+ /** The session the case ran on; absent when nothing ran (skipped, or unparseable). */
152
+ sessionId?: string;
153
+ verdict: CaseVerdict;
154
+ records: AssertionRecord[];
155
+ /** @deprecated Derived: `verdict.status === "skipped"`. Kept for one release. */
156
+ skipped?: boolean;
157
+ /** Why the case was skipped (`verdict.status === "skipped"`). */
158
+ skipReason?: string;
159
+ /** The terminating error of a case that died rather than halted. */
160
+ error?: string;
161
+ }
162
+ /**
163
+ * Why a suite ran no cases although its workflow loaded: `disabled` means the
164
+ * workflow declares itself out of service — "not run" rather than "nothing to run".
165
+ */
166
+ export type SuiteSkip = "disabled";
167
+ export interface RunTestsResult {
168
+ results: CaseResult[];
169
+ exitCode: number;
170
+ /** How many case files the suite holds, before `filter` — so a filter that matched nothing can say so. */
171
+ discovered: number;
172
+ /** Set when the suite was skipped rather than run (see {@link SuiteSkip}). */
173
+ skipped?: SuiteSkip;
174
+ }
175
+ /** One discovered case file: parsed, or the parse error that failed it. */
176
+ export interface DiscoveredCase {
177
+ file: string;
178
+ doc?: CaseDocument;
179
+ parseError?: string;
180
+ }
181
+ /**
182
+ * Find and parse a suite's case files. Every file is parsed up front so a suite
183
+ * never half-runs against an unreadable file: a schema violation becomes that
184
+ * case's failed result rather than a thrown error.
185
+ */
186
+ export declare function discoverCases(authoring: Workspace, testsDir: string): Promise<DiscoveredCase[]>;
187
+ export interface RunCaseOptions {
188
+ discovered: DiscoveredCase;
189
+ agent: GovernedAgent;
190
+ authoring: Workspace;
191
+ testsDir: string;
192
+ /** The agent session this case runs its conversation on. */
193
+ sessionId: string;
194
+ grade?: GradeFn;
195
+ caseTimeoutMs?: number;
196
+ }
197
+ /**
198
+ * Drive one case against the agent under test and settle its result. Never
199
+ * throws for a case's own failure — a died case reports its terminating error
200
+ * first, then whatever its already-evaluated records had missed, then the
201
+ * steps that never ran as `not-executed`.
202
+ */
203
+ export declare function runCase(opts: RunCaseOptions): Promise<CaseResult>;
204
+ /** Discover and run a workflow's cases. */
205
+ export declare function runTests(opts: RunTestsOptions): Promise<RunTestsResult>;
@@ -0,0 +1,266 @@
1
+ import { createCaseTarget } from "./target.js";
2
+ import { resolveWorkspaceRoot } from "../env.js";
3
+ import { createWorkspaceContext } from "../core/workspace-context.js";
4
+ import { Workspace } from "../core/workspace.js";
5
+ import { workflowPaths } from "../workflow/paths.js";
6
+ import { loadMachineSpec } from "../machine/load-spec.js";
7
+ import { specDisabled } from "../machine/types.js";
8
+ import { createJudgeModel, gradeClosedQA } from "./grade.js";
9
+ import { CaseSchemaError, normalizeFixturePath, parseCaseDocument, } from "./case-schema.js";
10
+ import { listCaseFiles } from "./discovery.js";
11
+ import { executeCase, notExecutedRecords } from "./interpreter.js";
12
+ /**
13
+ * Reduce recorded assertions to a verdict. Every failed record fails its case —
14
+ * there is no severity tier that records a failure without failing. A `grade`
15
+ * miss reads as a failure like any other, with its score beside the bar it
16
+ * missed. Every branch keys off `status`: with `not-executed` records present,
17
+ * "did not pass" and "failed" are different things.
18
+ */
19
+ export function reduceVerdict(records) {
20
+ const failures = [];
21
+ for (const r of records) {
22
+ if (r.status !== "failed")
23
+ continue;
24
+ const label = r.detail ? `${r.kind}: ${r.detail}` : r.kind;
25
+ failures.push(r.threshold != null ? `${label} (score ${r.score ?? 0} < ${r.threshold})` : label);
26
+ }
27
+ return failures.length > 0 ? { status: "failed", failures } : { status: "passed", failures: [] };
28
+ }
29
+ /** Map a verdict to a process exit code. */
30
+ export function exitCodeForVerdict(verdict) {
31
+ return verdict.status === "failed" ? 1 : 0;
32
+ }
33
+ /**
34
+ * The one contract a case target must satisfy, wherever it came from. Cases
35
+ * drive the agent through the workflow graph (and may resume human states), so
36
+ * the target must be workflow-governed. Both the default target builder and
37
+ * `runTests` enforce this, so a caller-supplied target is refused on the same
38
+ * terms as one the SDK built.
39
+ */
40
+ export function assertWorkflowGovernedTarget(agent, workflow) {
41
+ if (!agent.workflow) {
42
+ throw new Error(`Case target '${workflow}' has no workflow machine; cases require a workflow-governed agent.`);
43
+ }
44
+ }
45
+ const DEFAULT_CASE_TIMEOUT_MS = 120_000;
46
+ /**
47
+ * Find and parse a suite's case files. Every file is parsed up front so a suite
48
+ * never half-runs against an unreadable file: a schema violation becomes that
49
+ * case's failed result rather than a thrown error.
50
+ */
51
+ export async function discoverCases(authoring, testsDir) {
52
+ const discovered = [];
53
+ for (const file of await listCaseFiles(authoring, testsDir)) {
54
+ const source = await authoring.readText(file);
55
+ if (source == null) {
56
+ discovered.push({ file, parseError: `missing test file '${file}'` });
57
+ continue;
58
+ }
59
+ try {
60
+ discovered.push({ file, doc: parseCaseDocument(file, source, testsDir) });
61
+ }
62
+ catch (err) {
63
+ if (!(err instanceof CaseSchemaError))
64
+ throw err;
65
+ discovered.push({ file, parseError: err.message });
66
+ }
67
+ }
68
+ return discovered;
69
+ }
70
+ /**
71
+ * Reject when a case's execution exceeds its wall-clock budget, and abort the
72
+ * run behind it: a timed-out case that kept executing would go on spending
73
+ * tokens and emitting events under the next case's rendering.
74
+ */
75
+ async function withTimeout(work, ms, label, onTimeout) {
76
+ let timer;
77
+ try {
78
+ return await Promise.race([
79
+ work,
80
+ new Promise((_, reject) => {
81
+ timer = setTimeout(() => {
82
+ onTimeout();
83
+ reject(new Error(`${label} timed out after ${ms}ms (tests.caseTimeoutMs)`));
84
+ }, ms);
85
+ }),
86
+ ]);
87
+ }
88
+ finally {
89
+ clearTimeout(timer);
90
+ }
91
+ }
92
+ /**
93
+ * Materialize a case's seed files: inline workspace entries pass through
94
+ * (strings verbatim, non-strings JSON-serialized by the seed handle) and
95
+ * `from:` references are read from the tests directory. A missing fixture or
96
+ * an escaping path fails here — before any step runs.
97
+ */
98
+ async function materializeSeeds(authoring, testsDir, doc) {
99
+ const seeds = {};
100
+ for (const [path, entry] of Object.entries(doc.workspace)) {
101
+ if (entry.source === "inline") {
102
+ seeds[path] = entry.content;
103
+ continue;
104
+ }
105
+ const fixture = normalizeFixturePath(entry.from, doc.file);
106
+ const content = await authoring.readText(`${testsDir}/${fixture}`);
107
+ if (content == null) {
108
+ throw new Error(`workspace entry '${path}' references 'from: ${entry.from}', but '${testsDir}/${fixture}' does not exist`);
109
+ }
110
+ seeds[path] = content;
111
+ }
112
+ return seeds;
113
+ }
114
+ /**
115
+ * Drive one case against the agent under test and settle its result. Never
116
+ * throws for a case's own failure — a died case reports its terminating error
117
+ * first, then whatever its already-evaluated records had missed, then the
118
+ * steps that never ran as `not-executed`.
119
+ */
120
+ export async function runCase(opts) {
121
+ const { discovered, agent, authoring, testsDir, sessionId } = opts;
122
+ if (discovered.parseError !== undefined) {
123
+ return {
124
+ id: discovered.file,
125
+ verdict: { status: "failed", failures: [discovered.parseError] },
126
+ records: [],
127
+ error: discovered.parseError,
128
+ };
129
+ }
130
+ const doc = discovered.doc;
131
+ const head = { id: doc.id, title: doc.title, description: doc.description };
132
+ if (doc.skip !== undefined) {
133
+ return {
134
+ ...head,
135
+ verdict: { status: "skipped", failures: [] },
136
+ records: [],
137
+ skipped: true,
138
+ skipReason: doc.skip,
139
+ };
140
+ }
141
+ // Every record the case produces lands here as it is produced, and this is
142
+ // the only source the result reads — so the timeout path (which lets go of
143
+ // the `executeCase` promise) still reports what the case established.
144
+ const produced = [];
145
+ const failed = (message) => {
146
+ const recorded = new Set(produced.map((r) => r.step));
147
+ const records = [...produced, ...notExecutedRecords(doc, (step) => recorded.has(step))];
148
+ return {
149
+ ...head,
150
+ sessionId,
151
+ verdict: { status: "failed", failures: [message, ...reduceVerdict(records).failures] },
152
+ records,
153
+ error: message,
154
+ };
155
+ };
156
+ const controller = new AbortController();
157
+ try {
158
+ const seeds = await materializeSeeds(authoring, testsDir, doc);
159
+ const outcome = await withTimeout(executeCase({
160
+ doc,
161
+ seeds,
162
+ agent,
163
+ sessionId,
164
+ signal: controller.signal,
165
+ onRecord: (record) => produced.push(record),
166
+ ...(opts.grade ? { grade: opts.grade } : {}),
167
+ }), opts.caseTimeoutMs ?? DEFAULT_CASE_TIMEOUT_MS, `case '${doc.id}'`, () => controller.abort(new Error(`case '${doc.id}' timed out`)));
168
+ if (outcome.error !== undefined)
169
+ return failed(outcome.error);
170
+ return { ...head, sessionId, verdict: reduceVerdict(produced), records: [...produced] };
171
+ }
172
+ catch (err) {
173
+ return failed(err.message);
174
+ }
175
+ finally {
176
+ // Hermetic by session isolation: each case drives its own session, so its
177
+ // `scratchpad/…` files resolve per session — no cleanup between files.
178
+ agent.dispose(sessionId);
179
+ }
180
+ }
181
+ /** Discover and run a workflow's cases. */
182
+ export async function runTests(opts) {
183
+ const { workflow, filter } = opts;
184
+ const paths = workflowPaths(workflow);
185
+ const { testsDir } = paths;
186
+ // Every file this function reads — the spec, the suite config, the case
187
+ // documents, their `from:` fixtures — lives on the authoring backend under
188
+ // `workflows/<slug>/`. The agent driven by a case reaches none of it.
189
+ // Without `authoring` only a root is given, so one is always resolved
190
+ // (explicit, or the documented zero-config cwd) and the authoring plane is the
191
+ // filesystem under it. With `authoring` the whole context is skipped rather
192
+ // than built and half-used: its other members — the mount table, the session
193
+ // store — are the agent's, and the agent here is the host's own target. A
194
+ // host whose authored tree is a store would otherwise have to invent a local
195
+ // `rootDir` for filesystem defaults nothing reads.
196
+ const filesystem = opts.authoring === undefined ? createWorkspaceContext({ rootDir: opts.rootDir }) : undefined;
197
+ const authoring = opts.authoring !== undefined ? new Workspace(opts.authoring) : filesystem.authoring;
198
+ // Only the default target builder reads this; a host supplying `authoring`
199
+ // supplies its target too, so the cwd fallback here is never what runs.
200
+ const workspaceRoot = filesystem?.rootDir ?? resolveWorkspaceRoot(opts.rootDir);
201
+ // Suite configuration is declarative data in the spec (`tests:` block).
202
+ const { spec } = await loadMachineSpec(authoring, paths);
203
+ const config = spec?.tests ?? {};
204
+ // A disabled workflow runs nothing — including here. Skipped rather than
205
+ // failed, with a zero exit code: retiring a workflow must not turn CI red.
206
+ if (specDisabled(spec))
207
+ return { results: [], exitCode: 0, discovered: 0, skipped: "disabled" };
208
+ // Case concurrency is not implemented; a declared `maxConcurrency` above 1
209
+ // fails loudly rather than being accepted and then silently run sequentially.
210
+ if ((config.maxConcurrency ?? 1) > 1) {
211
+ throw new Error(`'tests.maxConcurrency' is ${config.maxConcurrency}, but case concurrency is not ` +
212
+ `implemented — cases run sequentially. Set it to 1 or remove the field.`);
213
+ }
214
+ const all = await discoverCases(authoring, testsDir);
215
+ const selected = filter ? all.filter((c) => c.file.includes(filter)) : all;
216
+ // Nothing to run — say so before assembling an agent (and before needing a
217
+ // model at all); the caller decides whether an empty selection is an error.
218
+ if (selected.length === 0)
219
+ return { results: [], exitCode: 0, discovered: all.length };
220
+ const agent = typeof opts.createTarget === "function"
221
+ ? await opts.createTarget({
222
+ workflow,
223
+ rootDir: workspaceRoot,
224
+ ...(opts.onEvent ? { onEvent: opts.onEvent } : {}),
225
+ })
226
+ : (opts.createTarget ??
227
+ (await createCaseTarget({
228
+ workflow,
229
+ rootDir: workspaceRoot,
230
+ onEvent: opts.onEvent,
231
+ ...(opts.sandboxRuntime ? { sandboxRuntime: opts.sandboxRuntime } : {}),
232
+ ...(opts.modelFactory ? { modelFactory: opts.modelFactory } : {}),
233
+ })));
234
+ // Re-checked here rather than trusted from the builder: a caller-supplied
235
+ // target has passed through no such gate, and a misconfigured host should
236
+ // fail on its first move instead of midway through a suite.
237
+ assertWorkflowGovernedTarget(agent, workflow);
238
+ // The grading model is wired only when the spec declares one; a `grade:`
239
+ // step without it records an actionable failure.
240
+ let grade;
241
+ if (config.judge !== undefined) {
242
+ const model = createJudgeModel(config, opts.modelFactory);
243
+ grade = (criteria, evidence) => gradeClosedQA(model, criteria, evidence);
244
+ }
245
+ const runId = `test-run-${Date.now()}`;
246
+ const results = [];
247
+ for (const discovered of selected) {
248
+ const sessionId = opts.sessionIdForCase?.(discovered.file) ??
249
+ `test-default-${runId}-${discovered.file.replace(/\//g, "-")}`;
250
+ opts.onCaseStart?.(discovered.file, sessionId);
251
+ const result = await runCase({
252
+ discovered,
253
+ agent,
254
+ authoring,
255
+ testsDir,
256
+ sessionId,
257
+ ...(grade ? { grade } : {}),
258
+ ...(config.caseTimeoutMs !== undefined ? { caseTimeoutMs: config.caseTimeoutMs } : {}),
259
+ });
260
+ results.push(result);
261
+ opts.onCaseResult?.(result);
262
+ }
263
+ const exitCode = results.some((r) => exitCodeForVerdict(r.verdict) !== 0) ? 1 : 0;
264
+ return { results, exitCode, discovered: all.length };
265
+ }
266
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/testing/runner.ts"],"names":[],"mappings":"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"}