Skip to content

[Enhancement] Read‑Only Production Mode #367

@mc-dorzo

Description

@mc-dorzo

Motivation

In production we must guarantee that an agent’s behavior cannot be altered through the public API.

A first‑class read‑only mode gives ops teams an “immutable” deployment switch, preventing any call that could change runtime behavior or stored state.

Solution Proposal

  1. Enum for mode:
  class ServerMode(Enum):
      """Server operation modes."""
      DEVELOPMENT = "development"
      PRODUCTION = "production"
  1. Create middleware for ProductionMode
class ProductionAccessMiddleware(BaseHTTPMiddleware):
    def __init__(
        self,
        app: FastAPI,
        mode: ServerMode,
    ):
        super().__init__(app)
        self.is_prod = mode == ServerMode.PRODUCTION

    async def dispatch(
        self,
        request: Request,
        call_next: Callable[[Request], Awaitable[Response]],
    ) -> Response:
        path = request.url.path
        method = request.method

        for route in request.app.routes:
            if hasattr(route, "path_regex") and hasattr(route, "methods"):
                if route.path_regex.match(path) and method in route.methods:
                    openapi_extras = getattr(route, "openapi_extra", {})
                    mode = openapi_extras["mode"]

                    if self.is_prod and mode == ServerMode.DEVELOPMENT:
                        raise HTTPException(status_code=404)
                    break

        return await call_next(request)
  1. rename apigen_config to api_config function, and add mode like so:
def api_config(
    group_name: str,
    method_name: str,
    mode: ServerMode = ServerMode.PRODUCTION,
) -> Mapping[str, Any]:
    return {
        "openapi_extra": {
            "x-fern-sdk-group-name": group_name,
            "x-fern-sdk-method-name": method_name,
            "mode": mode,
        }
    }
  1. add to each endpoint e.g.

e.g.

 @router.post(
        "",
        status_code=status.HTTP_201_CREATED,
        operation_id="create_agent",
        response_model=AgentDTO,
        responses={
            status.HTTP_201_CREATED: {
                "description": "Agent successfully created. Returns the complete agent object including generated ID.",
                "content": example_json_content(agent_example),
            },
            status.HTTP_422_UNPROCESSABLE_ENTITY: {
                "description": "Validation error in request parameters"
            },
        },
        **api_config(
            group_name=API_GROUP,
            method_name="create",
            mode=ServerMode.DEVELOPMENT,
        ),
    )
    async def create_agent(
        params: AgentCreationParamsDTO,
    ) -> AgentDTO: ...
  1. add --producton/deployment/read-mode flag

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions