Fixing tools calling failure

This commit is contained in:
Dita Aji Pratama 2026-07-03 10:45:00 +07:00
parent f32e2330a7
commit 9993f1f0e7
6 changed files with 39 additions and 13 deletions

View File

@ -115,7 +115,11 @@ def _agent_loop(app):
break
app.scroll = 999999
response = app.llm.chat(app.messages, tools=app.TOOLS, on_stream_chunk=on_stream_chunk)
tool_reminder = None
if config.AGENT_SKILL in ("programmer", "analyst"):
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
response = app.llm.chat(app.messages, tools=app.TOOLS, on_stream_chunk=on_stream_chunk, tool_reminder=tool_reminder)
# Hapus "Thinking..." log
for i in range(len(app.log) - 1, -1, -1):

View File

@ -24,7 +24,7 @@ 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):
def run_agent_loop(session, llm_client, TOOLS, TOOL_HANDLERS, max_iterations, on_tool_calls=None, tool_reminder=None):
for step in range(max_iterations):
print(f'[{_ts()}] Step {step + 1} — calling LLM...', flush=True)
@ -33,7 +33,7 @@ def run_agent_loop(session, llm_client, TOOLS, TOOL_HANDLERS, max_iterations, on
personality = getattr(session, 'personality', {})
disable_reasoning = personality.get('disable_reasoning', False)
response = llm_client.chat(session.messages, tools=TOOLS, disable_reasoning=disable_reasoning)
response = llm_client.chat(session.messages, tools=TOOLS, disable_reasoning=disable_reasoning, tool_reminder=tool_reminder)
if response.tool_calls:
amsg = {

View File

@ -181,9 +181,9 @@ def _build_tools_block(tools_definition: list[dict]) -> str:
lines.append(f"{i}. {name}: {desc}")
lines.append("")
lines.append(
"Use tools by returning tool calls when needed. After receiving tool "
"results, continue your reasoning. When you have the final answer, "
"return it as plain text without tool calls."
"Always use tools first before answering from your own knowledge. "
"After receiving tool results, continue your reasoning. When you have "
"the final answer, return it as plain text without tool calls."
)
return "\n".join(lines)

View File

@ -19,7 +19,7 @@ class LLMClient:
self.timeout = timeout
self.cancel_requested = False
def chat(self, messages, tools=None, on_stream_chunk=None, disable_reasoning=False):
def chat(self, messages, tools=None, on_stream_chunk=None, disable_reasoning=False, tool_reminder=None):
url = f"{self.base_url}/chat/completions"
payload = {
"model": self.model,
@ -29,6 +29,14 @@ class LLMClient:
if tools:
payload["tools"] = tools
payload["tool_choice"] = "auto"
if tool_reminder:
# Inject tool reminder sebagai system message sebelum user message terakhir
for i in range(len(messages) - 1, -1, -1):
if messages[i].get("role") == "user":
payload["messages"] = messages[:i] + [
{"role": "system", "content": tool_reminder}
] + messages[i:]
break
# Hanya kirim parameter reasoning jika diminta eksplisit
# Beberapa model/provider justru error jika parameter ini ada tapi tidak didukung

View File

@ -207,9 +207,13 @@ class TelegramClient:
if not is_roleplay:
self._schedule_send(chat_id, info, reply_to_msg_id)
tool_reminder = None
if not is_roleplay:
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
final_content = run_agent_loop(
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
self._max_iterations, on_tool_calls=on_tool_calls
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
)
if final_content is not None:

View File

@ -313,9 +313,13 @@ class XMPPClient(ClientXMPP):
if not is_roleplay:
self._schedule_send(jid, f'> {quote}\nUsing: {", ".join(tnames)}', 'chat')
tool_reminder = None
if not is_roleplay:
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
final_content = run_agent_loop(
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
self._max_iterations, on_tool_calls=on_tool_calls
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
)
if final_content is not None:
@ -387,17 +391,23 @@ class XMPPClient(ClientXMPP):
my_name = personality.PERSONALITY.name
quote = f'[{nick}] {body}'
_is_roleplay = self._skill == 'roleplayer'
def on_tool_calls(tnames):
if not is_roleplay:
if not _is_roleplay:
self._schedule_send(room, f'> {quote}\nUsing: {", ".join(tnames)}', 'groupchat')
tool_reminder = None
if not _is_roleplay:
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
final_content = run_agent_loop(
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
self._max_iterations, on_tool_calls=on_tool_calls
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
)
if final_content is not None:
if is_roleplay:
if _is_roleplay:
if config.XMPP_SELECTIVE_RESPONSE:
recent_msgs = []
for msg in session.messages[-6:]:
@ -428,7 +438,7 @@ class XMPPClient(ClientXMPP):
self._schedule_send(room, f'> {quote}\n{final_content}', 'groupchat')
else:
msg = 'Max iterations reached without final answer.'
if is_roleplay:
if _is_roleplay:
self._schedule_send(room, msg, 'groupchat')
else:
self._schedule_send(room, f'> {quote}\n{msg}', 'groupchat')