@mastra/code-sdk 1.0.3-alpha.1 → 1.1.0-alpha.2

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 (258) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/acp/agent.js +155 -167
  3. package/dist/acp/agent.js.map +1 -1
  4. package/dist/acp/event-mapper.js +193 -168
  5. package/dist/acp/event-mapper.js.map +1 -1
  6. package/dist/acp/index.js +60 -49
  7. package/dist/acp/index.js.map +1 -1
  8. package/dist/acp/server.js +31 -30
  9. package/dist/acp/server.js.map +1 -1
  10. package/dist/acp.js +1 -4
  11. package/dist/agents/credential-resolver.js +40 -29
  12. package/dist/agents/credential-resolver.js.map +1 -1
  13. package/dist/agents/custom-provider-source.js +16 -9
  14. package/dist/agents/custom-provider-source.js.map +1 -1
  15. package/dist/agents/instructions.js +27 -36
  16. package/dist/agents/instructions.js.map +1 -1
  17. package/dist/agents/mastracode-gateway.js +355 -428
  18. package/dist/agents/mastracode-gateway.js.map +1 -1
  19. package/dist/agents/memory.js +87 -78
  20. package/dist/agents/memory.js.map +1 -1
  21. package/dist/agents/model.js +114 -119
  22. package/dist/agents/model.js.map +1 -1
  23. package/dist/agents/modes/build.js +12 -13
  24. package/dist/agents/modes/build.js.map +1 -1
  25. package/dist/agents/modes/explore.js +14 -13
  26. package/dist/agents/modes/explore.js.map +1 -1
  27. package/dist/agents/modes/plan.js +14 -15
  28. package/dist/agents/modes/plan.js.map +1 -1
  29. package/dist/agents/prompts/agent-instructions.js +78 -69
  30. package/dist/agents/prompts/agent-instructions.js.map +1 -1
  31. package/dist/agents/prompts/build.js +19 -16
  32. package/dist/agents/prompts/build.js.map +1 -1
  33. package/dist/agents/prompts/fast.js +8 -4
  34. package/dist/agents/prompts/fast.js.map +1 -1
  35. package/dist/agents/prompts/index.js +48 -47
  36. package/dist/agents/prompts/index.js.map +1 -1
  37. package/dist/agents/prompts/model.js +6 -5
  38. package/dist/agents/prompts/model.js.map +1 -1
  39. package/dist/agents/prompts/plan.js +20 -16
  40. package/dist/agents/prompts/plan.js.map +1 -1
  41. package/dist/agents/prompts/tool-guidance.js +77 -109
  42. package/dist/agents/prompts/tool-guidance.js.map +1 -1
  43. package/dist/agents/sandbox-filesystem.js +245 -259
  44. package/dist/agents/sandbox-filesystem.js.map +1 -1
  45. package/dist/agents/sandbox-reattach.js +9 -11
  46. package/dist/agents/sandbox-reattach.js.map +1 -1
  47. package/dist/agents/thread-caveman-state.js +92 -81
  48. package/dist/agents/thread-caveman-state.js.map +1 -1
  49. package/dist/agents/tool-availability.js +62 -80
  50. package/dist/agents/tool-availability.js.map +1 -1
  51. package/dist/agents/tools.js +99 -139
  52. package/dist/agents/tools.js.map +1 -1
  53. package/dist/agents/workspace.js +232 -225
  54. package/dist/agents/workspace.js.map +1 -1
  55. package/dist/analytics.js +139 -128
  56. package/dist/analytics.js.map +1 -1
  57. package/dist/auth/authorization-input.js +39 -25
  58. package/dist/auth/authorization-input.js.map +1 -1
  59. package/dist/auth/device-code.js +112 -80
  60. package/dist/auth/device-code.js.map +1 -1
  61. package/dist/auth/index.js +2 -9
  62. package/dist/auth/pkce.js +27 -16
  63. package/dist/auth/pkce.js.map +1 -1
  64. package/dist/auth/providers/anthropic.js +107 -93
  65. package/dist/auth/providers/anthropic.js.map +1 -1
  66. package/dist/auth/providers/github-copilot.js +304 -293
  67. package/dist/auth/providers/github-copilot.js.map +1 -1
  68. package/dist/auth/providers/openai-codex.js +442 -460
  69. package/dist/auth/providers/openai-codex.js.map +1 -1
  70. package/dist/auth/providers/xai.js +179 -145
  71. package/dist/auth/providers/xai.js.map +1 -1
  72. package/dist/auth/storage.js +182 -175
  73. package/dist/auth/storage.js.map +1 -1
  74. package/dist/auth/types.js +1 -1
  75. package/dist/clipboard/index.js +206 -172
  76. package/dist/clipboard/index.js.map +1 -1
  77. package/dist/constants.js +11 -16
  78. package/dist/constants.js.map +1 -1
  79. package/dist/error-classification.js +19 -11
  80. package/dist/error-classification.js.map +1 -1
  81. package/dist/evals/context-builder.js +145 -104
  82. package/dist/evals/context-builder.js.map +1 -1
  83. package/dist/evals/index.js +4 -7
  84. package/dist/evals/scorers/classify-command.js +62 -41
  85. package/dist/evals/scorers/classify-command.js.map +1 -1
  86. package/dist/evals/scorers/efficiency.js +239 -181
  87. package/dist/evals/scorers/efficiency.js.map +1 -1
  88. package/dist/evals/scorers/extract-tools.js +51 -47
  89. package/dist/evals/scorers/extract-tools.js.map +1 -1
  90. package/dist/evals/scorers/index.js +1 -5
  91. package/dist/evals/scorers/outcome.js +321 -212
  92. package/dist/evals/scorers/outcome.js.map +1 -1
  93. package/dist/goal-manager.js +266 -261
  94. package/dist/goal-manager.js.map +1 -1
  95. package/dist/goal-signal.js +14 -13
  96. package/dist/goal-signal.js.map +1 -1
  97. package/dist/headless/cli.js +153 -154
  98. package/dist/headless/cli.js.map +1 -1
  99. package/dist/headless/flags.js +180 -178
  100. package/dist/headless/flags.js.map +1 -1
  101. package/dist/headless/format.js +72 -71
  102. package/dist/headless/format.js.map +1 -1
  103. package/dist/headless/index.js +5 -31
  104. package/dist/headless/policy.js +35 -31
  105. package/dist/headless/policy.js.map +1 -1
  106. package/dist/headless/run-mc.js +332 -334
  107. package/dist/headless/run-mc.js.map +1 -1
  108. package/dist/headless/types.js +16 -7
  109. package/dist/headless/types.js.map +1 -1
  110. package/dist/hooks/config.js +56 -61
  111. package/dist/hooks/config.js.map +1 -1
  112. package/dist/hooks/executor.js +118 -116
  113. package/dist/hooks/executor.js.map +1 -1
  114. package/dist/hooks/index.js +4 -15
  115. package/dist/hooks/manager.js +221 -280
  116. package/dist/hooks/manager.js.map +1 -1
  117. package/dist/hooks/types.js +5 -4
  118. package/dist/hooks/types.js.map +1 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +632 -712
  121. package/dist/index.js.map +1 -1
  122. package/dist/ipc/ipc-reporter.js +19 -22
  123. package/dist/ipc/ipc-reporter.js.map +1 -1
  124. package/dist/lsp/client.js +248 -306
  125. package/dist/lsp/client.js.map +1 -1
  126. package/dist/lsp/index.js +1 -6
  127. package/dist/lsp/language.js +39 -43
  128. package/dist/lsp/language.js.map +1 -1
  129. package/dist/lsp/manager.js +78 -93
  130. package/dist/lsp/manager.js.map +1 -1
  131. package/dist/lsp/server.js +151 -120
  132. package/dist/lsp/server.js.map +1 -1
  133. package/dist/lsp/workspace.js +50 -47
  134. package/dist/lsp/workspace.js.map +1 -1
  135. package/dist/mcp/config.js +210 -199
  136. package/dist/mcp/config.js.map +1 -1
  137. package/dist/mcp/index.js +2 -9
  138. package/dist/mcp/manager.js +482 -475
  139. package/dist/mcp/manager.js.map +1 -1
  140. package/dist/mcp/types.js +1 -1
  141. package/dist/onboarding/custom-packs.js +14 -17
  142. package/dist/onboarding/custom-packs.js.map +1 -1
  143. package/dist/onboarding/custom-providers.js +22 -20
  144. package/dist/onboarding/custom-providers.js.map +1 -1
  145. package/dist/onboarding/index.d.ts +1 -1
  146. package/dist/onboarding/index.d.ts.map +1 -1
  147. package/dist/onboarding/index.js +3 -21
  148. package/dist/onboarding/om-settings.d.ts +5 -0
  149. package/dist/onboarding/om-settings.d.ts.map +1 -1
  150. package/dist/onboarding/om-settings.js +41 -20
  151. package/dist/onboarding/om-settings.js.map +1 -1
  152. package/dist/onboarding/packs.d.ts +4 -6
  153. package/dist/onboarding/packs.d.ts.map +1 -1
  154. package/dist/onboarding/packs.js +154 -105
  155. package/dist/onboarding/packs.js.map +1 -1
  156. package/dist/onboarding/settings.js +575 -517
  157. package/dist/onboarding/settings.js.map +1 -1
  158. package/dist/permissions.js +112 -99
  159. package/dist/permissions.js.map +1 -1
  160. package/dist/plugin.js +21 -23
  161. package/dist/plugin.js.map +1 -1
  162. package/dist/plugins/dependencies.js +64 -87
  163. package/dist/plugins/dependencies.js.map +1 -1
  164. package/dist/plugins/install.js +159 -169
  165. package/dist/plugins/install.js.map +1 -1
  166. package/dist/plugins/loader.js +170 -185
  167. package/dist/plugins/loader.js.map +1 -1
  168. package/dist/plugins/manager.js +374 -380
  169. package/dist/plugins/manager.js.map +1 -1
  170. package/dist/plugins/manifest.js +38 -63
  171. package/dist/plugins/manifest.js.map +1 -1
  172. package/dist/plugins/package-link.js +48 -64
  173. package/dist/plugins/package-link.js.map +1 -1
  174. package/dist/plugins/paths.js +18 -19
  175. package/dist/plugins/paths.js.map +1 -1
  176. package/dist/plugins/registry.js +97 -81
  177. package/dist/plugins/registry.js.map +1 -1
  178. package/dist/plugins/scaffold.js +62 -98
  179. package/dist/plugins/scaffold.js.map +1 -1
  180. package/dist/plugins/types.js +1 -1
  181. package/dist/processors/plan-rejection-abort.js +45 -44
  182. package/dist/processors/plan-rejection-abort.js.map +1 -1
  183. package/dist/providers/amazon-bedrock-gateway.js +134 -125
  184. package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
  185. package/dist/providers/amazon-bedrock.js +68 -47
  186. package/dist/providers/amazon-bedrock.js.map +1 -1
  187. package/dist/providers/claude-max.js +153 -133
  188. package/dist/providers/claude-max.js.map +1 -1
  189. package/dist/providers/github-copilot.js +232 -230
  190. package/dist/providers/github-copilot.js.map +1 -1
  191. package/dist/providers/openai-codex.js +271 -260
  192. package/dist/providers/openai-codex.js.map +1 -1
  193. package/dist/providers/xai.js +57 -50
  194. package/dist/providers/xai.js.map +1 -1
  195. package/dist/schema.js +91 -89
  196. package/dist/schema.js.map +1 -1
  197. package/dist/theme-palette.js +18 -14
  198. package/dist/theme-palette.js.map +1 -1
  199. package/dist/tool-names.js +46 -37
  200. package/dist/tool-names.js.map +1 -1
  201. package/dist/tools/index.js +2 -8
  202. package/dist/tools/request-sandbox-access.js +71 -80
  203. package/dist/tools/request-sandbox-access.js.map +1 -1
  204. package/dist/tools/utils.js +26 -16
  205. package/dist/tools/utils.js.map +1 -1
  206. package/dist/tools/web-search.js +51 -55
  207. package/dist/tools/web-search.js.map +1 -1
  208. package/dist/utils/binaries.js +65 -61
  209. package/dist/utils/binaries.js.map +1 -1
  210. package/dist/utils/debug-log.js +51 -47
  211. package/dist/utils/debug-log.js.map +1 -1
  212. package/dist/utils/errors.js +157 -192
  213. package/dist/utils/errors.js.map +1 -1
  214. package/dist/utils/gateway-sync.js +49 -37
  215. package/dist/utils/gateway-sync.js.map +1 -1
  216. package/dist/utils/path-security.js +7 -6
  217. package/dist/utils/path-security.js.map +1 -1
  218. package/dist/utils/plan-diff.js +58 -39
  219. package/dist/utils/plan-diff.js.map +1 -1
  220. package/dist/utils/plans.js +92 -74
  221. package/dist/utils/plans.js.map +1 -1
  222. package/dist/utils/project.js +318 -256
  223. package/dist/utils/project.js.map +1 -1
  224. package/dist/utils/signals-pubsub.js +117 -99
  225. package/dist/utils/signals-pubsub.js.map +1 -1
  226. package/dist/utils/slash-command-loader.js +118 -154
  227. package/dist/utils/slash-command-loader.js.map +1 -1
  228. package/dist/utils/slash-command-processor.js +92 -83
  229. package/dist/utils/slash-command-processor.js.map +1 -1
  230. package/dist/utils/stdin-pipe.js +87 -63
  231. package/dist/utils/stdin-pipe.js.map +1 -1
  232. package/dist/utils/storage-factory.js +104 -84
  233. package/dist/utils/storage-factory.js.map +1 -1
  234. package/dist/utils/storage-maintenance.js +249 -211
  235. package/dist/utils/storage-maintenance.js.map +1 -1
  236. package/dist/utils/thread-lock.js +96 -92
  237. package/dist/utils/thread-lock.js.map +1 -1
  238. package/dist/utils/token-estimator.js +12 -12
  239. package/dist/utils/token-estimator.js.map +1 -1
  240. package/dist/utils/update-check.d.ts +1 -1
  241. package/dist/utils/update-check.js +341 -259
  242. package/dist/utils/update-check.js.map +1 -1
  243. package/dist/voice/stt-registry.js +131 -113
  244. package/dist/voice/stt-registry.js.map +1 -1
  245. package/package.json +12 -12
  246. package/dist/acp.js.map +0 -1
  247. package/dist/auth/index.js.map +0 -1
  248. package/dist/auth/types.js.map +0 -1
  249. package/dist/evals/index.js.map +0 -1
  250. package/dist/evals/scorers/index.js.map +0 -1
  251. package/dist/headless/index.js.map +0 -1
  252. package/dist/hooks/index.js.map +0 -1
  253. package/dist/lsp/index.js.map +0 -1
  254. package/dist/mcp/index.js.map +0 -1
  255. package/dist/mcp/types.js.map +0 -1
  256. package/dist/onboarding/index.js.map +0 -1
  257. package/dist/plugins/types.js.map +0 -1
  258. package/dist/tools/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/evals/scorers/extract-tools.ts"],"sourcesContent":["/**\n * Shared tool invocation extraction from MastraDBMessages.\n *\n * Used by both the Outcome and Efficiency scorers to extract completed\n * tool calls from message content, handling both the `parts` array (primary)\n * and the legacy `toolInvocations` array.\n */\n\nimport type { MastraDBMessage } from '@mastra/core/agent';\nimport type { MastraMessagePart, MastraToolInvocation } from '@mastra/core/agent/message-list';\n\nexport type ExtractedToolCall = {\n toolCallId?: string;\n toolName: string;\n args: Record<string, unknown>;\n result: unknown;\n isError: boolean;\n index: number;\n};\n\nfunction isToolInvocationPart(part: MastraMessagePart): part is MastraMessagePart & {\n type: 'tool-invocation';\n toolInvocation: MastraToolInvocation;\n} {\n return 'type' in part && part.type === 'tool-invocation' && 'toolInvocation' in part;\n}\n\nfunction isCompleted(inv: { state: string }): boolean {\n return (\n inv.state === 'result' || inv.state === 'error' || inv.state === 'output-error' || inv.state === 'output-denied'\n );\n}\n\nfunction isErrorState(inv: { state: string }): boolean {\n return inv.state === 'error' || inv.state === 'output-error' || inv.state === 'output-denied';\n}\n\n/**\n * Extract completed tool invocations from MastraDBMessages.\n *\n * Handles both:\n * - `content.parts` (primary format, MastraToolInvocationPart)\n * - `content.toolInvocations` (legacy format, AI SDK ToolInvocation[])\n */\nexport function extractToolCalls(messages: MastraDBMessage[]): ExtractedToolCall[] {\n const results: ExtractedToolCall[] = [];\n const seenToolCallIds = new Set<string>();\n let index = 0;\n\n for (const msg of messages) {\n if (!msg.content) continue;\n\n // Primary format: parts array with tool-invocation parts\n for (const part of msg.content.parts ?? []) {\n if (isToolInvocationPart(part)) {\n const inv = part.toolInvocation;\n if (isCompleted(inv)) {\n const toolCallId = 'toolCallId' in inv ? (inv.toolCallId as string) : undefined;\n if (toolCallId) seenToolCallIds.add(toolCallId);\n\n results.push({\n toolCallId,\n toolName: inv.toolName ?? '',\n args: (inv.args ?? {}) as Record<string, unknown>,\n result: inv.result,\n isError: isErrorState(inv),\n index: index++,\n });\n }\n }\n }\n\n // Legacy format: toolInvocations array (AI SDK ToolInvocation)\n // Only states here are 'partial-call' | 'call' | 'result' — no error state.\n if (msg.content.toolInvocations) {\n for (const inv of msg.content.toolInvocations) {\n if (inv.state === 'result') {\n // Skip if we already extracted this from parts (deduplicate by toolCallId)\n const toolCallId = 'toolCallId' in inv ? inv.toolCallId : undefined;\n if (toolCallId && seenToolCallIds.has(toolCallId)) continue;\n if (toolCallId) seenToolCallIds.add(toolCallId);\n\n results.push({\n toolCallId,\n toolName: inv.toolName ?? '',\n args: (inv.args ?? {}) as Record<string, unknown>,\n result: inv.result,\n isError: false,\n index: index++,\n });\n }\n }\n }\n }\n\n return results;\n}\n"],"mappings":"AAoBA,SAAS,qBAAqB,MAG5B;AACA,SAAO,UAAU,QAAQ,KAAK,SAAS,qBAAqB,oBAAoB;AAClF;AAEA,SAAS,YAAY,KAAiC;AACpD,SACE,IAAI,UAAU,YAAY,IAAI,UAAU,WAAW,IAAI,UAAU,kBAAkB,IAAI,UAAU;AAErG;AAEA,SAAS,aAAa,KAAiC;AACrD,SAAO,IAAI,UAAU,WAAW,IAAI,UAAU,kBAAkB,IAAI,UAAU;AAChF;AASO,SAAS,iBAAiB,UAAkD;AACjF,QAAM,UAA+B,CAAC;AACtC,QAAM,kBAAkB,oBAAI,IAAY;AACxC,MAAI,QAAQ;AAEZ,aAAW,OAAO,UAAU;AAC1B,QAAI,CAAC,IAAI,QAAS;AAGlB,eAAW,QAAQ,IAAI,QAAQ,SAAS,CAAC,GAAG;AAC1C,UAAI,qBAAqB,IAAI,GAAG;AAC9B,cAAM,MAAM,KAAK;AACjB,YAAI,YAAY,GAAG,GAAG;AACpB,gBAAM,aAAa,gBAAgB,MAAO,IAAI,aAAwB;AACtE,cAAI,WAAY,iBAAgB,IAAI,UAAU;AAE9C,kBAAQ,KAAK;AAAA,YACX;AAAA,YACA,UAAU,IAAI,YAAY;AAAA,YAC1B,MAAO,IAAI,QAAQ,CAAC;AAAA,YACpB,QAAQ,IAAI;AAAA,YACZ,SAAS,aAAa,GAAG;AAAA,YACzB,OAAO;AAAA,UACT,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAIA,QAAI,IAAI,QAAQ,iBAAiB;AAC/B,iBAAW,OAAO,IAAI,QAAQ,iBAAiB;AAC7C,YAAI,IAAI,UAAU,UAAU;AAE1B,gBAAM,aAAa,gBAAgB,MAAM,IAAI,aAAa;AAC1D,cAAI,cAAc,gBAAgB,IAAI,UAAU,EAAG;AACnD,cAAI,WAAY,iBAAgB,IAAI,UAAU;AAE9C,kBAAQ,KAAK;AAAA,YACX;AAAA,YACA,UAAU,IAAI,YAAY;AAAA,YAC1B,MAAO,IAAI,QAAQ,CAAC;AAAA,YACpB,QAAQ,IAAI;AAAA,YACZ,SAAS;AAAA,YACT,OAAO;AAAA,UACT,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"file":"extract-tools.js","names":[],"sources":["../../../src/evals/scorers/extract-tools.ts"],"sourcesContent":["/**\n * Shared tool invocation extraction from MastraDBMessages.\n *\n * Used by both the Outcome and Efficiency scorers to extract completed\n * tool calls from message content, handling both the `parts` array (primary)\n * and the legacy `toolInvocations` array.\n */\n\nimport type { MastraDBMessage } from '@mastra/core/agent';\nimport type { MastraMessagePart, MastraToolInvocation } from '@mastra/core/agent/message-list';\n\nexport type ExtractedToolCall = {\n toolCallId?: string;\n toolName: string;\n args: Record<string, unknown>;\n result: unknown;\n isError: boolean;\n index: number;\n};\n\nfunction isToolInvocationPart(part: MastraMessagePart): part is MastraMessagePart & {\n type: 'tool-invocation';\n toolInvocation: MastraToolInvocation;\n} {\n return 'type' in part && part.type === 'tool-invocation' && 'toolInvocation' in part;\n}\n\nfunction isCompleted(inv: { state: string }): boolean {\n return (\n inv.state === 'result' || inv.state === 'error' || inv.state === 'output-error' || inv.state === 'output-denied'\n );\n}\n\nfunction isErrorState(inv: { state: string }): boolean {\n return inv.state === 'error' || inv.state === 'output-error' || inv.state === 'output-denied';\n}\n\n/**\n * Extract completed tool invocations from MastraDBMessages.\n *\n * Handles both:\n * - `content.parts` (primary format, MastraToolInvocationPart)\n * - `content.toolInvocations` (legacy format, AI SDK ToolInvocation[])\n */\nexport function extractToolCalls(messages: MastraDBMessage[]): ExtractedToolCall[] {\n const results: ExtractedToolCall[] = [];\n const seenToolCallIds = new Set<string>();\n let index = 0;\n\n for (const msg of messages) {\n if (!msg.content) continue;\n\n // Primary format: parts array with tool-invocation parts\n for (const part of msg.content.parts ?? []) {\n if (isToolInvocationPart(part)) {\n const inv = part.toolInvocation;\n if (isCompleted(inv)) {\n const toolCallId = 'toolCallId' in inv ? (inv.toolCallId as string) : undefined;\n if (toolCallId) seenToolCallIds.add(toolCallId);\n\n results.push({\n toolCallId,\n toolName: inv.toolName ?? '',\n args: (inv.args ?? {}) as Record<string, unknown>,\n result: inv.result,\n isError: isErrorState(inv),\n index: index++,\n });\n }\n }\n }\n\n // Legacy format: toolInvocations array (AI SDK ToolInvocation)\n // Only states here are 'partial-call' | 'call' | 'result' — no error state.\n if (msg.content.toolInvocations) {\n for (const inv of msg.content.toolInvocations) {\n if (inv.state === 'result') {\n // Skip if we already extracted this from parts (deduplicate by toolCallId)\n const toolCallId = 'toolCallId' in inv ? inv.toolCallId : undefined;\n if (toolCallId && seenToolCallIds.has(toolCallId)) continue;\n if (toolCallId) seenToolCallIds.add(toolCallId);\n\n results.push({\n toolCallId,\n toolName: inv.toolName ?? '',\n args: (inv.args ?? {}) as Record<string, unknown>,\n result: inv.result,\n isError: false,\n index: index++,\n });\n }\n }\n }\n }\n\n return results;\n}\n"],"mappings":";AAoBA,SAAS,qBAAqB,MAG5B;CACA,OAAO,UAAU,QAAQ,KAAK,SAAS,qBAAqB,oBAAoB;AAClF;AAEA,SAAS,YAAY,KAAiC;CACpD,OACE,IAAI,UAAU,YAAY,IAAI,UAAU,WAAW,IAAI,UAAU,kBAAkB,IAAI,UAAU;AAErG;AAEA,SAAS,aAAa,KAAiC;CACrD,OAAO,IAAI,UAAU,WAAW,IAAI,UAAU,kBAAkB,IAAI,UAAU;AAChF;;;;;;;;AASA,SAAgB,iBAAiB,UAAkD;CACjF,MAAM,UAA+B,CAAC;CACtC,MAAM,kCAAkB,IAAI,IAAY;CACxC,IAAI,QAAQ;CAEZ,KAAK,MAAM,OAAO,UAAU;EAC1B,IAAI,CAAC,IAAI,SAAS;EAGlB,KAAK,MAAM,QAAQ,IAAI,QAAQ,SAAS,CAAC,GACvC,IAAI,qBAAqB,IAAI,GAAG;GAC9B,MAAM,MAAM,KAAK;GACjB,IAAI,YAAY,GAAG,GAAG;IACpB,MAAM,aAAa,gBAAgB,MAAO,IAAI,aAAwB,KAAA;IACtE,IAAI,YAAY,gBAAgB,IAAI,UAAU;IAE9C,QAAQ,KAAK;KACX;KACA,UAAU,IAAI,YAAY;KAC1B,MAAO,IAAI,QAAQ,CAAC;KACpB,QAAQ,IAAI;KACZ,SAAS,aAAa,GAAG;KACzB,OAAO;IACT,CAAC;GACH;EACF;EAKF,IAAI,IAAI,QAAQ,iBACT;QAAA,MAAM,OAAO,IAAI,QAAQ,iBAC5B,IAAI,IAAI,UAAU,UAAU;IAE1B,MAAM,aAAa,gBAAgB,MAAM,IAAI,aAAa,KAAA;IAC1D,IAAI,cAAc,gBAAgB,IAAI,UAAU,GAAG;IACnD,IAAI,YAAY,gBAAgB,IAAI,UAAU;IAE9C,QAAQ,KAAK;KACX;KACA,UAAU,IAAI,YAAY;KAC1B,MAAO,IAAI,QAAQ,CAAC;KACpB,QAAQ,IAAI;KACZ,SAAS;KACT,OAAO;IACT,CAAC;GACH;;CAGN;CAEA,OAAO;AACT"}
@@ -1,7 +1,3 @@
1
1
  import { createOutcomeScorer } from "./outcome.js";
2
2
  import { createEfficiencyScorer } from "./efficiency.js";
3
- export {
4
- createEfficiencyScorer,
5
- createOutcomeScorer
6
- };
7
- //# sourceMappingURL=index.js.map
3
+ export { createEfficiencyScorer, createOutcomeScorer };
@@ -1,238 +1,347 @@
1
- import { createScorer, filterRun } from "@mastra/core/evals";
2
- import { isBuildCommand, isTestCommand, getExitCode } from "./classify-command.js";
1
+ import { getExitCode, isBuildCommand, isTestCommand } from "./classify-command.js";
3
2
  import { extractToolCalls } from "./extract-tools.js";
3
+ import { createScorer, filterRun } from "@mastra/core/evals";
4
+ //#region src/evals/scorers/outcome.ts
5
+ /**
6
+ * Dimension weights. Used to compute the weighted average of applicable dimensions.
7
+ * Dimensions that don't apply (e.g. no build ran) are excluded from the average.
8
+ */
4
9
  const WEIGHTS = {
5
- build: 0.3,
6
- tests: 0.25,
7
- toolErrors: 0.2,
8
- loops: 0.1,
9
- regression: 0.1,
10
- autonomy: 0.05
10
+ build: .3,
11
+ tests: .25,
12
+ toolErrors: .2,
13
+ loops: .1,
14
+ regression: .1,
15
+ autonomy: .05
11
16
  };
17
+ /**
18
+ * Scoring thresholds and multipliers.
19
+ */
12
20
  const THRESHOLDS = {
13
- /** Multiplier for tool error rate penalty. Score = max(0, 1 - rate × this). */
14
- toolErrorPenaltyMultiplier: 1,
15
- /** How many consecutive identical calls (or same-error repeats) before it's a "loop". */
16
- loopMinRepetitions: 3,
17
- /** Score penalty per detected loop. */
18
- loopPenaltyPerOccurrence: 0.3,
19
- /** Score deducted per ask_user call. */
20
- autonomyPenaltyPerAsk: 0.25,
21
- /** Score when a command ran but exit code is ambiguous. */
22
- ambiguousExitScore: 0.75,
23
- /** Minimum tool calls required to produce a meaningful score. */
24
- minToolCalls: 1,
25
- /** Tool names whose errors are expected/benign (not penalized). */
26
- benignErrorTools: ["search_content", "find_files", "lsp_inspect"]
21
+ /** Multiplier for tool error rate penalty. Score = max(0, 1 - rate × this). */
22
+ toolErrorPenaltyMultiplier: 1,
23
+ /** How many consecutive identical calls (or same-error repeats) before it's a "loop". */
24
+ loopMinRepetitions: 3,
25
+ /** Score penalty per detected loop. */
26
+ loopPenaltyPerOccurrence: .3,
27
+ /** Score deducted per ask_user call. */
28
+ autonomyPenaltyPerAsk: .25,
29
+ /** Score when a command ran but exit code is ambiguous. */
30
+ ambiguousExitScore: .75,
31
+ /** Minimum tool calls required to produce a meaningful score. */
32
+ minToolCalls: 1,
33
+ /** Tool names whose errors are expected/benign (not penalized). */
34
+ benignErrorTools: [
35
+ "search_content",
36
+ "find_files",
37
+ "lsp_inspect"
38
+ ]
27
39
  };
40
+ /**
41
+ * Check if the primary verb of an execute_command is a build/typecheck command.
42
+ * Splits compound commands (&&, ;) and checks the first segment.
43
+ */
44
+ /** Extract command string from tool call args, then delegate to shared classifier. */
28
45
  function isBuildArgs(args) {
29
- return isBuildCommand(String(args.command ?? ""));
46
+ return isBuildCommand(String(args.command ?? ""));
30
47
  }
31
48
  function isTestArgs(args) {
32
- return isTestCommand(String(args.command ?? ""));
49
+ return isTestCommand(String(args.command ?? ""));
33
50
  }
51
+ /**
52
+ * Score build/typecheck outcome (final state).
53
+ */
34
54
  function scoreBuild(execResults) {
35
- const builds = execResults.filter((r) => r.toolName === "execute_command" && isBuildArgs(r.args));
36
- if (builds.length === 0) return { score: 0, detail: "No build/typecheck ran", applicable: false };
37
- const last = builds[builds.length - 1];
38
- if (last.isError) return { score: 0, detail: "Build/typecheck tool errored", applicable: true };
39
- const exitCode = getExitCode(last.result);
40
- if (exitCode === 0) return { score: 1, detail: "Build/typecheck passed", applicable: true };
41
- if (exitCode !== null && exitCode !== 0)
42
- return { score: 0, detail: `Build failed (exit ${exitCode})`, applicable: true };
43
- const text = typeof last.result === "string" ? last.result : JSON.stringify(last.result ?? "");
44
- if (/error TS\d+|Cannot find module|is not assignable/i.test(text)) {
45
- return { score: 0, detail: "Build failed (TypeScript errors in output)", applicable: true };
46
- }
47
- return { score: THRESHOLDS.ambiguousExitScore, detail: "Build ran, outcome unclear", applicable: true };
55
+ const builds = execResults.filter((r) => r.toolName === "execute_command" && isBuildArgs(r.args));
56
+ if (builds.length === 0) return {
57
+ score: 0,
58
+ detail: "No build/typecheck ran",
59
+ applicable: false
60
+ };
61
+ const last = builds[builds.length - 1];
62
+ if (last.isError) return {
63
+ score: 0,
64
+ detail: "Build/typecheck tool errored",
65
+ applicable: true
66
+ };
67
+ const exitCode = getExitCode(last.result);
68
+ if (exitCode === 0) return {
69
+ score: 1,
70
+ detail: "Build/typecheck passed",
71
+ applicable: true
72
+ };
73
+ if (exitCode !== null && exitCode !== 0) return {
74
+ score: 0,
75
+ detail: `Build failed (exit ${exitCode})`,
76
+ applicable: true
77
+ };
78
+ const text = typeof last.result === "string" ? last.result : JSON.stringify(last.result ?? "");
79
+ if (/error TS\d+|Cannot find module|is not assignable/i.test(text)) return {
80
+ score: 0,
81
+ detail: "Build failed (TypeScript errors in output)",
82
+ applicable: true
83
+ };
84
+ return {
85
+ score: THRESHOLDS.ambiguousExitScore,
86
+ detail: "Build ran, outcome unclear",
87
+ applicable: true
88
+ };
48
89
  }
90
+ /**
91
+ * Score test outcome (final state).
92
+ */
49
93
  function scoreTests(execResults) {
50
- const tests = execResults.filter((r) => r.toolName === "execute_command" && isTestArgs(r.args));
51
- if (tests.length === 0) return { score: 0, detail: "No tests ran", applicable: false };
52
- const last = tests[tests.length - 1];
53
- if (last.isError) return { score: 0, detail: "Test command errored", applicable: true };
54
- const exitCode = getExitCode(last.result);
55
- if (exitCode === 0) return { score: 1, detail: "Tests passed", applicable: true };
56
- if (exitCode !== null && exitCode !== 0)
57
- return { score: 0, detail: `Tests failed (exit ${exitCode})`, applicable: true };
58
- const text = typeof last.result === "string" ? last.result : JSON.stringify(last.result ?? "");
59
- if (/\d+ (?:tests? )?passed|✓|PASS/i.test(text) && !/\bfail(?:ed|ure)?\b|\berror\b/i.test(text)) {
60
- return { score: 1, detail: "Tests passed (inferred)", applicable: true };
61
- }
62
- if (/\bFAIL\b|failed|✗|✘/i.test(text)) {
63
- return { score: 0, detail: "Tests failed (inferred)", applicable: true };
64
- }
65
- return { score: THRESHOLDS.ambiguousExitScore, detail: "Tests ran, outcome unclear", applicable: true };
94
+ const tests = execResults.filter((r) => r.toolName === "execute_command" && isTestArgs(r.args));
95
+ if (tests.length === 0) return {
96
+ score: 0,
97
+ detail: "No tests ran",
98
+ applicable: false
99
+ };
100
+ const last = tests[tests.length - 1];
101
+ if (last.isError) return {
102
+ score: 0,
103
+ detail: "Test command errored",
104
+ applicable: true
105
+ };
106
+ const exitCode = getExitCode(last.result);
107
+ if (exitCode === 0) return {
108
+ score: 1,
109
+ detail: "Tests passed",
110
+ applicable: true
111
+ };
112
+ if (exitCode !== null && exitCode !== 0) return {
113
+ score: 0,
114
+ detail: `Tests failed (exit ${exitCode})`,
115
+ applicable: true
116
+ };
117
+ const text = typeof last.result === "string" ? last.result : JSON.stringify(last.result ?? "");
118
+ if (/\d+ (?:tests? )?passed|✓|PASS/i.test(text) && !/\bfail(?:ed|ure)?\b|\berror\b/i.test(text)) return {
119
+ score: 1,
120
+ detail: "Tests passed (inferred)",
121
+ applicable: true
122
+ };
123
+ if (/\bFAIL\b|failed|✗|✘/i.test(text)) return {
124
+ score: 0,
125
+ detail: "Tests failed (inferred)",
126
+ applicable: true
127
+ };
128
+ return {
129
+ score: THRESHOLDS.ambiguousExitScore,
130
+ detail: "Tests ran, outcome unclear",
131
+ applicable: true
132
+ };
66
133
  }
134
+ /**
135
+ * Score tool error rate, excluding benign errors from expected-to-fail tools.
136
+ */
67
137
  function scoreToolErrors(results) {
68
- if (results.length === 0) return { score: 1, detail: "No tool calls", applicable: false };
69
- const nonBenign = results.filter((r) => !THRESHOLDS.benignErrorTools.includes(r.toolName));
70
- if (nonBenign.length === 0) return { score: 1, detail: "All tool calls are benign-error tools", applicable: true };
71
- const errors = nonBenign.filter((r) => r.isError);
72
- const rate = errors.length / nonBenign.length;
73
- if (rate === 0) return { score: 1, detail: "No tool errors", applicable: true };
74
- const score = Math.max(0, 1 - rate * THRESHOLDS.toolErrorPenaltyMultiplier);
75
- return {
76
- score,
77
- detail: `${errors.length}/${nonBenign.length} tools errored (${(rate * 100).toFixed(0)}%)`,
78
- applicable: true
79
- };
138
+ if (results.length === 0) return {
139
+ score: 1,
140
+ detail: "No tool calls",
141
+ applicable: false
142
+ };
143
+ const nonBenign = results.filter((r) => !THRESHOLDS.benignErrorTools.includes(r.toolName));
144
+ if (nonBenign.length === 0) return {
145
+ score: 1,
146
+ detail: "All tool calls are benign-error tools",
147
+ applicable: true
148
+ };
149
+ const errors = nonBenign.filter((r) => r.isError);
150
+ const rate = errors.length / nonBenign.length;
151
+ if (rate === 0) return {
152
+ score: 1,
153
+ detail: "No tool errors",
154
+ applicable: true
155
+ };
156
+ return {
157
+ score: Math.max(0, 1 - rate * THRESHOLDS.toolErrorPenaltyMultiplier),
158
+ detail: `${errors.length}/${nonBenign.length} tools errored (${(rate * 100).toFixed(0)}%)`,
159
+ applicable: true
160
+ };
80
161
  }
162
+ /**
163
+ * Detect stuck loops: same tool + same args appearing 3+ times consecutively,
164
+ * or same tool + same args erroring 3+ times total.
165
+ */
81
166
  function scoreStuckLoops(results) {
82
- if (results.length < 3) return { score: 1, detail: "Too few calls for loop detection", applicable: true };
83
- const fingerprint = (r) => `${r.toolName}:${JSON.stringify(r.args)}`;
84
- let maxConsecutive = 1;
85
- let currentRun = 1;
86
- for (let i = 1; i < results.length; i++) {
87
- if (fingerprint(results[i]) === fingerprint(results[i - 1])) {
88
- currentRun++;
89
- maxConsecutive = Math.max(maxConsecutive, currentRun);
90
- } else {
91
- currentRun = 1;
92
- }
93
- }
94
- const errorCounts = /* @__PURE__ */ new Map();
95
- for (const r of results) {
96
- if (!r.isError) continue;
97
- const fp = fingerprint(r);
98
- errorCounts.set(fp, (errorCounts.get(fp) ?? 0) + 1);
99
- }
100
- const maxErrorRepeat = Math.max(0, ...[...errorCounts.values()]);
101
- const minReps = THRESHOLDS.loopMinRepetitions;
102
- const loopSeverity = Math.max(
103
- maxConsecutive >= minReps ? maxConsecutive - (minReps - 1) : 0,
104
- maxErrorRepeat >= minReps ? maxErrorRepeat - (minReps - 1) : 0
105
- );
106
- if (loopSeverity === 0) return { score: 1, detail: "No stuck loops", applicable: true };
107
- const score = Math.max(0, 1 - loopSeverity * THRESHOLDS.loopPenaltyPerOccurrence);
108
- const details = [];
109
- if (maxConsecutive >= minReps) details.push(`${maxConsecutive} consecutive identical calls`);
110
- if (maxErrorRepeat >= minReps) details.push(`same error repeated ${maxErrorRepeat}x`);
111
- return { score, detail: details.join("; "), applicable: true };
167
+ if (results.length < 3) return {
168
+ score: 1,
169
+ detail: "Too few calls for loop detection",
170
+ applicable: true
171
+ };
172
+ const fingerprint = (r) => `${r.toolName}:${JSON.stringify(r.args)}`;
173
+ let maxConsecutive = 1;
174
+ let currentRun = 1;
175
+ for (let i = 1; i < results.length; i++) if (fingerprint(results[i]) === fingerprint(results[i - 1])) {
176
+ currentRun++;
177
+ maxConsecutive = Math.max(maxConsecutive, currentRun);
178
+ } else currentRun = 1;
179
+ const errorCounts = /* @__PURE__ */ new Map();
180
+ for (const r of results) {
181
+ if (!r.isError) continue;
182
+ const fp = fingerprint(r);
183
+ errorCounts.set(fp, (errorCounts.get(fp) ?? 0) + 1);
184
+ }
185
+ const maxErrorRepeat = Math.max(0, ...[...errorCounts.values()]);
186
+ const minReps = THRESHOLDS.loopMinRepetitions;
187
+ const loopSeverity = Math.max(maxConsecutive >= minReps ? maxConsecutive - (minReps - 1) : 0, maxErrorRepeat >= minReps ? maxErrorRepeat - (minReps - 1) : 0);
188
+ if (loopSeverity === 0) return {
189
+ score: 1,
190
+ detail: "No stuck loops",
191
+ applicable: true
192
+ };
193
+ const score = Math.max(0, 1 - loopSeverity * THRESHOLDS.loopPenaltyPerOccurrence);
194
+ const details = [];
195
+ if (maxConsecutive >= minReps) details.push(`${maxConsecutive} consecutive identical calls`);
196
+ if (maxErrorRepeat >= minReps) details.push(`same error repeated ${maxErrorRepeat}x`);
197
+ return {
198
+ score,
199
+ detail: details.join("; "),
200
+ applicable: true
201
+ };
112
202
  }
203
+ /**
204
+ * Detect regressions: build/test passed at some point, then failed later.
205
+ * Gives partial credit if the agent recovered (final state passes).
206
+ */
113
207
  function scoreRegression(execResults) {
114
- const regressions = [];
115
- for (const [label, filter] of [
116
- ["Build", isBuildArgs],
117
- ["Tests", isTestArgs]
118
- ]) {
119
- const cmds = execResults.filter((r) => r.toolName === "execute_command" && filter(r.args));
120
- if (cmds.length < 2) continue;
121
- let sawPass = false;
122
- let sawRegression = false;
123
- for (const cmd of cmds) {
124
- const exit = getExitCode(cmd.result);
125
- if (exit === 0) {
126
- if (sawRegression) {
127
- regressions.push({ label, recovered: true });
128
- sawRegression = false;
129
- }
130
- sawPass = true;
131
- }
132
- if (sawPass && exit !== null && exit !== 0) {
133
- sawRegression = true;
134
- }
135
- }
136
- if (sawRegression) {
137
- regressions.push({ label, recovered: false });
138
- }
139
- }
140
- if (regressions.length === 0) return { score: 1, detail: "No regressions", applicable: true };
141
- const persistentCount = regressions.filter((r) => !r.recovered).length;
142
- const recoveredCount = regressions.filter((r) => r.recovered).length;
143
- const score = Math.max(0, 1 - persistentCount * 0.5 - recoveredCount * 0.1);
144
- const details = regressions.map(
145
- (r) => `${r.label} ${r.recovered ? "regressed then recovered" : "regressed (persisted)"}`
146
- );
147
- return { score, detail: details.join("; "), applicable: true };
208
+ const regressions = [];
209
+ for (const [label, filter] of [["Build", isBuildArgs], ["Tests", isTestArgs]]) {
210
+ const cmds = execResults.filter((r) => r.toolName === "execute_command" && filter(r.args));
211
+ if (cmds.length < 2) continue;
212
+ let sawPass = false;
213
+ let sawRegression = false;
214
+ for (const cmd of cmds) {
215
+ const exit = getExitCode(cmd.result);
216
+ if (exit === 0) {
217
+ if (sawRegression) {
218
+ regressions.push({
219
+ label,
220
+ recovered: true
221
+ });
222
+ sawRegression = false;
223
+ }
224
+ sawPass = true;
225
+ }
226
+ if (sawPass && exit !== null && exit !== 0) sawRegression = true;
227
+ }
228
+ if (sawRegression) regressions.push({
229
+ label,
230
+ recovered: false
231
+ });
232
+ }
233
+ if (regressions.length === 0) return {
234
+ score: 1,
235
+ detail: "No regressions",
236
+ applicable: true
237
+ };
238
+ const persistentCount = regressions.filter((r) => !r.recovered).length;
239
+ const recoveredCount = regressions.filter((r) => r.recovered).length;
240
+ return {
241
+ score: Math.max(0, 1 - persistentCount * .5 - recoveredCount * .1),
242
+ detail: regressions.map((r) => `${r.label} ${r.recovered ? "regressed then recovered" : "regressed (persisted)"}`).join("; "),
243
+ applicable: true
244
+ };
148
245
  }
246
+ /**
247
+ * Score autonomy: penalize ask_user calls.
248
+ * 0 calls = 1.0, each call reduces by 0.25 (up to a floor of 0).
249
+ */
149
250
  function scoreAutonomy(results) {
150
- const askUserCalls = results.filter((r) => r.toolName === "ask_user");
151
- const count = askUserCalls.length;
152
- if (count === 0) return { score: 1, detail: "No ask_user calls (fully autonomous)", applicable: true };
153
- const score = Math.max(0, 1 - count * THRESHOLDS.autonomyPenaltyPerAsk);
154
- return { score, detail: `${count} ask_user call${count > 1 ? "s" : ""}`, applicable: true };
251
+ const count = results.filter((r) => r.toolName === "ask_user").length;
252
+ if (count === 0) return {
253
+ score: 1,
254
+ detail: "No ask_user calls (fully autonomous)",
255
+ applicable: true
256
+ };
257
+ return {
258
+ score: Math.max(0, 1 - count * THRESHOLDS.autonomyPenaltyPerAsk),
259
+ detail: `${count} ask_user call${count > 1 ? "s" : ""}`,
260
+ applicable: true
261
+ };
155
262
  }
263
+ /**
264
+ * Compute weighted average of only applicable dimensions.
265
+ * Returns null if no dimensions are applicable.
266
+ */
156
267
  function weightedAverage(dimensions, weights) {
157
- let totalWeight = 0;
158
- let weightedSum = 0;
159
- for (const [key, result] of Object.entries(dimensions)) {
160
- if (!result.applicable) continue;
161
- const weight = weights[key] ?? 0;
162
- totalWeight += weight;
163
- weightedSum += result.score * weight;
164
- }
165
- if (totalWeight === 0) return null;
166
- return weightedSum / totalWeight;
268
+ let totalWeight = 0;
269
+ let weightedSum = 0;
270
+ for (const [key, result] of Object.entries(dimensions)) {
271
+ if (!result.applicable) continue;
272
+ const weight = weights[key] ?? 0;
273
+ totalWeight += weight;
274
+ weightedSum += result.score * weight;
275
+ }
276
+ if (totalWeight === 0) return null;
277
+ return weightedSum / totalWeight;
167
278
  }
168
279
  function createOutcomeScorer() {
169
- return createScorer({
170
- id: "mastracode-outcome",
171
- name: "MastraCode Outcome",
172
- description: "Grades coding session outcomes: build/test pass, tool errors, stuck loops, regressions, autonomy. Always-on.",
173
- type: "agent",
174
- prepareRun: filterRun({ partTypes: ["tool-invocation", "text"] })
175
- }).preprocess(async ({ run }) => {
176
- const messages = run.output ?? [];
177
- const allResults = extractToolCalls(messages);
178
- const totalCalls = allResults.length;
179
- if (totalCalls < THRESHOLDS.minToolCalls) {
180
- const empty = { score: 0, detail: "No tool calls", applicable: false };
181
- return {
182
- empty: true,
183
- build: empty,
184
- tests: empty,
185
- toolErrors: empty,
186
- loops: empty,
187
- regression: empty,
188
- autonomy: empty,
189
- totalCalls
190
- };
191
- }
192
- const execResults = allResults.filter((r) => r.toolName === "execute_command");
193
- return {
194
- empty: false,
195
- build: scoreBuild(execResults),
196
- tests: scoreTests(execResults),
197
- toolErrors: scoreToolErrors(allResults),
198
- loops: scoreStuckLoops(allResults),
199
- regression: scoreRegression(execResults),
200
- autonomy: scoreAutonomy(allResults),
201
- totalCalls
202
- };
203
- }).generateScore(({ results }) => {
204
- const p = results.preprocessStepResult;
205
- if (p.empty) return 0;
206
- const score = weightedAverage(
207
- {
208
- build: p.build,
209
- tests: p.tests,
210
- toolErrors: p.toolErrors,
211
- loops: p.loops,
212
- regression: p.regression,
213
- autonomy: p.autonomy
214
- },
215
- WEIGHTS
216
- );
217
- return score === null ? 0 : Math.round(score * 100) / 100;
218
- }).generateReason(({ results, score }) => {
219
- const p = results.preprocessStepResult;
220
- if (p.empty) {
221
- return `Score: 0 (${p.totalCalls} tool calls \u2014 below minimum threshold for scoring)`;
222
- }
223
- const pct = (w) => `${(w * 100).toFixed(0)}%`;
224
- const dimLine = (name, weight, r) => r.applicable ? `${name} (${pct(weight)}): ${r.detail} [${r.score}]` : `${name}: ${r.detail} [N/A \u2014 excluded from average]`;
225
- const parts = [`Score: ${score} (${p.totalCalls} tool calls total)`];
226
- parts.push(dimLine("Build", WEIGHTS.build, p.build));
227
- parts.push(dimLine("Tests", WEIGHTS.tests, p.tests));
228
- parts.push(dimLine("Tool errors", WEIGHTS.toolErrors, p.toolErrors));
229
- parts.push(dimLine("Loops", WEIGHTS.loops, p.loops));
230
- parts.push(dimLine("Regression", WEIGHTS.regression, p.regression));
231
- parts.push(dimLine("Autonomy", WEIGHTS.autonomy, p.autonomy));
232
- return parts.join("\n");
233
- });
280
+ return createScorer({
281
+ id: "mastracode-outcome",
282
+ name: "MastraCode Outcome",
283
+ description: "Grades coding session outcomes: build/test pass, tool errors, stuck loops, regressions, autonomy. Always-on.",
284
+ type: "agent",
285
+ prepareRun: filterRun({ partTypes: ["tool-invocation", "text"] })
286
+ }).preprocess(async ({ run }) => {
287
+ const allResults = extractToolCalls(run.output ?? []);
288
+ const totalCalls = allResults.length;
289
+ if (totalCalls < THRESHOLDS.minToolCalls) {
290
+ const empty = {
291
+ score: 0,
292
+ detail: "No tool calls",
293
+ applicable: false
294
+ };
295
+ return {
296
+ empty: true,
297
+ build: empty,
298
+ tests: empty,
299
+ toolErrors: empty,
300
+ loops: empty,
301
+ regression: empty,
302
+ autonomy: empty,
303
+ totalCalls
304
+ };
305
+ }
306
+ const execResults = allResults.filter((r) => r.toolName === "execute_command");
307
+ return {
308
+ empty: false,
309
+ build: scoreBuild(execResults),
310
+ tests: scoreTests(execResults),
311
+ toolErrors: scoreToolErrors(allResults),
312
+ loops: scoreStuckLoops(allResults),
313
+ regression: scoreRegression(execResults),
314
+ autonomy: scoreAutonomy(allResults),
315
+ totalCalls
316
+ };
317
+ }).generateScore(({ results }) => {
318
+ const p = results.preprocessStepResult;
319
+ if (p.empty) return 0;
320
+ const score = weightedAverage({
321
+ build: p.build,
322
+ tests: p.tests,
323
+ toolErrors: p.toolErrors,
324
+ loops: p.loops,
325
+ regression: p.regression,
326
+ autonomy: p.autonomy
327
+ }, WEIGHTS);
328
+ return score === null ? 0 : Math.round(score * 100) / 100;
329
+ }).generateReason(({ results, score }) => {
330
+ const p = results.preprocessStepResult;
331
+ if (p.empty) return `Score: 0 (${p.totalCalls} tool calls — below minimum threshold for scoring)`;
332
+ const pct = (w) => `${(w * 100).toFixed(0)}%`;
333
+ const dimLine = (name, weight, r) => r.applicable ? `${name} (${pct(weight)}): ${r.detail} [${r.score}]` : `${name}: ${r.detail} [N/A — excluded from average]`;
334
+ const parts = [`Score: ${score} (${p.totalCalls} tool calls total)`];
335
+ parts.push(dimLine("Build", WEIGHTS.build, p.build));
336
+ parts.push(dimLine("Tests", WEIGHTS.tests, p.tests));
337
+ parts.push(dimLine("Tool errors", WEIGHTS.toolErrors, p.toolErrors));
338
+ parts.push(dimLine("Loops", WEIGHTS.loops, p.loops));
339
+ parts.push(dimLine("Regression", WEIGHTS.regression, p.regression));
340
+ parts.push(dimLine("Autonomy", WEIGHTS.autonomy, p.autonomy));
341
+ return parts.join("\n");
342
+ });
234
343
  }
235
- export {
236
- createOutcomeScorer
237
- };
344
+ //#endregion
345
+ export { createOutcomeScorer };
346
+
238
347
  //# sourceMappingURL=outcome.js.map