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

Code before:
                    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"],
                )
        self.fastapi_app.add_api_route(
            "/health_check", self.health_check, methods=["POST"]
        )

        self.shared_event_loop = asyncio.get_event_loop()
        if self.use_db:
            self.shared_event_loop.run_until_complete(db.connect())
        if self.use_redis:
            redis.connect()
        if self.rabbitmq_config:
            logger.info(f"[{self.__class__.__name__}] ⏳ Configuring RabbitMQ...")
            self.rabbitmq_service = rabbitmq.AsyncRabbitMQ(self.rabbitmq_config)
            self.shared_event_loop.run_until_complete(self.rabbitmq_service.connect())
        if self.use_supabase:
            from supabase import create_client

            secrets = Secrets()
            self.supabase = create_client(
                secrets.supabase_url, secrets.supabase_service_role_key

Review comment (suggestion):
```suggestion
        for attr_name, attr in vars(type(self)).items():
            if getattr(attr, "__exposed__", False):
                # attr is an exposed method
```

Code after:
            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)

    return custom_dict_to_class


def pyro_exposed_run_and_wait(
    f: Callable[P, Coroutine[None, None, R]]
) -> Callable[Concatenate[object, P], R]:
    @expose
    @wraps(f)
    def wrapper(self, *args: P.args, **kwargs: P.kwargs) -> R:
        coroutine = f(*args, **kwargs)
        res = self.run_and_wait(coroutine)
        return res

    # Register serializers for annotations on bare function
    register_pydantic_serializers(f)

    return wrapper