Skip to content

feat: async review flow (202 + reviewId, poll for result)#22

Draft
comlaterra wants to merge 1 commit into
mainfrom
feat/async-review
Draft

feat: async review flow (202 + reviewId, poll for result)#22
comlaterra wants to merge 1 commit into
mainfrom
feat/async-review

Conversation

@comlaterra

Copy link
Copy Markdown
Member

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

  1. review() sends { async: true } and returns { reviewId, reviewCount } (HTTP 202) instead of the review payload.
  2. Each of the three tools (review_local_changes, review_branch, review_diff_file) joins the progress socket room by the server's reviewId (handshake "Option A"), streams progress as MCP notifications exactly as before, then polls GET /api/review/result/:reviewId via waitForReviewResult until the review is done or failed.
  3. getReviewResult decodes the payload and maps pending / 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

  • Requires a backend with async review support deployed. A new MCP against an old backend would receive a 200 payload instead of a 202 receipt and break, so this must ship after the backend is deployed.
  • Auth is unchanged (same Bearer token on the new GET); no org id is persisted locally.

Tests

  • api.test.ts: review() sets async: true and returns the receipt; getReviewResult covers GET/auth, pending, done (decodes), failed, and not_found.
  • reviewPolling.test.ts: waitForReviewResult returns on done/failed, keeps polling through pending/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.
  • Full suite green (335 tests); coverage above the enforced 80%.

Note: the local/cloud Optibot review on this PR was blocked by the daily review limit at open time; it will run once the quota resets.

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.
@comlaterra

Copy link
Copy Markdown
Member Author

@optibot review

@agent-optibot agent-optibot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 sends async: true in the request body and returns a "receipt" containing a reviewId instead of the full review.
  • Result Polling: A new ApiClient.getReviewResult(reviewId) method and a corresponding polling utility waitForReviewResult have been introduced. These handle fetching the review result by polling a new API endpoint (/api/review/result/:reviewId) until a terminal status (done or failed) 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 a reviewId, and then poll for the result.
  • Progress Linking: The ReviewProgressService is now initialized using the reviewId from 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 the review method and added comprehensive tests for the new getReviewResult method, covering all possible statuses (pending, done, failed, not_found).
  • src/lib/api.ts: Modified the review method to initiate an asynchronous job and return a reviewId. Added the new getReviewResult method to fetch the outcome of the async job. Base64 comment decoding logic was moved from review to getReviewResult.
  • src/lib/reviewPolling.test.ts: New test file added to validate the logic of the waitForReviewResult polling utility, including success, failure, and timeout scenarios.
  • src/lib/reviewPolling.ts: New file containing the waitForReviewResult function, which encapsulates the logic for polling the getReviewResult endpoint with a configurable timeout and interval.
  • src/lib/reviewProgress.ts: The startSession method was updated to accept an optional sessionId (which will be the reviewId) to join a specific progress room.
  • src/tools/review.test.ts: Tooling tests were refactored to mock and assert the new asynchronous flow (calling review, then getReviewResult).
  • src/tools/review.ts: All review-related tools were updated to use the new asynchronous flow: client.review() -> waitForReviewResult().
  • src/types.ts: Added new AsyncReviewResponse and ReviewResultResponse types 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.

🔄 re-review this PR

@agent-optibot agent-optibot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status: Code Looks Good 👍

No blocking issues found.

⏱️ Review completed in 2 minutes

✅ Approved!

🔄 re-review this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant