[Session] Fix image append positions and parent metadata (#39145)

Co-authored-by: Byron Hsu <byron+per@periodiclabs.ai>
Co-authored-by: Manik Singhal <manikvsinghal.pub@gmail.com>
This commit is contained in:
Byron Hsu
2026-09-13 21:06:47 -07:00
committed by GitHub
co-authored by Byron Hsu Manik Singhal
parent 5a132c061b
commit 39e147443b
2 changed files with 165 additions and 2 deletions
+50 -1
View File
@@ -1414,11 +1414,60 @@ class Req(ReqDllmMixin):
self.spec_cap_lens_histogram[cap_len] += 1
def extend_image_inputs(self, image_inputs):
if self.multimodal_inputs is None:
if self.session is not None:
self._extend_session_image_inputs(image_inputs)
elif self.multimodal_inputs is None:
self.multimodal_inputs = image_inputs
else:
self.multimodal_inputs.merge(image_inputs)
def _extend_session_image_inputs(self, image_inputs):
"""Append media while preserving the saved session and its position history."""
# Padding can change token values without changing their count.
self.full_untruncated_fill_ids = array("q")
if self.multimodal_inputs is not None:
# Branches and aborted turns must leave the parent's metadata intact.
self.multimodal_inputs = dataclasses.replace(self.multimodal_inputs)
positions = image_inputs.mrope_positions
if positions is not None:
prefix_len = len(self.origin_input_ids) - positions.shape[1]
prefix = (
self.multimodal_inputs.mrope_positions
if self.multimodal_inputs is not None
else None
)
if prefix is None:
prefix = positions.new_empty((3, 0))
prefix = prefix[:, :prefix_len]
next_position = prefix.max() + 1 if prefix.numel() else 0
text_len = prefix_len - prefix.shape[1]
text_positions = (
torch.arange(
text_len, dtype=positions.dtype, device=positions.device
).expand(3, -1)
+ next_position
)
# Fill the reply/text gap, then shift the new turn's media coordinates.
positions = torch.cat(
[prefix, text_positions, positions + next_position + text_len], dim=1
)
if self.multimodal_inputs is None:
self.multimodal_inputs = image_inputs
else:
# Use the full table above, or let the scheduler compute missing positions.
self.multimodal_inputs.mrope_positions = None
self.multimodal_inputs.mrope_position_delta = None
self.multimodal_inputs.merge(image_inputs)
self.multimodal_inputs.mrope_position_delta_repeated_cache = None
if positions is not None:
self.multimodal_inputs.mrope_positions = positions
self.multimodal_inputs.mrope_position_delta = (
positions.max() + 1 - positions.shape[1]
).reshape(1, 1)
def finished(self) -> bool:
# Whether request reached finished condition
return self.finished_reason is not None