feat: migrate TTS providers to backend direct routing #50
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Codex PR Review | |
| on: | |
| pull_request_target: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| jobs: | |
| pr-review: | |
| if: | | |
| github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| steps: | |
| - name: Validate OpenAI configuration | |
| run: | | |
| if [ -z "${{ secrets.OPENAI_API_KEY }}" ]; then | |
| echo "::error::Missing required secret OPENAI_API_KEY (Settings → Secrets and variables → Actions)." | |
| exit 1 | |
| fi | |
| - name: Compute Responses API endpoint override (optional) | |
| id: responses_endpoint | |
| shell: bash | |
| run: | | |
| base="${{ secrets.OPENAI_BASE_URL }}" | |
| base="${base%/}" | |
| if [ -z "$base" ]; then | |
| echo "endpoint=" >> "$GITHUB_OUTPUT" | |
| elif [[ "$base" == */responses ]]; then | |
| echo "endpoint=$base" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "endpoint=$base/responses" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout base branch (safe) | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| fetch-depth: 0 | |
| - name: Run Codex review | |
| id: run_codex | |
| uses: openai/codex-action@v1 | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GITHUB_TOKEN: ${{ github.token }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| PR_REPO: ${{ github.repository }} | |
| with: | |
| openai-api-key: ${{ secrets.OPENAI_API_KEY }} | |
| # NOTE: openai/codex-action expects a full Responses endpoint (…/v1/responses). | |
| responses-api-endpoint: ${{ steps.responses_endpoint.outputs.endpoint }} | |
| model: ${{ vars.OPENAI_MODEL || 'gpt-5.2' }} | |
| effort: ${{ vars.OPENAI_EFFORT || 'high' }} | |
| sandbox: read-only | |
| safety-strategy: drop-sudo | |
| prompt-file: .github/prompts/codex-pr-review.md | |
| - name: Validate Codex output | |
| shell: bash | |
| env: | |
| FINAL_MESSAGE: ${{ steps.run_codex.outputs.final-message }} | |
| run: | | |
| if [[ -z "${FINAL_MESSAGE//[[:space:]]/}" ]]; then | |
| echo "::error::Codex returned empty output; failing to avoid passing a required check without a review." | |
| exit 1 | |
| fi | |
| - name: Upsert PR comment | |
| if: steps.run_codex.outputs.final-message != '' | |
| uses: actions/github-script@v7 | |
| env: | |
| REVIEW_BODY: ${{ steps.run_codex.outputs.final-message }} | |
| MARKER: "<!-- codex-pr-review -->" | |
| with: | |
| github-token: ${{ github.token }} | |
| script: | | |
| const marker = process.env.MARKER; | |
| const reviewBody = process.env.REVIEW_BODY || ""; | |
| let body = `${marker}\n${reviewBody}`.trim() + "\n"; | |
| const maxLen = 65000; | |
| if (body.length > maxLen) { | |
| body = | |
| body.slice(0, maxLen - 500) + | |
| "\n\n---\n(Truncated: review output exceeded GitHub comment limit.)\n"; | |
| } | |
| const { owner, repo } = context.repo; | |
| const issue_number = context.payload.pull_request.number; | |
| const comments = await github.paginate( | |
| github.rest.issues.listComments, | |
| { owner, repo, issue_number, per_page: 100 } | |
| ); | |
| const existing = comments.find((c) => { | |
| const isBot = c.user?.type === "Bot"; | |
| return isBot && typeof c.body === "string" && c.body.includes(marker); | |
| }); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner, | |
| repo, | |
| comment_id: existing.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number, | |
| body, | |
| }); | |
| } |