From a6d43cba2d194cfca8326b021dbe7d42aba57b61 Mon Sep 17 00:00:00 2001 From: Adam Weidman <65992621+adamfweidman@users.noreply.github.com> Date: Tue, 14 Apr 2026 15:31:48 -0400 Subject: [PATCH] ci: add agent session drift check workflow (#25389) --- .../workflows/agent-session-drift-check.yml | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 .github/workflows/agent-session-drift-check.yml diff --git a/.github/workflows/agent-session-drift-check.yml b/.github/workflows/agent-session-drift-check.yml new file mode 100644 index 0000000000..3601f5ab09 --- /dev/null +++ b/.github/workflows/agent-session-drift-check.yml @@ -0,0 +1,132 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json + +name: 'Agent Session Drift Check' + +on: + pull_request: + branches: + - 'main' + - 'release/**' + paths: + - 'packages/cli/src/nonInteractiveCli.ts' + - 'packages/cli/src/nonInteractiveCliAgentSession.ts' + +concurrency: + group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}' + cancel-in-progress: true + +jobs: + check-drift: + name: 'Check Agent Session Drift' + runs-on: 'ubuntu-latest' + if: "github.repository == 'google-gemini/gemini-cli'" + permissions: + contents: 'read' + pull-requests: 'write' + steps: + - name: 'Detect drift and comment' + uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' # ratchet:actions/github-script@v8 + with: + script: |- + // === Pair configuration — append here to cover more pairs === + const PAIRS = [ + { + legacy: 'packages/cli/src/nonInteractiveCli.ts', + session: 'packages/cli/src/nonInteractiveCliAgentSession.ts', + label: 'non-interactive CLI', + }, + // Future pairs can be added here. Remember to also add both + // paths to the `paths:` filter at the top of this workflow. + // Example: + // { + // legacy: 'packages/core/src/agents/local-invocation.ts', + // session: 'packages/core/src/agents/local-session-invocation.ts', + // label: 'local subagent invocation', + // }, + ]; + // ============================================================ + + const prNumber = context.payload.pull_request.number; + const { owner, repo } = context.repo; + + // Use the API to list changed files — no checkout/git diff needed. + const files = await github.paginate(github.rest.pulls.listFiles, { + owner, + repo, + pull_number: prNumber, + per_page: 100, + }); + const changed = new Set(files.map((f) => f.filename)); + + const warnings = []; + for (const { legacy, session, label } of PAIRS) { + const legacyChanged = changed.has(legacy); + const sessionChanged = changed.has(session); + if (legacyChanged && !sessionChanged) { + warnings.push( + `**${label}**: \`${legacy}\` was modified but \`${session}\` was not.`, + ); + } else if (!legacyChanged && sessionChanged) { + warnings.push( + `**${label}**: \`${session}\` was modified but \`${legacy}\` was not.`, + ); + } + } + + const MARKER = ''; + + // Look up our existing drift comment (for upsert/cleanup). + const comments = await github.paginate(github.rest.issues.listComments, { + owner, + repo, + issue_number: prNumber, + per_page: 100, + }); + const existing = comments.find( + (c) => c.user?.type === 'Bot' && c.body?.includes(MARKER), + ); + + if (warnings.length === 0) { + core.info('No drift detected.'); + // If drift was previously flagged and is now resolved, remove the comment. + if (existing) { + await github.rest.issues.deleteComment({ + owner, + repo, + comment_id: existing.id, + }); + core.info(`Deleted stale drift comment ${existing.id}.`); + } + return; + } + + const body = [ + MARKER, + '### ⚠️ Invocation Drift Warning', + '', + 'The following file pairs should generally be kept in sync during the AgentSession migration:', + '', + ...warnings.map((w) => `- ${w}`), + '', + 'If this is intentional (e.g., a bug fix specific to one implementation), you can ignore this comment.', + '', + '_This check will be removed once the legacy implementations are deleted._', + ].join('\n'); + + if (existing) { + core.info(`Updating existing drift comment ${existing.id}.`); + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existing.id, + body, + }); + } else { + core.info('Creating new drift comment.'); + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body, + }); + }