Skip to content

[None][fix] Align GPTOSS router tokenization and disagg draft scheduling#15605

Closed
SimengLiu-nv wants to merge 3 commits into
NVIDIA:mainfrom
SimengLiu-nv:migrate-bench-x
Closed

[None][fix] Align GPTOSS router tokenization and disagg draft scheduling#15605
SimengLiu-nv wants to merge 3 commits into
NVIDIA:mainfrom
SimengLiu-nv:migrate-bench-x

Conversation

@SimengLiu-nv

@SimengLiu-nv SimengLiu-nv commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Use tool-aware chat template and Harmony tokenization for KV-cache-aware router hashes without mutating forwarded OpenAI requests.

Sync disaggregated generation draft tokens from context-phase params before scheduling so batch capacity accounting sees transferred draft tokens.

Add unit coverage for router/server tokenization parity and disagg draft-token scheduler accounting.

Summary by CodeRabbit

  • New Features

    • Added optional Harmony tokenization support for block-hash routing, including automatic detection for compatible model configs.
    • Improved chat tokenization to pass tool and reasoning settings through correctly.
  • Bug Fixes

    • Fixed scheduling for generation requests so draft tokens are counted consistently after transfer completion.
    • Improved handling of requests with precomputed token IDs and prompts so they are no longer rewritten unnecessarily.

Description

Test Coverage

tests/unittest/_torch/executor/test_py_executor.py
tests/unittest/disaggregated/test_router.py

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

PyExecutor now synchronizes disaggregated draft-token fields before batch scheduling and uses the synchronized count in scheduled-token estimation. Router tokenization can select Harmony from use_harmony or config.json, forwards tool schemas, and stops rewriting request prompts. Tests cover both paths.

Changes

Draft token synchronization

Layer / File(s) Summary
Draft-token helpers and completion setup
tensorrt_llm/_torch/pyexecutor/py_executor.py
Adds helpers that sync disaggregated draft-token fields and normalizes transmission-complete requests into Python-visible draft-token state.
Batch scheduling and token estimation
tensorrt_llm/_torch/pyexecutor/py_executor.py
Calls the sync helper before scheduling and uses synchronized draft-token counts when estimating scheduled tokens.
Draft-token scheduler tests
tests/unittest/_torch/executor/test_py_executor.py
Extends request mocks and adds tests for synced, empty, and ignored disaggregated draft-token cases.

Harmony tokenization routing

Layer / File(s) Summary
Harmony initialization
tensorrt_llm/serve/router.py
Adds use_harmony initialization, model config loading, and Harmony-selection logging.
Harmony and chat tokenization
tensorrt_llm/serve/router.py
Adds Harmony selection helpers, forwards tool schemas into chat tokenization, and stops mutating request prompt fields.
Tokenization behavior tests
tests/unittest/disaggregated/test_router.py
Adds tokenization helpers and tests for tool arguments, empty tools, completion prompts, and prompt_token_ids short-circuiting.
Harmony selection tests
tests/unittest/disaggregated/test_router.py
Adds tests for GPT-OSS Harmony tokenization, router/server parity, explicit Harmony selection, and config.json inference.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • suyoggupta
  • MrGeva
  • galagam
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main changes: GPTOSS router tokenization and disaggregated draft scheduling.
Description check ✅ Passed The description includes a clear summary, test coverage, and checklist, though the dedicated Description section is mostly left as a template placeholder.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tensorrt_llm/serve/router.py (1)

772-785: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Forward all worker-side chat-template inputs into router hashing.

The router now mirrors tools, but the worker also renders with request.documents and request.chat_template. Requests that differ only by RAG documents or a custom template can still produce identical router hashes while generating different worker prompts.

Suggested fix
 chat_template_kwargs = dict(request.chat_template_kwargs or {})
 chat_template_kwargs["tools"] = self._tool_dicts(request)
