Skip to content

Commit 0218fb7

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
Fix Babysit wait-only budgeting
1 parent 9ad1c66 commit 0218fb7

2 files changed

Lines changed: 69 additions & 7 deletions

File tree

apps/sim/executor/handlers/pi/babysit-backend.test.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ function commandResult(stdout = '', stderr = '', exitCode = 0) {
162162
}
163163

164164
function makeRunner(options: {
165+
cloneResult?: ReturnType<typeof commandResult>
165166
prepareStdout?: string | string[]
166167
pushResult?: ReturnType<typeof commandResult>
167168
roundFile?: string
@@ -186,7 +187,7 @@ function makeRunner(options: {
186187
) => {
187188
runCalls.push({ command, envs: runOptions.envs, timeoutMs: runOptions.timeoutMs })
188189
if (command.includes('git clone')) {
189-
return commandResult('__GIT_CONFIG_DIGEST__=digest-1\n')
190+
return options.cloneResult ?? commandResult('__GIT_CONFIG_DIGEST__=digest-1\n')
190191
}
191192
if (command.includes('pi -p --mode json')) {
192193
runOptions.onStdout?.('{"type":"agent_end"}\n')
@@ -312,6 +313,58 @@ describe('runBabysitPiWithOptions', () => {
312313
expect(mockReviewLanded).toHaveBeenCalledTimes(1)
313314
})
314315

316+
it('preserves known clean flags when the Babysit clone fails after the review request', async () => {
317+
mockFetchSnapshot.mockResolvedValue(snapshot)
318+
mockFetchThreads.mockResolvedValue({
319+
actionable: [],
320+
skipped: [],
321+
totalUnresolved: 0,
322+
latestReview: null,
323+
})
324+
mockFetchChecks.mockResolvedValue(greenChecks)
325+
const { runner } = makeRunner({
326+
cloneResult: commandResult('', 'clone failed', 1),
327+
})
328+
mockWithPiSandbox.mockImplementation(async (callback) => callback(runner))
329+
330+
const result = await runBabysitPiWithOptions(params(), { onEvent: vi.fn() })
331+
332+
expect(result).toMatchObject({
333+
stopReason: 'agent_failure',
334+
threadsClean: true,
335+
checksGreen: true,
336+
rounds: 0,
337+
commitsPushed: 0,
338+
})
339+
})
340+
341+
it('uses remaining time for wait-only polling without reserving an agent round', async () => {
342+
mockFetchSnapshot.mockResolvedValue(snapshot)
343+
mockFetchThreads.mockResolvedValue({
344+
actionable: [],
345+
skipped: [],
346+
totalUnresolved: 0,
347+
latestReview: null,
348+
})
349+
mockFetchChecks.mockResolvedValue(greenChecks)
350+
const { runner } = makeRunner({})
351+
mockWithPiSandbox.mockImplementation(async (callback) => callback(runner))
352+
353+
const result = await runBabysitPiWithOptions(
354+
params({ executionBudgetMs: 2 * 60 * 1000 }),
355+
{ onEvent: vi.fn() },
356+
{ roundWaitMs: 30_000 }
357+
)
358+
359+
expect(mockReviewLanded).toHaveBeenCalledTimes(1)
360+
expect(result).toMatchObject({
361+
stopReason: 'clean',
362+
threadsClean: true,
363+
checksGreen: true,
364+
rounds: 0,
365+
})
366+
})
367+
315368
it('refuses excess failing checks before fetching discarded diagnostics', async () => {
316369
const failures = Array.from({ length: 21 }, (_, index) => ({
317370
...failingCheck,

apps/sim/executor/handlers/pi/babysit-backend.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -686,12 +686,24 @@ export async function runBabysitPiWithOptions(
686686
progress.notes.push(
687687
`Clone failed: ${scrubGitSecrets(clone.stderr || clone.stdout, params.githubToken)}`
688688
)
689-
return resultFor(totals, 'agent_failure', progress, false, false)
689+
return resultFor(
690+
totals,
691+
'agent_failure',
692+
progress,
693+
threadsAreClean(latestThreads),
694+
lastKnownChecksGreen
695+
)
690696
}
691697
const gitConfigDigest = extractMarkerValues(clone.stdout, GIT_CONFIG_DIGEST_MARKER)[0]
692698
if (!gitConfigDigest) {
693699
progress.notes.push('Clone did not report the repository Git-config digest.')
694-
return resultFor(totals, 'agent_failure', progress, false, false)
700+
return resultFor(
701+
totals,
702+
'agent_failure',
703+
progress,
704+
threadsAreClean(latestThreads),
705+
lastKnownChecksGreen
706+
)
695707
}
696708
if (params.search) {
697709
await runner.writeFile(PI_SEARCH_EXTENSION_PATH, PI_SEARCH_EXTENSION_SOURCE)
@@ -725,10 +737,7 @@ export async function runBabysitPiWithOptions(
725737
latestThreads!.actionable.length > 0 || latestChecks!.blockingFailing.length > 0
726738
if (!needsAgent) {
727739
const remaining = lifetime - (Date.now() - startedAt)
728-
if (
729-
remaining <=
730-
options.roundWaitMs + MIN_ROUND_BUDGET_MS + ROUND_FINALIZATION_RESERVE_MS
731-
) {
740+
if (remaining <= options.roundWaitMs) {
732741
const reason = outstandingReason(
733742
'budget_exhausted',
734743
latestThreads!,

0 commit comments

Comments
 (0)