Просмотр исходного кода

fix(web): use prompt_async endpoint to avoid timeout over VPN/tunnel (#12749)

eytans 6 месяцев назад
Родитель
Сommit
e242fe19e4

+ 43 - 0
packages/app/e2e/prompt/prompt-async.spec.ts

@@ -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)
+  }
+})

+ 1 - 1
packages/app/src/components/prompt-input/submit.ts

@@ -385,7 +385,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
     const send = async () => {
       const ok = await waitForWorktree()
       if (!ok) return
-      await client.session.prompt({
+      await client.session.promptAsync({
         sessionID: session.id,
         agent,
         model,