mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 17:47:40 +00:00
test(wsl): wait for the chat provider's report to settle instead of reading it once (#35603)
* test(wsl): wait for the chat provider's report to settle instead of reading it once * test(wsl): wait for the resumed turn's message, not just its launch
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { vi } from 'vitest'
|
||||
import { z } from 'zod'
|
||||
import { folderWorkspaceKey } from '../../shared/workspace-scope'
|
||||
import { readFileSync } from 'node:fs'
|
||||
@@ -126,3 +127,34 @@ export const WslChatProviderReport = z.object({
|
||||
controlRequests: z.array(z.object({ request: z.object({ subtype: z.string() }) })),
|
||||
controlResponses: z.array(z.object({ response: z.object({ response: z.unknown().optional() }) }))
|
||||
})
|
||||
|
||||
const PROVIDER_REPORT_TIMEOUT_MS = 30_000
|
||||
|
||||
/** Scripted providers rewrite their report in place after each act, so one read can see a torn file or a stale one. */
|
||||
export async function waitForProviderReport<T>(
|
||||
host: WslChatHost,
|
||||
path: string,
|
||||
schema: z.ZodType<T>,
|
||||
settled: (report: T) => boolean,
|
||||
awaiting: string
|
||||
): Promise<T> {
|
||||
let lastRead = ''
|
||||
try {
|
||||
return await vi.waitFor(
|
||||
async () => {
|
||||
lastRead = await host.guest(`cat ${quotePosixShell(path)} 2>/dev/null || true`)
|
||||
const report = schema.parse(JSON.parse(lastRead))
|
||||
if (!settled(report)) {
|
||||
throw new Error(`report does not show ${awaiting} yet`)
|
||||
}
|
||||
return report
|
||||
},
|
||||
{ timeout: PROVIDER_REPORT_TIMEOUT_MS, interval: 250 }
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Provider report ${path} did not show ${awaiting} within ${PROVIDER_REPORT_TIMEOUT_MS} ms; last read ${JSON.stringify(lastRead.slice(-600))}`,
|
||||
{ cause: error }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ import type { AgentSessionSubscribeEvent } from '../../shared/agent-session-wire
|
||||
import { ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES } from '../../shared/electron-remote-runtime-client-capabilities'
|
||||
import { subscribeRemoteRuntimeRequest } from '../../shared/remote-runtime/remote-runtime-client'
|
||||
import { quotePosixShell } from '../../shared/shell-argument-quoting'
|
||||
import type { WslScriptedProviderInstall } from './wsl-orcad-chat-provider-fixture'
|
||||
import {
|
||||
waitForProviderReport,
|
||||
type WslScriptedProviderInstall
|
||||
} from './wsl-orcad-chat-provider-fixture'
|
||||
import { assistantText } from './wsl-orcad-chat-assistant-text'
|
||||
import { envelope } from './wsl-orcad-chat-envelope'
|
||||
import type { ChatLane } from './wsl-orcad-structured-chat-contract'
|
||||
@@ -167,8 +170,13 @@ export async function exerciseScriptedProviderChat(
|
||||
},
|
||||
{ timeout: 30_000 }
|
||||
)
|
||||
const report = await readReport()
|
||||
expect(report.methods).toContain(provider.stopMethod)
|
||||
const report = await waitForProviderReport(
|
||||
lane,
|
||||
install.reportPath,
|
||||
ScriptedProviderReport,
|
||||
(written) => written.methods.includes(provider.stopMethod),
|
||||
provider.stopMethod
|
||||
)
|
||||
expect(report.cwd).toBe(cwd)
|
||||
// The guest's own runtime ran the guest install found on its login PATH: never a /mnt/ copy.
|
||||
expect(report.execPath).toMatch(/^\/(?!mnt\/)/u)
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
import {
|
||||
installWslChatFixture,
|
||||
WslChatProviderReport,
|
||||
waitForProviderReport,
|
||||
writeChatFixtureFile,
|
||||
type WslChatHost
|
||||
} from './wsl-orcad-chat-provider-fixture'
|
||||
@@ -180,8 +181,12 @@ async function exerciseChat(
|
||||
envelope: envelope(sessionId, 'agentSession.cancel', {}, fence)
|
||||
})
|
||||
).toMatchObject({ ok: true, value: { cancelled: true } })
|
||||
const report = WslChatProviderReport.parse(
|
||||
JSON.parse(await lane.guest(`cat ${quotePosixShell(reportPath)}`))
|
||||
const report = await waitForProviderReport(
|
||||
lane,
|
||||
reportPath,
|
||||
WslChatProviderReport,
|
||||
(written) => written.controlRequests.some((entry) => entry.request.subtype === 'interrupt'),
|
||||
'the Stop interrupt'
|
||||
)
|
||||
expect(report.cwd).toBe(cwd)
|
||||
expect(report.execPath).toMatch(/^\//u)
|
||||
@@ -192,7 +197,6 @@ async function exerciseChat(
|
||||
ORCA_AGENT_SESSION_ID: sessionId,
|
||||
ORCA_STRUCTURED_SESSION: '1'
|
||||
})
|
||||
expect(report.controlRequests.some((entry) => entry.request.subtype === 'interrupt')).toBe(true)
|
||||
expect(report.controlResponses).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
@@ -257,11 +261,16 @@ async function exerciseChat(
|
||||
},
|
||||
{ timeout: 30_000 }
|
||||
)
|
||||
const resumed = WslChatProviderReport.parse(
|
||||
JSON.parse(await lane.guest(`cat ${quotePosixShell(reportPath)}`))
|
||||
const resumedArgv = new RegExp(`--resume(?:=| )${providerId}`)
|
||||
const resumed = await waitForProviderReport(
|
||||
lane,
|
||||
reportPath,
|
||||
WslChatProviderReport,
|
||||
(written) => resumedArgv.test(written.argv.join(' ')) && written.userMessages.length > 0,
|
||||
'the resumed turn'
|
||||
)
|
||||
expect(resumed.cwd).toBe(cwd)
|
||||
expect(resumed.argv.join(' ')).toMatch(new RegExp(`--resume(?:=| )${providerId}`))
|
||||
expect(resumed.argv.join(' ')).toMatch(resumedArgv)
|
||||
expect(resumed.userMessages).toHaveLength(1)
|
||||
return {
|
||||
sessionId,
|
||||
|
||||
Reference in New Issue
Block a user