@wix/pathgrade 0.29.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 (238) hide show
  1. package/bin/pathgrade.js +2 -0
  2. package/dist/affected/anchor.d.ts +18 -0
  3. package/dist/affected/anchor.js +42 -0
  4. package/dist/affected/config.d.ts +25 -0
  5. package/dist/affected/config.js +98 -0
  6. package/dist/affected/format.d.ts +45 -0
  7. package/dist/affected/format.js +87 -0
  8. package/dist/affected/git.d.ts +33 -0
  9. package/dist/affected/git.js +68 -0
  10. package/dist/affected/glob.d.ts +17 -0
  11. package/dist/affected/glob.js +25 -0
  12. package/dist/affected/meta.d.ts +26 -0
  13. package/dist/affected/meta.js +158 -0
  14. package/dist/affected/select.d.ts +30 -0
  15. package/dist/affected/select.js +101 -0
  16. package/dist/affected/sidecar.d.ts +32 -0
  17. package/dist/affected/sidecar.js +86 -0
  18. package/dist/affected/types.d.ts +43 -0
  19. package/dist/affected/types.js +7 -0
  20. package/dist/agents/claude/ask-user-answer-store.d.ts +28 -0
  21. package/dist/agents/claude/ask-user-answer-store.js +29 -0
  22. package/dist/agents/claude/ask-user-bridge.d.ts +56 -0
  23. package/dist/agents/claude/ask-user-bridge.js +162 -0
  24. package/dist/agents/claude/sdk-message-projector.d.ts +43 -0
  25. package/dist/agents/claude/sdk-message-projector.js +208 -0
  26. package/dist/agents/claude/sdk-options.d.ts +52 -0
  27. package/dist/agents/claude/sdk-options.js +79 -0
  28. package/dist/agents/claude.d.ts +56 -0
  29. package/dist/agents/claude.js +143 -0
  30. package/dist/agents/codex-app-server/agent.d.ts +35 -0
  31. package/dist/agents/codex-app-server/agent.js +388 -0
  32. package/dist/agents/codex-app-server/fixtures/app-server-client.d.ts +19 -0
  33. package/dist/agents/codex-app-server/fixtures/app-server-client.js +104 -0
  34. package/dist/agents/codex-app-server/fixtures/run-gate.d.ts +25 -0
  35. package/dist/agents/codex-app-server/fixtures/run-gate.js +48 -0
  36. package/dist/agents/codex-app-server/protocol/ClientRequest.d.ts +27 -0
  37. package/dist/agents/codex-app-server/protocol/ClientRequest.js +7 -0
  38. package/dist/agents/codex-app-server/protocol/DynamicToolCallParams.d.ts +9 -0
  39. package/dist/agents/codex-app-server/protocol/DynamicToolCallParams.js +4 -0
  40. package/dist/agents/codex-app-server/protocol/GrantedPermissionProfile.d.ts +6 -0
  41. package/dist/agents/codex-app-server/protocol/GrantedPermissionProfile.js +7 -0
  42. package/dist/agents/codex-app-server/protocol/McpElicitationRequestParams.d.ts +23 -0
  43. package/dist/agents/codex-app-server/protocol/McpElicitationRequestParams.js +8 -0
  44. package/dist/agents/codex-app-server/protocol/Op.d.ts +11 -0
  45. package/dist/agents/codex-app-server/protocol/Op.js +5 -0
  46. package/dist/agents/codex-app-server/protocol/PermissionsRequestApprovalParams.d.ts +10 -0
  47. package/dist/agents/codex-app-server/protocol/PermissionsRequestApprovalParams.js +6 -0
  48. package/dist/agents/codex-app-server/protocol/PermissionsRequestApprovalResponse.d.ts +15 -0
  49. package/dist/agents/codex-app-server/protocol/PermissionsRequestApprovalResponse.js +4 -0
  50. package/dist/agents/codex-app-server/protocol/SandboxMode.d.ts +1 -0
  51. package/dist/agents/codex-app-server/protocol/SandboxMode.js +4 -0
  52. package/dist/agents/codex-app-server/protocol/ServerRequest.d.ts +42 -0
  53. package/dist/agents/codex-app-server/protocol/ServerRequest.js +7 -0
  54. package/dist/agents/codex-app-server/protocol/ThreadStartParams.d.ts +45 -0
  55. package/dist/agents/codex-app-server/protocol/ThreadStartParams.js +10 -0
  56. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputAnswer.d.ts +6 -0
  57. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputAnswer.js +4 -0
  58. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputOption.d.ts +7 -0
  59. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputOption.js +4 -0
  60. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputParams.d.ts +10 -0
  61. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputParams.js +4 -0
  62. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputQuestion.d.ts +12 -0
  63. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputQuestion.js +4 -0
  64. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputResponse.d.ts +9 -0
  65. package/dist/agents/codex-app-server/protocol/ToolRequestUserInputResponse.js +4 -0
  66. package/dist/agents/codex-app-server/protocol/TurnCompletedNotification.d.ts +5 -0
  67. package/dist/agents/codex-app-server/protocol/TurnCompletedNotification.js +4 -0
  68. package/dist/agents/codex-app-server/protocol/index.d.ts +16 -0
  69. package/dist/agents/codex-app-server/protocol/index.js +11 -0
  70. package/dist/agents/codex-app-server/transport.d.ts +84 -0
  71. package/dist/agents/codex-app-server/transport.js +246 -0
  72. package/dist/agents/codex-app-server/wire-translators.d.ts +19 -0
  73. package/dist/agents/codex-app-server/wire-translators.js +52 -0
  74. package/dist/agents/codex.d.ts +7 -0
  75. package/dist/agents/codex.js +164 -0
  76. package/dist/agents/cursor.d.ts +39 -0
  77. package/dist/agents/cursor.js +233 -0
  78. package/dist/agents/registry.d.ts +17 -0
  79. package/dist/agents/registry.js +27 -0
  80. package/dist/agents/transcript-agent.d.ts +14 -0
  81. package/dist/agents/transcript-agent.js +59 -0
  82. package/dist/analytics/engine.d.ts +18 -0
  83. package/dist/analytics/engine.js +66 -0
  84. package/dist/commands/affected.d.ts +31 -0
  85. package/dist/commands/affected.js +150 -0
  86. package/dist/commands/analyze.d.ts +21 -0
  87. package/dist/commands/analyze.js +167 -0
  88. package/dist/commands/init.d.ts +3 -0
  89. package/dist/commands/init.js +242 -0
  90. package/dist/commands/preview-reactions.d.ts +10 -0
  91. package/dist/commands/preview-reactions.js +88 -0
  92. package/dist/commands/preview.d.ts +5 -0
  93. package/dist/commands/preview.js +17 -0
  94. package/dist/commands/report.d.ts +39 -0
  95. package/dist/commands/report.js +108 -0
  96. package/dist/commands/run-args.d.ts +22 -0
  97. package/dist/commands/run-args.js +69 -0
  98. package/dist/commands/run-changed.d.ts +26 -0
  99. package/dist/commands/run-changed.js +138 -0
  100. package/dist/commands/validate.d.ts +13 -0
  101. package/dist/commands/validate.js +233 -0
  102. package/dist/core/mcp-mock.d.ts +3 -0
  103. package/dist/core/mcp-mock.js +23 -0
  104. package/dist/core/mcp-mock.types.d.ts +15 -0
  105. package/dist/core/mcp-mock.types.js +1 -0
  106. package/dist/core/skills.d.ts +15 -0
  107. package/dist/core/skills.js +76 -0
  108. package/dist/evals/discovery.d.ts +7 -0
  109. package/dist/evals/discovery.js +69 -0
  110. package/dist/mcp-mock-server.d.ts +1 -0
  111. package/dist/mcp-mock-server.js +116 -0
  112. package/dist/pathgrade.d.ts +10 -0
  113. package/dist/pathgrade.js +243 -0
  114. package/dist/plugin/index.d.ts +9 -0
  115. package/dist/plugin/index.js +81 -0
  116. package/dist/plugin/lifecycle.d.ts +45 -0
  117. package/dist/plugin/lifecycle.js +146 -0
  118. package/dist/plugin/reporter.d.ts +36 -0
  119. package/dist/plugin/reporter.js +275 -0
  120. package/dist/plugin/setup.d.ts +1 -0
  121. package/dist/plugin/setup.js +3 -0
  122. package/dist/providers/copy-filter.d.ts +18 -0
  123. package/dist/providers/copy-filter.js +66 -0
  124. package/dist/providers/credentials.d.ts +36 -0
  125. package/dist/providers/credentials.js +202 -0
  126. package/dist/providers/mcp-config.d.ts +34 -0
  127. package/dist/providers/mcp-config.js +55 -0
  128. package/dist/providers/sandbox-exec.d.ts +8 -0
  129. package/dist/providers/sandbox-exec.js +82 -0
  130. package/dist/providers/sandbox.d.ts +22 -0
  131. package/dist/providers/sandbox.js +158 -0
  132. package/dist/providers/sandboxed-claude-spawn.d.ts +24 -0
  133. package/dist/providers/sandboxed-claude-spawn.js +57 -0
  134. package/dist/providers/workspace.d.ts +15 -0
  135. package/dist/providers/workspace.js +73 -0
  136. package/dist/reporters/browser.d.ts +2 -0
  137. package/dist/reporters/browser.js +85 -0
  138. package/dist/reporters/cli.d.ts +2 -0
  139. package/dist/reporters/cli.js +131 -0
  140. package/dist/reporters/diagnostics.d.ts +46 -0
  141. package/dist/reporters/diagnostics.js +147 -0
  142. package/dist/reporters/github-comment.d.ts +67 -0
  143. package/dist/reporters/github-comment.js +252 -0
  144. package/dist/reporters/loader.d.ts +8 -0
  145. package/dist/reporters/loader.js +36 -0
  146. package/dist/reporters/results-path.d.ts +2 -0
  147. package/dist/reporters/results-path.js +10 -0
  148. package/dist/reporters/verbose-emitter.d.ts +69 -0
  149. package/dist/reporters/verbose-emitter.js +103 -0
  150. package/dist/sdk/agent-crash.d.ts +19 -0
  151. package/dist/sdk/agent-crash.js +20 -0
  152. package/dist/sdk/agent-resolution.d.ts +12 -0
  153. package/dist/sdk/agent-resolution.js +21 -0
  154. package/dist/sdk/agent-result-log.d.ts +19 -0
  155. package/dist/sdk/agent-result-log.js +45 -0
  156. package/dist/sdk/agent.d.ts +4 -0
  157. package/dist/sdk/agent.js +354 -0
  158. package/dist/sdk/ask-bus/bus.d.ts +21 -0
  159. package/dist/sdk/ask-bus/bus.js +129 -0
  160. package/dist/sdk/ask-bus/handler.d.ts +31 -0
  161. package/dist/sdk/ask-bus/handler.js +244 -0
  162. package/dist/sdk/ask-bus/parsers.d.ts +9 -0
  163. package/dist/sdk/ask-bus/parsers.js +30 -0
  164. package/dist/sdk/ask-bus/projection.d.ts +26 -0
  165. package/dist/sdk/ask-bus/projection.js +45 -0
  166. package/dist/sdk/ask-bus/types.d.ts +69 -0
  167. package/dist/sdk/ask-bus/types.js +1 -0
  168. package/dist/sdk/chat.d.ts +29 -0
  169. package/dist/sdk/chat.js +93 -0
  170. package/dist/sdk/conversation-window.d.ts +14 -0
  171. package/dist/sdk/conversation-window.js +38 -0
  172. package/dist/sdk/converse.d.ts +42 -0
  173. package/dist/sdk/converse.js +329 -0
  174. package/dist/sdk/eval-runtime.d.ts +10 -0
  175. package/dist/sdk/eval-runtime.js +17 -0
  176. package/dist/sdk/evaluate.d.ts +13 -0
  177. package/dist/sdk/evaluate.js +325 -0
  178. package/dist/sdk/index.d.ts +31 -0
  179. package/dist/sdk/index.js +20 -0
  180. package/dist/sdk/judge-pipeline.d.ts +7 -0
  181. package/dist/sdk/judge-pipeline.js +178 -0
  182. package/dist/sdk/judge-prompt-builder.d.ts +7 -0
  183. package/dist/sdk/judge-prompt-builder.js +76 -0
  184. package/dist/sdk/judge-tool-runner.d.ts +19 -0
  185. package/dist/sdk/judge-tool-runner.js +51 -0
  186. package/dist/sdk/judge-tool-session.d.ts +47 -0
  187. package/dist/sdk/judge-tool-session.js +213 -0
  188. package/dist/sdk/judge-tools.d.ts +29 -0
  189. package/dist/sdk/judge-tools.js +283 -0
  190. package/dist/sdk/managed-session.d.ts +50 -0
  191. package/dist/sdk/managed-session.js +110 -0
  192. package/dist/sdk/persona.d.ts +5 -0
  193. package/dist/sdk/persona.js +33 -0
  194. package/dist/sdk/reaction-loader.d.ts +4 -0
  195. package/dist/sdk/reaction-loader.js +119 -0
  196. package/dist/sdk/reaction-preview.d.ts +6 -0
  197. package/dist/sdk/reaction-preview.js +94 -0
  198. package/dist/sdk/run-scorer.d.ts +10 -0
  199. package/dist/sdk/run-scorer.js +124 -0
  200. package/dist/sdk/runtime-policy.d.ts +21 -0
  201. package/dist/sdk/runtime-policy.js +89 -0
  202. package/dist/sdk/scorer-utils.d.ts +6 -0
  203. package/dist/sdk/scorer-utils.js +39 -0
  204. package/dist/sdk/scorers.d.ts +64 -0
  205. package/dist/sdk/scorers.js +80 -0
  206. package/dist/sdk/snapshots.d.ts +41 -0
  207. package/dist/sdk/snapshots.js +148 -0
  208. package/dist/sdk/types.d.ts +416 -0
  209. package/dist/sdk/types.js +17 -0
  210. package/dist/sdk/visible-turn.d.ts +4 -0
  211. package/dist/sdk/visible-turn.js +23 -0
  212. package/dist/tool-events.d.ts +45 -0
  213. package/dist/tool-events.js +167 -0
  214. package/dist/types.d.ts +372 -0
  215. package/dist/types.js +37 -0
  216. package/dist/utils/cli.d.ts +55 -0
  217. package/dist/utils/cli.js +131 -0
  218. package/dist/utils/env.d.ts +8 -0
  219. package/dist/utils/env.js +26 -0
  220. package/dist/utils/llm-mocks.d.ts +43 -0
  221. package/dist/utils/llm-mocks.js +108 -0
  222. package/dist/utils/llm-providers/anthropic.d.ts +2 -0
  223. package/dist/utils/llm-providers/anthropic.js +132 -0
  224. package/dist/utils/llm-providers/cli.d.ts +20 -0
  225. package/dist/utils/llm-providers/cli.js +162 -0
  226. package/dist/utils/llm-providers/openai.d.ts +2 -0
  227. package/dist/utils/llm-providers/openai.js +56 -0
  228. package/dist/utils/llm-types.d.ts +107 -0
  229. package/dist/utils/llm-types.js +1 -0
  230. package/dist/utils/llm.d.ts +36 -0
  231. package/dist/utils/llm.js +209 -0
  232. package/dist/utils/shutdown.d.ts +15 -0
  233. package/dist/utils/shutdown.js +41 -0
  234. package/dist/utils/timeout.d.ts +8 -0
  235. package/dist/utils/timeout.js +32 -0
  236. package/dist/viewer.html +1178 -0
  237. package/package.json +88 -0
  238. package/templates/eval.ts.template +28 -0
