Skip to content

Commit e48b412

Browse files
Danelegendclaude
andcommitted
feat(health): include service version in /health response
Clients can now read ``version`` from the ``/health`` payload to gate calls to functionality that's only available in newer releases. The value is sourced from the installed package metadata rather than a hardcoded string, so the FastAPI app and the health response stay in sync with the version declared in pyproject.toml. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8d21be9 commit e48b412

3 files changed

Lines changed: 28 additions & 4 deletions

File tree

code-interpreter/app/main.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import logging
55
import subprocess
66
from collections.abc import AsyncGenerator
7-
from contextlib import asynccontextmanager, suppress
7+
from contextlib import asynccontextmanager
8+
from contextlib import suppress
9+
from importlib.metadata import version as _package_version
810
from shutil import which
911
from typing import Final
1012

@@ -25,6 +27,8 @@
2527

2628
logger = logging.getLogger(__name__)
2729

30+
SERVICE_VERSION: Final[str] = _package_version("code-interpreter")
31+
2832

2933
def _ensure_docker_image_available() -> None:
3034
"""Ensure the Docker executor image is available locally.
@@ -123,7 +127,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
123127
def create_app() -> FastAPI:
124128
app = FastAPI(
125129
title="Code Interpreter API",
126-
version="0.1.0",
130+
version=SERVICE_VERSION,
127131
docs_url="/docs",
128132
redoc_url="/redoc",
129133
openapi_url="/openapi.json",
@@ -134,7 +138,11 @@ def create_app() -> FastAPI:
134138
def health() -> HealthResponse:
135139
"""Health check that verifies the executor backend is operational."""
136140
result = get_executor().check_health()
137-
return HealthResponse(status=result.status, message=result.message)
141+
return HealthResponse(
142+
status=result.status,
143+
message=result.message,
144+
version=SERVICE_VERSION,
145+
)
138146

139147
app.include_router(api_router, prefix="/v1")
140148
return app

code-interpreter/app/models/schemas.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ class ListFilesResponse(BaseModel):
120120
class HealthResponse(BaseModel):
121121
status: Literal["ok", "error"]
122122
message: StrictStr | None = None
123+
version: StrictStr = Field(
124+
...,
125+
description=(
126+
"Semver of the running service. Clients can compare against a "
127+
"required minimum to detect whether new functionality is available."
128+
),
129+
)
123130

124131

125132
DEFAULT_SESSION_TTL_SEC = 15 * 60

code-interpreter/tests/integration_tests/test_health.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import pytest
88
from fastapi.testclient import TestClient
99

10-
from app.main import create_app
10+
from app.main import SERVICE_VERSION, create_app
1111
from app.services.executor_base import HealthCheck
1212
from app.services.executor_docker import DockerExecutor
1313
from app.services.executor_factory import get_executor
@@ -29,6 +29,7 @@ def test_health_returns_ok_when_backend_healthy() -> None:
2929
body = response.json()
3030
assert body["status"] == "ok"
3131
assert body["message"] is None
32+
assert body["version"] == SERVICE_VERSION
3233

3334

3435
def test_health_returns_error_when_backend_unhealthy() -> None:
@@ -42,6 +43,14 @@ def test_health_returns_error_when_backend_unhealthy() -> None:
4243
body = response.json()
4344
assert body["status"] == "error"
4445
assert body["message"] == "daemon down"
46+
assert body["version"] == SERVICE_VERSION
47+
48+
49+
def test_health_version_matches_package_metadata() -> None:
50+
"""The version should come from the installed package, not be hardcoded."""
51+
from importlib.metadata import version as package_version
52+
53+
assert package_version("code-interpreter") == SERVICE_VERSION
4554

4655

4756
def _make_completed(returncode: int, stderr: bytes = b"") -> subprocess.CompletedProcess[bytes]:

0 commit comments

Comments
 (0)