CaroFernando opened a new pull request, #8753:
URL: https://github.com/apache/texera/pull/8753

   ### What changes were proposed in this PR?
   
   A prompt arriving while an agent run is already in flight could
   re-point that run's warehouse mid-execution, and race on shared agent
   state.
   
   Before:  prompt A starts run (GENERATING) -> prompt B arrives mid-run
            -> setDelegateWarehouse() applies B's warehouse unconditionally
            -> A's still-running execution tools read the new warehouse
   After:   prompt A starts run -> prompt B arrives mid-run -> rejected
            with a busy error, A's warehouse/state untouched
   
   Root cause, two parts:
   1. `server.ts`'s `WsClientPromptCommand` handler called
      `agent.setDelegateWarehouse(...)` unconditionally on every prompt,
      with no check for whether a run was already in progress.
   2. `TexeraAgent.sendMessage` didn't flip `state` to `GENERATING` until
      after its first `await` (`refreshWorkflowFromBackend()`). Since two
      `message` handler invocations can interleave across that await, a
      second prompt could see stale `state` and proceed concurrently,
      racing on `head`, `abortController`, and `currentMessageId` as well.
   
   Fix: `sendMessage` now flips `state` (and resets `abortController`)
   synchronously before any `await`, and throws if already `GENERATING`.
   The WebSocket handler checks `agent.getState()` and rejects a busy
   agent with a `WsServerErrorEvent` before it ever calls
   `setDelegateWarehouse`, so a rejected prompt's delegate config is left
   untouched.
   
   ### Any related issues, documentation, discussions?
   
   Closes #8711
   
   ### How was this PR tested?
   
   Added two regression tests, verified red without the fix / green with it:
   
   - `agent-service/src/agent/texera-agent.spec.ts`: gates a mock LLM call
     open, asserts a concurrent `sendMessage()` call throws "busy" instead
     of interleaving.
   - `agent-service/src/server.ws.spec.ts`: same scenario over the real
     WebSocket protocol; also pins an initial `warehouseId` and asserts a
     busy-rejected prompt carrying a different `warehouseId` never reaches
     `setDelegateWarehouse` — `agent.getDelegateConfig().warehouseId`
     stays at the original value throughout.
   
   Run with:
   cd agent-service && bun test
   312 tests pass (0 fail).
   
   Additionally verified manually against the real running stack (real
   signed JWT, real WebSocket, and an actual LLM API key generating a real
   response) rather than a stubbed model: sent two prompts back-to-back
   with different `warehouseId`s, confirmed the second is rejected with
   "Agent is busy processing another message" while the first's run — and
   its `warehouseId` — is unaffected.
   
   ### Was this PR authored or co-authored using generative AI tooling?
   
   Generated-by: Claude


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to