-
Notifications
You must be signed in to change notification settings - Fork 140
feat: Add cloud mode for PR review workflow #1966
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This adds a new 'cloud' mode to the PR review workflow that launches reviews in OpenHands Cloud instead of running locally in GitHub Actions. Changes: - Add MODE environment variable (sdk/cloud) to agent_script.py - Add run_cloud_mode() function that: - Calls OpenHands Cloud API to start a conversation - Posts a comment on the PR with the cloud conversation URL - Exits without monitoring (review continues asynchronously) - Add post_github_comment() helper function - Add _start_cloud_conversation() helper function - Update composite action.yml with new inputs: - mode (sdk/cloud) - openhands-cloud-api-key - openhands-cloud-api-url - Update workflow.yml example to support cloud mode - Update README.md with cloud mode documentation - Add tests for the new functionality Cloud mode benefits: - Faster CI completion (exits after starting the review) - Track review progress in OpenHands Cloud UI - Interact with the review conversation - Uses the LLM model configured in OpenHands Cloud account Co-authored-by: openhands <openhands@all-hands.dev>
- Extract shared setup code into _prepare_review_context() helper function to eliminate code duplication between run_cloud_mode() and run_sdk_mode() - Fix inconsistent GITHUB_TOKEN requirements: update action.yml to correctly document that GITHUB_TOKEN is required for both modes (used to post PR comments) - Remove redundant OPENHANDS_CLOUD_API_KEY validation in run_cloud_mode() (already validated in main()) - Extract comment body into CLOUD_REVIEW_COMMENT_TEMPLATE constant - Improve tests to actually test behavior by calling main() instead of just verifying list membership - Add test for _prepare_review_context() helper function
Move _prepare_review_context call to main() and pass the prompt to both run_sdk_mode and run_cloud_mode functions. This reduces code duplication and makes the flow clearer - context preparation happens once, then the mode-specific logic runs. - run_cloud_mode now takes (pr_info, prompt) instead of (pr_info, review_style) - run_sdk_mode now takes (prompt, skill_trigger) instead of (pr_info, review_style)
🧪 Cloud Mode Test Results (Bug Fix Verification)Status: ✅ Bug fix verified - Cloud mode working correctly Issue Found and FixedThe Fix Applied
Test Results
📍 Test Conversation URL: https://app.all-hands.dev/conversations/5be1faf2ef364d3f84df3055922867db This test was performed to verify the bug fix for PR #1966. |
The OpenHands Cloud API does not accept a 'secrets' field in the request payload (causes HTTP 422 'Extra inputs are not permitted' error). The Cloud API has 'additionalProperties: false' in its schema, which means it only accepts the documented fields: initial_user_msg, repository, git_provider, selected_branch, etc. Instead of passing secrets directly, OpenHands Cloud uses the user's connected GitHub account for repository access. Added an informational log message to explain this behavior when github_token is provided. Co-authored-by: openhands <openhands@all-hands.dev>
Rewrote cloud mode to use OpenHandsCloudWorkspace instead of directly calling the /api/conversations endpoint. This provides: - Proper sandbox provisioning via OpenHands Cloud API - LLM configuration sent to the cloud sandbox - GITHUB_TOKEN passed to sandbox for posting review comments - Same agent capabilities as SDK mode, but running in the cloud Changes: - agent_script.py: Rewrite run_cloud_mode() to use OpenHandsCloudWorkspace - agent_script.py: Remove _start_cloud_conversation() and CLOUD_REVIEW_COMMENT_TEMPLATE - agent_script.py: Cloud mode now requires LLM_API_KEY (sent to sandbox) - action.yml: Update to require LLM_API_KEY for both modes - action.yml: Add openhands-workspace to dependencies - README.md: Update documentation for new cloud mode architecture - tests: Update tests for new requirements See: https://docs.openhands.dev/sdk/guides/agent-server/cloud-workspace Co-authored-by: openhands <openhands@all-hands.dev>
🔧 Major Refactor: Cloud Mode Now Uses OpenHandsCloudWorkspaceI've refactored the cloud mode implementation to properly use What ChangedBefore:
After:
New Requirements for Cloud ModeCloud mode now requires both:
DocumentationSee the official guide: https://docs.openhands.dev/sdk/guides/agent-server/cloud-workspace Commits
|
- Revert agent_script.py to main version and add cloud mode support - Share core agent definition logic between SDK and cloud modes - Cloud mode uses OpenHandsCloudWorkspace with keep_alive=True - Cloud mode calls run(blocking=False) to start agent without waiting - Add CLOUD_MODE_INSTRUCTION to instruct agent to post review comment when done - Post PR comment with conversation URL for tracking progress - Update tests to match new implementation The only difference between modes is: - SDK mode: runs locally and waits for completion - Cloud mode: runs in cloud sandbox, exits immediately after starting Co-authored-by: openhands <openhands@all-hands.dev>
|
@OpenHands pls merge from main and resolve the conflicts |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
Resolved conflicts in: - .github/actions/pr-review/action.yml: Added both cloud mode inputs and lmnr-api-key - examples/03_github_workflows/02_pr_review/agent_script.py: Kept cloud mode logic and added Laminar trace handling - examples/03_github_workflows/02_pr_review/README.md: Combined cloud mode docs with observability section Co-authored-by: openhands <openhands@all-hands.dev>
|
Successfully merged Summary of Conflict ResolutionThree files had merge conflicts that were resolved: 1.
|
|
🤖 OpenHands PR Review Started The code review is running in OpenHands Cloud. 📍 Track progress: https://app.all-hands.dev/conversations/8cff5913-4ed8-48c9-9473-e00e443de03f The agent will post a review comment when the analysis is complete. |
✅ Cloud Mode Testing ResultsI tested the cloud mode feature using the Test Configuration
Results
Cloud ConversationThe PR review is running here: https://app.all-hands.dev/conversations/8cff5913-4ed8-48c9-9473-e00e443de03f Minor ObservationThere were some validation warnings about an SummaryThe cloud mode implementation works as expected:
Great work on this feature! 🎉 |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
🤖 OpenHands PR Review Started The code review is running in OpenHands Cloud. 📍 Track progress: https://app.all-hands.dev/conversations/578fcb531dd34ef3b87fe7fd55b29e46 The agent will post a review comment when the analysis is complete. |
Instead of using OpenHandsCloudWorkspace to create a sandbox and then creating a conversation on the agent-server inside it, this change uses the OpenHands Cloud /api/conversations endpoint directly. Benefits: - No LLM credentials needed - cloud uses user's configured LLM - Proper conversation URL that works in the OpenHands Cloud UI - Simpler implementation - just one API call Changes: - Add _start_cloud_conversation() to call Cloud API directly - Update validation to only require LLM_API_KEY for sdk mode - Include GITHUB_TOKEN in the prompt for cloud mode (API doesn't support passing secrets separately) - Update action.yml descriptions to reflect mode differences Tested: Successfully created conversation 578fcb531dd34ef3b87fe7fd55b29e46 Co-authored-by: openhands <openhands@all-hands.dev>
Cloud mode should NOT require LLM_API_KEY - it uses the user's cloud-configured LLM via the /api/conversations endpoint. This reverts the refactoring to use OpenHandsCloudWorkspace, which required passing LLM configuration. Cloud mode: - Uses Cloud API Direct (/api/conversations endpoint) - No LLM_API_KEY needed (uses cloud-configured LLM) - Asynchronous (fire and forget) - Posts comment with conversation URL SDK mode: - Uses local workspace with Conversation + Agent - Requires LLM_API_KEY - Synchronous (waits for completion) Co-authored-by: openhands <openhands@all-hands.dev>
|
🤖 OpenHands PR Review Started The code review is running in OpenHands Cloud. 📍 Track progress: https://app.all-hands.dev/conversations/16dd88f3ab9c4af89ecb83436e35a172 The agent will post review comments when the analysis is complete. |
🔴 Code Review: Needs ImprovementTaste Rating: 🔴 Needs improvement - Violates fundamental principles of simplicity and good design. [CRITICAL ISSUES] (Must fix - these break fundamental principles)[agent_script.py, Lines 154-180] 🔨 Data Structure & Duplication: [agent_script.py, Lines 260-400+] 🔨 Complexity Explosion:
This violates every principle of clean code. Split it up. [agent_script.py, Lines 182-230] 🔒 Security Risk - Token in Prompt: CLOUD_MODE_PROMPT = """...
The GITHUB_TOKEN environment variable is already set for you...
"""You're telling an AI agent that [action.yml, Line 14] llm-api-key:
description: LLM API key (required for 'sdk' mode only...)
required: false # WAS: required: trueYou've changed [IMPROVEMENT OPPORTUNITIES] (Should fix - violates good taste)[agent_script.py, Lines 182-230] 📝 Prompt Engineering Smell: [test_pr_review_agent.py, Lines 1-20] 🔧 Import Hack: sys.path.insert(0, str(pr_review_path))This is the kind of import hack that makes Python projects unmaintainable. If you need to test this module, either:
Don't paper over structural problems with [test_pr_review_agent.py, Lines 75-95] 🤔 Trivial Tests: def test_mode_defaults_to_sdk():
mode = os.getenv("MODE", "sdk").lower()
assert mode == "sdk"You're testing that [agent_script.py, Lines 260-280] 📊 Implicit Data Structure: class PRInfo(TypedDict):
number: str
title: str
body: str
repo_name: str
base_branch: str
head_branch: strThis makes the code self-documenting and catches bugs at type-check time. [action.yml, Lines 90-95] 🔧 Unnecessary Dependency: uv pip install --system ./software-agent-sdk/openhands-workspaceYou've added [STYLE NOTES] (Minor - only mention if genuinely important)[README.md, Lines 91-120] 📚 Documentation Duplication: [agent_script.py, Line 17-45] 📝 Docstring Bloat: VERDICT:❌ Needs rework - Fundamental design issues must be addressed first. The core feature (cloud mode) is reasonable, but the implementation violates basic software engineering principles:
KEY INSIGHT: "Talk is cheap. Show me the code." - But in this case, show me LESS code that does the same thing. |
|
@OpenHands please help me fix this: #1966 (comment) |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
- Extract common HTTP helper (_make_http_request) to reduce duplication - Refactor main() into run_sdk_mode() and run_cloud_mode() functions - Add PRInfo TypedDict for type safety - Improve test quality with meaningful tests for actual functions - Trim module docstring to focus on API documentation - Remove unused openhands-workspace dependency from action.yml Co-authored-by: openhands <openhands@all-hands.dev>
|
I've addressed the code review feedback from the PR comment. Here's a summary of the changes: Changes Made1. Extracted common HTTP helper (
|
- Replace direct API calls to /api/conversations with OpenHandsCloudWorkspace - Cloud mode now uses the SDK's proper abstraction for cloud sandbox management - Cloud mode now requires both OPENHANDS_CLOUD_API_KEY and LLM_API_KEY (LLM config is sent to the cloud sandbox) - Update tests to reflect the new requirements Co-authored-by: openhands <openhands@all-hands.dev>
all-hands-bot
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 Needs improvement - Critical documentation/implementation mismatch
Taste Rating: 🔴 Violates fundamental principles
[CRITICAL ISSUES] (Must fix)
-
Documentation Lie: The README and PR description claim cloud mode doesn't need
LLM_API_KEY, but the code atagent_script.pyline ~143 doesllm_api_key = _get_required_env("LLM_API_KEY"). Either the code is wrong or the docs are wrong. This will cause user confusion and workflow failures. -
Over-Engineering: You wrote a 65-line generic HTTP client (
_make_http_request) in a PR review script. Either use therequestslibrary or stick withghCLI. This reinvents the wheel and makes the script harder to understand. "Bad programmers worry about the code. Good programmers use libraries." -
Architecture Problem:
main()has two completely different execution paths based on mode. This violates single responsibility. Better design:workspace = CloudWorkspace(...) if mode == 'cloud' else LocalWorkspace(...); run_review(workspace, pr_info). One execution path, workspace abstraction handles differences. -
Testing Theater: The tests mock
urllib.request.urlopenand assert it was called. They don't test actual logic. What happens if the response is malformed JSON? Your tests won't catch it. Test real code paths or don't bother testing.
[IMPROVEMENT OPPORTUNITIES]
-
Special Case Hell: Mode validation appears in 3+ places (Python, bash, action.yml). This is a leaking abstraction. Consider a strategy pattern where each mode registers its requirements.
-
Missing Error Handling: In
run_cloud_mode(), ifconversation.run()fails, you already posted "review started" but it never completes. User is left hanging. -
Breaking Change Not Highlighted: Cloud mode changes workflow from blocking to non-blocking. SDK mode waits for completion; cloud mode exits immediately. This could break CI/CD pipelines.
VERDICT: ❌ Needs rework
Fix the LLM_API_KEY documentation/code mismatch first. Then address the over-engineering and architecture issues.
KEY INSIGHT:
The fundamental problem is trying to bolt two completely different execution models (local blocking vs cloud async) onto the same codebase without proper abstraction. This creates leaky abstractions, duplicated validation logic, and contradictory documentation.
Additional Inline Comments📍 Line-by-Line Issuesexamples/03_github_workflows/02_pr_review/README.md:66 examples/03_github_workflows/02_pr_review/agent_script.py:257 examples/03_github_workflows/02_pr_review/agent_script.py:49-114 examples/03_github_workflows/02_pr_review/agent_script.py:381-395 tests/github_workflows/test_pr_review_agent.py:29-50 |
|
Looks like there are a few issues preventing this PR from being merged!
If you'd like me to help, just leave a comment, like Feel free to include any additional details that might help me get this PR into a better state. You can manage your notification settings |
|
@OpenHands pls fix #1966 (review) |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
- Fix documentation/code mismatch: Update README.md and action.yml to clarify that cloud mode requires both OPENHANDS_CLOUD_API_KEY and LLM_API_KEY (the LLM config is sent to the cloud sandbox) - Replace _make_http_request with requests library for simpler HTTP handling - Add error handling for cloud mode: Post failure comment if conversation.run() fails after posting 'review started' comment - Add openhands-workspace package to action.yml dependencies (required for OpenHandsCloudWorkspace) - Update tests to work with requests library Co-authored-by: openhands <openhands@all-hands.dev>
|
I've addressed the PR review feedback from #1966 (review). The changes have been pushed to the Summary of Changes1. Fixed Documentation/Code Mismatch (Critical Issue #1)
2. Replaced Over-Engineered HTTP Client (Critical Issue #2)
3. Added Error Handling for Cloud Mode (Improvement #6)
4. Fixed Missing Dependency
5. Updated Tests
Checklist
|
|
@OpenHands /codereview-roasted |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
Code Review Summary for PR #1966: "feat: Add cloud mode for PR review workflow"🔴 Taste Rating: Needs ImprovementI performed a Linus Torvalds-style "roasted" code review of this PR. Here are the key findings: Critical Issues (Must Fix)
Improvement Opportunities
Verdict❌ Needs rework before merging. The Key InsightThe cloud mode implementation tries to be both "fire-and-forget" and "wait for completion". Pick one design and commit to it. No code changes were made - this was a review-only task as requested by |
|
@OpenHands pls address #1966 (comment) keep_alive=True, we should exit the script once we've hit the .run()
We should fix the validation - we should only validate it on the SDK path |
…ional Address review feedback from PR #1966: 1. Cloud mode with keep_alive=True now exits immediately after starting the conversation by using run(blocking=False). This provides the intended 'faster CI completion' benefit where the workflow exits immediately while the review continues asynchronously in the cloud. 2. LLM_API_KEY is now optional for cloud mode - the cloud uses the user's configured LLM settings from their OpenHands Cloud account. SDK mode still requires LLM_API_KEY for local execution. Changes: - agent_script.py: Use run(blocking=False) for cloud mode, make LLM_API_KEY optional with graceful handling - action.yml: Update validation to only require llm-api-key for SDK mode, update description to clarify - tests: Update tests to reflect new behavior - README.md: Update documentation to reflect LLM_API_KEY is optional for cloud mode Co-authored-by: openhands <openhands@all-hands.dev>
|
@OpenHands /codereview-roasted |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
Code Review Summary for PR #1966: "feat: Add cloud mode for PR review workflow"Taste Rating: 🔴 Needs ImprovementI provided a Linus Torvalds-style "roasted" code review of this PR. No code changes were made - this was a review-only request. Critical Issues Identified:
Improvement Opportunities:
Key Insight:The fundamental issue is that "cloud mode" and "sdk mode" have different data requirements but share the same entry point with conditional logic scattered throughout. A cleaner design would have each mode as a separate, focused module with a thin dispatcher in Verdict: ❌ Needs reworkThe core functionality is sound, but the |
Summary
This PR adds a new 'cloud' mode to the PR review workflow that launches reviews in OpenHands Cloud instead of running locally in GitHub Actions. This is inspired by and builds upon PR #1927.
Changes
examples/03_github_workflows/02_pr_review/agent_script.py:MODEenvironment variable support (sdkorcloud)post_github_comment()helper function to post PR comments_start_cloud_conversation()helper function to call OpenHands Cloud APIrun_cloud_mode()function that creates a cloud conversation and posts a comment with the URLrun_sdk_mode()functionOPENHANDS_CLOUD_API_KEY(ignoresLLM_MODELandLLM_BASE_URL).github/actions/pr-review/action.yml:mode,openhands-cloud-api-key,openhands-cloud-api-urlexamples/03_github_workflows/02_pr_review/workflow.yml:modeinput with comment explaining both modesexamples/03_github_workflows/02_pr_review/README.md:tests/github_workflows/test_pr_review_agent.py(new):Cloud Mode Benefits
Usage
SDK Mode (default):
Cloud Mode:
Checklist
@xingyaoww can click here to continue refining the PR
Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.12-nodejs22golang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:94e4b0d-pythonRun
All tags pushed for this build
About Multi-Architecture Support
94e4b0d-python) is a multi-arch manifest supporting both amd64 and arm6494e4b0d-python-amd64) are also available if needed