fix(web): use prompt_async endpoint to avoid timeout over VPN/tunnel (#12749)
This commit is contained in:
43
packages/app/e2e/prompt/prompt-async.spec.ts
Normal file
43
packages/app/e2e/prompt/prompt-async.spec.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { test, expect } from "../fixtures"
|
||||||
|
import { promptSelector } from "../selectors"
|
||||||
|
import { sessionIDFromUrl } from "../actions"
|
||||||
|
|
||||||
|
// Regression test for Issue #12453: the synchronous POST /message endpoint holds
|
||||||
|
// the connection open while the agent works, causing "Failed to fetch" over
|
||||||
|
// VPN/Tailscale. The fix switches to POST /prompt_async which returns immediately.
|
||||||
|
test("prompt succeeds when sync message endpoint is unreachable", async ({ page, sdk, gotoSession }) => {
|
||||||
|
test.setTimeout(120_000)
|
||||||
|
|
||||||
|
// Simulate Tailscale/VPN killing the long-lived sync connection
|
||||||
|
await page.route("**/session/*/message", (route) => route.abort("connectionfailed"))
|
||||||
|
|
||||||
|
await gotoSession()
|
||||||
|
|
||||||
|
const token = `E2E_ASYNC_${Date.now()}`
|
||||||
|
await page.locator(promptSelector).click()
|
||||||
|
await page.keyboard.type(`Reply with exactly: ${token}`)
|
||||||
|
await page.keyboard.press("Enter")
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(/\/session\/[^/?#]+/, { timeout: 30_000 })
|
||||||
|
const sessionID = sessionIDFromUrl(page.url())!
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Agent response arrives via SSE despite sync endpoint being dead
|
||||||
|
await expect
|
||||||
|
.poll(
|
||||||
|
async () => {
|
||||||
|
const messages = await sdk.session.messages({ sessionID, limit: 50 }).then((r) => r.data ?? [])
|
||||||
|
return messages
|
||||||
|
.filter((m) => m.info.role === "assistant")
|
||||||
|
.flatMap((m) => m.parts)
|
||||||
|
.filter((p) => p.type === "text")
|
||||||
|
.map((p) => p.text)
|
||||||
|
.join("\n")
|
||||||
|
},
|
||||||
|
{ timeout: 90_000 },
|
||||||
|
)
|
||||||
|
.toContain(token)
|
||||||
|
} finally {
|
||||||
|
await sdk.session.delete({ sessionID }).catch(() => undefined)
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -385,7 +385,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
|
|||||||
const send = async () => {
|
const send = async () => {
|
||||||
const ok = await waitForWorktree()
|
const ok = await waitForWorktree()
|
||||||
if (!ok) return
|
if (!ok) return
|
||||||
await client.session.prompt({
|
await client.session.promptAsync({
|
||||||
sessionID: session.id,
|
sessionID: session.id,
|
||||||
agent,
|
agent,
|
||||||
model,
|
model,
|
||||||
|
|||||||
Reference in New Issue
Block a user