fix: keep ACP prompts alive across gateway reconnects#59473
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5e1a5433cb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Greptile SummaryThis PR fixes a long-standing bug where ACP prompt completion was being treated as both a long-lived The second part of the fix addresses a previously-flagged issue: in-flight prompts no longer immediately reject on gateway disconnect. Instead, a Key implementation details that look correct:
Confidence Score: 5/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/acp/translator.ts
Line: 440-445
Comment:
**Grace window resets on each additional disconnect**
Each new `handleGatewayDisconnect` call clears the previous timer and restarts the 5-second clock. In a flapping-connection scenario (e.g. the gateway issues rapid close/reconnect cycles where reconnect stalls), the deadline shifts to 5 seconds after the *last* disconnect rather than the *first*, potentially extending the window for an unbounded number of additional intervals.
This is generally fine for the intended transient-reconnect case — a gateway that is legitimately reconnecting will call `handleGatewayReconnect` and clear the timer. If the connection is continuously flapping without ever reconnecting, the prompts will be held longer than intended. Since the gateway has its own exponential backoff, this scenario is unlikely in practice, but it may be worth documenting the intent.
How can I resolve this? If you propose a fix, please make it concise.Reviews (2): Last reviewed commit: "fix: preserve ACP send timeout semantics" | Re-trigger Greptile |
|
@greptile-apps re-review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c76fda51f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9adb1a103c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1520a7b176
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 401c3ccb79
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 373d56d037
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
373d56d to
6e8b876
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6e8b87669b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4379e6c366
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
🔒 Aisle Security AnalysisWe found 2 potential security issue(s) in this PR:
1. 🟡 Gateway/agent error status is treated as successful prompt completion (error masking)
DescriptionIn This occurs in multiple places:
Security/consistency impact:
Vulnerable code: if (result?.status === "error") {
void this.finishPrompt(sessionId, pending, "end_turn");
continue;
}RecommendationTreat gateway/agent run errors as errors at the ACP layer rather than a normal stop reason.
Example fix (reject on error): if (result?.status === "error") {
this.pendingPrompts.delete(sessionId);
this.sessionStore.clearActiveRun(sessionId);
pending.reject(new Error(result.error ?? "Gateway run failed"));
continue;
}Also apply the same change to the 2. 🟡 Pending prompts can hang indefinitely when created after a gateway disconnect (deadline map not updated)
DescriptionWhen the gateway is already disconnected, calling
Vulnerable code: void sendWithProvenanceFallback().catch((err) => {
if (isGatewayCloseError(err) && this.getPendingPrompt(params.sessionId, runId)) {
return; // leaves pending prompt stored; not added to disconnectDeadlineRunIds
}
this.pendingPrompts.delete(params.sessionId);
...
});RecommendationEnsure prompts created while disconnected are still covered by a rejection deadline. Options:
if (!this.gateway.isConnected()) {
this.sessionStore.clearActiveRun(params.sessionId);
throw new Error("Gateway disconnected");
}
void sendWithProvenanceFallback().catch((err) => {
if (isGatewayCloseError(err) && this.getPendingPrompt(params.sessionId, runId)) {
this.disconnectDeadlineRunIds.set(params.sessionId, runId);
if (!this.disconnectTimer) {
this.disconnectTimer = setTimeout(() => {
this.disconnectTimer = null;
void this.expireDisconnectDeadline(new Error("Gateway disconnected"));
}, ACP_GATEWAY_DISCONNECT_GRACE_MS);
this.disconnectTimer.unref?.();
}
return;
}
...
});Also consider clearing/rejecting all pending prompts on a subsequent disconnect event even if already disconnected, to prevent stale state. Analyzed PR: #59473 at commit Last updated on: 2026-04-02T09:45:34Z |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4691e9e577
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1dc0e0c14a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
baf5ef3 to
2ad774e
Compare
|
Landed in 304da2c. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2ad774eed1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| void this.finishPrompt(sessionId, currentPending, "end_turn"); | ||
| continue; | ||
| } | ||
| this.rejectPendingPrompts(error, [[sessionId, runId]]); |
There was a problem hiding this comment.
Do not fail reconnecting prompts while run is still active
When the disconnect grace timer expires, expireDisconnectDeadline rejects any prompt whose agent.wait probe is not terminal, including status: "timeout". A timeout here only means the run is still in progress (the probe uses timeoutMs: 0), so a prompt that successfully resumed after reconnect but takes longer than 5s to finish will be rejected incorrectly. This creates false failures for slow/long responses after transient websocket drops, even though the run can still complete and emit later chat events.
Useful? React with 👍 / 👎.
* fix: keep acp prompts alive across gateway reconnects * fix: bound ACP prompts after disconnect grace * fix: preserve ACP send timeout semantics * fix: defer pre-ack ACP disconnect failures * fix: reconcile ACP runs after reconnect * fix: keep ACP reconnect deadlines monotonic * fix: keep pre-ack ACP deadlines after reconnect * fix: keep ACP prompts alive across gateway reconnects (#59473) * fix: reject superseded ACP pre-ack prompts (#59473) * style: format ACP reconnect regression updates (#59473) * style: format ACP reconnect regression updates (#59473) * fix: guard ACP send acceptance by run id (#59473) * fix: scope ACP reconnect deadline by prompt (#59473) * fix: recheck ACP prompts at reconnect deadline (#59473) * fix: key ACP reconnect deadline by run (#59473)
* fix: keep acp prompts alive across gateway reconnects * fix: bound ACP prompts after disconnect grace * fix: preserve ACP send timeout semantics * fix: defer pre-ack ACP disconnect failures * fix: reconcile ACP runs after reconnect * fix: keep ACP reconnect deadlines monotonic * fix: keep pre-ack ACP deadlines after reconnect * fix: keep ACP prompts alive across gateway reconnects (openclaw#59473) * fix: reject superseded ACP pre-ack prompts (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * fix: guard ACP send acceptance by run id (openclaw#59473) * fix: scope ACP reconnect deadline by prompt (openclaw#59473) * fix: recheck ACP prompts at reconnect deadline (openclaw#59473) * fix: key ACP reconnect deadline by run (openclaw#59473)
* fix: keep acp prompts alive across gateway reconnects * fix: bound ACP prompts after disconnect grace * fix: preserve ACP send timeout semantics * fix: defer pre-ack ACP disconnect failures * fix: reconcile ACP runs after reconnect * fix: keep ACP reconnect deadlines monotonic * fix: keep pre-ack ACP deadlines after reconnect * fix: keep ACP prompts alive across gateway reconnects (openclaw#59473) * fix: reject superseded ACP pre-ack prompts (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * fix: guard ACP send acceptance by run id (openclaw#59473) * fix: scope ACP reconnect deadline by prompt (openclaw#59473) * fix: recheck ACP prompts at reconnect deadline (openclaw#59473) * fix: key ACP reconnect deadline by run (openclaw#59473)
* fix: keep acp prompts alive across gateway reconnects * fix: bound ACP prompts after disconnect grace * fix: preserve ACP send timeout semantics * fix: defer pre-ack ACP disconnect failures * fix: reconcile ACP runs after reconnect * fix: keep ACP reconnect deadlines monotonic * fix: keep pre-ack ACP deadlines after reconnect * fix: keep ACP prompts alive across gateway reconnects (openclaw#59473) * fix: reject superseded ACP pre-ack prompts (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * fix: guard ACP send acceptance by run id (openclaw#59473) * fix: scope ACP reconnect deadline by prompt (openclaw#59473) * fix: recheck ACP prompts at reconnect deadline (openclaw#59473) * fix: key ACP reconnect deadline by run (openclaw#59473)
* fix: keep acp prompts alive across gateway reconnects * fix: bound ACP prompts after disconnect grace * fix: preserve ACP send timeout semantics * fix: defer pre-ack ACP disconnect failures * fix: reconcile ACP runs after reconnect * fix: keep ACP reconnect deadlines monotonic * fix: keep pre-ack ACP deadlines after reconnect * fix: keep ACP prompts alive across gateway reconnects (openclaw#59473) * fix: reject superseded ACP pre-ack prompts (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * fix: guard ACP send acceptance by run id (openclaw#59473) * fix: scope ACP reconnect deadline by prompt (openclaw#59473) * fix: recheck ACP prompts at reconnect deadline (openclaw#59473) * fix: key ACP reconnect deadline by run (openclaw#59473)
* fix: keep acp prompts alive across gateway reconnects * fix: bound ACP prompts after disconnect grace * fix: preserve ACP send timeout semantics * fix: defer pre-ack ACP disconnect failures * fix: reconcile ACP runs after reconnect * fix: keep ACP reconnect deadlines monotonic * fix: keep pre-ack ACP deadlines after reconnect * fix: keep ACP prompts alive across gateway reconnects (openclaw#59473) * fix: reject superseded ACP pre-ack prompts (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * style: format ACP reconnect regression updates (openclaw#59473) * fix: guard ACP send acceptance by run id (openclaw#59473) * fix: scope ACP reconnect deadline by prompt (openclaw#59473) * fix: recheck ACP prompts at reconnect deadline (openclaw#59473) * fix: key ACP reconnect deadline by run (openclaw#59473)
Summary
chat.sendrequest and an event stream; the translator now waits only for send acceptance and keeps completion event-drivenTesting
pnpm test -- src/acp/translator.stop-reason.test.ts src/acp/translator.prompt-prefix.test.ts src/acp/translator.cancel-scoping.test.ts src/acp/translator.session-rate-limit.test.tspnpm tsgoFixes #59334
Fixes #31686
Fixes #28708