Skip to content

Commit 8246e2a

Browse files
committed
fix(desktop): keep a recovered result's mark while it is parked
1 parent ab40352 commit 8246e2a

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

‎apps/desktop/src/main/desktop-executor/executor.test.ts‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,23 @@ describe('restarting', () => {
568568
expect(notDelivered).toEqual([])
569569
})
570570

571+
it('still leaves a recovered result open when Sim held one, after parking it', async () => {
572+
const { sim, journal, executor, onUnregistered, delivered, notDelivered } = setup()
573+
sim.completeErrors = [new DeviceRequestError(401, 'unregistered')]
574+
sim.completionOutcome = 'duplicate'
575+
await journal.put({ toolCallId: 'started-1', state: 'started', executionToken: 't-started' })
576+
await executor.recover()
577+
await vi.waitFor(() => expect(onUnregistered).toHaveBeenCalledTimes(1))
578+
579+
// Registered again.
580+
executor.resumeParked()
581+
582+
await vi.waitFor(() => expect(sim.completions).toHaveLength(1))
583+
await vi.waitFor(() => expect(journal.entries.size).toBe(0))
584+
expect(delivered).toEqual([])
585+
expect(notDelivered).toEqual([])
586+
})
587+
571588
it('reports a recovered result too large to send, then held as a duplicate, as never reaching the model', async () => {
572589
const { sim, journal, executor, delivered, notDelivered } = setup()
573590
// No run could have sent this result: it is too large every time.

‎apps/desktop/src/main/desktop-executor/executor.ts‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ export class DesktopExecutor {
129129
private recovering: Promise<void> | null = null
130130
/** Results a previous app run left, still on their way to Sim. */
131131
private readonly recoveringIds = new Set<string>()
132+
/**
133+
* Results a previous app run left, until Sim answers for them, parked ones included: that run's
134+
* send of the real result may already have landed.
135+
*/
136+
private readonly recoveredResults = new Set<string>()
132137
/** Results that have failed to reach Sim for longer than {@link DELIVERY_AWAKE_LIMIT_MS}. */
133138
private readonly stalledDeliveries = new Set<string>()
134139
/** Results Sim refused because it no longer recognized this device; sent once it registers again. */
@@ -190,6 +195,7 @@ export class DesktopExecutor {
190195
})
191196
// Held awake like a running call: the result exists only on this machine until Sim has it.
192197
this.recoveringIds.add(entry.toolCallId)
198+
this.recoveredResults.add(entry.toolCallId)
193199
this.updateBusy()
194200
void this.deliver(entry.toolCallId, entry.executionToken, completion).finally(() => {
195201
this.recoveringIds.delete(entry.toolCallId)
@@ -434,7 +440,7 @@ export class DesktopExecutor {
434440
// A duplicate holds what this app run sent, unless the result was recovered unchanged from
435441
// an earlier run, whose send of the real result may have landed before the restart.
436442
const takenEarlier =
437-
outcome === 'duplicate' && pending === completion && this.recoveringIds.has(toolCallId)
443+
outcome === 'duplicate' && pending === completion && this.recoveredResults.has(toolCallId)
438444
notDelivered = !delivered && !takenEarlier
439445
break
440446
} catch (error) {
@@ -492,6 +498,7 @@ export class DesktopExecutor {
492498
)
493499
}
494500
}
501+
this.recoveredResults.delete(toolCallId)
495502
if (this.disposed) return
496503
if (notDelivered) this.options.onResultNotDelivered?.(toolCallId)
497504
await this.forget(toolCallId)

0 commit comments

Comments
 (0)