Skip to content

feat: add smg-grpc-servicer package - #638

Merged
CatherineSue merged 18 commits into
mainfrom
chang/grpc-servicer
Mar 5, 2026
Merged

CatherineSue merged 18 commits into
mainfrom
chang/grpc-servicer

Conversation

@CatherineSue

@CatherineSue CatherineSue commented Mar 5, 2026 •

Copy link
Copy Markdown
Member

Description

Problem

The gRPC servicer code (VllmEngineServicer + server launcher) currently lives inside the vLLM repo, tightly coupled to their release cycle. We need to control our own release cadence for the gRPC layer independently.

Solution

Extract the servicer into a standalone PyPI package smg-grpc-servicer that depends on vllm and smg-grpc-proto. vLLM gains a --grpc flag (vllm serve --grpc) that lazy-imports from this package. No circular dependency — vLLM optionally depends on smg-grpc-servicer at runtime.

Changes

  • grpc_servicer/ — New Python package (smg-grpc-servicer v0.4.2)
    • smg_grpc_servicer/vllm/servicer.py — VllmEngineServicer (copied from vLLM, updated imports to use smg_grpc_proto)
    • smg_grpc_servicer/vllm/server.py — serve_grpc() launcher + standalone main()
    • pyproject.toml — Dependencies: smg-grpc-proto>=0.4.2, vllm>=0.16.0, grpcio>=1.78.0
  • .github/workflows/release-grpc-servicer.yml — PyPI release workflow with workflow_run sequencing (waits for proto release if both change)
  • scripts/ci_install_vllm.sh — Install grpc packages from source for CI testing
  • grpc_servicer/README.md and DEVELOPMENT.md — Usage and release workflow docs

Companion vLLM PR: adds --grpc flag, removes old vllm/grpc/ and vllm/entrypoints/grpc_server.py.

Test Plan

Manually tested vllm serve --grpc with gpt-oss-20b on 4xGPU. Screenshots attached below.

  • gpt-oss
Screenshot 2026-03-04 at 7 59 10 PM
  • qwen3
Screenshot 2026-03-04 at 7 59 53 PM
  • n>1
Screenshot 2026-03-04 at 8 34 02 PM
  • logprobs
curl request
curl http://localhost:3002/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "/raid/models/Qwen/Qwen3-VL-8B-Instruct",
    "messages": [
      {
        "role": "user",
        "content": "What is the capital of France? Answer in a few words."
      }
    ],
    "max_tokens": 200,
    "ignore_eos": false,
    "temperature": 0,
    "stream": false,
    "top_p": 0.75,
    "top_k": 2,
    "logprobs": true,
    "top_logprobs": 5
  }' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1653  100  1283  100   370  57722  16646 --:--:-- --:--:-- --:--:-- 75136
{
  "id": "chatcmpl-019cbc3c-d06d-70e2-aaa6-d6d078a23f55",
  "object": "chat.completion",
  "created": 1772684628,
  "model": "/raid/models/Qwen/Qwen3-VL-8B-Instruct",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Paris",
        "reasoning_content": null
      },
      "logprobs": {
        "content": [
          {
            "token": "Paris",
            "logprob": -2.7418098e-06,
            "bytes": [
              80,
              97,
              114,
              105,
              115
            ],
            "top_logprobs": [
              {
                "token": "Paris",
                "logprob": -2.7418098e-06,
                "bytes": [
                  80,
                  97,
                  114,
                  105,
                  115
                ]
              },
              {
                "token": " Paris",
                "logprob": -13.000003,
                "bytes": [
                  32,
                  80,
                  97,
                  114,
                  105,
                  115
                ]
              },
              {
                "token": "巴黎",
                "logprob": -14.500003,
                "bytes": [
                  229,
                  183,
                  180,
                  233,
                  187,
                  142
                ]
              },
              {
                "token": "Par",
                "logprob": -17.250002,
                "bytes": [
                  80,
                  97,
                  114
                ]
              },
              {
                "token": "PAR",
                "logprob": -21.500002,
                "bytes": [
                  80,
                  65,
                  82
                ]
              }
            ]
          },
          {
            "token": "<|im_end|>",
            "logprob": -2.8610189e-06,
            "bytes": [
              60,
              124,
              105,
              109,
              95,
              101,
              110,
              100,
              124,
              62
            ],
            "top_logprobs": [
              {
                "token": "<|im_end|>",
                "logprob": -2.8610189e-06,
                "bytes": [
                  60,
                  124,
                  105,
                  109,
                  95,
                  101,
                  110,
                  100,
                  124,
                  62
                ]
              },
              {
                "token": ".",
                "logprob": -12.750003,
                "bytes": [
                  46
                ]
              },
              {
                "token": "\n\n",
                "logprob": -20.875002,
                "bytes": [
                  10,
                  10
                ]
              },
              {
                "token": " is",
                "logprob": -25.875002,
                "bytes": [
                  32,
                  105,
                  115
                ]
              },
              {
                "token": "\n",
                "logprob": -26.750002,
                "bytes": [
                  10
                ]
              }
            ]
          }
        ]
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 21,
    "completion_tokens": 2,
    "total_tokens": 23,
    "prompt_tokens_details": {
      "cached_tokens": 16
    }
  },
  "system_fingerprint": "default"
}
Checklist
  • ruff passes
  • ruff format passes
  • codespell passes
  • Manual testing on GPU machine

