feat: async review flow (202 + reviewId, poll for result)#22
Conversation
The three review tools now use the Optibot backend's async review path instead
of holding the request open for the whole review:
- review() sends { async: true } and returns a receipt { reviewId, reviewCount }.
- Each tool joins the progress socket room by the server's reviewId (handshake
Option A), streaming progress notifications as before, then polls
GET /api/review/result/:reviewId via waitForReviewResult until done or failed.
- getReviewResult decodes the payload and maps pending/done/failed/not_found.
The tool contract to the host is unchanged (still returns the full review). The
socket drives live progress; the GET is the source of truth. Requires a backend
with async review support deployed.
|
@optibot review |
There was a problem hiding this comment.
Summary
This PR refactors the core code review feature from a synchronous, long-running HTTP request to an asynchronous, polling-based mechanism. The apparent goal is to improve the reliability and user experience of the review process by avoiding potential request timeouts for large reviews.
Instead of a single API call that waits for the entire review to complete, the client now makes an initial request that immediately returns a reviewId. The client then uses this reviewId to poll a new endpoint until the review is complete, while also using it to connect to a websocket for real-time progress updates.
Key Changes
- Asynchronous API Flow: The
ApiClient.review()method has been changed to be asynchronous. It now sendsasync: truein the request body and returns a "receipt" containing areviewIdinstead of the full review. - Result Polling: A new
ApiClient.getReviewResult(reviewId)method and a corresponding polling utilitywaitForReviewResulthave been introduced. These handle fetching the review result by polling a new API endpoint (/api/review/result/:reviewId) until a terminal status (doneorfailed) is reached. - Tool Integration: All review tools (
review_local_changes,review_branch,review_patch) have been updated to use this new two-step process: first, submit the review to get areviewId, and then poll for the result. - Progress Linking: The
ReviewProgressServiceis now initialized using thereviewIdfrom the API response. This links the real-time progress updates streamed over the websocket directly to the specific asynchronous review job. - Type Definitions: New types (
AsyncReviewResponse,ReviewResultResponse) have been added to accurately model the responses for the new asynchronous API endpoints.
All Relevant File Changes (click to expand)
src/lib/api.test.ts: Updated tests to reflect the new asynchronous behavior of thereviewmethod and added comprehensive tests for the newgetReviewResultmethod, covering all possible statuses (pending,done,failed,not_found).src/lib/api.ts: Modified thereviewmethod to initiate an asynchronous job and return areviewId. Added the newgetReviewResultmethod to fetch the outcome of the async job. Base64 comment decoding logic was moved fromreviewtogetReviewResult.src/lib/reviewPolling.test.ts: New test file added to validate the logic of thewaitForReviewResultpolling utility, including success, failure, and timeout scenarios.src/lib/reviewPolling.ts: New file containing thewaitForReviewResultfunction, which encapsulates the logic for polling thegetReviewResultendpoint with a configurable timeout and interval.src/lib/reviewProgress.ts: ThestartSessionmethod was updated to accept an optionalsessionId(which will be thereviewId) to join a specific progress room.src/tools/review.test.ts: Tooling tests were refactored to mock and assert the new asynchronous flow (callingreview, thengetReviewResult).src/tools/review.ts: All review-related tools were updated to use the new asynchronous flow:client.review()->waitForReviewResult().src/types.ts: Added newAsyncReviewResponseandReviewResultResponsetypes to define the contracts for the asynchronous review submission and result polling API endpoints.
💬 Feedback & Commands
Share feedback on my comments with 👍 👎 — I'll stop raising issues you push back on. Think I missed something? Adjust my sensitivity →
4 things I can do →
#optibot review— I'll re-review your latest changes#optibot fix— I'll apply my suggested fixes to your code#optibot compliance— I'll run a compliance check on your changes#optibot release notes— I'll write up release notes for your production release
💡 Tip: Get notified on Slack when I finish a review — connect in Integrations.
What
Move the MCP review tools to the Optibot backend's async review flow. Instead of holding the request open for the whole review, each tool submits the review, gets a receipt, and fetches the result separately.
How
review()sends{ async: true }and returns{ reviewId, reviewCount }(HTTP202) instead of the review payload.review_local_changes,review_branch,review_diff_file) joins the progress socket room by the server'sreviewId(handshake "Option A"), streams progress as MCP notifications exactly as before, then pollsGET /api/review/result/:reviewIdviawaitForReviewResultuntil the review isdoneorfailed.getReviewResultdecodes the payload and mapspending/done/failed/not_found(HTTP 404).Contract
The tool contract to the host is unchanged — each tool still returns the full formatted review as its result. Only the mechanism for obtaining the review changes. The MCP→host channel is not subject to the HTTP/proxy timeouts that motivated this, so the tool call simply runs until the result is ready.
Compatibility / rollout
200payload instead of a202receipt and break, so this must ship after the backend is deployed.GET); no org id is persisted locally.Tests
api.test.ts:review()setsasync: trueand returns the receipt;getReviewResultcovers GET/auth, pending, done (decodes), failed, andnot_found.reviewPolling.test.ts:waitForReviewResultreturns on done/failed, keeps polling throughpending/not_found, and times out.tools/review.test.ts: the new submit → join-by-reviewId → fetch flow, the submit-failure and result-failure paths, and progress-session cleanup.