@mastra/code-sdk 1.0.3-alpha.0 → 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.
- package/CHANGELOG.md +49 -0
- package/dist/acp/agent.js +155 -167
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.js +193 -168
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp/index.js +60 -49
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/server.js +31 -30
- package/dist/acp/server.js.map +1 -1
- package/dist/acp.js +1 -4
- package/dist/agents/credential-resolver.js +40 -29
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/custom-provider-source.js +16 -9
- package/dist/agents/custom-provider-source.js.map +1 -1
- package/dist/agents/instructions.js +27 -36
- package/dist/agents/instructions.js.map +1 -1
- package/dist/agents/mastracode-gateway.js +355 -428
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.js +87 -78
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.js +114 -119
- package/dist/agents/model.js.map +1 -1
- package/dist/agents/modes/build.js +12 -13
- package/dist/agents/modes/build.js.map +1 -1
- package/dist/agents/modes/explore.js +14 -13
- package/dist/agents/modes/explore.js.map +1 -1
- package/dist/agents/modes/plan.js +14 -15
- package/dist/agents/modes/plan.js.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +78 -69
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/build.js +19 -16
- package/dist/agents/prompts/build.js.map +1 -1
- package/dist/agents/prompts/fast.js +8 -4
- package/dist/agents/prompts/fast.js.map +1 -1
- package/dist/agents/prompts/index.js +48 -47
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/prompts/model.js +6 -5
- package/dist/agents/prompts/model.js.map +1 -1
- package/dist/agents/prompts/plan.js +20 -16
- package/dist/agents/prompts/plan.js.map +1 -1
- package/dist/agents/prompts/tool-guidance.js +77 -109
- package/dist/agents/prompts/tool-guidance.js.map +1 -1
- package/dist/agents/sandbox-filesystem.js +245 -259
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/sandbox-reattach.js +9 -11
- package/dist/agents/sandbox-reattach.js.map +1 -1
- package/dist/agents/thread-caveman-state.js +92 -81
- package/dist/agents/thread-caveman-state.js.map +1 -1
- package/dist/agents/tool-availability.js +62 -80
- package/dist/agents/tool-availability.js.map +1 -1
- package/dist/agents/tools.js +99 -139
- package/dist/agents/tools.js.map +1 -1
- package/dist/agents/workspace.js +232 -225
- package/dist/agents/workspace.js.map +1 -1
- package/dist/analytics.js +139 -128
- package/dist/analytics.js.map +1 -1
- package/dist/auth/authorization-input.js +39 -25
- package/dist/auth/authorization-input.js.map +1 -1
- package/dist/auth/device-code.js +112 -80
- package/dist/auth/device-code.js.map +1 -1
- package/dist/auth/index.js +2 -9
- package/dist/auth/pkce.js +27 -16
- package/dist/auth/pkce.js.map +1 -1
- package/dist/auth/providers/anthropic.js +107 -93
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.js +304 -293
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/openai-codex.js +442 -460
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.js +179 -145
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/auth/storage.js +182 -175
- package/dist/auth/storage.js.map +1 -1
- package/dist/auth/types.js +1 -1
- package/dist/clipboard/index.js +206 -172
- package/dist/clipboard/index.js.map +1 -1
- package/dist/constants.js +11 -16
- package/dist/constants.js.map +1 -1
- package/dist/error-classification.js +19 -11
- package/dist/error-classification.js.map +1 -1
- package/dist/evals/context-builder.js +145 -104
- package/dist/evals/context-builder.js.map +1 -1
- package/dist/evals/index.js +4 -7
- package/dist/evals/scorers/classify-command.js +62 -41
- package/dist/evals/scorers/classify-command.js.map +1 -1
- package/dist/evals/scorers/efficiency.js +239 -181
- package/dist/evals/scorers/efficiency.js.map +1 -1
- package/dist/evals/scorers/extract-tools.js +51 -47
- package/dist/evals/scorers/extract-tools.js.map +1 -1
- package/dist/evals/scorers/index.js +1 -5
- package/dist/evals/scorers/outcome.js +321 -212
- package/dist/evals/scorers/outcome.js.map +1 -1
- package/dist/goal-manager.js +266 -261
- package/dist/goal-manager.js.map +1 -1
- package/dist/goal-signal.js +14 -13
- package/dist/goal-signal.js.map +1 -1
- package/dist/headless/cli.js +153 -154
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/flags.js +180 -178
- package/dist/headless/flags.js.map +1 -1
- package/dist/headless/format.js +72 -71
- package/dist/headless/format.js.map +1 -1
- package/dist/headless/index.js +5 -31
- package/dist/headless/policy.js +35 -31
- package/dist/headless/policy.js.map +1 -1
- package/dist/headless/run-mc.js +332 -334
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/headless/types.js +16 -7
- package/dist/headless/types.js.map +1 -1
- package/dist/hooks/config.js +56 -61
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/executor.js +118 -116
- package/dist/hooks/executor.js.map +1 -1
- package/dist/hooks/index.js +4 -15
- package/dist/hooks/manager.js +221 -280
- package/dist/hooks/manager.js.map +1 -1
- package/dist/hooks/types.js +5 -4
- package/dist/hooks/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +632 -712
- package/dist/index.js.map +1 -1
- package/dist/ipc/ipc-reporter.js +19 -22
- package/dist/ipc/ipc-reporter.js.map +1 -1
- package/dist/lsp/client.js +248 -306
- package/dist/lsp/client.js.map +1 -1
- package/dist/lsp/index.js +1 -6
- package/dist/lsp/language.js +39 -43
- package/dist/lsp/language.js.map +1 -1
- package/dist/lsp/manager.js +78 -93
- package/dist/lsp/manager.js.map +1 -1
- package/dist/lsp/server.js +151 -120
- package/dist/lsp/server.js.map +1 -1
- package/dist/lsp/workspace.js +50 -47
- package/dist/lsp/workspace.js.map +1 -1
- package/dist/mcp/config.js +210 -199
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/index.js +2 -9
- package/dist/mcp/manager.js +482 -475
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/types.js +1 -1
- package/dist/onboarding/custom-packs.js +14 -17
- package/dist/onboarding/custom-packs.js.map +1 -1
- package/dist/onboarding/custom-providers.js +22 -20
- package/dist/onboarding/custom-providers.js.map +1 -1
- package/dist/onboarding/index.d.ts +1 -1
- package/dist/onboarding/index.d.ts.map +1 -1
- package/dist/onboarding/index.js +3 -21
- package/dist/onboarding/om-settings.d.ts +5 -0
- package/dist/onboarding/om-settings.d.ts.map +1 -1
- package/dist/onboarding/om-settings.js +41 -20
- package/dist/onboarding/om-settings.js.map +1 -1
- package/dist/onboarding/packs.d.ts +4 -6
- package/dist/onboarding/packs.d.ts.map +1 -1
- package/dist/onboarding/packs.js +154 -105
- package/dist/onboarding/packs.js.map +1 -1
- package/dist/onboarding/settings.js +575 -517
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/permissions.js +112 -99
- package/dist/permissions.js.map +1 -1
- package/dist/plugin.js +21 -23
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/dependencies.js +64 -87
- package/dist/plugins/dependencies.js.map +1 -1
- package/dist/plugins/install.js +159 -169
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/loader.js +170 -185
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/manager.js +374 -380
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manifest.js +38 -63
- package/dist/plugins/manifest.js.map +1 -1
- package/dist/plugins/package-link.js +48 -64
- package/dist/plugins/package-link.js.map +1 -1
- package/dist/plugins/paths.js +18 -19
- package/dist/plugins/paths.js.map +1 -1
- package/dist/plugins/registry.js +97 -81
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/scaffold.js +62 -98
- package/dist/plugins/scaffold.js.map +1 -1
- package/dist/plugins/types.js +1 -1
- package/dist/processors/plan-rejection-abort.js +45 -44
- package/dist/processors/plan-rejection-abort.js.map +1 -1
- package/dist/providers/amazon-bedrock-gateway.js +134 -125
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +68 -47
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/claude-max.js +153 -133
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot.js +232 -230
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/openai-codex.js +271 -260
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/xai.js +57 -50
- package/dist/providers/xai.js.map +1 -1
- package/dist/schema.js +91 -89
- package/dist/schema.js.map +1 -1
- package/dist/theme-palette.js +18 -14
- package/dist/theme-palette.js.map +1 -1
- package/dist/tool-names.js +46 -37
- package/dist/tool-names.js.map +1 -1
- package/dist/tools/index.js +2 -8
- package/dist/tools/request-sandbox-access.js +71 -80
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/tools/utils.js +26 -16
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/web-search.js +51 -55
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/binaries.js +65 -61
- package/dist/utils/binaries.js.map +1 -1
- package/dist/utils/debug-log.js +51 -47
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/errors.js +157 -192
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/gateway-sync.js +49 -37
- package/dist/utils/gateway-sync.js.map +1 -1
- package/dist/utils/path-security.js +7 -6
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/plan-diff.js +58 -39
- package/dist/utils/plan-diff.js.map +1 -1
- package/dist/utils/plans.js +92 -74
- package/dist/utils/plans.js.map +1 -1
- package/dist/utils/project.js +318 -256
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/signals-pubsub.js +117 -99
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/slash-command-loader.js +118 -154
- package/dist/utils/slash-command-loader.js.map +1 -1
- package/dist/utils/slash-command-processor.js +92 -83
- package/dist/utils/slash-command-processor.js.map +1 -1
- package/dist/utils/stdin-pipe.js +87 -63
- package/dist/utils/stdin-pipe.js.map +1 -1
- package/dist/utils/storage-factory.js +104 -84
- package/dist/utils/storage-factory.js.map +1 -1
- package/dist/utils/storage-maintenance.js +249 -211
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/dist/utils/thread-lock.js +96 -92
- package/dist/utils/thread-lock.js.map +1 -1
- package/dist/utils/token-estimator.js +12 -12
- package/dist/utils/token-estimator.js.map +1 -1
- package/dist/utils/update-check.d.ts +1 -1
- package/dist/utils/update-check.js +341 -259
- package/dist/utils/update-check.js.map +1 -1
- package/dist/voice/stt-registry.js +131 -113
- package/dist/voice/stt-registry.js.map +1 -1
- package/package.json +11 -11
- package/dist/acp.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/evals/index.js.map +0 -1
- package/dist/evals/scorers/index.js.map +0 -1
- package/dist/headless/index.js.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/lsp/index.js.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/types.js.map +0 -1
- package/dist/onboarding/index.js.map +0 -1
- package/dist/plugins/types.js.map +0 -1
- 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;
|
|
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 {
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
46
|
+
return isBuildCommand(String(args.command ?? ""));
|
|
30
47
|
}
|
|
31
48
|
function isTestArgs(args) {
|
|
32
|
-
|
|
49
|
+
return isTestCommand(String(args.command ?? ""));
|
|
33
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Score build/typecheck outcome (final state).
|
|
53
|
+
*/
|
|
34
54
|
function scoreBuild(execResults) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
344
|
+
//#endregion
|
|
345
|
+
export { createOutcomeScorer };
|
|
346
|
+
|
|
238
347
|
//# sourceMappingURL=outcome.js.map
|