Summary by CodeRabbit

  • New Features

    • Added a vLLM-based gRPC servicer offering streaming generation, model info, health checks, aborts, and server metadata.
  • Documentation

    • Added a development guide with local setup and release procedures.
    • Expanded README with installation, usage examples, architecture notes, and development references.
  • Chores

    • Added packaging config for the servicer to enable distribution.
    • Reworked release automation to coordinate proto/servicer publishing and updated CI install steps.

Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
Signed-off-by: Chang Su <chang.s.su@oracle.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Dependency updates ci CI/CD configuration changes labels Mar 5, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the gRPC serving layer for vLLM by extracting it into a dedicated, independently releasable Python package, smg-grpc-servicer. This change addresses the tight coupling of the gRPC servicer with the vLLM repository, allowing for separate versioning and release management. The new package integrates with vLLM via an optional runtime dependency, activated by a new --grpc flag, ensuring no circular dependencies and maintaining flexibility.

Highlights

  • Decoupled gRPC Servicer: The vLLM gRPC servicer code has been extracted into a new, standalone PyPI package named smg-grpc-servicer, allowing for independent release cycles and version management from the main vLLM repository.
  • New PyPI Package and Release Workflow: A new Python package smg-grpc-servicer (v0.4.2) has been created with its own pyproject.toml and a dedicated GitHub Actions workflow (.github/workflows/release-grpc-servicer.yml) for automated PyPI releases.
  • Optional vLLM Integration: vLLM will now optionally depend on smg-grpc-servicer at runtime, activated via a new --grpc flag (vllm serve --grpc), ensuring no circular dependencies.
  • Updated CI and Documentation: The CI script (scripts/ci_install_vllm.sh) has been updated to install gRPC packages from source for testing, and comprehensive documentation (DEVELOPMENT.md, README.md) has been added for the new package's usage and development.
  • Core Servicer Implementation: The VllmEngineServicer and serve_grpc() launcher have been implemented within the new package, handling streaming generation, health checks, and model/server information requests.
Changelog
  • grpc_servicer/DEVELOPMENT.md
    • Documented local development, CI, and release processes for smg-grpc-proto and smg-grpc-servicer.
  • grpc_servicer/README.md
    • Provided an overview, installation instructions, usage examples, and architectural details for the smg-grpc-servicer package.
  • grpc_servicer/pyproject.toml
    • Defined the metadata, dependencies (smg-grpc-proto, vllm, grpcio), and package structure for smg-grpc-servicer.
  • grpc_servicer/smg_grpc_servicer/init.py
    • Initialized the smg_grpc_servicer Python package.
  • grpc_servicer/smg_grpc_servicer/vllm/init.py
    • Initialized the vLLM-specific submodule within smg_grpc_servicer, exposing VllmEngineServicer and serve_grpc.
  • grpc_servicer/smg_grpc_servicer/vllm/server.py
    • Implemented the serve_grpc function and main entry point for launching the vLLM gRPC server.
  • grpc_servicer/smg_grpc_servicer/vllm/servicer.py
    • Provided the VllmEngineServicer class, which implements the gRPC service methods for generation, health checks, model info, and server info.
  • scripts/ci_install_vllm.sh
    • Updated the CI script to install smg-grpc-proto and smg-grpc-servicer from their local source directories.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/release-grpc-servicer.yml
Activity
  • The author manually tested vllm serve --grpc with gpt-oss-20b on a 4xGPU setup, including attached screenshots.
  • The author confirmed that ruff, ruff format, and codespell checks passed.
  • The author confirmed manual testing on a GPU machine was completed.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@coderabbitai

coderabbitai Bot commented Mar 5, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new smg-grpc-servicer package with a vLLM-based async gRPC server and VllmEngineServicer (streaming Generate and other RPCs), packaging and docs for the servicer, CI scripts to install local gRPC packages, and a unified GitHub Actions workflow to build and publish proto and servicer packages to PyPI.

