Repository: Significant-Gravitas/Auto-GPT
File: autogpt_platform/backend/backend/util/service.py (Python)

Code before:
                continue

            # Use the provided annotation or fallback to str if not specified
            annotation = (
                param.annotation if param.annotation != inspect.Parameter.empty else str
            )

            # If a default value is provided, use it; otherwise, mark the field as required with '...'
            default = param.default if param.default != inspect.Parameter.empty else ...

            fields[name] = (annotation, default)

        # Dynamically create a Pydantic model for the request body
        RequestBodyModel = create_model("RequestBodyModel", **fields)
        f = func.__get__(self) if is_bounded_method else func

        if asyncio.iscoroutinefunction(f):

            async def async_endpoint(body: RequestBodyModel):  # type: ignore
                try:
                    return await f(
                        **{name: getattr(body, name) for name in body.model_fields}
                    )
                except Exception as e:
                    logger.exception(f"Error in {func.__name__}: {e}")
                    return responses.JSONResponse(status_code=500, content=e)

            return async_endpoint
        else:

            def sync_endpoint(body: RequestBodyModel):  # type: ignore
                try:
                    return f(
                        **{name: getattr(body, name) for name in body.model_fields}
                    )
                except Exception as e:
                    logger.exception(f"Error in {func.__name__}: {e}")
                    return responses.JSONResponse(status_code=500, content=e)

            return sync_endpoint

    def run(self):
        self.fastapi_app = FastAPI()
        # Register the exposed API routes.
        for attr_name, attr in type(self).__dict__.items():
            if getattr(attr, "__exposed__", False):
                route_path = f"/{attr_name}"
                self.fastapi_app.add_api_route(
                    route_path,
                    self._create_fastapi_endpoint(attr),
                    methods=["POST"],

Review comment (suggestion):
```suggestion
                    raise HTTPException(status_code=500, detail=e)
```

Code after:
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            msg = f"Error in {func.__name__}: {e}"
            if isinstance(e, ValueError):
                logger.warning(msg)
            else:
                logger.exception(msg)
            raise

    register_pydantic_serializers(func)

    return pyro.expose(wrapper)  # type: ignore


def register_pydantic_serializers(func: Callable):
    """Register custom serializers and deserializers for annotated Pydantic models"""
    for name, annotation in func.__annotations__.items():
        try:
            pydantic_types = _pydantic_models_from_type_annotation(annotation)
        except Exception as e:
            raise TypeError(f"Error while exposing {func.__name__}: {e}")

        for model in pydantic_types:
            logger.debug(
                f"Registering Pyro (de)serializers for {func.__name__} annotation "
                f"'{name}': {model.__qualname__}"
            )
            pyro.register_class_to_dict(model, _make_custom_serializer(model))
            pyro.register_dict_to_class(
                model.__qualname__, _make_custom_deserializer(model)
            )


def _make_custom_serializer(model: Type[BaseModel]):
    def custom_class_to_dict(obj):
        data = {
            "__class__": obj.__class__.__qualname__,
            **obj.model_dump(),
        }
        logger.debug(f"Serializing {obj.__class__.__qualname__} with data: {data}")
        return data

    return custom_class_to_dict


def _make_custom_deserializer(model: Type[BaseModel]):
    def custom_dict_to_class(qualname, data: dict):
        logger.debug(f"Deserializing {model.__qualname__} from data: {data}")
        return model(**data)