Skip to content

vllm_mlx.reasoning.glm4_parser

Reasoning parser for GLM-4 models (GLM-4.5-Air, GLM-4.6V, GLM-4.7, etc.).

View the complete module source at #L1-L113.

API details

Each callable below includes its exact signature, type annotations, inputs, defaults, return contract, documented exceptions, implementation source, and parsed docstring sections when the source provides them.

vllm_mlx.reasoning.glm4_parser

Reasoning parser for GLM-4 models (GLM-4.5-Air, GLM-4.6V, GLM-4.7, etc.).

GLM-4 uses ... tags for reasoning content, same as Qwen3. However, unlike Qwen3, GLM-4 does NOT inject in the prompt — the model decides autonomously whether to reason.

This means: - Output without tags = normal response (no reasoning) - Output with tags = reasoning + content

This is the opposite of Qwen3 where no tags = pure reasoning (because was injected in the prompt and the model hit max_tokens).

GLM-4.6V also wraps responses in <|begin_of_box|>...<|end_of_box|> container tags which must be stripped before returning content.

vllm_mlx.reasoning.glm4_parser._BOX_START module-attribute

_BOX_START = '<|begin_of_box|>'

vllm_mlx.reasoning.glm4_parser._BOX_END module-attribute

_BOX_END = '<|end_of_box|>'

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser

Glm4ReasoningParser(tokenizer=None)

Bases: BaseThinkingReasoningParser

Reasoning parser for GLM-4 models.

GLM-4 uses ... tokens to denote reasoning text. Unlike Qwen3, the template does NOT inject in the prompt, so output without tags is a normal response (not truncated reasoning).

Supports three scenarios: 1. Both tags in output: reasoningcontent 2. Only closing tag (think in prompt): reasoningcontent 3. No tags: pure content (NOT reasoning)

Example (with thinking): Input: "Let me analyze...The answer is 42." Output: reasoning="Let me analyze...", content="The answer is 42."

Example (no thinking): Input: "The answer is 42." Output: reasoning=None, content="The answer is 42."

Source code in vllm_mlx/reasoning/think_parser.py
def __init__(self, tokenizer=None):
    super().__init__(tokenizer)
    # Streaming state — reset per request via reset_state()
    self._phase: str = "pre_think"  # "pre_think" | "thinking" | "content"
    self._content_started = False
    self._content_buffer = ""
    # Tool call promotion state.
    self._in_tool_call = False
    self._tool_call_buffer = ""

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.start_token property

start_token: str

Return the marker that opens a GLM reasoning span.

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.end_token property

end_token: str

Return the marker that closes a GLM reasoning span.

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.extract_reasoning

extract_reasoning(model_output: str) -> tuple[str | None, str | None]

Strip GLM box markers and split complete reasoning from content.

Source code in vllm_mlx/reasoning/glm4_parser.py
def extract_reasoning(
    self,
    model_output: str,
) -> tuple[str | None, str | None]:
    """Strip GLM box markers and split complete reasoning from content."""

    cleaned = model_output.replace(_BOX_START, "").replace(_BOX_END, "")
    return super().extract_reasoning(cleaned)

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.extract_reasoning_streaming

extract_reasoning_streaming(previous_text: str, current_text: str, delta_text: str) -> DeltaMessage | None

Extract reasoning from streaming delta.

Overrides base class pre_think behavior: when no tags have been seen, emit delta as content (not reasoning). GLM-4 doesn't inject in the prompt, so early tokens without tags are normal content.

Once is seen, delegates to base class state machine.

Source code in vllm_mlx/reasoning/glm4_parser.py
def extract_reasoning_streaming(
    self,
    previous_text: str,
    current_text: str,
    delta_text: str,
) -> DeltaMessage | None:
    """
    Extract reasoning from streaming delta.

    Overrides base class pre_think behavior: when no tags have been seen,
    emit delta as content (not reasoning). GLM-4 doesn't inject <think>
    in the prompt, so early tokens without tags are normal content.

    Once <think> is seen, delegates to base class state machine.
    """
    # Strip GLM-4.6V box container tags (special tokens, always whole)
    delta_text = delta_text.replace(_BOX_START, "").replace(_BOX_END, "")
    if not delta_text:
        return None

    start_tok = self.start_token
    end_tok = self.end_token

    # In pre_think phase: check if we should treat as content
    if self._phase == "pre_think":
        # If start tag appeared, transition to thinking via base class
        if start_tok in current_text:
            return super().extract_reasoning_streaming(
                previous_text, current_text, delta_text
            )

        # If end tag appeared without start (implicit mode from agent)
        if end_tok in current_text:
            return super().extract_reasoning_streaming(
                previous_text, current_text, delta_text
            )

        # No tags yet — GLM-4 doesn't inject <think>, so this is content
        return DeltaMessage(content=delta_text)

    # In thinking or content phase, delegate to base class
    return super().extract_reasoning_streaming(
        previous_text, current_text, delta_text
    )

