Coverage for /home/admin/Documents/AI/applications/lexigram-dev/lexigram/experimental/ai/lexigram-ai-llm/src/lexigram/ai/llm/thinking/patterns.py: 100%

10 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 07:19 +0800

1"""Thinking block pattern definitions for LLM output extraction.""" 

2 

3from __future__ import annotations 

4 

5from dataclasses import dataclass 

6 

7 

8@dataclass(frozen=True) 

9class ThinkingPattern: 

10 """Pattern for detecting and extracting thinking blocks from LLM output. 

11 

12 Attributes: 

13 name: Human-readable name of the pattern. 

14 start_marker: Opening delimiter. May be empty string for bare-closing variant. 

15 end_marker: Closing delimiter. 

16 strip_end_marker: Whether the end marker itself should be removed from content. 

17 """ 

18 

19 name: str 

20 start_marker: str 

21 end_marker: str 

22 strip_end_marker: bool 

23 

24 

25# Ordered list of patterns (most specific first) 

26# Ordered list of patterns (most specific first) 

27THINKING_PATTERNS: list[ThinkingPattern] = [ 

28 # Gemma-4 channel format — handled by _extract_gemma_channel() in normalizer.py. 

29 # Official format: <|channel>thought\n...thinking...\n<channel|>\n...response... 

30 # The start_marker here is unused by the special-case handler but kept for 

31 # documentation. The normalizer identifies this entry by name="gemma_channel". 

32 ThinkingPattern( 

33 name="gemma_channel", 

34 start_marker="<|channel>thought", 

35 end_marker="<channel|>", 

36 strip_end_marker=True, 

37 ), 

38 # Qwen3 pipe-delimited format: <|think|>...</|think|> 

39 ThinkingPattern( 

40 name="qwen3_pipe", 

41 start_marker="<|think|>", 

42 end_marker="</|think|>", 

43 strip_end_marker=True, 

44 ), 

45 # XML think tags (DeepSeek-R1, Qwen3): <think>...</think> 

46 ThinkingPattern( 

47 name="xml_think", 

48 start_marker="<think>", 

49 end_marker="</think>", 

50 strip_end_marker=True, 

51 ), 

52 # Markdown fence: ```thinking\n...\n``` 

53 ThinkingPattern( 

54 name="markdown_fence", 

55 start_marker="```thinking", 

56 end_marker="```", 

57 strip_end_marker=True, 

58 ), 

59 # Bare closing tag (no opening): ...thinking text...</think> 

60 ThinkingPattern( 

61 name="bare_closing_tag", 

62 start_marker="", 

63 end_marker="</think>", 

64 strip_end_marker=True, 

65 ), 

66] 

67 

68__all__ = ["THINKING_PATTERNS", "ThinkingPattern"]