@@ -0,0 +1,329 @@
1
+ import { buildAskBatchLogEntries, buildModelAgentResultLogEntry, } from './agent-result-log.js';
2
+ import { inspectReactions } from './reaction-preview.js';
3
+ import { getVisibleAssistantMessage, normalizeTurnResult } from './visible-turn.js';
4
+ import { AskBusTimeoutError } from './ask-bus/bus.js';
5
+ import { createAskUserHandler } from './ask-bus/handler.js';
6
+ import { AgentCrashError } from './agent-crash.js';
7
+ function isTimeoutError(err) {
8
+ return err instanceof Error && /timed out/i.test(err.message);
9
+ }
10
+ /**
11
+ * Translate a non-zero-exit `AgentTurnResult` into the Error the conversation
12
+ * loop throws after `pushModelAgentMessage` records the partial turn. The
13
+ * message shape mirrors what `AgentImpl.sendTurn` previously threw so
14
+ * downstream catch blocks (`isTimeoutError`, `AgentCrashError`,
15
+ * `AskBusTimeoutError`) keep matching by error class and message.
16
+ */
17
+ function buildTurnExitError(turnResult, timeoutSec) {
18
+ if (turnResult.timedOut) {
19
+ const limit = timeoutSec !== undefined ? `Agent (limit: ${timeoutSec}s)` : 'Agent';
20
+ return new Error(`${limit} timed out (agent killed)`);
21
+ }
22
+ const detail = turnResult.rawOutput?.trim();
23
+ const suffix = detail ? `: ${detail}` : '';
24
+ if (turnResult.crashInfo) {
25
+ return new AgentCrashError(`Agent crashed${suffix}`, {
26
+ ...(turnResult.crashInfo.pid !== undefined ? { pid: turnResult.crashInfo.pid } : {}),
27
+ ...(turnResult.crashInfo.signal !== undefined ? { signal: turnResult.crashInfo.signal } : {}),
28
+ ...(turnResult.crashInfo.exitCode !== undefined ? { exitCode: turnResult.crashInfo.exitCode } : {}),
29
+ partialToolEvents: turnResult.toolEvents,
30
+ });
31
+ }
32
+ return new Error(`Agent exited with code ${turnResult.exitCode}${suffix}`);
33
+ }
34
+ export async function runConversation(opts, deps) {
35
+ const maxTurns = opts.maxTurns ?? 30;
36
+ const reactions = opts.reactions ?? [];
37
+ const stepScorers = opts.stepScorers ?? [];
38
+ const firedOnce = new Set();
39
+ const stepResults = [];
40
+ const turnTimings = [];
41
+ const turnDetails = [];
42
+ const reactionsFired = [];
43
+ let turn = 0;
44
+ const conversationStart = Date.now();
45
+ const askUserHandlerApi = deps.askBus
46
+ ? createAskUserHandler({
47
+ reactions,
48
+ onUnmatchedAskUser: opts.onUnmatchedAskUser ?? 'error',
49
+ firedOnce,
50
+ })
51
+ : null;
52
+ const unsubscribeAsk = askUserHandlerApi && deps.askBus
53
+ ? deps.askBus.onAsk(askUserHandlerApi.handler)
54
+ : null;
55
+ const checkAskUserUnmatched = () => {
56
+ if (!askUserHandlerApi)
57
+ return null;
58
+ const err = askUserHandlerApi.getUnmatchedError();
59
+ if (!err)
60
+ return null;
61
+ // Include the first question text so the surfaced detail names
62
+ // *what* the agent asked, not just that some batch on some
63
+ // turn failed. Multi-question batches list only the first to keep
64
+ // detail strings bounded — full list ships on the structured
65
+ // signal for any tooling that needs it.
66
+ const firstText = err.questionTexts[0];
67
+ const detail = firstText
68
+ ? `unmatched ask_user on turn ${err.turnNumber}: ${err.batchId}: ${firstText}`
69
+ : `unmatched ask_user on turn ${err.turnNumber}: ${err.batchId}`;
70
+ return buildResult('error', detail);
71
+ };
72
+ const MAX_TURN_RETRIES = 2;
73
+ const RETRY_DELAY_MS = 2_000;
74
+ const buildResult = (completionReason, completionDetail, crashDiagnostic) => {
75
+ deps.log.push({
76
+ type: 'conversation_end',
77
+ timestamp: new Date().toISOString(),
78
+ turn_number: turn,
79
+ completion_reason: completionReason,
80
+ completion_detail: completionDetail,
81
+ turn_timings: turnTimings,
82
+ turn_details: turnDetails,
83
+ reactions_fired: reactionsFired,
84
+ });
85
+ deps.verbose?.conversationEnd({
86
+ reason: completionReason,
87
+ turns: turn,
88
+ durationMs: Date.now() - conversationStart,
89
+ ...(completionDetail ? { detail: completionDetail } : {}),
90
+ });
91
+ return {
92
+ turns: turn,
93
+ completionReason,
94
+ completionDetail,
95
+ turnTimings,
96
+ turnDetails,
97
+ reactionsFired,
98
+ stepResults,
99
+ ...(crashDiagnostic ? { crashDiagnostic } : {}),
100
+ };
101
+ };
102
+ const buildCrashDiagnostic = (err) => {
103
+ const allAsks = deps.askBus?.snapshot() ?? [];
104
+ const nonAskEvents = (err.partialToolEvents ?? []).filter((e) => e.action !== 'ask_user');
105
+ return {
106
+ pid: err.pid,
107
+ signal: err.signal ?? null,
108
+ exitCode: err.exitCode ?? null,
109
+ lastTurnNumber: turn,
110
+ partialAsks: allAsks,
111
+ partialToolEvents: nonAskEvents,
112
+ };
113
+ };
114
+ // Send a message to the agent, update messages/log, return response.
115
+ // Turn counter increments only after the agent responds successfully.
116
+ // Retries transient agent errors (non-zero exit) up to MAX_TURN_RETRIES times.
117
+ const isFirstTurn = () => turn === 0;
118
+ const pushUserMessage = (message, kind, turnNumber) => {
119
+ deps.messages.push({ role: 'user', content: message });
120
+ deps.log.push({
121
+ type: kind,
122
+ timestamp: new Date().toISOString(),
123
+ instruction: message,
124
+ ...(kind === 'user_reply' ? { turn_number: turnNumber } : {}),
125
+ });
126
+ deps.verbose?.turnStart({
127
+ turn: turnNumber ?? turn + 1,
128
+ kind,
129
+ message,
130
+ });
131
+ };
132
+ const pushModelAgentMessage = (response, turnNumber, durationMs, turnResult) => {
133
+ turnTimings.push({ turn: turnNumber, durationMs });
134
+ turnDetails.push({
135
+ turn: turnNumber,
136
+ durationMs,
137
+ outputLines: response.split('\n').length,
138
+ outputChars: response.length,
139
+ });
140
+ deps.messages.push({ role: 'agent', content: response });
141
+ const timestamp = new Date().toISOString();
142
+ if (deps.askBus) {
143
+ for (const entry of buildAskBatchLogEntries({
144
+ askBus: deps.askBus,
145
+ turnNumber,
146
+ timestamp,
147
+ })) {
148
+ deps.log.push(entry);
149
+ }
150
+ }
151
+ deps.log.push(buildModelAgentResultLogEntry({
152
+ timestamp,
153
+ turnNumber,
154
+ durationMs,
155
+ turnResult,
156
+ assistantMessage: response,
157
+ }));
158
+ for (const toolEvent of turnResult.toolEvents) {
159
+ deps.verbose?.toolEvent({
160
+ action: toolEvent.action,
161
+ summary: toolEvent.summary,
162
+ });
163
+ }
164
+ deps.verbose?.turnEnd({
165
+ turn: turnNumber,
166
+ durationMs,
167
+ outputLines: response.split('\n').length,
168
+ messagePreview: response,
169
+ });
170
+ };
171
+ const doModelTurn = async (message, options = {}) => {
172
+ if (!options.preLogged) {
173
+ pushUserMessage(message, options.kind ?? (isFirstTurn() ? 'agent_start' : 'user_reply'), turn + 1);
174
+ }
175
+ const turnStart = Date.now();
176
+ // Under app-server the child process holds thread state; a crashed
177
+ // turn is not safely replayable, so retries are suppressed.
178
+ const maxRetries = deps.transport === 'app-server' ? 0 : MAX_TURN_RETRIES;
179
+ let lastError;
180
+ let turnResult;
181
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
182
+ try {
183
+ turnResult = normalizeTurnResult(await deps.sendTurn(message));
184
+ break;
185
+ }
186
+ catch (err) {
187
+ lastError = err;
188
+ // Don't retry timeouts — only transient agent errors
189
+ if (isTimeoutError(err))
190
+ throw err;
191
+ // Subprocess crashes bypass retries regardless of transport —
192
+ // the error itself is the signal that replay is unsafe.
193
+ if (err instanceof AgentCrashError)
194
+ throw err;
195
+ // Ask-bus rejections (no subscriber, slow subscriber) do
196
+ // not recover on retry — retrying just burns the retry
197
+ // window before the same `error` completion. Surface the
198
+ // bus error immediately.
199
+ if (err instanceof AskBusTimeoutError)
200
+ throw err;
201
+ if (attempt < maxRetries) {
202
+ deps.log.push({
203
+ type: 'agent_result',
204
+ timestamp: new Date().toISOString(),
205
+ assistant_message: `[retry ${attempt + 1}/${maxRetries}] ${err.message}`,
206
+ });
207
+ deps.verbose?.retry({
208
+ attempt: attempt + 1,
209
+ maxAttempts: maxRetries,
210
+ errorMessage: err.message,
211
+ });
212
+ // Remove the user message we pushed so it gets re-pushed on retry
213
+ if (!options.preLogged) {
214
+ deps.messages.pop();
215
+ }
216
+ await new Promise((r) => setTimeout(r, RETRY_DELAY_MS * (attempt + 1)));
217
+ if (!options.preLogged) {
218
+ deps.messages.push({ role: 'user', content: message });
219
+ }
220
+ }
221
+ }
222
+ }
223
+ if (turnResult === undefined)
224
+ throw lastError;
225
+ turn++;
226
+ const response = getVisibleAssistantMessage(turnResult);
227
+ const durationMs = Date.now() - turnStart;
228
+ // Project the partial turn (`pushModelAgentMessage`) BEFORE any
229
+ // exit-code throw so the failure mode is observable in the same
230
+ // shape as a successful turn — `model_agent_result`, `ask_batch`,
231
+ // turn timings/details all capture the rejected turn before the
232
+ // runner propagates the error. Exit-code failures bypass retry by
233
+ // construction (already logged): retrying would re-emit those log
234
+ // entries on a successful retry, double-counting the turn.
235
+ pushModelAgentMessage(response, turn, durationMs, turnResult);
236
+ if (turnResult.exitCode !== 0) {
237
+ throw buildTurnExitError(turnResult, deps.agentTimeoutSec);
238
+ }
239
+ return response;
240
+ };
241
+ try {
242
+ // Preflight: transport 'exec' + AskUserReaction is unreachable. Fail fast
243
+ // (before any turn runs) unless the caller opted out.
244
+ if (deps.transport === 'exec'
245
+ && !opts.allowUnreachableReactions
246
+ && reactions.some((r) => 'whenAsked' in r)) {
247
+ return buildResult('error', "AskUserReaction defined but transport is 'exec'; the handshake cannot fire under exec mode.");
248
+ }
249
+ // Turn 1: send opener
250
+ let agentMessage = await doModelTurn(opts.firstMessage, { kind: 'agent_start' });
251
+ const unmatchedAfterOpener = checkAskUserUnmatched();
252
+ if (unmatchedAfterOpener)
253
+ return unmatchedAfterOpener;
254
+ while (true) {
255
+ // Check until predicate
256
+ if (opts.until) {
257
+ const done = await opts.until({
258
+ turn,
259
+ lastMessage: agentMessage,
260
+ workspace: deps.workspace,
261
+ messages: deps.messages,
262
+ hasFile: deps.hasFile,
263
+ });
264
+ if (done)
265
+ return buildResult('until');
266
+ }
267
+ // Check maxTurns
268
+ if (turn >= maxTurns) {
269
+ return buildResult('maxTurns');
270
+ }
271
+ // Run step scorers scheduled for this turn
272
+ for (const sg of stepScorers) {
273
+ if (sg.afterTurn === turn && deps.runStepScorers) {
274
+ const result = await deps.runStepScorers(sg.scorers);
275
+ stepResults.push({ afterTurn: sg.afterTurn, result });
276
+ }
277
+ }
278
+ // Pick reply: reactions first, then persona fallback.
279
+ // Only text-variant reactions fire from assistant free text; ask_user
280
+ // reactions are handled by the bus subscription (slice #4).
281
+ const reactionEvaluations = inspectReactions(agentMessage, reactions, firedOnce);
282
+ const firedTextEvaluation = reactionEvaluations.find((reaction) => reaction.fired && reaction.kind === 'text');
283
+ let reply = firedTextEvaluation && firedTextEvaluation.kind === 'text'
284
+ ? firedTextEvaluation.reply ?? null
285
+ : null;
286
+ if (firedTextEvaluation && firedTextEvaluation.kind === 'text') {
287
+ const firedReactionCfg = reactions[firedTextEvaluation.reactionIndex];
288
+ const pattern = firedReactionCfg && 'when' in firedReactionCfg
289
+ ? String(firedReactionCfg.when)
290
+ : '';
291
+ reactionsFired.push({
292
+ turn,
293
+ reactionIndex: firedTextEvaluation.reactionIndex,
294
+ pattern,
295
+ reply: firedTextEvaluation.reply ?? '',
296
+ });
297
+ deps.verbose?.reactionFired({
298
+ turn,
299
+ reactionIndex: firedTextEvaluation.reactionIndex,
300
+ pattern,
301
+ reply: firedTextEvaluation.reply ?? '',
302
+ });
303
+ }
304
+ if (reply === null && deps.personaReply) {
305
+ reply = await deps.personaReply();
306
+ }
307
+ if (reply === null) {
308
+ return buildResult('noReply');
309
+ }
310
+ agentMessage = await doModelTurn(reply, { kind: 'user_reply' });
311
+ const unmatched = checkAskUserUnmatched();
312
+ if (unmatched)
313
+ return unmatched;
314
+ }
315
+ }
316
+ catch (err) {
317
+ if (err instanceof AgentCrashError) {
318
+ return buildResult('agent_crashed', err.message, buildCrashDiagnostic(err));
319
+ }
320
+ const reason = isTimeoutError(err) ? 'timeout' : 'error';
321
+ const detail = err instanceof Error ? err.message : String(err);
322
+ return buildResult(reason, detail);
323
+ }
324
+ finally {
325
+ if (unsubscribeAsk)
326
+ unsubscribeAsk();
327
+ }
328
+ }
329
+ export { previewReactions } from './reaction-preview.js';
@@ -0,0 +1,10 @@
1
+ import type { LLMPort } from '../utils/llm-types.js';
2
+ import type { Agent, RecordedEvalResult } from './types.js';
3
+ export type { LLMPort } from '../utils/llm-types.js';
4
+ export interface EvalRuntime {
5
+ llm: LLMPort;
6
+ onResult: (result: RecordedEvalResult, agent: Agent) => void;
7
+ }
8
+ export declare function getRuntime(): EvalRuntime;
9
+ export declare function setRuntime(partial: Partial<EvalRuntime>): void;
10
+ export declare function resetRuntime(): void;
@@ -0,0 +1,17 @@
1
+ import { callLLM } from '../utils/llm.js';
2
+ function makeDefaultRuntime() {
3
+ return {
4
+ llm: { call: (prompt, opts) => callLLM(prompt, opts) },
5
+ onResult: () => { },
6
+ };
7
+ }
8
+ let current = makeDefaultRuntime();
9
+ export function getRuntime() {
10
+ return current;
11
+ }
12
+ export function setRuntime(partial) {
13
+ current = { ...current, ...partial };
14
+ }
15
+ export function resetRuntime() {
16
+ current = makeDefaultRuntime();
17
+ }
@@ -0,0 +1,13 @@
1
+ import type { Agent, Scorer, EvalResult, RecordedEvalResult, ScorerResultEntry, EvaluateOptions } from './types.js';
2
+ export type OnScorerErrorMode = NonNullable<EvaluateOptions['onScorerError']>;
3
+ export declare class EvalScorerError extends Error {
4
+ readonly scorerErrors: ScorerResultEntry[];
5
+ readonly result: RecordedEvalResult;
6
+ constructor(result: RecordedEvalResult, scorerErrors: ScorerResultEntry[]);
7
+ }
8
+ type EvaluateFromSnapshot = (snapshotPath: string, scorers: Scorer[], opts?: EvaluateOptions) => Promise<EvalResult>;
9
+ type EvaluateFn = ((agent: Agent, scorers: Scorer[], opts?: EvaluateOptions) => Promise<EvalResult>) & {
10
+ fromSnapshot: EvaluateFromSnapshot;
11
+ };
12
+ export declare const evaluate: EvaluateFn;
13
+ export {};