Files
vllm/rust/src/chat/src/parser/unified.rs
T
+1 6570c9800c [Model] Add Inkling model support [1/N] (#48799)
Signed-off-by: Woosuk Kwon <woosuk@inferact.ai>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Co-authored-by: Bugen Zhao <i@bugenzhao.com>
Co-authored-by: Giancarlo Delfin <32987265+TheEpicDolphin@users.noreply.github.com>
Co-authored-by: Isotr0py <Isotr0py@outlook.com>
Co-authored-by: Isotr0py <mozf@inferact.ai>
Co-authored-by: Jee Jee Li <jeejeelee@inferact.ai>
Co-authored-by: Roger Wang <hey@rogerw.io>
Co-authored-by: Yifan Qiao <yifanqiao@inferact.ai>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-15 23:40:07 -07:00

125 lines
3.8 KiB
Rust

// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
//! Unified parser registration and selection boundary for `vllm-chat`.
use std::sync::LazyLock;
pub use vllm_parser::unified::{Gemma4UnifiedParser, InklingUnifiedParser, UnifiedParser};
use vllm_tokenizer::DynTokenizer;
use crate::parser::ParserFactory;
use crate::request::ChatTool;
/// Canonical public names for registered unified parsers.
pub mod names {
pub const GEMMA4: &str = "gemma4";
pub const INKLING: &str = "inkling";
}
/// Constructor signature for one registered unified parser implementation.
type UnifiedParserCreator =
fn(&[ChatTool], DynTokenizer) -> vllm_parser::unified::Result<Box<dyn UnifiedParser>>;
/// Registry and model matcher for unified parsers.
pub type UnifiedParserFactory = ParserFactory<UnifiedParserCreator>;
impl UnifiedParserFactory {
/// Get the global unified parser factory with built-in registrations and
/// model mappings.
pub fn global() -> &'static Self {
static INSTANCE: LazyLock<UnifiedParserFactory> = LazyLock::new(UnifiedParserFactory::new);
&INSTANCE
}
/// Create the default registry with built-in parser names and model
/// mappings.
pub fn new() -> Self {
let mut factory = Self::default();
factory.register_parser::<Gemma4UnifiedParser>(names::GEMMA4);
factory.register_parser::<InklingUnifiedParser>(names::INKLING);
factory
.register_pattern("gemma-4", names::GEMMA4)
.register_pattern("gemma4", names::GEMMA4)
.register_pattern("inkling", names::INKLING);
factory
}
/// Register one parser type that exposes a static `create()` constructor.
pub fn register_parser<T>(&mut self, name: &str) -> &mut Self
where
T: UnifiedParser + 'static,
{
self.register_creator(name, T::create)
}
/// Construct a parser from an exact name.
pub fn create(
&self,
name: &str,
tools: &[ChatTool],
tokenizer: DynTokenizer,
) -> crate::Result<Box<dyn UnifiedParser>> {
let creator = self.creator(name).ok_or_else(|| crate::Error::ParserUnavailableByName {
kind: "unified",
name: name.to_string(),
available_names: self.list(),
})?;
creator(tools, tokenizer).map_err(|error| crate::Error::ParserInitialization {
kind: "unified",
name: name.to_string(),
error: error.into(),
})
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use vllm_tokenizer::test_utils::TestTokenizer;
use super::{UnifiedParserFactory, names};
fn tokenizer() -> TestTokenizer {
TestTokenizer::new()
.with_regular_token("<|channel>", 256)
.with_regular_token("<channel|>", 257)
}
fn inkling_tokenizer() -> TestTokenizer {
TestTokenizer::new()
.with_regular_token("<|message_model|>", 200001)
.with_regular_token("<|content_text|>", 200004)
.with_regular_token("<|content_thinking|>", 200008)
}
#[test]
fn factory_registers_gemma4() {
let factory = UnifiedParserFactory::new();
assert!(factory.contains(names::GEMMA4));
assert_eq!(
factory.resolve_name_for_model("google/gemma-4-27b-it"),
Some(names::GEMMA4)
);
factory.create(names::GEMMA4, &[], Arc::new(tokenizer())).unwrap();
}
#[test]
fn factory_registers_inkling() {
let factory = UnifiedParserFactory::new();
assert!(factory.contains(names::INKLING));
assert_eq!(
factory.resolve_name_for_model("thinkingmachines/Inkling"),
Some(names::INKLING)
);
factory.create(names::INKLING, &[], Arc::new(inkling_tokenizer())).unwrap();
}
}