-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathcontent_utils.py
More file actions
69 lines (53 loc) · 2.03 KB
/
content_utils.py
File metadata and controls
69 lines (53 loc) · 2.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
"""Utilities for message content processing."""
from __future__ import annotations
import re
START_BLOCK_REASONING = "<think>"
END_REASONING = "</think>"
_THINK_BLOCK_PATTERN = re.compile(r"```think\s*\n(.*?)\n```\s*", re.DOTALL)
_REASONING_BLOCK_PATTERN = re.compile(
rf"{re.escape(START_BLOCK_REASONING)}\s*\n(.*?)\n{re.escape(END_REASONING)}\s*",
re.DOTALL,
)
def split_reasoning_and_content(text: str) -> tuple[str | None, str]:
"""Split content into reasoning and official response.
Handles legacy format where reasoning was concatenated as ```think...```
before the response. Used when loading from DB or after streaming.
Args:
text: Content that may contain ```think...``` block.
Returns:
Tuple of (reasoning, content). If no think block, returns (None, text).
"""
if not text:
return None, text or ""
match = _THINK_BLOCK_PATTERN.search(text)
if not match:
return None, text
reasoning = match.group(1).strip()
content = (_THINK_BLOCK_PATTERN.sub("", text) or "").strip()
return reasoning or None, content
def format_response_for_display(
reasoning: str | None, content: str, show_reasoning: bool
) -> str:
"""Format response for display (reasoning + content or content only)."""
if show_reasoning and reasoning:
return f"{START_BLOCK_REASONING}\n{reasoning}\n{END_REASONING}\n\n{content}"
return content
def split_reasoning_and_content_from_display(
text: str,
) -> tuple[str | None, str]:
"""Split display text (<think>...</think> format) into reasoning and content.
Used when parsing user-edited response text (e.g. in edit block dialog).
Args:
text: Display text that may contain <think>...</think> block.
Returns:
Tuple of (reasoning, content). If no block, returns (None, text).
"""
if not text:
return None, text or ""
# Try <think> format first, then legacy ```think
match = _REASONING_BLOCK_PATTERN.search(text)
if not match:
return split_reasoning_and_content(text)
reasoning = match.group(1).strip()
content = (_REASONING_BLOCK_PATTERN.sub("", text) or "").strip()
return reasoning or None, content