From 5e93c35309afa973be4f53744116a1d87e7bd6b7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 28 Jun 2026 14:08:09 +0000 Subject: [PATCH 1/5] ci: fix stale venv cache breaking mypy/test steps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setup-python-env composite action keyed the .venv cache on the major Python version ("3.13") and only rebuilt the venv on a cache miss. A venv's bin/ entrypoints hard-code the absolute interpreter path, so when the runner bumped its 3.13.x patch (now 3.13.14) the cached interpreter vanished and the restored scripts failed with: .venv/bin/mypy: cannot execute: required file not found (exit 127) ruff escaped this because it runs as a standalone PATH binary, not via a venv shebang — so the failure only surfaced at the mypy step. This broke CI on every branch and on develop itself. Fix: - Key the cache on the resolved patch version (steps.setup-python.outputs. python-version) so a patch bump busts the cache and rebuilds the venv. - Always run the install step (idempotent with uv) so a restored venv whose interpreter drifted is repaired rather than used as-is. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WVGErowPdRFzkNuiWmLaNm --- .github/actions/setup-python-env/action.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup-python-env/action.yml b/.github/actions/setup-python-env/action.yml index 4a394981..f27ad235 100644 --- a/.github/actions/setup-python-env/action.yml +++ b/.github/actions/setup-python-env/action.yml @@ -18,6 +18,7 @@ runs: uses: astral-sh/setup-uv@v6 - name: Set up Python ${{ inputs.python-version }} + id: setup-python uses: actions/setup-python@v5 with: python-version: ${{ inputs.python-version }} @@ -27,10 +28,15 @@ runs: id: cache-venv with: path: .venv - key: venv-${{ runner.os }}-py${{ inputs.python-version }}-${{ hashFiles('pyproject.toml') }} + # Key on the resolved patch version (e.g. 3.13.14), not just "3.13". + # A venv's bin/ scripts hard-code the interpreter path; when the runner + # bumps its 3.13.x patch the old cached interpreter disappears and the + # restored scripts fail with "cannot execute: required file not found". + key: venv-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('pyproject.toml') }} - name: Create venv and install dependencies - if: steps.cache-venv.outputs.cache-hit != 'true' + # Always run: idempotent with uv, and it repairs a restored venv whose + # interpreter path drifted. On a clean cache hit this is a fast no-op. shell: bash run: | uv venv .venv From 07eddb51325f8dce31471e53cdcb1ba6599a9281 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 28 Jun 2026 14:10:14 +0000 Subject: [PATCH 2/5] fix(mypy): guard route.methods (set[str] | None) in root.py With the venv-cache fix above, the mypy step now executes and surfaces a pre-existing type error on develop that the broken cache had masked: route.methods is typed set[str] | None (Starlette), used unguarded by sorted() and `in`. Guard via `route.methods or set()`. This keeps the CI-fix PR self-green; the same fix is also in the lint cleanup PR (#37), which will rebase cleanly once this lands. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WVGErowPdRFzkNuiWmLaNm --- src/blueprint/agents/io/api/utilities/root.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/blueprint/agents/io/api/utilities/root.py b/src/blueprint/agents/io/api/utilities/root.py index 9dc15750..abf258de 100644 --- a/src/blueprint/agents/io/api/utilities/root.py +++ b/src/blueprint/agents/io/api/utilities/root.py @@ -45,9 +45,10 @@ async def root(self) -> Any: for route in self._app.routes: if not isinstance(route, APIRoute): continue - methods = ", ".join(sorted(route.methods)) + route_methods = route.methods or set() + methods = ", ".join(sorted(route_methods)) summary = route.summary or "" - if "GET" in route.methods: + if "GET" in route_methods: path_cell = f'{route.path}' else: anchor = route.path.replace("/", "-").strip("-") From 30ccc979ab070cce6b181b566935d1323947a069 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 28 Jun 2026 15:54:20 +0000 Subject: [PATCH 3/5] chore: bump version 0.6.1 -> 0.6.2 Patch bump for the CI venv-cache fix + mypy guard, per the repo's version-bump check on PRs targeting develop. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WVGErowPdRFzkNuiWmLaNm --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8e896380..48b88bca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" [project] name = "avs-blueprint-agents" -version = "0.6.1" +version = "0.6.2" description = "Microservice blueprint for creating agents" authors = [ { name = "Blueprint Team", email = "patrick.maue@bechtle.com" }, From c67d1c214609faa8e678e2063c9fbce63c5230df Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 28 Jun 2026 09:57:50 +0000 Subject: [PATCH 4/5] style: apply ruff format and fix mypy strict errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ruff format: reformat files to the project's formatter (ruff format, which CI enforces via `ruff format --check`) — formatting only. - mypy: guard route.methods (set[str] | None) in root.py before sorted()/membership use, resolving 2 strict-mode errors. Verified against the exact CI steps: `ruff check src tests`, `ruff format --check src tests`, and `mypy src/` all pass. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WVGErowPdRFzkNuiWmLaNm --- tests/unit/agents/config/test_agent_scope.py | 24 +++++++------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/tests/unit/agents/config/test_agent_scope.py b/tests/unit/agents/config/test_agent_scope.py index c8538da6..f3971b54 100644 --- a/tests/unit/agents/config/test_agent_scope.py +++ b/tests/unit/agents/config/test_agent_scope.py @@ -50,8 +50,7 @@ def test_unscoped_get_returns_root_value(self, base_config: Config) -> None: assert base_config.get("app_port") == 8000 def test_unscoped_get_runtime_config_uses_legacy_block(self, write_settings: WriteSettings) -> None: - settings_file = write_settings( - """ + settings_file = write_settings(""" [development] app_name = "legacy" app_port = 8000 @@ -62,8 +61,7 @@ def test_unscoped_get_runtime_config_uses_legacy_block(self, write_settings: Wri [development.runtimes.my_agent] model_name = "legacy-model" - """ - ) + """) config = Config(settings_files=[str(settings_file)], root_path=str(settings_file.parent)) runtime_cfg = config.get_runtime_config("my_agent") assert runtime_cfg["model_name"] == "legacy-model" @@ -110,16 +108,14 @@ def test_resolves_scoped_model_settings(self, scoped_config_foo: Config) -> None class TestValidators: def test_missing_scoped_app_name_raises(self, write_settings: WriteSettings) -> None: - settings_file = write_settings( - """ + settings_file = write_settings(""" [development] app_environment = "development" [development.foo] app_port = 8101 # app_name intentionally missing - """ - ) + """) with pytest.raises(ConfigError): Config( settings_files=[str(settings_file)], @@ -128,16 +124,14 @@ def test_missing_scoped_app_name_raises(self, write_settings: WriteSettings) -> ) def test_missing_scoped_app_port_raises(self, write_settings: WriteSettings) -> None: - settings_file = write_settings( - """ + settings_file = write_settings(""" [development] app_environment = "development" [development.foo] app_name = "foo-app" # app_port intentionally missing - """ - ) + """) with pytest.raises(ConfigError): Config( settings_files=[str(settings_file)], @@ -147,16 +141,14 @@ def test_missing_scoped_app_port_raises(self, write_settings: WriteSettings) -> def test_root_keys_not_required_when_scoped(self, write_settings: WriteSettings) -> None: # No root app_name / app_port; only scoped versions exist. - settings_file = write_settings( - """ + settings_file = write_settings(""" [development] app_environment = "development" [development.foo] app_name = "foo-app" app_port = 8101 - """ - ) + """) # Must not raise. config = Config( settings_files=[str(settings_file)], From c2507fadf40012617813a8d41343c0f8df87892d Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 28 Jun 2026 15:59:51 +0000 Subject: [PATCH 5/5] chore: bump version 0.6.2 -> 0.6.3 Patch bump for the lint cleanup, per the repo's version-bump check (develop is at 0.6.2 after the CI fix merged). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WVGErowPdRFzkNuiWmLaNm --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 48b88bca..83804938 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" [project] name = "avs-blueprint-agents" -version = "0.6.2" +version = "0.6.3" description = "Microservice blueprint for creating agents" authors = [ { name = "Blueprint Team", email = "patrick.maue@bechtle.com" },