Complete contract reference

Expand any definition for its exact inputs, annotations, defaults, return contract, directly raised exceptions, source-grounded behavior, and immutable line link. This section includes private and nested definitions that ordinary API generators omit.

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser · class
vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser()

Reasoning parser for GLM-4 models.

Parameters

This callable has no explicit inputs.

Returns

  • Constructs: vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser

Exceptions and behavior

Class Glm4ReasoningParser derives from BaseThinkingReasoningParser and declares 4 direct member(s). No direct raise statement appears in this definition.

View source #L27-L113.

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.start_token · method
vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.start_token() -> str

Return the marker that opens a GLM reasoning span.

Parameters

This callable has no explicit inputs.

Returns

  • Type: str
  • Direct return expressions: '<think>'

Exceptions and behavior

Method Glm4ReasoningParser.start_token returns '<think>'. No direct raise statement appears in this definition.

View source #L50-L53.

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.end_token · method
vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.end_token() -> str

Return the marker that closes a GLM reasoning span.

Parameters

This callable has no explicit inputs.

Returns

  • Type: str
  • Direct return expressions: '</think>'

Exceptions and behavior

Method Glm4ReasoningParser.end_token returns '</think>'. No direct raise statement appears in this definition.

View source #L56-L59.

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.extract_reasoning · method
vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.extract_reasoning(model_output: str) -> tuple[str | None, str | None]

Strip GLM box markers and split complete reasoning from content.

Parameters

Name Type Required Default Description
model_output str yes none Required positional or keyword input.

Returns

  • Type: tuple[str | None, str | None]
  • Direct return expressions: super().extract_reasoning(cleaned)

Exceptions and behavior

Method Glm4ReasoningParser.extract_reasoning calls model_output.replace(_BOX_START, '').replace, model_output.replace, super().extract_reasoning, super; returns super().extract_reasoning(cleaned). No direct raise statement appears in this definition.

View source #L61-L68.

vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.extract_reasoning_streaming · method
vllm_mlx.reasoning.glm4_parser.Glm4ReasoningParser.extract_reasoning_streaming(previous_text: str, current_text: str, delta_text: str) -> DeltaMessage | None

Extract reasoning from streaming delta.

Parameters

Name Type Required Default Description
previous_text str yes none Required positional or keyword input.
current_text str yes none Required positional or keyword input.
delta_text str yes none Required positional or keyword input.

Returns

  • Type: DeltaMessage | None
  • Direct return expressions: None; super().extract_reasoning_streaming(previous_text, current_text, delta_text); DeltaMessage(content=delta_text)

Exceptions and behavior

Method Glm4ReasoningParser.extract_reasoning_streaming calls delta_text.replace(_BOX_START, '').replace, delta_text.replace, super().extract_reasoning_streaming, super; has 3 explicit return paths. No direct raise statement appears in this definition.

View source #L70-L113.

Complete symbol map

This map also includes private definitions and nested helpers. The signature column exposes every explicit input even when an internal helper has no dedicated parameter prose.

Symbol Kind Signature and inputs What it does Source
Glm4ReasoningParser class Glm4ReasoningParser() Reasoning parser for GLM-4 models. #L27-L113
Glm4ReasoningParser.start_token method Glm4ReasoningParser.start_token() -> str Return the marker that opens a GLM reasoning span. #L50-L53
Glm4ReasoningParser.end_token method Glm4ReasoningParser.end_token() -> str Return the marker that closes a GLM reasoning span. #L56-L59
Glm4ReasoningParser.extract_reasoning method Glm4ReasoningParser.extract_reasoning(model_output: str) -> tuple[str \| None, str \| None] Strip GLM box markers and split complete reasoning from content. #L61-L68
Glm4ReasoningParser.extract_reasoning_streaming method Glm4ReasoningParser.extract_reasoning_streaming(previous_text: str, current_text: str, delta_text: str) -> DeltaMessage \| None Extract reasoning from streaming delta. #L70-L113