Repository: ray-project/ray
File: python/ray/llm/examples/sglang/modules/sglang_engine.py (Python)

Code before:
        prompt_lines: List[str] = []
        for message in messages:
            role = str(message.get("role", "user"))
            content = message.get("content", "")
            if content is None:
                content = ""
            prompt_lines.append(f"{role}: {content}")
        prompt_lines.append("assistant:")
        return "\n".join(prompt_lines)

    async def start(self) -> None:
        # Engine is initialized in __init__; keep start idempotent for protocol
        # compatibility.
        return

    async def check_health(self) -> None:
        if not hasattr(self, "engine") or self.engine is None:
            raise RuntimeError("SGLang engine is not initialized.")

        engine_check_health = getattr(self.engine, "check_health", None)
        if callable(engine_check_health):
            maybe_awaitable = engine_check_health()
            if inspect.isawaitable(maybe_awaitable):
                await maybe_awaitable

    async def _generate_and_extract_metadata(
        self,
        request: Any,
        prompt: Any,
    ) -> dict[str, Any]:
        """
        Handles parameter extraction, calls the SGLang engine, and processes the
        raw response to extract common metadata and generated text.
        """
        sampling_params = self._build_sampling_params(request)
        generate_kwargs = {
            "prompt": prompt,
            "sampling_params": sampling_params,
            "stream": False,
        }

        raw = await self.engine.async_generate(**generate_kwargs)

        if isinstance(raw, list):
            if not raw:
                raise RuntimeError(
                    "SGLang engine returned an empty response list during generation."
                )
            raw = raw[0]

        text: str = raw.get("text", "")

Review comment (refactor):
In the future we may want to change this to integrate with SGLang at a different layer.

But for now, let's refactor so the function returns the `self.engine.async_generate(**generate_kwargs)` outputs, which can be piped into specific helper functions to create `ChatCompletionResponse`, `CompletionResponse`, etc.

Code after:
    @staticmethod
    def _extract_generation_metadata(raw: dict[str, Any]) -> dict[str, Any]:
        """Extract normalized generation metadata from one raw engine payload."""
        text: str = raw.get("text", "")
        meta: dict[str, Any] = raw.get("meta_info", {}) or {}
        finish_reason_info = meta.get("finish_reason", {}) or {}

        if isinstance(finish_reason_info, dict):
            finish_reason = finish_reason_info.get("type", "length")
        else:
            finish_reason = str(finish_reason_info)

        prompt_tokens = int(meta.get("prompt_tokens", 0))
        completion_tokens = int(meta.get("completion_tokens", 0))
        total_tokens = prompt_tokens + completion_tokens

        return {
            "text": text.strip(),
            "id": meta.get("id", f"sglang-gen-{int(time.time())}"),
            "created": int(time.time()),
            "finish_reason": finish_reason,
            "prompt_tokens": prompt_tokens,
            "completion_tokens": completion_tokens,
            "total_tokens": total_tokens,
        }

    async def _generate_and_extract_metadata(
        self,
        request: Any,
        prompt: Any,
    ) -> dict[str, Any]:
        """
        Handles parameter extraction, calls the SGLang engine, and processes the
        raw response to extract common metadata and generated text.
        """
        raw = await self._generate_raw(request, prompt)
        if isinstance(raw, list):
            if not raw:
                raise RuntimeError(
                    "SGLang engine returned an empty response list during generation."
                )
            raw = raw[0]
        return self._extract_generation_metadata(raw)

    async def chat(
        self,
        request: ChatCompletionRequest,
        raw_request_info: Optional[RawRequestInfo] = None,
    ) -> AsyncGenerator[ChatCompletionResponse, None]:
        chat_messages = self._build_chat_messages(request.messages)
        prompt = self._render_chat_prompt(request, chat_messages)