Skip to content

fix(web): recover from quiet or stalled connections - #370

Merged
tt-a1i merged 23 commits into
openpi-dev:mainfrom
testikun:codex/issue-363-web-resilience
Sep 5, 2026
Merged

fix(web): recover from quiet or stalled connections#370
tt-a1i merged 23 commits into
openpi-dev:mainfrom
testikun:codex/issue-363-web-resilience

Conversation

@testikun

@testikun testikun commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

When a browser loses a prompt response, the server may already have accepted the request. Retrying now preserves the original admission ID and replays the first result instead of dispatching another model/tool execution.

Related to #363.

The Host stores bounded admission receipts, including the original follow-up queue snapshot and cursor. In-flight records are not evicted. Explicit retries with missing records, including after a Host restart, return COMMAND_ADMISSION_UNKNOWN without dispatch. Different content under one ID is rejected. Known preflight or capacity rejection permits a new attempt; timeout, connection loss, and response-body failures preserve the original ID and the existing execution state.

SSE heartbeats and bounded reads recover quiet/stalled connections. Non-cached page departure cancels the reader and stops reconnection; bfcache preserves the single connection loop. Tests clean up their readers, sockets, and timers and exit normally. The integration preserves canonical themes, execution cancellation, and admission-time queue feedback.

Validation: final integrated Node 22 focused tests passed 104/104; bun run check passed; full Node suite passed 1423 tests with one skip, plus Vitest 30/30. Coverage includes lost response and retry with exactly one dispatch, first-receipt replay after the native queue changes, bounded pending capacity, unknown retries, and SSE/page lifecycle cleanup. CI will validate the final published head. No new live-provider or release acceptance is claimed.

@tt-a1i tt-a1i left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

缝是对的,请先变绿;用这份替代 #377/#364

只给 /api/prompt 准入加超时,SSE comment 不推进游标,心跳在 disconnect/shutdown 时清掉 — 这是对的全局 30s api()#377)不该做的事。#364 改的同一批 running 行会被这份盖掉,请把那份并进来。

应修:CI 在 bun run test 中途取消。readEventChunk(45s)加重连,在只心跳、永不 settle 的 mock 上可能挂住套件。请先有一次绿的测试再合。

@tt-a1i tt-a1i left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head review: 72b334d

[P1] Timing out prompt admission creates an uncertain mutation that the UI presents as a safe retry. web/ui/app.js:803-825 aborts POST /api/prompt after 30 seconds, removes the optimistic row, restores the draft, and reports failure. The server path at web/host/web-host.ts:492-527 has already generated a new command id and may still complete runtime.sendPrompt(); it neither binds client disconnect to cancellation nor accepts a client idempotency key. Retrying the restored draft therefore creates another command id and can execute the same model/tool turn twice.

Please make admission retry-safe: use a stable client-generated idempotency key with server-side deduplication and a queryable receipt, or expose timeout as unknown/pending and reconcile canonical state before allowing retry. Add a test where the client times out just before the first admission completes, retries, and proves only one turn is admitted.

Verification boundary: exact-head cross-layer Standards + Spec review. Existing liveness tests cover bounded waiting, not the timeout/late-success/retry race.

@testikun

testikun commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

已按 P1 review 修复并推送到 683a6c8:Web UI 为每次 prompt 生成稳定 commandId 并随 POST 发送;Host 按 commandId + sessionId + content 做 admission 去重,超时后的重试会等待并复用第一次 admission,不会再次调用 runtime 或执行第二个 turn;同一 commandId 搭配不同 prompt 会返回 COMMAND_CONFLICT。新增真实 Host 重试回归测试,确认 runtime 只收到一次 prompt。web-host 测试 20/20 通过。

Real UI verification

截图来自本地直接启动的 Web Host(commit 683a6c8,真实 Chrome 1280×900),页面通过实际 token 访问,未使用 mock 页面或生成图片:

Real OpenPI prompt admission verification

@github-actions github-actions Bot added the area:github GitHub workflows, templates, ownership, or tests label Sep 5, 2026
@tt-a1i
tt-a1i merged commit 731fc6b into openpi-dev:main Sep 5, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:github GitHub workflows, templates, ownership, or tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants