refactor(settings): split agent and conversation settings schemas #1703
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: REST API breakage checks | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| jobs: | |
| agent-server-rest-api: | |
| name: REST API (OpenAPI) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| enable-cache: true | |
| - name: Install workspace deps (dev) | |
| run: uv sync --frozen --group dev | |
| - name: Install oasdiff | |
| run: | | |
| curl -L https://raw.githubusercontent.com/oasdiff/oasdiff/main/install.sh | sh -s -- -b /usr/local/bin | |
| oasdiff --version | |
| - name: Run agent server REST API breakage check | |
| id: api_breakage | |
| # Let this step fail so CI is visibly red on breakage. | |
| # Later reporting steps still run because they use if: always(). | |
| run: | | |
| uv run --with packaging python .github/scripts/check_agent_server_rest_api_breakage.py 2>&1 | tee api-breakage.log | |
| exit_code=${PIPESTATUS[0]} | |
| echo "exit_code=${exit_code}" >> "$GITHUB_OUTPUT" | |
| exit "${exit_code}" | |
| - name: Write REST API breakage summary | |
| if: ${{ always() }} | |
| env: | |
| EXIT_CODE: ${{ steps.api_breakage.outputs.exit_code }} | |
| IS_FORK: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }} | |
| LOG_PATH: api-breakage.log | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| run: | | |
| python3 <<'PY' >> "$GITHUB_STEP_SUMMARY" | |
| import os | |
| from pathlib import Path | |
| exit_code = int(os.environ.get('EXIT_CODE', '0') or '0') | |
| is_fork = os.environ.get('IS_FORK', 'false') == 'true' | |
| run_url = os.environ['RUN_URL'] | |
| status = '✅ **PASSED**' if exit_code == 0 else '❌ **FAILED**' | |
| print(f'## REST API breakage checks (OpenAPI) — {status}') | |
| print() | |
| print(f"**Result:** {status}") | |
| if exit_code != 0: | |
| print() | |
| print('> ⚠️ Breaking REST API changes or policy violations detected.') | |
| print() | |
| if is_fork: | |
| print( | |
| '_Fork PR detected: sticky PR comment was skipped because ' | |
| 'the GitHub token is read-only for `pull_request` workflows ' | |
| 'from forks._' | |
| ) | |
| print() | |
| if exit_code != 0: | |
| try: | |
| log = Path(os.environ['LOG_PATH']).read_text() | |
| except Exception as exc: | |
| log = f'Unable to read log file: {exc}' | |
| excerpt = log[:1000].replace('```', '``\\`') | |
| print('<details><summary>Log excerpt (first 1000 characters)</summary>') | |
| print() | |
| print('```text') | |
| print(excerpt) | |
| print('```') | |
| print() | |
| print('</details>') | |
| print() | |
| print(f'[Action log]({run_url})') | |
| PY | |
| - name: Post REST API breakage report to PR | |
| if: ${{ always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }} | |
| uses: actions/github-script@v8 | |
| env: | |
| EXIT_CODE: ${{ steps.api_breakage.outputs.exit_code }} | |
| LOG_PATH: api-breakage.log | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const marker = '<!-- agent-server-rest-api-breakage-report -->'; | |
| const exitCode = Number(process.env.EXIT_CODE || '0'); | |
| const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | |
| const status = exitCode === 0 ? '✅ **PASSED**' : '❌ **FAILED**'; | |
| let body = `${marker}\n## REST API breakage checks (OpenAPI) — ${status}\n\n**Result:** ${status}\n`; | |
| if (exitCode !== 0) { | |
| body += `\n> ⚠️ Breaking REST API changes or policy violations detected.\n`; | |
| let log = ''; | |
| try { | |
| log = fs.readFileSync(process.env.LOG_PATH, 'utf8'); | |
| } catch (e) { | |
| log = `Unable to read log file: ${e}`; | |
| } | |
| const excerpt = log.slice(0, 1000).replace(/```/g, '``\\`'); | |
| body += `\n<details><summary>Log excerpt (first 1000 characters)</summary>\n\n\`\`\`text\n${excerpt}\n\`\`\`\n\n</details>\n`; | |
| } | |
| body += `\n[Action log](${runUrl})\n`; | |
| const { owner, repo } = context.repo; | |
| const issue_number = context.issue.number; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner, | |
| repo, | |
| issue_number, | |
| per_page: 100, | |
| }); | |
| const existing = comments.find((c) => c.body && 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, | |
| }); | |
| } |