+chat_template_kwargs["documents"] = request.documents
+if request.chat_template is not None:
+    chat_template_kwargs["chat_template"] = request.chat_template
 result = tokenizer.apply_chat_template(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/serve/router.py` around lines 772 - 785, Forward the remaining
worker-side chat-template inputs into the router hash computation in router.py’s
tokenizer.apply_chat_template path: the current hash only mirrors tools via
chat_template_kwargs, but it also needs request.documents and
request.chat_template so router hashing matches the worker-rendered prompt.
Update the chat_template_kwargs assembly in the same block that builds result to
include these request fields before calling apply_chat_template, ensuring
requests that differ by RAG documents or a custom template no longer collide.
🧹 Nitpick comments (3)
tests/unittest/disaggregated/test_router.py (2)

1118-1181: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the disabled-Harmony selection path.

The selection tests cover explicit use_harmony=True and config.json inference, but not the server-compatible disabled path. Add a monkeypatch.setenv("DISABLE_HARMONY_ADAPTER", "1") case in tests/unittest/disaggregated/test_router.py asserting GPT-OSS requests use the tokenizer path and do not call Harmony. As per path instructions, coverage needs follow-up in this PR.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/disaggregated/test_router.py` around lines 1118 - 1181, Add a
test case in test_use_harmony_flag_for_alias_model or a nearby test in
KvCacheAwareRouter coverage that sets DISABLE_HARMONY_ADAPTER via monkeypatch
before calling _tokenize; verify the disabled-Harmony path uses
tokenizer.apply_chat_template, does not invoke
harmony_adapter.get_harmony_adapter or openai_to_harmony_tokens, and leaves
req.prompt_token_ids populated as expected for GPT-OSS/server-compatible
requests. Use the existing test helpers and symbols like KvCacheAwareRouter,
_tokenize, and ChatCompletionRequest to keep the new case aligned with the
current Harmony selection tests.

Source: Path instructions


1037-1117: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add parity cases for documents and custom chat_template.

Coverage is insufficient for the remaining worker-side template inputs. Extend tests/unittest/disaggregated/test_router.py with parametrized router/server parity cases where request.documents and request.chat_template are set, so cache-hash tokenization stays aligned with serving tokenization. As per path instructions, this names the concrete test file and coverage gap.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/disaggregated/test_router.py` around lines 1037 - 1117, Add
router/server parity coverage for the remaining worker-side template inputs by
extending the existing
`test_gpt_oss_router_and_server_create_same_tokenized_input` in
`test_router.py`. Parametrize new cases where `ChatCompletionRequest.documents`
is populated and where a custom `chat_template` is set, then verify
`KvCacheAwareRouter._tokenize` and `OpenAIServer.chat_harmony` produce identical
tokenized inputs. Reuse the current `fake_harmony_tokens`,
`harmony.openai_to_harmony_tokens`, and `generate_async` assertions so the new
cases exercise the same cache-hash/tokenization path.

Source: Path instructions

tests/unittest/_torch/executor/test_py_executor.py (1)

378-408: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Coverage is insufficient for the executor integration paths.

tests/unittest/_torch/executor/test_py_executor.py now covers the static helper directly, but should also cover: (1) trans-complete draft_tokens=None with enable_spec_decode=True / max_total_draft_tokens > 0, and (2) the PP scheduling path that bypasses _prepare_and_schedule_batch. As per path instructions, tests under tests/** should be reviewed for actionable coverage sufficiency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/_torch/executor/test_py_executor.py` around lines 378 - 408,
The executor tests only cover the helper directly and miss key integration
coverage. Add a test around trans-complete requests with draft_tokens=None when
enable_spec_decode is true and max_total_draft_tokens is positive, and add a PP
scheduling test that exercises the path bypassing _prepare_and_schedule_batch.
Use the existing PyExecutor and
_sync_disagg_generation_trans_complete_draft_tokens / _compute_scheduled_tokens
helpers to locate the relevant flow, but assert behavior through the
higher-level scheduling integration rather than only the static helper.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_torch/pyexecutor/py_executor.py`:
- Around line 2617-2633: The draft-token sync in
_sync_disagg_generation_trans_complete_draft_tokens is using a different draft
count rule than _prepare_disagg_gen_transmission_complete, which can undercount
capacity when spec decode is enabled. Update the transmission-complete sync to
use the same draft-token resolver/logic as
_prepare_disagg_gen_transmission_complete, and move this sync so it runs after
the spec-decode decision is applied. Keep the behavior aligned for empty or None
context drafts and ensure py_draft_tokens, draft_tokens, and
py_draft_pages_allocated are derived from the shared resolution path.
- Around line 2651-2652: The PP executor path is missing the same disagg
generation transition sync that `_prepare_and_schedule_batch` already performs,
so `pp_size > 1` can schedule requests with stale draft-token state. Add the
`_sync_disagg_generation_trans_complete_draft_tokens` call in
`_executor_loop_pp` before it invokes `_pp_schedule_and_propagate()` or
`_schedule()`, mirroring the existing behavior in `_prepare_and_schedule_batch`
and using `self.active_requests` there as the source.

In `@tensorrt_llm/serve/router.py`:
- Around line 736-740: The Harmony tokenization decision in
`_uses_harmony_tokenization` is still defaulting GPT-OSS models to Harmony even
when the server has disabled it. Update `KvCacheAwareRouter` to use the same
resolved `use_harmony` value that `OpenAIServer` derives from
`DISABLE_HARMONY_ADAPTER`, or otherwise apply that env gate here, so router KV
hashing and worker chat template rendering stay aligned.

---

Outside diff comments:
In `@tensorrt_llm/serve/router.py`:
- Around line 772-785: Forward the remaining worker-side chat-template inputs
into the router hash computation in router.py’s tokenizer.apply_chat_template
path: the current hash only mirrors tools via chat_template_kwargs, but it also
needs request.documents and request.chat_template so router hashing matches the
worker-rendered prompt. Update the chat_template_kwargs assembly in the same
block that builds result to include these request fields before calling
apply_chat_template, ensuring requests that differ by RAG documents or a custom
template no longer collide.

---

Nitpick comments:
In `@tests/unittest/_torch/executor/test_py_executor.py`:
- Around line 378-408: The executor tests only cover the helper directly and
miss key integration coverage. Add a test around trans-complete requests with
draft_tokens=None when enable_spec_decode is true and max_total_draft_tokens is
positive, and add a PP scheduling test that exercises the path bypassing
_prepare_and_schedule_batch. Use the existing PyExecutor and
_sync_disagg_generation_trans_complete_draft_tokens / _compute_scheduled_tokens
helpers to locate the relevant flow, but assert behavior through the
higher-level scheduling integration rather than only the static helper.

In `@tests/unittest/disaggregated/test_router.py`:
- Around line 1118-1181: Add a test case in
test_use_harmony_flag_for_alias_model or a nearby test in KvCacheAwareRouter
coverage that sets DISABLE_HARMONY_ADAPTER via monkeypatch before calling
_tokenize; verify the disabled-Harmony path uses tokenizer.apply_chat_template,
does not invoke harmony_adapter.get_harmony_adapter or openai_to_harmony_tokens,
and leaves req.prompt_token_ids populated as expected for
GPT-OSS/server-compatible requests. Use the existing test helpers and symbols
like KvCacheAwareRouter, _tokenize, and ChatCompletionRequest to keep the new
case aligned with the current Harmony selection tests.
- Around line 1037-1117: Add router/server parity coverage for the remaining
worker-side template inputs by extending the existing
`test_gpt_oss_router_and_server_create_same_tokenized_input` in
`test_router.py`. Parametrize new cases where `ChatCompletionRequest.documents`
is populated and where a custom `chat_template` is set, then verify
`KvCacheAwareRouter._tokenize` and `OpenAIServer.chat_harmony` produce identical
tokenized inputs. Reuse the current `fake_harmony_tokens`,
`harmony.openai_to_harmony_tokens`, and `generate_async` assertions so the new
cases exercise the same cache-hash/tokenization path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1001c8fd-15d1-46f1-9553-f45f1bea19cf

📥 Commits

Reviewing files that changed from the base of the PR and between f28a832 and 3081468.

📒 Files selected for processing (4)
  • tensorrt_llm/_torch/pyexecutor/py_executor.py
  • tensorrt_llm/serve/router.py
  • tests/unittest/_torch/executor/test_py_executor.py
  • tests/unittest/disaggregated/test_router.py

Comment thread tensorrt_llm/_torch/pyexecutor/py_executor.py
Comment thread tensorrt_llm/_torch/pyexecutor/py_executor.py Outdated
Comment thread tensorrt_llm/serve/router.py Outdated
@SimengLiu-nv
SimengLiu-nv force-pushed the migrate-bench-x branch 2 times, most recently from 1f3dde4 to f9eafa9 Compare June 29, 2026 22:15
@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #56482 [ run ] triggered by Bot. Commit: f9eafa9 Link to invocation

Comment thread tensorrt_llm/_torch/pyexecutor/py_executor.py
Comment thread tensorrt_llm/_torch/pyexecutor/py_executor.py
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #56482 [ run ] completed with state FAILURE. Commit: f9eafa9
/LLM/main/L0_MergeRequest_PR pipeline #45322 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@SimengLiu-nv
SimengLiu-nv requested a review from a team as a code owner July 6, 2026 21:13
@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57828 [ run ] triggered by Bot. Commit: 13f8391 Link to invocation

Comment thread tensorrt_llm/serve/router.py Outdated
@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57837 [ run ] triggered by Bot. Commit: f76ed6d Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57828 [ run ] completed with state ABORTED. Commit: 13f8391

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57837 [ run ] completed with state FAILURE. Commit: f76ed6d
/LLM/main/L0_MergeRequest_PR pipeline #46533 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Comment thread tests/integration/test_lists/test-db/l0_dgx_b200.yml Outdated

Copy link
Copy Markdown
Collaborator Author

/bot run --extra-stage "DGX_B200-4_GPUs-PyTorch-Post-Merge-*"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58515 [ run ] triggered by Bot. Commit: feb2394 Link to invocation

@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59549 [ run ] triggered by Bot. Commit: 6fe5e03 Link to invocation

@fredricz-20070104

Copy link
Copy Markdown
Collaborator

Follow-up: the PP scheduling path still misses the disagg draft-token sync

Re: the earlier CodeRabbit thread "Mirror this sync in the PP scheduling path", which was marked Resolved in new commit — on the current head (6fe5e03) the sync is still only wired into the non-PP loop, so the PP path is not actually covered.

What's in the code today (tensorrt_llm/_torch/pyexecutor/py_executor.py):

  • _sync_disagg_generation_trans_complete_draft_tokens is defined at line 3352.
  • Its only call site is at line 3598, inside _prepare_and_schedule_batch (the non-PP executor loop):
    if self.kv_cache_transceiver:
        self._check_disagg_ctx_schedulable_status(new_requests)
        self._check_disagg_gen_transfer_status()
        self._check_kv_transfer_timeout()
        self._sync_disagg_generation_trans_complete_draft_tokens(  # line 3598
            self.active_requests)
  • The PP loop _executor_loop_pp (line 2510) does not go through _prepare_and_schedule_batch. Its own if self.kv_cache_transceiver: block (lines 2534-2536) only calls:
    if self.kv_cache_transceiver:
        self._check_disagg_ctx_schedulable_status(new_requests)   # line 2535
        self._check_disagg_gen_transfer_status()                  # line 2536
        # <-- no _sync_disagg_generation_trans_complete_draft_tokens here
    Scheduling for PP happens in _pp_schedule_and_propagate (line 2412), which calls self._schedule() directly (line 2423). So the sync never runs on the PP path.

Impact — performance only, not correctness. The synced draft-token count feeds _get_generation_num_draft_tokens (line 3370) → _compute_scheduled_tokens (line 5181) → _waiting_requests (line 5234), which is only exercised under should_check_waiting = not enable_attention_dp and enable_batch_waiting and len(ctx) > 0 and len(gen) > 0 (in _schedule, ~line 5254). Since _schedule is reachable from the PP path, PP + disagg + batch-waiting will read un-synced draft-token counts and under-estimate scheduled tokens, giving a suboptimal batch-waiting decision. The tokens actually executed are still set correctly later by _prepare_disagg_gen_transmission_complete (py_draft_tokens), so there is no correctness bug — just a narrow, PP-specific batch-waiting inefficiency.

Suggestion: either genuinely mirror the sync into the PP path (add the _sync_disagg_generation_trans_complete_draft_tokens(self.active_requests) call inside the if self.kv_cache_transceiver: block at lines 2534-2536, matching the non-PP loop), or, if PP + disagg + draft is intentionally out of scope for now, please note that on the thread rather than leaving it marked resolved — the current resolved state is misleading for reviewers.

@fredricz-20070104 fredricz-20070104 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved.

@Shixiaowei02

Copy link
Copy Markdown
Collaborator

@SimengLiu-nv Thank you for the update! I noticed that modular tests have already been added as part of this change, which is a great practice. Given our current GPU resource constraints, would it be possible to reuse and extend existing E2E test coverage for this scenario instead of adding a new E2E test? Thank you very much for your consideration!

Comment thread tensorrt_llm/serve/router.py Outdated
Comment thread tensorrt_llm/_torch/pyexecutor/py_executor.py Outdated
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59549 [ run ] completed with state SUCCESS. Commit: 6fe5e03
/LLM/main/L0_MergeRequest_PR pipeline #47997 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Use tool-aware chat template and Harmony tokenization for KV-cache-aware
router hashes without mutating forwarded OpenAI requests.

Sync disaggregated generation draft tokens from context-phase params before
scheduling so batch capacity accounting sees transferred draft tokens.

Add unit coverage for router/server tokenization parity and disagg draft-token
scheduler accounting.

Signed-off-by: Simeng Liu <simengl@nvidia.com>
Signed-off-by: Simeng Liu <simengl@nvidia.com>
Signed-off-by: Simeng Liu <simengl@nvidia.com>
@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

Follow-up: the PP scheduling path still misses the disagg draft-token sync

Re: the earlier CodeRabbit thread "Mirror this sync in the PP scheduling path", which was marked Resolved in new commit — on the current head (6fe5e03) the sync is still only wired into the non-PP loop, so the PP path is not actually covered.

What's in the code today (tensorrt_llm/_torch/pyexecutor/py_executor.py):

  • _sync_disagg_generation_trans_complete_draft_tokens is defined at line 3352.

  • Its only call site is at line 3598, inside _prepare_and_schedule_batch (the non-PP executor loop):

    if self.kv_cache_transceiver:
        self._check_disagg_ctx_schedulable_status(new_requests)
        self._check_disagg_gen_transfer_status()
        self._check_kv_transfer_timeout()
        self._sync_disagg_generation_trans_complete_draft_tokens(  # line 3598
            self.active_requests)
  • The PP loop _executor_loop_pp (line 2510) does not go through _prepare_and_schedule_batch. Its own if self.kv_cache_transceiver: block (lines 2534-2536) only calls:

    if self.kv_cache_transceiver:
        self._check_disagg_ctx_schedulable_status(new_requests)   # line 2535
        self._check_disagg_gen_transfer_status()                  # line 2536
        # <-- no _sync_disagg_generation_trans_complete_draft_tokens here

    Scheduling for PP happens in _pp_schedule_and_propagate (line 2412), which calls self._schedule() directly (line 2423). So the sync never runs on the PP path.

Impact — performance only, not correctness. The synced draft-token count feeds _get_generation_num_draft_tokens (line 3370) → _compute_scheduled_tokens (line 5181) → _waiting_requests (line 5234), which is only exercised under should_check_waiting = not enable_attention_dp and enable_batch_waiting and len(ctx) > 0 and len(gen) > 0 (in _schedule, ~line 5254). Since _schedule is reachable from the PP path, PP + disagg + batch-waiting will read un-synced draft-token counts and under-estimate scheduled tokens, giving a suboptimal batch-waiting decision. The tokens actually executed are still set correctly later by _prepare_disagg_gen_transmission_complete (py_draft_tokens), so there is no correctness bug — just a narrow, PP-specific batch-waiting inefficiency.

Suggestion: either genuinely mirror the sync into the PP path (add the _sync_disagg_generation_trans_complete_draft_tokens(self.active_requests) call inside the if self.kv_cache_transceiver: block at lines 2534-2536, matching the non-PP loop), or, if PP + disagg + draft is intentionally out of scope for now, please note that on the thread rather than leaving it marked resolved — the current resolved state is misleading for reviewers.

Thanks for the detailed review. Changes in the new commit.

@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60459 [ run ] triggered by Bot. Commit: cdcdad1 Link to invocation

@schetlur-nv schetlur-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

approving for multi-gpu tests

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60459 [ run ] completed with state FAILURE. Commit: cdcdad1
/LLM/main/L0_MergeRequest_PR pipeline #48792 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

self.kv_cache_manager.commit_scheduled_kv_cache_stats(
scheduled_batch)

@staticmethod

@Shixiaowei02 Shixiaowei02 Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The draft-token sync itself is small, but it adds ~10 helpers, two tracking dicts, and 6 touch points in py_executor.py (our most safety-critical file) mainly to avoid an active_requests scan. Could check_gen_transfer_status return the completed request objects (as it already does for cancelled ones) so we can set the draft tokens inline on completion? That would let us drop the _disagg_generation_trans_in_progress_requests tracking layer (and the cancel-path leak it introduces) and keep the footprint much smaller. cc @chuangz0

return

for req in new_gen_reqs:
self._track_disagg_generation_trans_in_progress([req])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Entries added here are only popped via check_gen_transfer_status, but a user cancel of an in-flight gen transfer deletes the recv session synchronously (transceiver.cancel_request), so the rid never resurfaces and this entry (plus the LlmRequest it holds) leaks for the process lifetime. Could we pop it on the terminate/cancel path? (The timeout path may need the same.) Thanks!

tool.model_dump() if hasattr(tool, "model_dump") else tool for tool in request.tools
]

def _tokenize_harmony_chat(self, request: ChatCompletionRequest) -> list[list[int]]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could we unify this implementation with openai_server.py:2053 added by @reasonsolo ?


def _mock_tokenizer(token_ids=None):
"""Return a mock tokenizer with a recorded apply_chat_template.
def _mock_tokenizer(token_ids: list[int] | None = None) -> mock.MagicMock:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

_get_weather_tool and _mock_tokenizer are each defined twice at module scope. Could we keep just one of each? Thanks!

@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

Close the PR to break into smaller pieces and improve the implementation.

@SimengLiu-nv

Copy link
Copy Markdown
Collaborator Author

The functionalities of the PR is carried on with #16760 and #16805

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.