@@ -112,14 +112,36 @@ def detect_and_parse(self, text: str, tools: List[Tool]) -> StreamingParseResult
112112 logger .warning (f"Official parser failed, falling back to regex: { e } " )
113113
114114 # Fallback to regex-based parsing
115- idx = text .find (self .bot_token )
116- normal_text = text [:idx ].strip () if idx != - 1 else text
117- return self ._parse_with_regex (text , tools , normal_text )
115+ return self ._parse_with_regex (text , tools )
118116
119- def _parse_with_regex (self , text : str , tools : List [Tool ], normal_text : str ) -> StreamingParseResult :
117+ def _parse_with_regex (self , text : str , tools : List [Tool ]) -> StreamingParseResult :
120118 """Fallback regex-based parsing when official parser is not available."""
121119 import re
122120
121+ # Find the tool calls section boundaries
122+ start_idx = text .find (self .bot_token )
123+ end_idx = text .find (self .eot_token )
124+
125+ if start_idx == - 1 :
126+ return StreamingParseResult (normal_text = text , calls = [])
127+
128+ # Extract normal text before and after tool calls
129+ text_before = text [:start_idx ].strip ()
130+ text_after = ""
131+ if end_idx != - 1 :
132+ # Find the actual end position (after the closing tag)
133+ end_pos = end_idx + len (self .eot_token )
134+ text_after = text [end_pos :].strip ()
135+
136+ # Combine before and after text
137+ normal_text_parts = []
138+ if text_before :
139+ normal_text_parts .append (text_before )
140+ if text_after :
141+ normal_text_parts .append (text_after )
142+ normal_text = "\n \n " .join (normal_text_parts )
143+
144+ # Parse tool calls using regex
123145 invoke_pattern = re .compile (
124146 rf'<{ re .escape (self .dsml_token )} invoke name="(.*?)">(.*?)</{ re .escape (self .dsml_token )} invoke>' ,
125147 re .DOTALL
0 commit comments