diff --git a/lib/crewai/src/crewai/new_agent/executor.py b/lib/crewai/src/crewai/new_agent/executor.py
index 640d32e1b..35b6c03dd 100644
--- a/lib/crewai/src/crewai/new_agent/executor.py
+++ b/lib/crewai/src/crewai/new_agent/executor.py
@@ -625,22 +625,14 @@ class ConversationalAgentExecutor(BaseModel):
pass
return ""
- _SUMMARY_EXTRACT_RE = re.compile(
- r"\s*(.*?)\s*", re.DOTALL
+ _INTERNAL_TAG_RE = re.compile(
+ r".*?", re.DOTALL
)
def _strip_internal_tags(self, text: str) -> str:
- """Handle tags leaked from the summarization prompt.
-
- Some models (e.g. gpt-4.1) wrap their actual response in
- tags, treating the preceding text as chain-of-thought. When summary
- tags are present we extract the inner content as the real answer.
- """
- match = self._SUMMARY_EXTRACT_RE.search(text)
- if match:
- inner = match.group(1).strip()
- return inner if inner else text
- return text
+ """Strip blocks that leak from the summarization prompt."""
+ cleaned = self._INTERNAL_TAG_RE.sub("", text).strip()
+ return cleaned if cleaned else text
def _detect_artifacts(self, tool_name: str, result_str: str) -> list[Artifact]:
"""GAP-67: Detect artifacts from tool results.
@@ -2413,77 +2405,38 @@ class ConversationalAgentExecutor(BaseModel):
invoke_task = asyncio.create_task(self.ainvoke(user_message))
_streamed_chars = 0
_last_status_time = time.monotonic()
-
- # States: "preflight" (buffering, no seen yet),
- # "inside" ( found, yielding inner content),
- # "done" ( seen, suppress the rest),
- # "passthrough" (no summary tags — yield everything)
- _state = "preflight"
- _preflight_buf: list[str] = []
_tag_buf = ""
+ _suppressing = False
def _filter_chunk(raw: str) -> str:
- nonlocal _state, _tag_buf
- out: list[str] = []
+ """Suppress ... blocks from streamed chunks."""
+ nonlocal _tag_buf, _suppressing
+ out = []
for ch in raw:
- if _state == "done":
- break
-
- if _state == "passthrough":
- out.append(ch)
+ if _suppressing:
+ _tag_buf += ch
+ if _tag_buf.endswith(""):
+ _suppressing = False
+ _tag_buf = ""
continue
-
- # Accumulate into tag buffer when we might be mid-tag
if _tag_buf:
_tag_buf += ch
-
- if _state == "preflight":
- target = ""
- if target[: len(_tag_buf)] == _tag_buf:
- if _tag_buf == target:
- _state = "inside"
- _preflight_buf.clear()
- _tag_buf = ""
+ if len(_tag_buf) <= len(""):
+ if ""[: len(_tag_buf)] == _tag_buf:
+ if _tag_buf == "":
+ _suppressing = True
continue
- # Not a match — dump tag_buf to preflight buffer
- _preflight_buf.append(_tag_buf)
- _tag_buf = ""
-
- elif _state == "inside":
- target = ""
- if target[: len(_tag_buf)] == _tag_buf:
- if _tag_buf == target:
- _state = "done"
- _tag_buf = ""
- continue
- # Not a closing tag — flush buffered chars
out.append(_tag_buf)
_tag_buf = ""
- continue
-
- if ch == "<":
+ else:
+ out.append(_tag_buf)
+ _tag_buf = ""
+ elif ch == "<":
_tag_buf = ch
- continue
-
- if _state == "preflight":
- _preflight_buf.append(ch)
- elif _state == "inside":
+ else:
out.append(ch)
-
return "".join(out)
- def _flush_preflight() -> str:
- """If we never saw , flush buffered text."""
- nonlocal _state
- if _state == "preflight":
- _state = "passthrough"
- result = "".join(_preflight_buf)
- _preflight_buf.clear()
- if _tag_buf:
- result += _tag_buf
- return result
- return ""
-
try:
while not invoke_task.done():
try:
@@ -2507,10 +2460,8 @@ class ConversationalAgentExecutor(BaseModel):
_streamed_chars += len(filtered)
yield filtered
- leftover = _flush_preflight()
- if leftover:
- _streamed_chars += len(leftover)
- yield leftover
+ if _tag_buf and not _suppressing:
+ yield _tag_buf
result = invoke_task.result()
self._last_stream_result = result