Changes

Cohort / File(s) Summary
Core vLLM Servicer & Server
grpc_servicer/smg_grpc_servicer/vllm/servicer.py, grpc_servicer/smg_grpc_servicer/vllm/server.py
New VllmEngineServicer implementing streaming Generate, other RPCs (Embed, HealthCheck, Abort, GetModelInfo, GetServerInfo), extensive proto↔runtime translation, multimodal input handling, logprob assembly, and an async serve_grpc entrypoint with graceful shutdown.
Package metadata & exports
grpc_servicer/pyproject.toml, grpc_servicer/smg_grpc_servicer/__init__.py, grpc_servicer/smg_grpc_servicer/vllm/__init__.py
Adds pyproject for smg-grpc-servicer (v0.4.2) with dependencies and packaging settings; module docstring and public exports (VllmEngineServicer, serve_grpc).
Documentation & development guide
grpc_servicer/README.md, grpc_servicer/DEVELOPMENT.md
Adds README with installation/usage and architecture notes; DEVELOPMENT.md documents local editable installs, CI behavior, and release scenarios (servicer-only, proto-only, combined).
CI scripts and workflows
scripts/ci_install_vllm.sh, .github/workflows/release-grpc.yml, .github/workflows/release-grpc-proto.yml
CI script updated to install local gRPC packages editable during CI. New unified release workflow that detects changes to proto and/or servicer, builds artifacts, and conditionally uploads to PyPI; removed legacy proto-only workflow.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant GRPC_Server as gRPC Server
    participant Servicer as VllmEngineServicer
    participant Engine as AsyncLLM

    Client->>GRPC_Server: Stream GenerateRequest
    GRPC_Server->>Servicer: route to Generate()
    Servicer->>Servicer: validate request, build inputs & SamplingParams
    Servicer->>Engine: request generation (async)
    Engine-->>Servicer: stream RequestOutput chunks
    loop per chunk
        Servicer->>Servicer: assemble tokens, logprobs, metadata
        Servicer-->>Client: yield GenerateResponse (chunk)
    end
    Engine-->>Servicer: final output
    Servicer-->>Client: yield final GenerateResponse
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #409: Updates grpcio/grpcio-tools packaging constraints used by gRPC Python packages.
  • PR #386: Modifies gRPC proto CI/release workflows; conceptually related to replacing the proto-only workflow.
  • PR #610: Introduces CI/release changes around pyproject-based versioning and idempotent PyPI uploads (--skip-existing).

Suggested labels

grpc, workflow

Suggested reviewers

  • key4ng
  • slin1237

Poem

🐰 A spry servicer hops with code so bright,
Streaming tokens through day and night,
Proto and package aligned in tune,
CI hums beneath the moon,
The rabbit cheers: "Deploy it right!" 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add smg-grpc-servicer package' accurately and concisely summarizes the main change—adding a new gRPC servicer package to PyPI.
Docstring Coverage ✅ Passed Docstring coverage is 89.47% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chang/grpc-servicer

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31e4aedf03

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py Outdated
Comment thread .github/workflows/release-grpc-servicer.yml Outdated
Signed-off-by: Chang Su <chang.s.su@oracle.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request successfully extracts the gRPC servicer logic into a new standalone Python package, smg-grpc-servicer, which is a good architectural improvement for decoupling release cycles. The new package structure, dependencies, and documentation are well-defined, and the core servicer logic handles streaming, non-streaming, and multimodal generation cases. However, several security vulnerabilities were identified, including a critical Denial of Service risk due to unrestricted gRPC message sizes, a high-severity SSRF vulnerability via unvalidated KV transfer parameters, and medium-severity issues related to missing authorization in the Abort RPC and insecure communication by default. Addressing these issues is essential before deploying this servicer in a production environment. Additionally, for general improvements, the last_receive_timestamp metric in GetServerInfo within servicer.py is not being tracked correctly, and it's recommended to use uv pip instead of pip in ci_install_vllm.sh for consistency.

Comment thread grpc_servicer/smg_grpc_servicer/vllm/server.py
Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py Outdated
Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py
Comment thread grpc_servicer/smg_grpc_servicer/vllm/server.py
Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py
Comment thread scripts/ci_install_vllm.sh Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release-grpc-servicer.yml:
- Around line 4-13: The push trigger can fire when both
grpc_servicer/pyproject.toml and grpc_client/python/pyproject.toml are changed,
bypassing the intended workflow_run ordering; update the push trigger to ignore
changes to the client pyproject by adding a paths-ignore entry for
"grpc_client/python/pyproject.toml" (so push only fires for servicer-only
changes), and apply the same paths-ignore change to the other similar push block
referenced in the file; locate the push block and the workflow_run block
(symbols: push, paths, workflow_run) and add the paths-ignore entry accordingly.

