fix: register OpenResponses runId in chatAbortControllers for chat.abort support#30737
fix: register OpenResponses runId in chatAbortControllers for chat.abort support#30737davidemanuelDEV wants to merge 2 commits intoopenclaw:mainfrom
Conversation
…ort support OpenResponses HTTP API tasks (resp_xxx) were not registered in the Gateway's chatAbortControllers Map, causing chat.abort requests to silently fail with aborted: false. This patch: - Creates an AbortController for each OpenResponses request and registers it in chatAbortControllers with the responseId as key - Cleans up the registration on completion, error, client disconnect, and stream finalization - Threads chatAbortControllers from server-runtime-state through server-http to the OpenResponses handler Fixes openclaw#30558
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0c6539d457
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const abortController = new AbortController(); | ||
| if (opts.chatAbortControllers) { |
There was a problem hiding this comment.
Wire OpenResponses abort controller into agent command
This registers a new AbortController for each /v1/responses run, but the controller’s signal is never threaded into runResponsesAgentCommand/agentCommand (which supports abortSignal), so chat.abort can now report aborted: true while the underlying run continues to execute. In environments using OpenResponses plus chat.abort, this causes false-positive aborts and ongoing token/runtime usage even after a claimed cancellation.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch — wiring the abort signal through now.
Greptile SummaryRegisters OpenResponses HTTP requests in Key changes:
Critical issue:
Confidence Score: 1/5
Last reviewed commit: 0c6539d |
| const abortController = new AbortController(); | ||
| if (opts.chatAbortControllers) { | ||
| const now = Date.now(); | ||
| const timeoutMs = 10 * 60_000; // 10 minute default | ||
| opts.chatAbortControllers.set(responseId, { | ||
| controller: abortController, | ||
| sessionId: responseId, | ||
| sessionKey, | ||
| startedAtMs: now, | ||
| expiresAtMs: resolveChatRunExpiresAtMs({ now, timeoutMs }), | ||
| }); | ||
| } | ||
| const cleanupAbortController = () => { | ||
| opts.chatAbortControllers?.delete(responseId); | ||
| }; |
There was a problem hiding this comment.
abortController.signal must be passed to runResponsesAgentCommand
The AbortController is created and registered in chatAbortControllers, but the signal is never passed to the agent command execution. When chat.abort is called, it will call controller.abort(), but since the agent command doesn't have a reference to the signal, it won't actually stop executing.
Compare with the WebSocket path in server-methods/chat.ts:867 which passes abortSignal: abortController.signal to dispatchInboundMessage.
Fix by:
- Adding
abortSignal?: AbortSignalparameter torunResponsesAgentCommand - Passing it to the
agentCommandcall (line 261) - Passing
abortController.signalin both calls torunResponsesAgentCommand(lines 474 and 710)
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/openresponses-http.ts
Line: 456-470
Comment:
`abortController.signal` must be passed to `runResponsesAgentCommand`
The `AbortController` is created and registered in `chatAbortControllers`, but the signal is never passed to the agent command execution. When `chat.abort` is called, it will call `controller.abort()`, but since the agent command doesn't have a reference to the signal, it won't actually stop executing.
Compare with the WebSocket path in `server-methods/chat.ts:867` which passes `abortSignal: abortController.signal` to `dispatchInboundMessage`.
Fix by:
1. Adding `abortSignal?: AbortSignal` parameter to `runResponsesAgentCommand`
2. Passing it to the `agentCommand` call (line 261)
3. Passing `abortController.signal` in both calls to `runResponsesAgentCommand` (lines 474 and 710)
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Agreed, fixing — will pass the signal to runResponsesAgentCommand.
The AbortController was created and registered in the abort map but its signal was never passed to runResponsesAgentCommand, making chat.abort a no-op. Pass abortController.signal at both call sites (non-streaming and streaming paths). Addresses review comment on PR openclaw#30737.
|
@greptile-apps Good catch on the abort signal flow! Looking at the diff, I see we're passing Could you clarify: does the If
What's the current abort interface for |
|
Yes, Looking at abortSignal?: AbortSignal;And in
So the abort signal path in this PR is complete:
The PR should work as intended for both ACP and embedded Pi agent executions. |
Summary
OpenResponses HTTP API tasks (
resp_xxx) were not registered in the Gateway'schatAbortControllersMap, causingchat.abortrequests to silently returnaborted: falsewhile the task continued executing.Root Cause
When a task is started via the OpenResponses
/v1/responsesendpoint, the generatedresponseIdwas never added tochatAbortControllers. The Gateway RPC WebSocket (chat.send) correctly registers run IDs, but the HTTP path was missing this registration.Changes
openresponses-http.ts: Create anAbortControllerfor each request, register it inchatAbortControllerswith theresponseIdas key before running the agent command. Clean up on completion (finallyblock for non-streaming,requestFinalize/error/close handlers for streaming).server-http.ts: ThreadchatAbortControllersthroughcreateGatewayHttpServeroptions to the OpenResponses handler.server-runtime-state.ts: Pass the existingchatAbortControllersMap tocreateGatewayHttpServer, moved declaration before the bind-host loop.Testing
Fixes #30558