Skip to content

Commit ab40352

Browse files
committed
fix(desktop): only a recovered result leaves a duplicate open
1 parent 5861b1d commit ab40352

2 files changed

Lines changed: 40 additions & 3 deletions

File tree

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,23 @@ describe('claiming', () => {
256256
expect(delivered).toEqual([])
257257
})
258258

259+
it('reports a stand-in Sim holds as a duplicate as never reaching the model, within one app run', async () => {
260+
const { sim, runner, executor, delivered, notDelivered } = setup()
261+
// Too large to send, so Sim never took the real result; the stand-in's first answer was lost.
262+
runner.immediate = DONE
263+
sim.completeErrors = [
264+
new DeviceRequestError(413, 'too large'),
265+
new DeviceRequestError(0, 'connection reset'),
266+
]
267+
sim.completionOutcome = 'duplicate'
268+
sim.inbox = [callItem('call-1', 'chat-a', 'terminal')]
269+
270+
await executor.reconcile()
271+
272+
await vi.waitFor(() => expect(notDelivered).toEqual(['call-1']))
273+
expect(delivered).toEqual([])
274+
})
275+
259276
it('reports a result Sim refused as never reaching the model', async () => {
260277
const { sim, runner, executor, notDelivered } = setup()
261278
runner.immediate = DONE
@@ -550,6 +567,24 @@ describe('restarting', () => {
550567
expect(delivered).toEqual([])
551568
expect(notDelivered).toEqual([])
552569
})
570+
571+
it('reports a recovered result too large to send, then held as a duplicate, as never reaching the model', async () => {
572+
const { sim, journal, executor, delivered, notDelivered } = setup()
573+
// No run could have sent this result: it is too large every time.
574+
sim.completeErrors = [new DeviceRequestError(413, 'too large')]
575+
sim.completionOutcome = 'duplicate'
576+
await journal.put({
577+
toolCallId: 'result-1',
578+
state: 'result',
579+
executionToken: 't',
580+
completion: DONE,
581+
})
582+
583+
await executor.recover()
584+
585+
await vi.waitFor(() => expect(notDelivered).toEqual(['result-1']))
586+
expect(delivered).toEqual([])
587+
})
553588
})
554589

555590
describe('delivery', () => {

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,11 @@ export class DesktopExecutor {
431431
// Superseded: Sim settled the call first, so this result never reached the model.
432432
const delivered = outcome !== 'superseded' && isDeliveredResult(pending)
433433
if (delivered) this.options.onResultDelivered?.(toolCallId)
434-
// A stand-in Sim already holds leaves open which result it took first: a send from before
435-
// a restart may have carried the real one.
436-
notDelivered = !delivered && outcome !== 'duplicate'
434+
// A duplicate holds what this app run sent, unless the result was recovered unchanged from
435+
// an earlier run, whose send of the real result may have landed before the restart.
436+
const takenEarlier =
437+
outcome === 'duplicate' && pending === completion && this.recoveringIds.has(toolCallId)
438+
notDelivered = !delivered && !takenEarlier
437439
break
438440
} catch (error) {
439441
// Encoding failed on this machine, so nothing was sent; the same data would fail again.

0 commit comments

Comments
 (0)