In `@grpc_servicer/pyproject.toml`:
- Around line 10-15: Add uvloop as an explicit dependency in pyproject.toml to
match its direct import in smg_grpc_servicer/vllm/server.py; update the
dependencies list to include "uvloop>=0.17.0" (or a compatible minimum) so the
package no longer relies on a transitive dependency from vllm, and ensure the
project build/publish includes this new declared dependency.

In `@grpc_servicer/smg_grpc_servicer/vllm/server.py`:
- Around line 79-111: The startup and serve lifecycle isn't protected by an
outer try/finally so if an exception happens during startup the cleanup (notably
async_llm.shutdown()) may be skipped; wrap the sequence that creates/starts the
server and awaits stop_event (including await server.start(),
loop.add_signal_handler setup, and the await stop_event.wait()) in a single
try/finally block and call async_llm.shutdown() and await server.stop(grace=5.0)
in the finally to guarantee cleanup; also remove/restore any signal handlers
registered via loop.add_signal_handler after shutdown to avoid leaking handlers.

In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py`:
- Around line 202-204: The except block in the Generate handler currently sends
raw exception text back to the client via await
context.abort(grpc.StatusCode.INTERNAL, str(e)) which can leak internal details;
instead keep the logger.exception(...) call for detailed server-side logging (it
already logs request_id and traceback) but change the context.abort call in the
except block to send a generic message (e.g., "Internal server error" or "An
internal error occurred") rather than str(e); update the code around the
Generate handler’s exception handling (references: logger.exception,
context.abort, request_id, exception variable e) accordingly.
- Around line 371-406: The code trusts multimodal metadata (flat, hf_dict
entries, and placeholder ranges) before indexing; add explicit validation to
return INVALID_ARGUMENT for malformed inputs: ensure each key used (flat[key]
and hf_dict[...] in the block building sizes and fields_config) exists in flat
and hf_dict before accessing, verify sizes.flatten() is valid tensor type before
to(torch.int64), and when iterating mm_proto.mm_placeholders validate each
PlaceholderRange p has non-negative offset and length and that p.offset +
p.length does not exceed len(prompt_token_ids) before slicing; also check
mm_proto.HasField("im_token_id") and that im_token_id is a valid token value
before comparing, and when any validation fails raise a clear INVALID_ARGUMENT
error (rather than letting indexing or torch ops raise INTERNAL). Use the
existing symbols (flat, hf_dict, sizes, MultiModalFieldConfig.flat_from_sizes,
mm_proto, prompt_token_ids, PlaceholderRange) to locate where to insert these
guards.
- Around line 321-323: The health/status response is setting
last_receive_timestamp to time.time() at read time, which is wrong; instead
track and return the actual last request arrival time: add a persistent
attribute (e.g., self.last_receive_timestamp initialized in the servicer class
constructor near self.start_time), update self.last_receive_timestamp in the
request ingress handler where new requests arrive, and in the status response
use that stored self.last_receive_timestamp (leave uptime_seconds = time.time()
- self.start_time as-is). Ensure the identifier last_receive_timestamp in the
response maps to the stored self.last_receive_timestamp.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 715b876e-7429-4c27-bf6f-051fb835b219

📥 Commits

Reviewing files that changed from the base of the PR and between 92ef6e9 and 31e4aed.

📒 Files selected for processing (9)
  • .github/workflows/release-grpc-servicer.yml
  • grpc_servicer/DEVELOPMENT.md
  • grpc_servicer/README.md
  • grpc_servicer/pyproject.toml
  • grpc_servicer/smg_grpc_servicer/__init__.py
  • grpc_servicer/smg_grpc_servicer/vllm/__init__.py
  • grpc_servicer/smg_grpc_servicer/vllm/server.py
  • grpc_servicer/smg_grpc_servicer/vllm/servicer.py
  • scripts/ci_install_vllm.sh

Comment thread .github/workflows/release-grpc-servicer.yml Outdated
Comment thread grpc_servicer/pyproject.toml
Comment thread grpc_servicer/smg_grpc_servicer/vllm/server.py Outdated
Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py
Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py
Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 30941ac367

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
grpc_servicer/smg_grpc_servicer/vllm/servicer.py (3)

202-204: ⚠️ Potential issue | 🟠 Major

Avoid leaking internal exception details in gRPC INTERNAL errors.

context.abort(..., str(e)) can expose internal state and implementation details to clients. Return a generic message and keep details in server logs.

🔒 Suggested fix
-        except Exception as e:
+        except Exception:
             logger.exception("Error in Generate for request %s", request_id)
-            await context.abort(grpc.StatusCode.INTERNAL, str(e))
+            await context.abort(grpc.StatusCode.INTERNAL, "Internal server error")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py` around lines 202 - 204, The
catch block in Generate is currently calling await
context.abort(grpc.StatusCode.INTERNAL, str(e)), which leaks internal exception
details to clients; change it to send a generic error message (e.g., "Internal
server error") while keeping the full exception in server logs
(logger.exception("Error in Generate for request %s", request_id) already
present) so remove str(e) from the abort and replace with the generic message in
the except block of Generate in servicer.py.

321-323: ⚠️ Potential issue | 🟡 Minor

Track and return actual last request ingress time.

last_receive_timestamp=time.time() reports “now” at read time, not the last request arrival. Persist it on ingress and return the stored value.

🕒 Suggested fix
@@
     def __init__(self, async_llm: AsyncLLM, start_time: float):
@@
         self.async_llm = async_llm
         self.start_time = start_time
+        self.last_receive_timestamp = start_time
         logger.info("VllmEngineServicer initialized")
@@
     async def Generate(
@@
         request_id = request.request_id
+        self.last_receive_timestamp = time.time()
@@
         return vllm_engine_pb2.GetServerInfoResponse(
@@
-            last_receive_timestamp=time.time(),  # TODO looks wrong?
+            last_receive_timestamp=self.last_receive_timestamp,
             uptime_seconds=time.time() - self.start_time,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py` around lines 321 - 323, The
code is returning time.time() for last_receive_timestamp instead of the actual
last ingress time; persist and update a field (e.g.,
self.last_receive_timestamp) when requests arrive in the request-ingress handler
(the method that receives/queues requests) and return that stored value here
instead of calling time.time(); keep uptime_seconds computed as time.time() -
self.start_time and ensure self.last_receive_timestamp is initialized (e.g.,
None or start_time) in the servicer constructor where self.start_time is set.

371-406: ⚠️ Potential issue | 🟠 Major

Validate multimodal metadata before indexing/slicing.

flat_keys and placeholder ranges are currently trusted. Malformed metadata can trigger runtime failures or incorrect masking behavior instead of a clean INVALID_ARGUMENT.

🧪 Suggested fix
         for key in hf_dict:
             on_cpu = key in cpu_keys
             if key in batched:
                 fields_config[key] = MultiModalFieldConfig.batched("image", keep_on_cpu=on_cpu)
             elif key in flat:
-                sizes = hf_dict[flat[key]].flatten().to(torch.int64)
+                size_key = flat[key]
+                if size_key not in hf_dict:
+                    raise ValueError(
+                        f"Invalid mm_inputs.flat_keys mapping: {key!r} -> {size_key!r} (missing tensor)"
+                    )
+                sizes = hf_dict[size_key].flatten().to(torch.int64)
                 fields_config[key] = MultiModalFieldConfig.flat_from_sizes(
                     "image", sizes, keep_on_cpu=on_cpu
                 )
@@
             placeholders = []
             for p in mm_proto.mm_placeholders:
+                if p.offset < 0 or p.length < 0 or p.offset + p.length > len(prompt_token_ids):
+                    raise ValueError(
+                        "Invalid mm placeholder range: "
+                        f"offset={p.offset}, length={p.length}, prompt_len={len(prompt_token_ids)}"
+                    )
                 is_embed = None
                 if im_token_id is not None:
                     token_slice = prompt_token_ids[p.offset : p.offset + p.length]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py` around lines 371 - 406,
Validate multimodal metadata before using it: check that keys referenced in flat
(used as flat[key] and hf_dict[flat[key]]) actually exist and that resulting
tensors/sizes have expected dims/lengths before calling flatten()/to(); validate
mm_proto.mm_hashes types/lengths if present; for each PlaceholderRange p ensure
p.offset and p.length are non-negative and that p.offset + p.length does not
exceed len(prompt_token_ids) before slicing prompt_token_ids[p.offset : p.offset
+ p.length]; also ensure im_token_id presence is correctly checked via HasField
and that mask length matches slice length; on any invalid metadata raise a clear
INVALID_ARGUMENT error (or propagate an appropriate grpc status) rather than
proceeding.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py`:
- Around line 127-133: The current check only rejects port 0; update the
validation around request.kv_transfer_params (remote_host and remote_port) in
servicer.py to ensure remote_port is an integer within the valid TCP/UDP port
range (1–65535) and remote_host is non-empty, and call await
context.abort(grpc.StatusCode.INVALID_ARGUMENT, ...) if remote_port is outside
that range or not provided; keep the existing error message or improve it to
mention the allowed port range so sampling args are never built with an invalid
port.

---

Duplicate comments:
In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py`:
- Around line 202-204: The catch block in Generate is currently calling await
context.abort(grpc.StatusCode.INTERNAL, str(e)), which leaks internal exception
details to clients; change it to send a generic error message (e.g., "Internal
server error") while keeping the full exception in server logs
(logger.exception("Error in Generate for request %s", request_id) already
present) so remove str(e) from the abort and replace with the generic message in
the except block of Generate in servicer.py.
- Around line 321-323: The code is returning time.time() for
last_receive_timestamp instead of the actual last ingress time; persist and
update a field (e.g., self.last_receive_timestamp) when requests arrive in the
request-ingress handler (the method that receives/queues requests) and return
that stored value here instead of calling time.time(); keep uptime_seconds
computed as time.time() - self.start_time and ensure self.last_receive_timestamp
is initialized (e.g., None or start_time) in the servicer constructor where
self.start_time is set.
- Around line 371-406: Validate multimodal metadata before using it: check that
keys referenced in flat (used as flat[key] and hf_dict[flat[key]]) actually
exist and that resulting tensors/sizes have expected dims/lengths before calling
flatten()/to(); validate mm_proto.mm_hashes types/lengths if present; for each
PlaceholderRange p ensure p.offset and p.length are non-negative and that
p.offset + p.length does not exceed len(prompt_token_ids) before slicing
prompt_token_ids[p.offset : p.offset + p.length]; also ensure im_token_id
presence is correctly checked via HasField and that mask length matches slice
length; on any invalid metadata raise a clear INVALID_ARGUMENT error (or
propagate an appropriate grpc status) rather than proceeding.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 25cc250e-49fc-4f52-9698-005f755b4060

📥 Commits

Reviewing files that changed from the base of the PR and between 31e4aed and 30941ac.

📒 Files selected for processing (1)
  • grpc_servicer/smg_grpc_servicer/vllm/servicer.py

Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py Outdated
- use uv pip in CI script for consistency
- wrap server startup in try/finally for guaranteed cleanup
- guard islice against negative logprobs values
- validate kv_transfer_params port range [1, 65535]

Signed-off-by: Chang Su <chang.s.su@oracle.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (3)
grpc_servicer/smg_grpc_servicer/vllm/servicer.py (2)

202-204: ⚠️ Potential issue | 🟠 Major

Avoid leaking raw exception details in INTERNAL responses.

Returning str(e) to clients can expose internal state (stack frames, file paths, internal identifiers). Keep details in server logs and send a generic message to clients.

🔒 Suggested fix
-        except Exception as e:
-            logger.exception("Error in Generate for request %s", request_id)
-            await context.abort(grpc.StatusCode.INTERNAL, str(e))
+        except Exception:
+            logger.exception("Error in Generate for request %s", request_id)
+            await context.abort(grpc.StatusCode.INTERNAL, "Internal server error")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py` around lines 202 - 204, In
the Generate handler's exception block (the except Exception in servicer.py
around the Generate method), stop sending str(e) to the client via await
context.abort and instead send a generic message (e.g., "Internal server error")
while keeping the full exception details in the server log via logger.exception;
replace await context.abort(grpc.StatusCode.INTERNAL, str(e)) with await
context.abort(grpc.StatusCode.INTERNAL, "<generic message>") and ensure
logger.exception(...) still records e and request_id for debugging.

367-408: ⚠️ Potential issue | 🟠 Major

Validate multimodal metadata before indexing.

flat_keys mappings and placeholder ranges are trusted without validation. Malformed inputs will raise KeyError or out-of-bounds errors that surface as INTERNAL rather than INVALID_ARGUMENT.

🛡️ Suggested validation
         for key in hf_dict:
             on_cpu = key in cpu_keys
             if key in batched:
                 fields_config[key] = MultiModalFieldConfig.batched("image", keep_on_cpu=on_cpu)
             elif key in flat:
+                size_key = flat[key]
+                if size_key not in hf_dict:
+                    raise ValueError(
+                        f"Invalid mm_inputs.flat_keys: {key!r} -> {size_key!r} (tensor not found)"
+                    )
-                sizes = hf_dict[flat[key]].flatten().to(torch.int64)
+                sizes = hf_dict[size_key].flatten().to(torch.int64)
                 fields_config[key] = MultiModalFieldConfig.flat_from_sizes(
                     "image", sizes, keep_on_cpu=on_cpu
                 )
@@
             for p in mm_proto.mm_placeholders:
+                if p.offset < 0 or p.length < 0:
+                    raise ValueError(f"Invalid placeholder: offset={p.offset}, length={p.length}")
+                if p.offset + p.length > len(prompt_token_ids):
+                    raise ValueError(
+                        f"Placeholder out of bounds: offset={p.offset}, length={p.length}, "
+                        f"prompt_len={len(prompt_token_ids)}"
+                    )
                 is_embed = None
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py` around lines 367 - 408, The
code assumes multimodal metadata (keys in flat/batched, indices in flat mapping,
and placeholder ranges) are valid and can raise KeyError or index errors; update
validation in the vllm servicer before using hf_dict/flat/batched and
mm_proto.mm_placeholders: verify that every flat[key] exists in hf_dict and that
sizes tensors are non-empty and convertible to int64 before calling
MultiModalFieldConfig.flat_from_sizes, and check placeholder offsets/lengths
against prompt_token_ids length and that im_token_id handling uses HasField
correctly before creating PlaceholderRange; on invalid inputs, raise/return an
INVALID_ARGUMENT style error (or convert to a well-defined gRPC status) rather
than letting KeyError/IndexError propagate.
grpc_servicer/smg_grpc_servicer/vllm/server.py (1)

46-77: 🧹 Nitpick | 🔵 Trivial

Consider wrapping more setup in try/finally for complete cleanup.

If an exception occurs between AsyncLLM.from_vllm_config() (line 46) and the try block (line 79)—e.g., during server.add_insecure_port() with an invalid address—async_llm.shutdown() would not be called.

While the risk is low since most operations here don't fail, for robustness you could either:

  1. Move the try block earlier to wrap servicer/server creation
  2. Use a context manager pattern for AsyncLLM lifecycle
🛠️ Example restructure
     # Create AsyncLLM
     async_llm = AsyncLLM.from_vllm_config(
         vllm_config=vllm_config,
         usage_context=UsageContext.OPENAI_API_SERVER,
         enable_log_requests=args.enable_log_requests,
         disable_log_stats=args.disable_log_stats,
     )
 
+    try:
         # Create servicer
         servicer = VllmEngineServicer(async_llm, start_time)
 
         # Create gRPC server
         server = grpc.aio.server(...)
         ...
-
-    try:
         # Start server
         await server.start()
         ...
     finally:
         ...
         async_llm.shutdown()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grpc_servicer/smg_grpc_servicer/vllm/server.py` around lines 46 - 77, The
setup between AsyncLLM.from_vllm_config(...) and server.add_insecure_port(...)
can raise and leak resources because async_llm.shutdown() is only called inside
the later try block; wrap the creation of AsyncLLM, VllmEngineServicer, and the
gRPC server (i.e. the calls to AsyncLLM.from_vllm_config,
VllmEngineServicer(...), grpc.aio.server(...), adding the servicer, enabling
reflection, and server.add_insecure_port(...)) in a try/finally (or use a
context manager) so that async_llm.shutdown() is always called in the finally
block (and server cleanup is performed) if any of these steps fail.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@grpc_servicer/smg_grpc_servicer/vllm/server.py`:
- Around line 46-77: The setup between AsyncLLM.from_vllm_config(...) and
server.add_insecure_port(...) can raise and leak resources because
async_llm.shutdown() is only called inside the later try block; wrap the
creation of AsyncLLM, VllmEngineServicer, and the gRPC server (i.e. the calls to
AsyncLLM.from_vllm_config, VllmEngineServicer(...), grpc.aio.server(...), adding
the servicer, enabling reflection, and server.add_insecure_port(...)) in a
try/finally (or use a context manager) so that async_llm.shutdown() is always
called in the finally block (and server cleanup is performed) if any of these
steps fail.

In `@grpc_servicer/smg_grpc_servicer/vllm/servicer.py`:
- Around line 202-204: In the Generate handler's exception block (the except
Exception in servicer.py around the Generate method), stop sending str(e) to the
client via await context.abort and instead send a generic message (e.g.,
"Internal server error") while keeping the full exception details in the server
log via logger.exception; replace await context.abort(grpc.StatusCode.INTERNAL,
str(e)) with await context.abort(grpc.StatusCode.INTERNAL, "<generic message>")
and ensure logger.exception(...) still records e and request_id for debugging.
- Around line 367-408: The code assumes multimodal metadata (keys in
flat/batched, indices in flat mapping, and placeholder ranges) are valid and can
raise KeyError or index errors; update validation in the vllm servicer before
using hf_dict/flat/batched and mm_proto.mm_placeholders: verify that every
flat[key] exists in hf_dict and that sizes tensors are non-empty and convertible
to int64 before calling MultiModalFieldConfig.flat_from_sizes, and check
placeholder offsets/lengths against prompt_token_ids length and that im_token_id
handling uses HasField correctly before creating PlaceholderRange; on invalid
inputs, raise/return an INVALID_ARGUMENT style error (or convert to a
well-defined gRPC status) rather than letting KeyError/IndexError propagate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e2f55268-4f86-4dc7-b2a8-89d608d82c64

📥 Commits

Reviewing files that changed from the base of the PR and between 30941ac and 3838999.

📒 Files selected for processing (3)
  • grpc_servicer/smg_grpc_servicer/vllm/server.py
  • grpc_servicer/smg_grpc_servicer/vllm/servicer.py
  • scripts/ci_install_vllm.sh

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 383899940a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py
Replace separate release-grpc-proto.yml and release-grpc-servicer.yml
with a single workflow that enforces proto-first ordering via job
dependencies. Fixes race when both pyproject.toml files change in one
merge.

Signed-off-by: Chang Su <chang.s.su@oracle.com>
context.abort() raises grpc.aio.AbortError which was caught by the
broad except Exception handler, remapping INVALID_ARGUMENT to INTERNAL.

Signed-off-by: Chang Su <chang.s.su@oracle.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 231531a903

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/release-grpc.yml Outdated
Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release-grpc.yml:
- Around line 35-37: The current package-change detection uses a single-commit
diff (git diff HEAD~1) which misses multi-commit pushes; update the steps that
set the proto and servicer flags (the proto and servicer variable assignments)
to use the full push commit range by diffing from ${{ github.event.before }} to
${{ github.sha }} instead of HEAD~1, and ensure the workflow checkout step
increases fetch-depth to 0 so both commits are available locally; keep the
output writing to GITHUB_OUTPUT as-is.
- Around line 102-108: The job currently only declares needs: [detect,
upload-proto] and checks needs.upload-proto.result != 'failure', which lets
build-servicer run when build-proto was skipped/failed; add build-proto to the
needs list and tighten the if condition to require a successful proto build.
Specifically, update needs to include build-proto (needs: [detect, build-proto,
upload-proto]) and change the if expression to include needs.build-proto.result
== 'success' (e.g., always() && needs.detect.outputs.servicer == 'true' &&
needs.build-proto.result == 'success' && needs.upload-proto.result != 'failure')
so the servicer job only proceeds when the proto build succeeded.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 04665434-67f8-4c4f-932c-1ac665042bfe

📥 Commits

Reviewing files that changed from the base of the PR and between 3838999 and 231531a.

📒 Files selected for processing (3)
  • .github/workflows/release-grpc-proto.yml
  • .github/workflows/release-grpc.yml
  • grpc_servicer/smg_grpc_servicer/vllm/servicer.py
💤 Files with no reviewable changes (1)
  • .github/workflows/release-grpc-proto.yml

Comment thread .github/workflows/release-grpc.yml Outdated
Comment thread .github/workflows/release-grpc.yml Outdated
- Use github.event.before..github.sha instead of HEAD~1 to detect
  changes across multi-commit pushes
- Use fetch-depth: 0 to ensure full history is available
- Add build-proto to servicer needs and tighten condition to block
  servicer release when proto build fails (skipped != failure)

Signed-off-by: Chang Su <chang.s.su@oracle.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release-grpc.yml:
- Around line 35-37: Detect when github.event.before (the variable assigned to
base) is the 40-zero SHA and handle that case before running git diff; if base
equals "0000000000000000000000000000000000000000" then populate changed using an
alternative command such as listing files in the head commit (e.g., use git
ls-tree -r --name-only "$head" or git diff --name-only "$head"^ "$head" when
appropriate) instead of running git diff "$base" "$head", otherwise continue
using changed="$(git diff --name-only "$base" "$head")". Ensure you reference
the base, head and changed variables in the conditional so the workflow remains
robust for initial/edge pushes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2afbaf05-50ef-4965-8541-6cd5a1402bb0

📥 Commits

Reviewing files that changed from the base of the PR and between 231531a and 3513b4f.

📒 Files selected for processing (1)
  • .github/workflows/release-grpc.yml

Comment thread .github/workflows/release-grpc.yml
Move context.abort() call outside the try/except Exception scope so it
can't be caught by the broad handler. This removes the need for the
grpc.aio.AbortError re-raise workaround.

Signed-off-by: Chang Su <chang.s.su@oracle.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb35905d0e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread grpc_servicer/smg_grpc_servicer/vllm/servicer.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI/CD configuration changes dependencies Dependency updates documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant