use serde::{Deserialize, Serialize};
use serde_json::Value;
use uuid::Uuid;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ReplayPromptTokenSource {
#[default]
Materialized,
LengthOnlySynthetic,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ReplayRequestContext {
pub authored_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub turn_index: Option<usize>,
#[serde(default, skip_serializing_if = "Value::is_null")]
pub metadata: Value,
#[serde(default)]
pub prompt_token_source: ReplayPromptTokenSource,
}
#[doc(hidden)]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DirectRequest {
pub tokens: Vec<u32>,
pub max_output_tokens: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub output_token_ids: Option<Vec<u32>>,
pub uuid: Option<Uuid>,
pub dp_rank: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub preferred_dp_rank: Option<u32>,
pub arrival_timestamp_ms: Option<f64>,
#[serde(default, skip_serializing_if = "is_zero_i32")]
pub priority: i32,
#[serde(default, skip_serializing_if = "is_zero_u32")]
pub strict_priority: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub policy_class: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub replay_context: Option<ReplayRequestContext>,
}
fn is_zero_i32(value: &i32) -> bool {
*value == 0
}
fn is_zero_u32(value: &u32) -> bool {
*value == 0
}
impl DirectRequest {
pub fn request_id(&self) -> Option<Uuid> {
self.uuid
}
pub fn input_tokens(&self) -> &[u32] {
&self.tokens
}
pub fn max_output_tokens(&self) -> usize {
self.max_output_tokens
}
#[inline]
pub fn effective_max_output_tokens(&self) -> usize {
self.output_token_ids
.as_ref()
.map_or(self.max_output_tokens, Vec::len)
}
pub(crate) fn clone_with_output_limit(&self, limit: usize) -> Self {
let max_output_tokens = self.effective_max_output_tokens().min(limit);
let mut request = self.clone();
request.max_output_tokens = max_output_tokens;
request.output_token_ids = self
.output_token_ids
.as_ref()
.map(|ids| ids[..max_output_tokens].to_vec());
request
}
pub fn arrival_time_ms(&self) -> Option<f64> {
self.arrival_timestamp_ms
}
pub fn preferred_dp_rank(&self) -> Option<u32> {
self.preferred_dp_rank
}
pub fn router_priorities(&self) -> (f64, u32) {
(f64::from(self.priority.max(0)), self.strict_priority)
}
pub fn policy_class(&self) -> Option<&str> {
self.policy_class.as_deref()
}
pub fn prompt_tokens_are_placement_safe(&self) -> bool {
self.replay_context.as_ref().is_none_or(|context| {
context.prompt_token_source != ReplayPromptTokenSource::LengthOnlySynthetic
})
}
}
#[cfg(test)]
mod tests {
use super::DirectRequest;
#[test]
fn output_plan_is_authoritative_when_limited() {
let request = DirectRequest {
tokens: vec![1, 2],
max_output_tokens: 0,
output_token_ids: Some(vec![7, 8]),
..Default::default()
};
assert_eq!(request.effective_max_output_tokens(), 2);
let limited = request.clone_with_output_limit(1);
assert_eq!(limited.max_output_tokens, 1);
assert_eq!(limited.output_token_ids.as_deref(), Some(&[7][..]));
assert_eq!(limited.output_token_ids.unwrap().capacity(), 1);
assert_eq!(request.output_token_ids.as_deref(), Some(&[7, 8][..]));
let empty_plan = DirectRequest {
max_output_tokens: 4,
output_token_ids: Some(Vec::new()),
..Default::default()
};
assert_eq!(empty_plan.effective_max_output_tokens(), 0);
let limited = empty_plan.clone_with_output_limit(1);
assert_eq!(limited.max_output_tokens, 0);
assert_eq!(limited.output_token_ids.as_deref(), Some(&[][..]));
let unplanned = DirectRequest::default();
assert_eq!(unplanned.effective_max_output_tokens(), 0);
let limited = unplanned.clone_with_output_limit(1);
assert_eq!(limited.max_output_tokens, 0);
assert!(limited.output_token_ids.is_none());
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct OutputSignal {
pub(crate) uuid: Uuid,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) token_id: Option<u32>,
pub(crate) completed: bool,
#[serde(default)]
pub(crate) rejected: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) handoff_delay_ms: Option<f64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) cached_tokens: Option<usize>,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct ForwardPassSnapshot {
pub version: u32,
pub worker_id: String,
pub dp_rank: u32,
pub counter_id: u64,
pub num_prefill_requests: u32,
pub sum_prefill_tokens: u64,
pub var_prefill_length: f64,
pub sum_prefill_kv_tokens: u64,
pub num_decode_requests: u32,
pub sum_decode_kv_tokens: u64,
pub var_decode_kv_tokens: f64,
pub num_queued_prefill: u32,
pub sum_queued_prefill_tokens: u64,
pub var_queued_prefill_length: f64,
pub num_queued_decode: u32,
pub sum_queued_decode_kv_tokens: u64,
pub var_queued_decode_kv_tokens: f64,
pub wall_time_secs: f64,
}