diff --git a/.github/workflows/agents-auto-pilot.yml b/.github/workflows/agents-auto-pilot.yml index 4e09ad429..c656587a5 100644 --- a/.github/workflows/agents-auto-pilot.yml +++ b/.github/workflows/agents-auto-pilot.yml @@ -238,8 +238,7 @@ jobs: if: steps.check_enabled.outputs.enabled == 'true' run: | python -m pip install --upgrade pip - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - pip install -r tools/requirements-llm.txt + python -m pip install -r tools/requirements-llm.txt - name: Initialize auto-pilot metrics logs if: steps.check_enabled.outputs.enabled == 'true' diff --git a/.github/workflows/agents-issue-optimizer.yml b/.github/workflows/agents-issue-optimizer.yml index 12e5d211e..d4cba6550 100644 --- a/.github/workflows/agents-issue-optimizer.yml +++ b/.github/workflows/agents-issue-optimizer.yml @@ -130,10 +130,7 @@ jobs: if: steps.check.outputs.should_run == 'true' run: | python -m pip install --upgrade pip - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - # Install langchain dependencies - pip install langchain langchain-core langchain-openai \ - langchain-anthropic langchain-community + python -m pip install -r tools/requirements-llm.txt - name: Check optimizer recursion guard if: steps.check.outputs.should_run == 'true' diff --git a/agents/codex-1447.md b/agents/codex-1447.md index ee145ee3f..79a0084b1 100644 --- a/agents/codex-1447.md +++ b/agents/codex-1447.md @@ -1,5 +1,5 @@ diff --git a/config/template-drift-allowlist.txt b/config/template-drift-allowlist.txt index 4f1fba9d1..e95432670 100644 --- a/config/template-drift-allowlist.txt +++ b/config/template-drift-allowlist.txt @@ -93,9 +93,9 @@ reason = Intentional divergence re-baselined 2026-06-30: root and consumer guard [pair.11] main = .github/workflows/agents-issue-optimizer.yml template = templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml -main_sha256 = 26806e76cd620e227c81566f4db0cb9a4eca2ddd4c3e05a941d2c4072b2fe3b5 -template_sha256 = ea5a33238a2dfc8bbc5e4661f66751dde1e9ca853b2cf77ed4eb286865fb9c93 -reason = Intentional divergence (re-baselined 2026-06-14): consumer template SHA-pins third-party actions per the fleet action-pin contract (docs/HISTORY.md, PR #1925) and sets LangSmith tracing env; root uses floating major tags with repo-internal concurrency + sparse-checkout (docs/fixes/sparse-checkout-audit-2026-02-03.csv). Fingerprints refreshed after #2391/#2394 bumps. Do not align: would strip consumer action pins. +main_sha256 = 1e2fb1b588d00f694fd9d02816944e68a4d1a8041f4f052730b1f30f3ad696db +template_sha256 = bbd9d30e392d3df884ebabd9738fcd5864d79754dcfc04068466132e4c2e769d +reason = Intentional divergence re-baselined 2026-07-07: root and consumer issue-optimizer workflows keep different auth plumbing/action pin surfaces, but both now use the pinned tools/requirements-llm.txt install path with python -m pip. Do not align wholesale because that would strip consumer action pins/token setup. [pair.12] main = .github/workflows/agents-keepalive-loop-reporter.yml diff --git a/docs/workflow-snippets/agents-auto-pilot-install.yml b/docs/workflow-snippets/agents-auto-pilot-install.yml index ee970d967..a50290991 100644 --- a/docs/workflow-snippets/agents-auto-pilot-install.yml +++ b/docs/workflow-snippets/agents-auto-pilot-install.yml @@ -2,5 +2,4 @@ if: steps.check_enabled.outputs.enabled == 'true' run: | python -m pip install --upgrade pip - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - pip install -r tools/requirements-llm.txt + python -m pip install -r tools/requirements-llm.txt diff --git a/docs/workflow-updates/README.md b/docs/workflow-updates/README.md index 247f17ccd..d79c46187 100644 --- a/docs/workflow-updates/README.md +++ b/docs/workflow-updates/README.md @@ -7,19 +7,23 @@ This folder contains YAML snippets that must be manually applied to protected Gi 3. Insert the cache step from `docs/workflow-updates/agents-auto-pilot-changes.yml` immediately after the updated `Set up Python` step. 4. Replace the existing `Install Python dependencies` step with the install step from `docs/workflow-updates/agents-auto-pilot-changes.yml`. -5. Open `.github/workflows/reusable-agents-verifier.yml`. -6. Update the existing `Setup Python for LLM evaluation` step to include `id: setup-python-evaluate`. -7. Insert the evaluate-mode cache step from `docs/workflow-updates/reusable-agents-verifier-changes.yml` immediately after that setup step. -8. Replace the existing `Install LLM evaluation dependencies` step with the evaluate install step from `docs/workflow-updates/reusable-agents-verifier-changes.yml`. +5. Open `.github/workflows/agents-issue-optimizer.yml`. +6. Confirm the `Install dependencies` step uses `python -m pip install -r tools/requirements-llm.txt` and does not install unpinned `langchain` packages. -9. Update the existing `Setup Python for comparison` step to include `id: setup-python-compare`. -10. Insert the compare-mode cache step from `docs/workflow-updates/reusable-agents-verifier-changes.yml` immediately after that setup step. -11. Replace the existing `Install comparison dependencies` step with the compare install step from `docs/workflow-updates/reusable-agents-verifier-changes.yml`. +7. Open `.github/workflows/reusable-agents-verifier.yml`. +8. Update the existing `Setup Python for LLM evaluation` step to include `id: setup-python-evaluate`. +9. Insert the evaluate-mode cache step from `docs/workflow-updates/reusable-agents-verifier-changes.yml` immediately after that setup step. +10. Replace the existing `Install LLM evaluation dependencies` step with the evaluate install step from `docs/workflow-updates/reusable-agents-verifier-changes.yml`. + +11. Update the existing `Setup Python for comparison` step to include `id: setup-python-compare`. +12. Insert the compare-mode cache step from `docs/workflow-updates/reusable-agents-verifier-changes.yml` immediately after that setup step. +13. Replace the existing `Install comparison dependencies` step with the compare install step from `docs/workflow-updates/reusable-agents-verifier-changes.yml`. **Verification** -1. Confirm `.github/workflows/agents-auto-pilot.yml` contains `pip install -r tools/requirements-llm.txt` and no unpinned `langchain` install commands. -2. Confirm `.github/workflows/reusable-agents-verifier.yml` contains `pip install -r .workflows-lib/tools/requirements-llm.txt` in both evaluate and compare paths. -3. Confirm both workflows include `actions/cache@v4` steps with keys that include `python-version` and the relevant `hashFiles(...)` call. +1. Confirm `.github/workflows/agents-auto-pilot.yml` contains `python -m pip install -r tools/requirements-llm.txt` and no unpinned `langchain` install commands. +2. Confirm `.github/workflows/agents-issue-optimizer.yml` contains `python -m pip install -r tools/requirements-llm.txt` and no unpinned `langchain` install commands. +3. Confirm `.github/workflows/reusable-agents-verifier.yml` contains `pip install -r .workflows-lib/tools/requirements-llm.txt` in both evaluate and compare paths. +4. Confirm both cached workflows include `actions/cache@v4` steps with keys that include `python-version` and the relevant `hashFiles(...)` call. **Notes** The cache key format uses `steps..outputs.python-version`, so the `id` additions are required for the cache key to include the Python version. diff --git a/docs/workflow-updates/agents-auto-pilot-changes.yml b/docs/workflow-updates/agents-auto-pilot-changes.yml index 1538aec34..267ae8587 100644 --- a/docs/workflow-updates/agents-auto-pilot-changes.yml +++ b/docs/workflow-updates/agents-auto-pilot-changes.yml @@ -16,5 +16,4 @@ if: steps.check_enabled.outputs.enabled == 'true' run: | python -m pip install --upgrade pip - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - pip install -r tools/requirements-llm.txt + python -m pip install -r tools/requirements-llm.txt diff --git a/scripts/check_test_dependencies.sh b/scripts/check_test_dependencies.sh index 4fbb01d93..1aeacc185 100755 --- a/scripts/check_test_dependencies.sh +++ b/scripts/check_test_dependencies.sh @@ -131,7 +131,11 @@ if [ "$all_ok" = true ]; then echo -e "${GREEN}All required dependencies are available!${NC}" echo "" echo "You can run the full test suite with:" - echo " ./scripts/run_tests.sh" + if [ -x ./scripts/run_tests.sh ]; then + echo " ./scripts/run_tests.sh" + else + echo " python -m pytest" + fi exit 0 else echo -e "${RED}Some required dependencies are missing!${NC}" diff --git a/scripts/generate_llm_workflow_update_comment.py b/scripts/generate_llm_workflow_update_comment.py index 623aef98c..6861ad248 100755 --- a/scripts/generate_llm_workflow_update_comment.py +++ b/scripts/generate_llm_workflow_update_comment.py @@ -9,6 +9,7 @@ DEFAULT_WORKFLOWS = ( Path(".github/workflows/agents-auto-pilot.yml"), + Path(".github/workflows/agents-issue-optimizer.yml"), Path(".github/workflows/reusable-agents-verifier.yml"), ) @@ -54,9 +55,10 @@ def _build_label_line(include_label: bool) -> list[str]: def _build_main_body() -> str: """Build the main instruction body of the comment.""" return ( - "Workflow updates required in .github/workflows/agents-auto-pilot.yml and " + "Workflow updates required in .github/workflows/agents-auto-pilot.yml, " + ".github/workflows/agents-issue-optimizer.yml, and " ".github/workflows/reusable-agents-verifier.yml. Add pinned installs " - "(`pip install -r tools/requirements-llm.txt` and " + "(`python -m pip install -r tools/requirements-llm.txt` and " "`pip install -r .workflows-lib/tools/requirements-llm.txt` for evaluate/compare), " "add actions/cache@v4 pip cache keyed by requirements hash + Python version, " "and remove any floating `pip install langchain*` lines. Workflow edits require " diff --git a/templates/consumer-repo/.github/workflows/agents-auto-pilot.yml b/templates/consumer-repo/.github/workflows/agents-auto-pilot.yml index 4e09ad429..c656587a5 100644 --- a/templates/consumer-repo/.github/workflows/agents-auto-pilot.yml +++ b/templates/consumer-repo/.github/workflows/agents-auto-pilot.yml @@ -238,8 +238,7 @@ jobs: if: steps.check_enabled.outputs.enabled == 'true' run: | python -m pip install --upgrade pip - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - pip install -r tools/requirements-llm.txt + python -m pip install -r tools/requirements-llm.txt - name: Initialize auto-pilot metrics logs if: steps.check_enabled.outputs.enabled == 'true' diff --git a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml index 51baab12e..7d402819f 100644 --- a/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml +++ b/templates/consumer-repo/.github/workflows/agents-issue-optimizer.yml @@ -147,10 +147,7 @@ jobs: if: steps.check.outputs.should_run == 'true' run: | python -m pip install --upgrade pip - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - # Install langchain dependencies - pip install langchain langchain-core langchain-openai \ - langchain-anthropic langchain-community + python -m pip install -r workflows-scripts/tools/requirements-llm.txt - name: Check optimizer recursion guard if: steps.check.outputs.should_run == 'true' diff --git a/tests/docs/test_workflow_snippets_yaml.py b/tests/docs/test_workflow_snippets_yaml.py index 146961652..6cf541463 100644 --- a/tests/docs/test_workflow_snippets_yaml.py +++ b/tests/docs/test_workflow_snippets_yaml.py @@ -63,21 +63,38 @@ def test_install_snippets_reference_requirements_llm( snippet_path: Path, requirements_path: str ) -> None: contents = snippet_path.read_text(encoding="utf-8") - assert requirements_path in contents + expected_commands = { + f"pip install -r {requirements_path}", + f"python -m pip install -r {requirements_path}", + } + assert any(command in contents for command in expected_commands), ( + f"Expected {snippet_path} to include one of " f"{sorted(expected_commands)!r}" + ) parsed = yaml.safe_load(contents) assert isinstance(parsed, list), f"{snippet_path} should contain a YAML list" assert any( isinstance(step, dict) and isinstance(step.get("run"), str) - and any( - line.strip() == f"pip install -r {requirements_path}" - for line in step["run"].splitlines() - ) + and any(line.strip() in expected_commands for line in step["run"].splitlines()) for step in parsed ), f"Expected install snippet to include pip install for {requirements_path}" +def test_install_snippets_keep_literal_expected_commands() -> None: + auto_pilot_text = Path("docs/workflow-snippets/agents-auto-pilot-install.yml").read_text( + encoding="utf-8" + ) + verifier_text = Path("docs/workflow-snippets/reusable-agents-verifier-install.yml").read_text( + encoding="utf-8" + ) + auto_pilot_command = "python -m pip install -r tools/requirements-llm.txt" + verifier_command = "pip install -r .workflows-lib/tools/requirements-llm.txt" + + assert auto_pilot_text.count(auto_pilot_command) == 1 + assert verifier_text.count(verifier_command) == 2 + + def test_pip_freeze_step_runs_python_module() -> None: snippet_path = Path("docs/workflow-snippets/pip-freeze-step.yml") parsed = yaml.safe_load(snippet_path.read_text(encoding="utf-8")) diff --git a/tests/scripts/test_generate_llm_workflow_update_comment.py b/tests/scripts/test_generate_llm_workflow_update_comment.py index 6b0516f8e..13d742bd5 100644 --- a/tests/scripts/test_generate_llm_workflow_update_comment.py +++ b/tests/scripts/test_generate_llm_workflow_update_comment.py @@ -21,6 +21,7 @@ def test_build_comment_includes_label_and_requirements() -> None: assert "Label: needs-human" in comment assert ".github/workflows/agents-auto-pilot.yml" in comment + assert ".github/workflows/agents-issue-optimizer.yml" in comment assert ".github/workflows/reusable-agents-verifier.yml" in comment assert "pip install -r tools/requirements-llm.txt" in comment assert "pip install -r .workflows-lib/tools/requirements-llm.txt" in comment @@ -34,6 +35,7 @@ def test_build_comment_lists_default_workflows() -> None: assert "Affected workflows:" in comment assert "- .github/workflows/agents-auto-pilot.yml" in comment + assert "- .github/workflows/agents-issue-optimizer.yml" in comment assert "- .github/workflows/reusable-agents-verifier.yml" in comment @@ -47,6 +49,7 @@ def test_build_comment_preserves_output_without_notes() -> None: assert "Workflow updates required" in comment assert "Affected workflows:" in comment assert "- .github/workflows/agents-auto-pilot.yml" in comment + assert "- .github/workflows/agents-issue-optimizer.yml" in comment assert "- .github/workflows/reusable-agents-verifier.yml" in comment # Verify no notes section is added assert "Notes:" not in comment @@ -123,6 +126,7 @@ def test_build_main_body() -> None: """Test main body generation.""" body = _build_main_body() assert "Workflow updates required" in body + assert ".github/workflows/agents-issue-optimizer.yml" in body assert "pip install -r tools/requirements-llm.txt" in body assert "agent-high-privilege" in body diff --git a/tests/workflows/test_workflow_llm_installs.py b/tests/workflows/test_workflow_llm_installs.py index 3da237732..430cc05a7 100644 --- a/tests/workflows/test_workflow_llm_installs.py +++ b/tests/workflows/test_workflow_llm_installs.py @@ -13,6 +13,7 @@ WORKFLOWS_DIR = Path(".github/workflows") AUTO_PILOT = WORKFLOWS_DIR / "agents-auto-pilot.yml" +ISSUE_OPTIMIZER = WORKFLOWS_DIR / "agents-issue-optimizer.yml" VERIFIER = WORKFLOWS_DIR / "reusable-agents-verifier.yml" REUSABLE_CODEX_RUN = WORKFLOWS_DIR / "reusable-codex-run.yml" REUSABLE_CLAUDE_RUN = WORKFLOWS_DIR / "reusable-claude-run.yml" @@ -191,12 +192,22 @@ def test_agents_auto_pilot_llm_install_is_pinned() -> None: text = _load_text(AUTO_PILOT) _assert_pinned_install( text, - "pip install -r tools/requirements-llm.txt", + "python -m pip install -r tools/requirements-llm.txt", AUTO_PILOT.name, ) _assert_no_floating_langchain(text, AUTO_PILOT.name) +def test_agents_issue_optimizer_llm_install_is_pinned() -> None: + text = _load_text(ISSUE_OPTIMIZER) + _assert_pinned_install( + text, + "python -m pip install -r tools/requirements-llm.txt", + ISSUE_OPTIMIZER.name, + ) + _assert_no_floating_langchain(text, ISSUE_OPTIMIZER.name) + + def test_agents_auto_pilot_pip_cache_is_configured() -> None: if os.environ.get("AGENT_ENV", "agent-standard") != "agent-high-privilege": pytest.skip("needs-human: workflow updates require agent-high-privilege") @@ -295,6 +306,7 @@ def test_workflow_llm_needs_human_comment_documents_blocker() -> None: required_phrases = [ "Label: needs-human", ".github/workflows/agents-auto-pilot.yml", + ".github/workflows/agents-issue-optimizer.yml", ".github/workflows/reusable-agents-verifier.yml", ACTIONS_CACHE_V6_REF, "tools/requirements-llm.txt",