fix: ESC key not interrupting during Working... state
Three related fixes:
1. google-gemini-cli: Handle abort signal in stream reading loop
- Add abort event listener to cancel reader immediately when signal fires
- Fix AbortError detection in retry catch block (fetch throws AbortError,
not our custom message)
- Swallow reader.cancel() rejection to avoid unhandled promise
2. agent-session: Fix retry attempt counter showing 0 on cancel
- abortRetry() was resetting _retryAttempt before the catch block could
read it for the error message
3. interactive-mode: Restore main escape handler on agent_start
- When auto-retry starts, onEscape is replaced with retry-specific handler
- auto_retry_end (which restores it) fires on turn_end, after streaming begins
- Now restore immediately on agent_start if retry handler is still active
Amended: suppress reader.cancel() rejection on abort.
This commit is contained in:
@@ -305,8 +305,11 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|||||||
// Not retryable or max retries exceeded
|
// Not retryable or max retries exceeded
|
||||||
throw new Error(`Cloud Code Assist API error (${response.status}): ${errorText}`);
|
throw new Error(`Cloud Code Assist API error (${response.status}): ${errorText}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error && error.message === "Request was aborted") {
|
// Check for abort - fetch throws AbortError, our code throws "Request was aborted"
|
||||||
throw error;
|
if (error instanceof Error) {
|
||||||
|
if (error.name === "AbortError" || error.message === "Request was aborted") {
|
||||||
|
throw new Error("Request was aborted");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lastError = error instanceof Error ? error : new Error(String(error));
|
lastError = error instanceof Error ? error : new Error(String(error));
|
||||||
// Network errors are retryable
|
// Network errors are retryable
|
||||||
@@ -338,7 +341,19 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
let buffer = "";
|
let buffer = "";
|
||||||
|
|
||||||
|
// Set up abort handler to cancel reader when signal fires
|
||||||
|
const abortHandler = () => {
|
||||||
|
void reader.cancel().catch(() => {});
|
||||||
|
};
|
||||||
|
options?.signal?.addEventListener("abort", abortHandler);
|
||||||
|
|
||||||
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Check abort signal before each read
|
||||||
|
if (options?.signal?.aborted) {
|
||||||
|
throw new Error("Request was aborted");
|
||||||
|
}
|
||||||
|
|
||||||
const { done, value } = await reader.read();
|
const { done, value } = await reader.read();
|
||||||
if (done) break;
|
if (done) break;
|
||||||
|
|
||||||
@@ -502,6 +517,9 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
options?.signal?.removeEventListener("abort", abortHandler);
|
||||||
|
}
|
||||||
|
|
||||||
if (currentBlock) {
|
if (currentBlock) {
|
||||||
if (currentBlock.type === "text") {
|
if (currentBlock.type === "text") {
|
||||||
|
|||||||
@@ -1567,7 +1567,7 @@ export class AgentSession {
|
|||||||
*/
|
*/
|
||||||
abortRetry(): void {
|
abortRetry(): void {
|
||||||
this._retryAbortController?.abort();
|
this._retryAbortController?.abort();
|
||||||
this._retryAttempt = 0;
|
// Note: _retryAttempt is reset in the catch block of _autoRetry
|
||||||
this._resolveRetry();
|
this._resolveRetry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1481,6 +1481,16 @@ export class InteractiveMode {
|
|||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case "agent_start":
|
case "agent_start":
|
||||||
|
// Restore main escape handler if retry handler is still active
|
||||||
|
// (retry success event fires later, but we need main handler now)
|
||||||
|
if (this.retryEscapeHandler) {
|
||||||
|
this.defaultEditor.onEscape = this.retryEscapeHandler;
|
||||||
|
this.retryEscapeHandler = undefined;
|
||||||
|
}
|
||||||
|
if (this.retryLoader) {
|
||||||
|
this.retryLoader.stop();
|
||||||
|
this.retryLoader = undefined;
|
||||||
|
}
|
||||||
if (this.loadingAnimation) {
|
if (this.loadingAnimation) {
|
||||||
this.loadingAnimation.stop();
|
this.loadingAnimation.stop();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user