Skip to content

Commit c33803e

Browse files
committed
test(mothership): a desktop tool's executor resolves only once the tool has settled
1 parent 9ed7eb9 commit c33803e

2 files changed

Lines changed: 70 additions & 0 deletions

File tree

‎apps/sim/lib/mothership/tools/client/browser-tool-execution.test.ts‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,35 @@ describe('executeBrowserToolOnClient', () => {
332332
})
333333
})
334334

335+
it('resolves only once the browser action has settled and its result is handed to delivery', async () => {
336+
let finishAction: (result: unknown) => void = () => {}
337+
mockExecuteBrowserTool.mockReturnValue(
338+
new Promise((resolve) => {
339+
finishAction = resolve
340+
})
341+
)
342+
const toolCallId = nextToolCallId()
343+
let resolved = false
344+
const running = executeBrowserToolOnClient(toolCallId, 'browser_snapshot', {}, CHAT_SCOPE).then(
345+
() => {
346+
resolved = true
347+
}
348+
)
349+
350+
await vi.waitFor(() => expect(mockExecuteBrowserTool).toHaveBeenCalled())
351+
await sleep(10)
352+
expect(resolved).toBe(false)
353+
expect(mockReportCompletion).not.toHaveBeenCalled()
354+
355+
finishAction({ text: 'page content' })
356+
await running
357+
// Delivery itself is owned by the retained-completion scheduler, which outlives the turn's
358+
// Stop and the page; what the caller waits for is the action, with its report under way.
359+
expect(mockReportCompletion).toHaveBeenCalledWith(toolCallId, 'success', expect.any(String), {
360+
text: 'page content',
361+
})
362+
})
363+
335364
it('lets a running invocation own the genuine result when the same call is re-delivered', async () => {
336365
let finishExecution: (result: { text: string }) => void = () => {}
337366
mockExecuteBrowserTool.mockImplementation(

‎apps/sim/lib/mothership/tools/client/local-filesystem.test.ts‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,45 @@ describe('executeLocalFilesystemTool', () => {
231231
})
232232
expect(mockReportCompletion).not.toHaveBeenCalled()
233233
})
234+
235+
it('resolves only once the tool has settled and its result is reported', async () => {
236+
let finishRead: (response: unknown) => void = () => {}
237+
let finishReport: () => void = () => {}
238+
localFilesystem.mockImplementation(async (request: { operation: string }) => {
239+
if (request.operation === 'list_mounts') return { ok: true, data: { mounts: [mount] } }
240+
return new Promise((resolve) => {
241+
finishRead = resolve
242+
})
243+
})
244+
mockReportCompletion.mockImplementation(
245+
() =>
246+
new Promise<void>((resolve) => {
247+
finishReport = resolve
248+
})
249+
)
250+
let resolved = false
251+
const running = executeLocalFilesystemTool(
252+
'tool-held',
253+
'read',
254+
{ path: `${vfsRoot}/README.md` },
255+
{ workspaceId: 'ws-1' }
256+
).then(() => {
257+
resolved = true
258+
})
259+
260+
await vi.waitFor(() =>
261+
expect(localFilesystem).toHaveBeenCalledWith(expect.objectContaining({ operation: 'read' }))
262+
)
263+
await new Promise((resolve) => setTimeout(resolve, 10))
264+
expect(resolved).toBe(false)
265+
266+
finishRead({ ok: true, data: { content: 'hello', totalLines: 1 } })
267+
await vi.waitFor(() => expect(mockReportCompletion).toHaveBeenCalled())
268+
await new Promise((resolve) => setTimeout(resolve, 10))
269+
expect(resolved).toBe(false)
270+
271+
finishReport()
272+
await running
273+
expect(resolved).toBe(true)
274+
})
234275
})

0 commit comments

Comments
 (0)