Skip to content

perf(message-stream): smooth live response rendering #1727

perf(message-stream): smooth live response rendering

perf(message-stream): smooth live response rendering #1727

name: AI PR Review (Single)
# Authentication defaults to Codex subscription auth for every allowed review. See
# .github/action/ai-review.md for the supported subscription and API-key fallback configurations
# and their security boundaries.
# - Shared API secrets: OPENAI_API_KEY and CODEX_BASE_URL
# - Review-specific secrets: CODEX_REVIEW_API_KEY and CODEX_REVIEW_BASE_URL
# - Legacy fallback secrets: complete correctness-specific and then architecture-specific key/URL pairs
# (base URLs may omit the trailing slash or include the full /v1/responses endpoint)
# - Subscription bootstrap secret: CODEX_AUTH_JSON
# Set CODEX_REVIEW_AUTH_MODE to subscription (default) or api-key. Automatic and manually
# dispatched reviews honor this preference. Missing, invalid, or rejected subscription credentials
# and subscription CLI setup failures fall back to the configured API-key credentials before
# checkout and review execution.
# Set ENABLE_CODEX_REVIEW=false to disable the automated reviewer.
# Legacy CODEX_REVIEW_MODE=disabled keeps automatic reviews disabled while preserving dispatch.
# CODEX_REVIEW_MODEL and CODEX_REVIEW_EFFORT select its model and effort. A selected legacy
# credential pair uses model/effort from the same scope; generic credentials keep ordered fallbacks.
# Set FORK_REVIEW_MODE to disabled, manual, or automatic (default: manual). Same-repository PRs
# always run. Manual mode permits workflow_dispatch reviews of forks; automatic mode also reviews
# fork PRs on opened, synchronize, and reopened events. Disabled mode blocks both fork paths.
# Set CODEX_REVIEW_MAX_ROUNDS to the maximum successful comments per PR (default: 20,
# 0 means unlimited). Rapid updates use concurrency cancellation so only the latest surviving run
# publishes a review and consumes a round.
#
# The reviewer does not post comments directly. It writes one schema-validated verdict covering
# correctness and architecture to a job output, and a separate trusted workflow publishes it.
on:
pull_request_target:
branches:
- main
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
pull_request_number:
description: Pull request number to review
required: true
concurrency:
group: ai-pr-review-${{ github.event.inputs.pull_request_number || github.event.pull_request.number }}
cancel-in-progress: true
jobs:
review_target:
name: Resolve AI review target
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
number: ${{ steps.target.outputs.number }}
head_ref: ${{ steps.target.outputs.head_ref }}
head_sha: ${{ steps.target.outputs.head_sha }}
base_sha: ${{ steps.target.outputs.base_sha }}
review_sha: ${{ steps.target.outputs.review_sha }}
state: ${{ steps.target.outputs.state }}
title: ${{ steps.target.outputs.title }}
is_fork: ${{ steps.target.outputs.is_fork }}
fork_mode: ${{ steps.target.outputs.fork_mode }}
review_allowed: ${{ steps.target.outputs.review_allowed }}
review_enabled: ${{ steps.target.outputs.review_enabled }}
auth_mode: ${{ steps.target.outputs.auth_mode }}
credential_scope: ${{ steps.target.outputs.credential_scope }}
steps:
- name: Resolve pull request metadata
id: target
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
DISPATCH_PR_NUMBER: ${{ github.event.inputs.pull_request_number }}
EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
FORK_REVIEW_MODE: ${{ vars.FORK_REVIEW_MODE || 'manual' }}
CODEX_REVIEW_AUTH_MODE: ${{ vars.CODEX_REVIEW_AUTH_MODE || 'subscription' }}
CODEX_REVIEW_MODE: ${{ vars.CODEX_REVIEW_MODE || 'correctness' }}
ENABLE_CODEX_REVIEW: ${{ vars.ENABLE_CODEX_REVIEW || 'true' }}
REVIEW_API_KEY_CONFIGURED: ${{ secrets.CODEX_REVIEW_API_KEY != '' }}
REVIEW_BASE_URL_CONFIGURED: ${{ secrets.CODEX_REVIEW_BASE_URL != '' }}
CORRECTNESS_API_KEY_CONFIGURED: ${{ secrets.CODEX_CORRECTNESS_API_KEY != '' }}
CORRECTNESS_BASE_URL_CONFIGURED: ${{ secrets.CODEX_CORRECTNESS_BASE_URL != '' }}
ARCHITECTURE_API_KEY_CONFIGURED: ${{ secrets.CODEX_ARCHITECTURE_API_KEY != '' }}
ARCHITECTURE_BASE_URL_CONFIGURED: ${{ secrets.CODEX_ARCHITECTURE_BASE_URL != '' }}
SHARED_API_KEY_CONFIGURED: ${{ secrets.OPENAI_API_KEY != '' }}
SHARED_BASE_URL_CONFIGURED: ${{ secrets.CODEX_BASE_URL != '' }}
REVIEW_EVENT: ${{ github.event_name }}
shell: bash
run: |
set -euo pipefail
case "$FORK_REVIEW_MODE" in
disabled|manual|automatic) ;;
*)
echo "FORK_REVIEW_MODE must be disabled, manual, or automatic." >&2
exit 1
;;
esac
case "$ENABLE_CODEX_REVIEW" in
true|false) ;;
*)
echo "ENABLE_CODEX_REVIEW must be true or false." >&2
exit 1
;;
esac
case "$CODEX_REVIEW_AUTH_MODE" in
api-key|subscription) ;;
*)
echo "CODEX_REVIEW_AUTH_MODE must be api-key or subscription." >&2
exit 1
;;
esac
case "$CODEX_REVIEW_MODE" in
both|correctness|architecture|disabled) ;;
*)
echo "CODEX_REVIEW_MODE must be both, correctness, architecture, or disabled." >&2
exit 1
;;
esac
pr_number="${DISPATCH_PR_NUMBER:-$EVENT_PR_NUMBER}"
if [[ -z "$pr_number" ]]; then
echo "No pull request number available (workflow_dispatch input or pull_request event)." >&2
exit 1
fi
gh pr view "$pr_number" --repo "$GH_REPO" \
--json number,headRefName,headRefOid,baseRefOid,title,isCrossRepository,state,mergeCommit \
> pr.json
state="$(jq -r '.state' pr.json)"
head_sha="$(jq -r '.headRefOid' pr.json)"
review_sha="$head_sha"
if [[ "$state" == "MERGED" ]]; then
review_sha="$(jq -r '.mergeCommit.oid // empty' pr.json)"
if [[ -z "$review_sha" ]]; then
echo "Merged pull request has no merge commit OID." >&2
exit 1
fi
fi
is_fork="$(jq -r '.isCrossRepository' pr.json)"
review_allowed=false
if [[ "$is_fork" != "true" ]] ||
[[ "$REVIEW_EVENT" == "workflow_dispatch" && "$FORK_REVIEW_MODE" != "disabled" ]] ||
[[ "$REVIEW_EVENT" != "workflow_dispatch" && "$FORK_REVIEW_MODE" == "automatic" ]]; then
review_allowed=true
fi
effective_auth_mode="$CODEX_REVIEW_AUTH_MODE"
credential_scope=none
if [[ "$REVIEW_API_KEY_CONFIGURED" == "true" &&
"$REVIEW_BASE_URL_CONFIGURED" == "true" ]]; then
credential_scope=review
elif [[ "$CORRECTNESS_API_KEY_CONFIGURED" == "true" &&
"$CORRECTNESS_BASE_URL_CONFIGURED" == "true" ]]; then
credential_scope=correctness
elif [[ "$ARCHITECTURE_API_KEY_CONFIGURED" == "true" &&
"$ARCHITECTURE_BASE_URL_CONFIGURED" == "true" ]]; then
credential_scope=architecture
elif [[ "$SHARED_API_KEY_CONFIGURED" == "true" &&
"$SHARED_BASE_URL_CONFIGURED" == "true" ]]; then
credential_scope=shared
fi
review_enabled="$ENABLE_CODEX_REVIEW"
if [[ "$REVIEW_EVENT" != "workflow_dispatch" && "$CODEX_REVIEW_MODE" == "disabled" ]]; then
review_enabled=false
fi
{
echo "number=$(jq -r '.number' pr.json)"
echo "head_ref=$(jq -r '.headRefName' pr.json)"
echo "head_sha=$head_sha"
echo "base_sha=$(jq -r '.baseRefOid' pr.json)"
echo "review_sha=$review_sha"
echo "state=$state"
echo "title=$(jq -r '.title' pr.json)"
echo "is_fork=$is_fork"
echo "fork_mode=$FORK_REVIEW_MODE"
echo "review_allowed=$review_allowed"
echo "review_enabled=$review_enabled"
echo "auth_mode=$effective_auth_mode"
echo "credential_scope=$credential_scope"
} >> "$GITHUB_OUTPUT"
codex_review_gate:
name: Check Codex review limits
needs: review_target
if: >-
${{ needs.review_target.outputs.review_allowed == 'true' &&
needs.review_target.outputs.review_enabled == 'true' }}
runs-on: ubuntu-latest
permissions:
issues: read
pull-requests: read
outputs:
should_run: ${{ steps.gate.outputs.should_run }}
steps:
- name: Check Codex review counts
id: gate
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ needs.review_target.outputs.number }}
CODEX_REVIEW_MAX_ROUNDS: ${{ vars.CODEX_REVIEW_MAX_ROUNDS || '20' }}
shell: bash
run: |
set -euo pipefail
max_reviews="$CODEX_REVIEW_MAX_ROUNDS"
if [[ ! "$max_reviews" =~ ^[0-9]+$ ]]; then
echo "CODEX_REVIEW_MAX_ROUNDS must be a non-negative integer." >&2
exit 1
fi
gh api --paginate --slurp \
"repos/${GH_REPO}/issues/${PR_NUMBER}/comments?per_page=100" > comments.json
review_count="$(
jq -r '
[.[][]
| select(.user.login == "github-actions[bot]")
| select((.body // "") | contains("<!-- ai-review:codex -->"))]
| length
' comments.json
)"
round=$((review_count + 1))
if (( max_reviews > 0 && review_count >= max_reviews )); then
echo 'should_run=false' >> "$GITHUB_OUTPUT"
echo "- Codex review skipped: ${review_count} successful reviews already published (limit ${max_reviews})." \
>> "$GITHUB_STEP_SUMMARY"
else
echo 'should_run=true' >> "$GITHUB_OUTPUT"
if (( max_reviews == 0 )); then
echo "- Codex review round ${round} (unlimited)." >> "$GITHUB_STEP_SUMMARY"
else
echo "- Codex review round ${round} of ${max_reviews}." >> "$GITHUB_STEP_SUMMARY"
fi
fi
codex_review:
name: Review
needs: [review_target, codex_review_gate]
if: ${{ needs.codex_review_gate.outputs.should_run == 'true' }}
permissions:
contents: read
uses: ./.github/workflows/ai-codex-review.yml
with:
auth_mode: ${{ needs.review_target.outputs.auth_mode }}
pull_request_number: ${{ needs.review_target.outputs.number }}
head_ref: ${{ needs.review_target.outputs.head_ref }}
head_sha: ${{ needs.review_target.outputs.head_sha }}
base_sha: ${{ needs.review_target.outputs.base_sha }}
review_sha: ${{ needs.review_target.outputs.review_sha }}
review_state: ${{ needs.review_target.outputs.state }}
review_event: ${{ github.event_name }}
pull_request_title: ${{ needs.review_target.outputs.title }}
is_fork: ${{ needs.review_target.outputs.is_fork == 'true' }}
fork_mode: ${{ needs.review_target.outputs.fork_mode }}
model: ${{ vars.CODEX_REVIEW_MODEL || (needs.review_target.outputs.credential_scope == 'correctness' && vars.CODEX_CORRECTNESS_MODEL) || (needs.review_target.outputs.credential_scope == 'architecture' && vars.CODEX_ARCHITECTURE_MODEL) || ((needs.review_target.outputs.credential_scope == 'review' || needs.review_target.outputs.credential_scope == 'shared' || needs.review_target.outputs.credential_scope == 'none') && (vars.CODEX_CORRECTNESS_MODEL || vars.CODEX_ARCHITECTURE_MODEL)) || 'gpt-5.6-sol' }}
effort: ${{ vars.CODEX_REVIEW_EFFORT || (needs.review_target.outputs.credential_scope == 'correctness' && vars.CODEX_CORRECTNESS_EFFORT) || (needs.review_target.outputs.credential_scope == 'architecture' && vars.CODEX_ARCHITECTURE_EFFORT) || ((needs.review_target.outputs.credential_scope == 'review' || needs.review_target.outputs.credential_scope == 'shared' || needs.review_target.outputs.credential_scope == 'none') && (vars.CODEX_CORRECTNESS_EFFORT || vars.CODEX_ARCHITECTURE_EFFORT)) || 'high' }}
secrets:
CODEX_AUTH_JSON: ${{ needs.review_target.outputs.auth_mode == 'subscription' && secrets.CODEX_AUTH_JSON || '' }}
OPENAI_API_KEY: ${{ (needs.review_target.outputs.credential_scope == 'review' && secrets.CODEX_REVIEW_API_KEY) || (needs.review_target.outputs.credential_scope == 'correctness' && secrets.CODEX_CORRECTNESS_API_KEY) || (needs.review_target.outputs.credential_scope == 'architecture' && secrets.CODEX_ARCHITECTURE_API_KEY) || (needs.review_target.outputs.credential_scope == 'shared' && secrets.OPENAI_API_KEY) || '' }}
CODEX_BASE_URL: ${{ (needs.review_target.outputs.credential_scope == 'review' && secrets.CODEX_REVIEW_BASE_URL) || (needs.review_target.outputs.credential_scope == 'correctness' && secrets.CODEX_CORRECTNESS_BASE_URL) || (needs.review_target.outputs.credential_scope == 'architecture' && secrets.CODEX_ARCHITECTURE_BASE_URL) || (needs.review_target.outputs.credential_scope == 'shared' && secrets.CODEX_BASE_URL) || '' }}
post_codex_feedback:
name: Post Codex feedback
needs: codex_review
if: >-
${{ needs.codex_review.result == 'success' &&
needs.codex_review.outputs.review_body != '' }}
uses: ./.github/workflows/ai-post-review.yml
permissions:
issues: write
pull-requests: write
with:
scope: review
marker: '<!-- ai-review:codex -->'
header: '## Codex Review'
review_body: ${{ needs.codex_review.outputs.review_body }}
pull_request_number: ${{ needs.codex_review.outputs.pr_number }}
head_sha: ${{ needs.codex_review.outputs.head_sha }}
max_rounds: ${{ vars.CODEX_REVIEW_MAX_ROUNDS || '20' }}
apply_review_outcome:
name: Apply review outcome label
if: ${{ always() && needs.review_target.result == 'success' }}
needs:
- review_target
- codex_review
- post_codex_feedback
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Apply ready-to-merge from published review outputs
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
PR_NUMBER: ${{ needs.review_target.outputs.number }}
REVIEW_HEAD_SHA: ${{ needs.review_target.outputs.head_sha }}
REVIEW_REQUIRED: ${{ needs.review_target.outputs.review_enabled }}
REVIEW_RESULT: ${{ needs.codex_review.result }}
REVIEW_POST_RESULT: ${{ needs.post_codex_feedback.result }}
REVIEW_POSTED: ${{ needs.post_codex_feedback.outputs.posted }}
REVIEW_BODY: ${{ needs.codex_review.outputs.review_body }}
with:
github-token: ${{ github.token }}
retries: 3
script: |
const issueNumber = Number(process.env.PR_NUMBER);
const reviewedHeadSha = process.env.REVIEW_HEAD_SHA;
const labelName = 'ready-to-merge';
const reviewers = [
{
name: 'Codex review',
header: '## Codex Review',
required: process.env.REVIEW_REQUIRED === 'true',
result: process.env.REVIEW_RESULT,
postResult: process.env.REVIEW_POST_RESULT,
posted: process.env.REVIEW_POSTED,
body: process.env.REVIEW_BODY,
},
];
const removeReadyLabel = async () => {
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
name: labelName,
});
} catch (error) {
if (error.status !== 404) throw error;
}
};
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: issueNumber,
});
if (pullRequest.state !== 'open') {
core.notice('Removing ready-to-merge because the pull request is not open.');
await removeReadyLabel();
return;
}
if (!reviewedHeadSha || pullRequest.head.sha !== reviewedHeadSha) {
core.notice('Skipping labels because a newer pull request commit exists.');
return;
}
const active = reviewers.filter(({ required }) => required);
if (active.length === 0) {
core.warning('No AI reviewer ran; removing ready-to-merge.');
await removeReadyLabel();
return;
}
const unpublished = active.filter(
({ result, postResult, posted }) =>
result !== 'success' || postResult !== 'success' || posted !== 'true',
);
if (unpublished.length > 0) {
const names = unpublished.map(({ name }) => name).join(', ');
core.warning(`Review output was not published for: ${names}; removing ${labelName}.`);
await removeReadyLabel();
return;
}
const verdicts = [];
for (const { name, header, body } of active) {
const matches = [...(body ?? '').matchAll(
/^\*\*Verdict:\s*(mergeable|needs changes)\*\*$/gm,
)];
if (!body?.startsWith(header) || matches.length !== 1) {
core.warning(`No unambiguous verdict output for "${name}"; removing ${labelName}.`);
await removeReadyLabel();
return;
}
verdicts.push(matches[0][1]);
}
if (verdicts.includes('needs changes')) {
core.notice('At least one reviewer requested changes; removing ready-to-merge.');
await removeReadyLabel();
return;
}
try {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: labelName,
color: '1f883d',
description: 'The completed AI reviewer found this pull request mergeable.',
});
} catch (error) {
if (error.status !== 422) throw error;
}
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: [labelName],
});