diff --git a/services/agent_loop.py b/scripts/agent_loop.py similarity index 99% rename from services/agent_loop.py rename to scripts/agent_loop.py index 5af5b19..cdbef1a 100644 --- a/services/agent_loop.py +++ b/scripts/agent_loop.py @@ -1,11 +1,9 @@ import json from datetime import datetime - def _ts(): return datetime.now().strftime('%H:%M:%S') - def execute_tool(tool_call, TOOL_HANDLERS): tname = tool_call['function']['name'] targs = json.loads(tool_call['function']['arguments']) @@ -26,7 +24,6 @@ def execute_tool(tool_call, TOOL_HANDLERS): except Exception as e: return f'Error executing tool: {str(e)}' - def run_agent_loop(session, llm_client, TOOLS, TOOL_HANDLERS, max_iterations, on_tool_calls=None): for step in range(max_iterations): print(f'[{_ts()}] Step {step + 1} — calling LLM...', flush=True) @@ -66,3 +63,4 @@ def run_agent_loop(session, llm_client, TOOLS, TOOL_HANDLERS, max_iterations, on 'content': 'Max iterations reached without final answer.', }) return None + diff --git a/scripts/gadget.py b/scripts/gadget.py index 81d3766..d2d00dc 100644 --- a/scripts/gadget.py +++ b/scripts/gadget.py @@ -1,4 +1,4 @@ -from .personality import build_system_prompt +import re def tools_mapping(schema, handler, name=None): tool_name = name or schema["function"]["name"] @@ -10,3 +10,25 @@ def tool_schemas(tools_definition): def tool_handlers(tools_definition): return {t["name"]: t["handler"] for t in tools_definition} +def strip_thinking(text: str) -> str: + if not text: + return text + # Strip XML-style thinking blocks (case-insensitive, DOTALL for multiline) + text = re.sub(r']*>.*?', '', text, flags=re.DOTALL | re.IGNORECASE) + text = re.sub(r']*>.*?', '', text, flags=re.DOTALL | re.IGNORECASE) + # Strip lines starting with Thinking: / Reasoning: / Let me think... + lines = text.splitlines() + cleaned = [] + skip_block = False + for line in lines: + stripped = line.strip().lower() + if stripped.startswith(('thinking:', 'reasoning:', 'let me thought', 'let me think')): + skip_block = True + continue + if skip_block and not stripped: + skip_block = False + continue + if not skip_block: + cleaned.append(line) + result = '\n'.join(cleaned).strip() + return result diff --git a/scripts/llm_client.py b/services/llm_client.py similarity index 87% rename from scripts/llm_client.py rename to services/llm_client.py index fc3a2ee..c32ec01 100644 --- a/scripts/llm_client.py +++ b/services/llm_client.py @@ -1,49 +1,14 @@ import json -import re +from scripts import gadget import urllib.request import urllib.error - -def _strip_thinking(text: str) -> str: - """ - Hapus semua bentuk thinking/reasoning dari response text. - Handles: - - ... blocks (any case) - - ... blocks - - "Thinking:" / "Reasoning:" inline prefixes - """ - if not text: - return text - - # Strip XML-style thinking blocks (case-insensitive, DOTALL for multiline) - text = re.sub(r']*>.*?', '', text, flags=re.DOTALL | re.IGNORECASE) - text = re.sub(r']*>.*?', '', text, flags=re.DOTALL | re.IGNORECASE) - - # Strip lines starting with Thinking: / Reasoning: / Let me think... - lines = text.splitlines() - cleaned = [] - skip_block = False - for line in lines: - stripped = line.strip().lower() - if stripped.startswith(('thinking:', 'reasoning:', 'let me thought', 'let me think')): - skip_block = True - continue - if skip_block and not stripped: - skip_block = False - continue - if not skip_block: - cleaned.append(line) - - result = '\n'.join(cleaned).strip() - return result - - class LLMClient: class Message: def __init__(self, msg): raw_content = msg.get('content', '') # Auto-strip thinking dari content - self.content = _strip_thinking(raw_content) if isinstance(raw_content, str) else raw_content + self.content = gadget.strip_thinking(raw_content) if isinstance(raw_content, str) else raw_content self.tool_calls = msg.get('tool_calls', None) self.warning = None diff --git a/services/telegram_client.py b/services/telegram_client.py index 40beaef..6564b2a 100644 --- a/services/telegram_client.py +++ b/services/telegram_client.py @@ -7,7 +7,7 @@ from datetime import datetime import config from services.session_manager import SessionManager -from services.agent_loop import run_agent_loop +from scripts.agent_loop import run_agent_loop from scripts.personality import PERSONALITY from tools.roleplayer import _name_mentioned diff --git a/services/xmpp_client.py b/services/xmpp_client.py index 0505f44..7e0be81 100644 --- a/services/xmpp_client.py +++ b/services/xmpp_client.py @@ -6,7 +6,7 @@ from datetime import datetime from slixmpp import ClientXMPP from services.session_manager import SessionManager -from services.agent_loop import run_agent_loop +from scripts.agent_loop import run_agent_loop import config from tools.roleplayer import should_respond @@ -436,7 +436,7 @@ class XMPPClient(ClientXMPP): session.start_timer(300, self._timeout_session, room, 'groupchat') def _execute_tool(self, tool_call): - from services.agent_loop import execute_tool + from scripts.agent_loop import execute_tool return execute_tool(tool_call, self._TOOL_HANDLERS) def _schedule_send(self, to, body, mtype='chat'):