@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / c02a2705f9
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 11, 03:45 UTC

Update MiniMax-M2 ToolCall and add MiniMax-M2.1 in Docs (#31083)

Signed-off-by: xuebi <xuebi@minimaxi.com> Co-authored-by: xuebi <xuebi@minimaxi.com>

Roger Young committed Dec 22, 2025 at 13:28 UTC c02a2705f9ceeb00b5d32453621f997b2ceafbea
2 files changed +167 -48
docs/models/supported_models.md
+1 -1
@@ -418,7 +418,7 @@ th {
418 | `MiMoV2FlashForCausalLM` | MiMoV2Flash | `XiaomiMiMo/MiMo-V2-Flash`, etc. | ︎| ✅︎ |
419 | `MiniCPMForCausalLM` | MiniCPM | `openbmb/MiniCPM-2B-sft-bf16`, `openbmb/MiniCPM-2B-dpo-bf16`, `openbmb/MiniCPM-S-1B-sft`, etc. | ✅︎ | ✅︎ |
420 | `MiniCPM3ForCausalLM` | MiniCPM3 | `openbmb/MiniCPM3-4B`, etc. | ✅︎ | ✅︎ |
421 -| `MiniMaxM2ForCausalLM` | MiniMax-M2 |`MiniMaxAI/MiniMax-M2`, etc. | | ✅︎ |
421 +| `MiniMaxM2ForCausalLM` | MiniMax-M2, MiniMax-M2.1 |`MiniMaxAI/MiniMax-M2`, etc. | | ✅︎ |
422 | `MistralForCausalLM` | Ministral-3, Mistral, Mistral-Instruct | `mistralai/Ministral-3-3B-Instruct-2512`, `mistralai/Mistral-7B-v0.1`, `mistralai/Mistral-7B-Instruct-v0.1`, etc. | ✅︎ | ✅︎ |
423 | `MistralLarge3ForCausalLM` | Mistral-Large-3-675B-Base-2512, Mistral-Large-3-675B-Instruct-2512 | `mistralai/Mistral-Large-3-675B-Base-2512`, `mistralai/Mistral-Large-3-675B-Instruct-2512`, etc. | ✅︎ | ✅︎ |
424 | `MixtralForCausalLM` | Mixtral-8x7B, Mixtral-8x7B-Instruct | `mistralai/Mixtral-8x7B-v0.1`, `mistralai/Mixtral-8x7B-Instruct-v0.1`, `mistral-community/Mixtral-8x22B-v0.1`, etc. | ✅︎ | ✅︎ |
vllm/tool_parsers/minimax_m2_tool_parser.py
+166 -47
@@ -138,37 +138,167 @@ class MinimaxM2ToolParser(ToolParser):
138 return name_str
139
140 def _convert_param_value(self, value: str, param_type: str) -> Any:
141 - """Convert parameter value to the correct type."""
141 + """Convert parameter value to the correct type (legacy single-type version)."""
142 + return self._convert_param_value_with_types(value, [param_type])
143 +
144 + def _extract_types_from_schema(self, schema: Any) -> list[str]:
145 + """
146 + Extract all possible types from a JSON schema definition.
147 + Handles anyOf, oneOf, allOf, type arrays, and enum fields.
148 +
149 + Args:
150 + schema: The JSON schema definition for a parameter
151 +
152 + Returns:
153 + List of type strings (e.g., ["string", "integer", "null"])
154 + """
155 + if schema is None:
156 + return ["string"]
157 +
158 + if not isinstance(schema, dict):
159 + return ["string"]
160 +
161 + types: set[str] = set()
162 +
163 + # Handle direct "type" field
164 + if "type" in schema:
165 + type_value = schema["type"]
166 + if isinstance(type_value, str):
167 + types.add(type_value)
168 + elif isinstance(type_value, list):
169 + for t in type_value:
170 + if isinstance(t, str):
171 + types.add(t)
172 +
173 + # Handle enum - infer types from enum values
174 + if "enum" in schema and isinstance(schema["enum"], list) and schema["enum"]:
175 + for value in schema["enum"]:
176 + if value is None:
177 + types.add("null")
178 + elif isinstance(value, bool):
179 + types.add("boolean")
180 + elif isinstance(value, int):
181 + types.add("integer")
182 + elif isinstance(value, float):
183 + types.add("number")
184 + elif isinstance(value, str):
185 + types.add("string")
186 + elif isinstance(value, list):
187 + types.add("array")
188 + elif isinstance(value, dict):
189 + types.add("object")
190 +
191 + # Handle anyOf, oneOf, allOf - recursively extract types
192 + for choice_field in ("anyOf", "oneOf", "allOf"):
193 + if choice_field in schema and isinstance(schema[choice_field], list):
194 + for choice in schema[choice_field]:
195 + extracted = self._extract_types_from_schema(choice)
196 + types.update(extracted)
197 +
198 + # If no types found, default to string
199 + if not types:
200 + return ["string"]
201 +
202 + return list(types)
203 +
204 + def _convert_param_value_with_types(
205 + self, value: str, param_types: list[str]
206 + ) -> Any:
207 + """
208 + Convert parameter value to the correct type based on a list of possible types.
209 + Tries each type in order until one succeeds.
210 +
211 + Args:
212 + value: The string value to convert
213 + param_types: List of possible type strings
214 +
215 + Returns:
216 + The converted value
217 + """
218 if value.lower() == "null":
219 return None
220
145 - param_type = param_type.lower()
146 - if param_type in ["string", "str", "text"]:
147 - return value
148 - elif param_type in ["integer", "int"]:
149 - try:
150 - return int(value)
151 - except (ValueError, TypeError):
152 - return value
153 - elif param_type in ["number", "float"]:
154 - try:
155 - val = float(value)
156 - return val if val != int(val) else int(val)
157 - except (ValueError, TypeError):
158 - return value
159 - elif param_type in ["boolean", "bool"]:
160 - return value.lower() in ["true", "1"]
161 - elif param_type in ["object", "array"]:
162 - try:
163 - return json.loads(value)
164 - except json.JSONDecodeError:
165 - return value
166 - else:
167 - # Try JSON parse first, fallback to string
168 - try:
169 - return json.loads(value)
170 - except json.JSONDecodeError:
221 + # Normalize types
222 + normalized_types = [t.lower() for t in param_types]
223 +
224 + # Try null first if it's in the list
225 + if "null" in normalized_types or value.lower() in ("null", "none", "nil"):
226 + return None
227 +
228 + # Try each type in order of preference (most specific first, string as fallback)
229 + # Priority: integer > number > boolean > object > array > string
230 + type_priority = [
231 + "integer",
232 + "int",
233 + "number",
234 + "float",
235 + "boolean",
236 + "bool",
237 + "object",
238 + "array",
239 + "string",
240 + "str",
241 + "text",
242 + ]
243 +
244 + for param_type in type_priority:
245 + if param_type not in normalized_types:
246 + continue
247 +
248 + if param_type in ["string", "str", "text"]:
249 return value
250 + elif param_type in ["integer", "int"]:
251 + try:
252 + return int(value)
253 + except (ValueError, TypeError):
254 + continue
255 + elif param_type in ["number", "float"]:
256 + try:
257 + val = float(value)
258 + return val if val != int(val) else int(val)
259 + except (ValueError, TypeError):
260 + continue
261 + elif param_type in ["boolean", "bool"]:
262 + lower_val = value.lower().strip()
263 + if lower_val in ["true", "1", "yes", "on"]:
264 + return True
265 + elif lower_val in ["false", "0", "no", "off"]:
266 + return False
267 + continue
268 + elif param_type in ["object", "array"]:
269 + try:
270 + return json.loads(value)
271 + except json.JSONDecodeError:
272 + continue
273 +
274 + # Fallback: try JSON parse, then return as string
275 + try:
276 + return json.loads(value)
277 + except json.JSONDecodeError:
278 + return value
279 +
280 + def _get_param_types_from_config(
281 + self, param_name: str, param_config: dict
282 + ) -> list[str]:
283 + """
284 + Get parameter types from parameter configuration.
285 + Handles anyOf, oneOf, allOf, and direct type definitions.
286 +
287 + Args:
288 + param_name: The name of the parameter
289 + param_config: The properties dict from the tool schema
290 +
291 + Returns:
292 + List of type strings
293 + """
294 + if param_name not in param_config:
295 + return ["string"]
296 +
297 + param_schema = param_config[param_name]
298 + if not isinstance(param_schema, dict):
299 + return ["string"]
300 +
301 + return self._extract_types_from_schema(param_schema)
302
303 def _parse_single_invoke(
304 self, invoke_str: str, tools: list | None
@@ -207,17 +337,11 @@ class MinimaxM2ToolParser(ToolParser):
337 if param_value.endswith("\n"):
338 param_value = param_value[:-1]
339
210 - # Get parameter type
211 - param_type = "string"
212 - if (
213 - param_name in param_config
214 - and isinstance(param_config[param_name], dict)
215 - and "type" in param_config[param_name]
216 - ):
217 - param_type = param_config[param_name]["type"]
340 + # Get parameter types (supports anyOf/oneOf/allOf)
341 + param_type = self._get_param_types_from_config(param_name, param_config)
342
343 # Convert value
220 - param_dict[param_name] = self._convert_param_value(
344 + param_dict[param_name] = self._convert_param_value_with_types(
345 param_value, param_type
346 )
347
@@ -593,7 +717,7 @@ class MinimaxM2ToolParser(ToolParser):
717 # Store raw value for later processing
718 self.accumulated_params[self.current_param_name] = param_value
719
596 - # Get parameter configuration for type conversion
720 + # Get parameter configuration with anyOf support
721 param_config = {}
722 if self.streaming_request and self.streaming_request.tools:
723 for tool in self.streaming_request.tools:
@@ -610,17 +734,12 @@ class MinimaxM2ToolParser(ToolParser):
734 param_config = params["properties"]
735 break
736
613 - # Get parameter type
614 - param_type = "string"
615 - if (
616 - self.current_param_name in param_config
617 - and isinstance(param_config[self.current_param_name], dict)
618 - and "type" in param_config[self.current_param_name]
619 - ):
620 - param_type = param_config[self.current_param_name]["type"]
737 + # Get parameter types (supports anyOf/oneOf/allOf)
738 + param_type = self._get_param_types_from_config(
739 + self.current_param_name, param_config
740 + )
741
622 - # Convert param value to appropriate type
623 - converted_value = self._convert_param_value(
742 + converted_value = self._convert_param_value_with_types(
743 param_value, param_type
744 )
745