From 6f1585e88f027195585c8ea17509eec67ab2e346 Mon Sep 17 00:00:00 2001 From: Liang Jiaqing Date: Sat, 11 Apr 2026 18:25:54 +0800 Subject: [PATCH] fix: comment out MixinSession copy to prevent tools not propagating to original session --- llmcore.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/llmcore.py b/llmcore.py index d1a9413..742a7a1 100644 --- a/llmcore.py +++ b/llmcore.py @@ -563,14 +563,7 @@ class NativeClaudeSession(BaseSession): text_parts = [b["text"] for b in content_blocks if b.get("type") == "text"] content = "\n".join(text_parts).strip() tool_calls = [MockToolCall(b["name"], b.get("input", {}), id=b.get("id", "")) for b in content_blocks if b.get("type") == "tool_use"] - if len(tool_calls) == 0 and content.endswith('}]'): - _pat = next((p for p in ['[{"type":"tool_use"', '[{"type": "tool_use"'] if p in content), None) - if _pat: - try: - idx = content.index(_pat); raw = json.loads(content[idx:]) - tool_calls = [MockToolCall(b["name"], b.get("input", {}), id=b.get("id", "")) for b in raw if b.get("type") == "tool_use"] - content = content[:idx].strip() - except: pass + if not tool_calls: tool_calls, content = _parse_text_tool_calls(content) think_pattern = r"(.*?)"; thinking = '' think_match = re.search(think_pattern, content, re.DOTALL) if think_match: @@ -747,6 +740,28 @@ class ToolClient: content = remaining_text.strip() return MockResponse(thinking, content, tool_calls, text) +def _parse_text_tool_calls(content): + """Fallback: extract tool calls from text when model doesn't use native tool_use blocks.""" + tcs = [] + # try JSON array: [{"type":"tool_use", "name":..., "input":...}] + _jp = next((p for p in ['[{"type":"tool_use"', '[{"type": "tool_use"'] if p in content), None) + if _jp and content.endswith('}]'): + try: + idx = content.index(_jp); raw = json.loads(content[idx:]) + tcs = [MockToolCall(b["name"], b.get("input", {}), id=b.get("id", "")) for b in raw if b.get("type") == "tool_use"] + return tcs, content[:idx].strip() + except: pass + # try XML tags: {"name":..., "arguments":...} + _xp = r"<(?:tool_use|tool_call)>((?:(?!<(?:tool_use|tool_call)>).){15,}?)" + for s in re.findall(_xp, content, re.DOTALL): + try: + d = tryparse(s.strip()); name = d.get('name') + args = d.get('arguments') or d.get('args') or d.get('input') or {} + if name: tcs.append(MockToolCall(name, args)) + except: pass + if tcs: content = re.sub(_xp, "", content, flags=re.DOTALL).strip() + return tcs, content + def _write_llm_log(label, content): log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'temp/model_responses') os.makedirs(log_dir, exist_ok=True) @@ -778,7 +793,7 @@ class MixinSession: assert len(groups) == 1, f"MixinSession: sessions must be in same group (Native or non-Native), got {[type(s).__name__ for s in self._sessions]}" self.name = '|'.join(s.name for s in self._sessions) self._orig_raw_asks = [s.raw_ask for s in self._sessions] - import copy; self._sessions[0] = copy.copy(self._sessions[0]) + #import copy; self._sessions[0] = copy.copy(self._sessions[0]) self._sessions[0].raw_ask = self._raw_ask self.default_model = getattr(self._sessions[0], 'default_model', None) self._cur_idx, self._switched_at = 0, 0.0