wooden-umbrella-84098
08/04/2026, 5:16 PMcalm-artist-7206
08/04/2026, 5:21 PMwooden-umbrella-84098
08/04/2026, 5:23 PMwooden-umbrella-84098
08/04/2026, 5:24 PMwooden-umbrella-84098
08/04/2026, 5:24 PMcalm-artist-7206
08/04/2026, 5:24 PMcalm-artist-7206
08/04/2026, 5:25 PMcalm-artist-7206
08/04/2026, 5:25 PMlimited-student-10747
08/04/2026, 5:45 PMwooden-umbrella-84098
08/04/2026, 7:08 PMcalm-artist-7206
08/04/2026, 7:29 PMfresh-machine-37269
08/04/2026, 7:35 PMfresh-machine-37269
08/04/2026, 7:36 PMpr-review plugin in @openhands/extensions, not the Automation running in my own environment. That GitHub Actions workflow triggers on PR open/ready-for-review/label/review-requested and runs an OpenHands agent in-process within the GH Actions runner. See my corrected answer below for the actual agent-canvas Automation. Γ’Γ―ΒΈcalm-artist-7206
08/04/2026, 7:41 PMfresh-machine-37269
08/04/2026, 7:45 PMautomations.db, one per repo, all running on the same pattern:
Each is a tarball containing config.json + main.py, run via python3 main.py with a 1200s timeout.
What the script (main.py) does On every poll it:
1. Verifies the GitHub token + repo access, then lists all open PRs in the configured repo.
2. Reconciles any in-flight reviews (checks if their agent-server conversations reached a terminal status, posts results, clears reviewer requests, handles stale/expired).
3. For each open PR, evaluates a 5-rule decision tree (in order) to decide what to do.
The 5 rules β in what conditions it sends a request to agent-server The key question is when it actually calls create_conversation() β POST /api/conversations on the agent-server. The rules, evaluated in order:
1. @all-hands-bot requested as reviewer β AI review unconditionally.
If the bot is currently in requested_reviewers, it spins up a full AI review immediately. This overrides everything else β failing CI, missing PR description, draft status, contributor trust level, all ignored. Checked fresh every poll, so a review request made after an earlier verdict is picked up without needing a new commit.
2. Missing HUMAN section β plain (non-AI) comment, no conversation.
If the PR description doesn't have a filled-in HUMAN: section (β₯20 chars of real content), it leaves a deterministic comment explaining what to fix. Dedupes on the section's content fingerprint (edits the existing comment in place rather than reposting). No agent-server call.
3. CI failing β plain comment, no conversation.
If CI is red on the head commit, it leaves a "fix your CI" comment (once per head SHA). No agent-server call.
(If CI is still running, it skips entirely and re-checks next poll.)
4. Trusted contributor β AI review.
If the author is an org OWNER/MEMBER/COLLABORATOR, or has β₯3 merged PRs in the repo, it spins up a full AI review. This calls agent-server.
5. Untrusted contributor β Slack ping, no conversation.
If none of the above, it posts a message to a Slack channel (C06R25BT5B2) saying the PR needs a human review. Fires at most once per PR (not per commit), with a live Slack history check as a safety net against duplicates. No agent-server call.
How the agent-server request actually happens When a PR qualifies for an AI review (rules 1 or 4), `_process_review_request()`:
1. Prepares a workspace β downloads the repo tarball at the exact head SHA from GitHub's API and extracts it (skipping symlinks/devices for safety).
2. Builds the review prompt β includes repo, PR metadata, head SHA, diff stats, full PR description, review tone (thorough/concise/friendly), and detailed instructions to post a GitHub PR review with inline comments via the API, plus the AI disclosure line.
3. Calls POST /api/conversations on the agent-server (AGENT_SERVER_URL) with the workspace dir, agent config, initial message (the prompt), secrets, and MCP config. This is the actual "request to agent-server for a conversation."
4. Posts an acknowledgement comment on the PR with a link to the conversation.
5. On subsequent polls, it polls the conversation status (GET /api/conversations/{id}) until it reaches a terminal state (`idle`/`finished`/`error`/`stuck`), then fetches the final response and verifies the review actually landed on GitHub.
Key design details β’ Concurrency: max 3 reviews in flight at once (max_concurrent_reviews: 3).
β’ Dedup: keyed on (pr_number, head_sha) β a new push is new work. Stored in crash-safe KV (state-v7).
β’ Expiry: reviews stuck for >2h are abandoned with a "gave up" comment.
β’ Retry: up to 3 creation attempts before giving up on a PR.
β’ Draft PRs: skipped entirely unless @all-hands-bot is requested as a reviewer (rule 1).
So the short answer to your question: it only sends the request to agent-server when (a) the bot is explicitly requested as a reviewer, or (b) the author is a trusted contributor AND the PR description has a HUMAN section AND CI is green. Everything else is handled deterministically without spinning up a conversation., with interactive elementscalm-artist-7206
08/04/2026, 7:50 PMDedup: keyed on (pr number, head sha) - a new push is new work.
calm-artist-7206
08/04/2026, 7:52 PMfresh-machine-37269
08/04/2026, 7:53 PMpr-review plugin rather than the agent-canvas Automation, and pointed to the corrected answer below.calm-artist-7206
08/04/2026, 7:54 PMfresh-machine-37269
08/04/2026, 7:55 PMopenhands/glm-5.2 (routed through the OpenHands LLM proxy)
Temperature: null Γ’ not set, so it uses the model's default
A few other notable settings it inherits:
β’ Reasoning effort: high
β’ Extended thinking budget: 200,000 tokens
β’ Native tool calling: enabled
β’ Max message chars: 30,000
β’ Timeout: 300s
β’ Retries: 5, with exponential backoff (8s Γ’ 64s)
β’ Prompt caching: enabled (24h retention)
The two Slack monitor automations ("All Joined Channels" and "OpenHands AI Authorized") are identical scripts Γ’ they differ only in which Slack workspace/bot they serve (all-hands-ai vs openhands-ai) and whether authorization is required. Both call create_conversation() which reads agent_settings.llm from /api/settings at runtime, so they both use the same global LLM config above.