| 1 | # SPDX-License-Identifier: Apache-2.0 |
| 2 | # SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | """DeepSeek V4.1 reasoning and spaced DSML tool calls.""" |
| 4 | |
| 5 | import functools |
| 6 | from dataclasses import replace |
| 7 | |
| 8 | from vllm.parser.deepseek_v4 import ( |
| 9 | DeepSeekV4Parser, |
| 10 | _dsml_arg_converter, |
| 11 | _param_patterns, |
| 12 | deepseek_v4_config, |
| 13 | ) |
| 14 | from vllm.parser.engine.parser_engine_config import ParserEngineConfig |
| 15 | |
| 16 | DSML_TOOL_START = "<|DSML| calls>" |
| 17 | DSML_TOOL_END = "</|DSML| calls>" |
| 18 | DSML_INVOKE_PREFIX = '<|DSML| invoke name="' |
| 19 | DSML_INVOKE_END = "</|DSML| invoke>" |
| 20 | DSML_PARAM_START = "<|DSML| parameter" |
| 21 | DSML_PARAM_CLOSE = "</|DSML| parameter>" |
| 22 | |
| 23 | _PARAM_RE, _PARTIAL_PARAM_RE = _param_patterns(DSML_PARAM_START, DSML_PARAM_CLOSE) |
| 24 | |
| 25 | |
| 26 | @functools.cache |
| 27 | def deepseek_v41_config(thinking: bool = False) -> ParserEngineConfig: |
| 28 | config = deepseek_v4_config(thinking=thinking) |
| 29 | terminal_overrides = { |
| 30 | "TOOL_START": DSML_TOOL_START, |
| 31 | "TOOL_END": DSML_TOOL_END, |
| 32 | "INVOKE_PREFIX": DSML_INVOKE_PREFIX, |
| 33 | "INVOKE_END": DSML_INVOKE_END, |
| 34 | "PARAM_START": DSML_PARAM_START, |
| 35 | "PARAM_CLOSE": DSML_PARAM_CLOSE, |
| 36 | } |
| 37 | return replace( |
| 38 | config, |
| 39 | name="deepseek_v41", |
| 40 | terminals={**config.terminals, **terminal_overrides}, |
| 41 | token_id_terminals={ |
| 42 | key: terminal_overrides.get(key, value) |
| 43 | for key, value in config.token_id_terminals.items() |
| 44 | }, |
| 45 | arg_converter=functools.partial( |
| 46 | _dsml_arg_converter, |
| 47 | param_re=_PARAM_RE, |
| 48 | partial_param_re=_PARTIAL_PARAM_RE, |
| 49 | ), |
| 50 | ) |
| 51 | |
| 52 | |
| 53 | class DeepSeekV41Parser(DeepSeekV4Parser): |
| 54 | parser_config = staticmethod(deepseek_v41_config) |