diff --git a/agent/component/docs_generator.py b/agent/component/docs_generator.py
index 297fac9b1..9c89eefbf 100644
--- a/agent/component/docs_generator.py
+++ b/agent/component/docs_generator.py
@@ -189,7 +189,7 @@ class DocGenerator(Message, ABC):
flags=re.DOTALL,
)
- return content
+ return self._strip_thinking(content)
def _get_output_directory(self) -> str:
os.makedirs(self._default_output_directory, exist_ok=True)
diff --git a/agent/component/message.py b/agent/component/message.py
index 6b03b5f44..d9077313d 100644
--- a/agent/component/message.py
+++ b/agent/component/message.py
@@ -365,10 +365,31 @@ class Message(ComponentBase):
return None
+ @staticmethod
+ def _strip_thinking(content: str) -> str:
+ """Remove ... reasoning blocks before document export.
+
+ Reasoning models (e.g. DeepSeek-R1, OpenAI o1) embed chain-of-thought
+ inside ```` tags. These blocks must not leak into exported
+ Word/PDF/Excel documents.
+ """
+ if not isinstance(content, str) or not content:
+ return content
+ # Remove complete think blocks (DOTALL so newlines are matched)
+ cleaned = re.sub(r".*?", "", content, flags=re.DOTALL)
+ # Remove any dangling unclosed opening tag + trailing content
+ cleaned = re.sub(r".*$", "", cleaned, flags=re.DOTALL)
+ # Remove leftover standalone tags
+ cleaned = re.sub(r"?think>", "", cleaned)
+ # Collapse 3+ consecutive newlines left behind by removed blocks
+ cleaned = re.sub(r"\n{3,}", "\n\n", cleaned)
+ return cleaned.strip()
+
def _convert_content(self, content):
if not self._param.output_format:
return
+ content = self._strip_thinking(content)
import pypandoc
doc_id = get_uuid()