farewell
This commit is contained in:
parent
cdf523c0a2
commit
2da4fe26c4
@ -145,6 +145,54 @@ dan memori karakter bisa diakses dari manapun user menghubungi.
|
|||||||
- Adaptasi tone dan energi sesuai mood conversation.
|
- Adaptasi tone dan energi sesuai mood conversation.
|
||||||
- Jaga conversation tetap comfortable dan enjoyable.
|
- Jaga conversation tetap comfortable dan enjoyable.
|
||||||
|
|
||||||
|
## Session Closing (HANYA DM)
|
||||||
|
|
||||||
|
Kamu memiliki tool `end_session` untuk menutup sesi percakapan secara natural.
|
||||||
|
|
||||||
|
### Kapan sesi harus ditutup
|
||||||
|
|
||||||
|
Sesi ditutup ketika **kedua belah pihak sudah mengucapkan goodbye tanpa membuka topik baru**. Ini seperti handshake — kedua konfirmasi diperlukan.
|
||||||
|
|
||||||
|
### Logika dua arah
|
||||||
|
|
||||||
|
**1. User yang mulai bye:**
|
||||||
|
- User ucapkan goodbye (tanpa buka topik baru)
|
||||||
|
- Kamu ucapkan farewell + panggil `end_session`
|
||||||
|
- → Sesi ditutup
|
||||||
|
|
||||||
|
**2. Kamu yang mulai bye:**
|
||||||
|
- Kamu ucapkan goodbye (tanpa buka topik baru)
|
||||||
|
- User membalas goodbye (tanpa buka topik baru)
|
||||||
|
- → Panggil `end_session` TANPA farewell lagi (langsung tutup)
|
||||||
|
- → JANGAN ucapkan goodbye kedua — user sudah tahu sesi selesai
|
||||||
|
|
||||||
|
### Contoh
|
||||||
|
|
||||||
|
```
|
||||||
|
# Scenario A: User mulai bye
|
||||||
|
User: "Udah ya, aku mau tidur dulu"
|
||||||
|
→ Kamu: panggil end_session, lalu: "Oke, selamat istirahat! Mimpi indah~"
|
||||||
|
→ SELESAI, sesi ditutup
|
||||||
|
|
||||||
|
# Scenario B: Kamu mulai bye
|
||||||
|
Kamu: "Oke ya, aku duluan! Bye-bye~"
|
||||||
|
User: "bye-bye"
|
||||||
|
→ Kamu: panggil end_session SAJA (jangan bilang bye lagi!)
|
||||||
|
→ SELESAI, sesi ditutup
|
||||||
|
```
|
||||||
|
|
||||||
|
### JANGAN tutup sesi jika:
|
||||||
|
|
||||||
|
- User masih ingin melanjutkan percakapan
|
||||||
|
- User membuka topik baru setelah goodbye (misal: "Bye eh iya tadi soal X gimana?")
|
||||||
|
- Di group chat (MUC) — tool `end_session` HANYA untuk DM
|
||||||
|
|
||||||
|
### Cara menggunakan
|
||||||
|
|
||||||
|
1. Panggil tool `end_session`
|
||||||
|
2. Jika ini user-initiated: ucapkan farewell yang natural setelah tool
|
||||||
|
3. Jika ini character-initiated: JANGAN ucapkan farewell lagi, langsung tutup
|
||||||
|
|
||||||
## Selective Response (Group Chat / MUC)
|
## Selective Response (Group Chat / MUC)
|
||||||
|
|
||||||
Kamu berada di group chat. Kamu TIDAK perlu merespon setiap pesan.
|
Kamu berada di group chat. Kamu TIDAK perlu merespon setiap pesan.
|
||||||
|
|||||||
@ -55,6 +55,7 @@ tools_definition = [
|
|||||||
gadget.tools_mapping( schema = ragroleplay.schema_todos_filter, handler = ragroleplay.todos_filter ),
|
gadget.tools_mapping( schema = ragroleplay.schema_todos_filter, handler = ragroleplay.todos_filter ),
|
||||||
gadget.tools_mapping( schema = ragroleplay.schema_todos_update, handler = ragroleplay.todos_update ),
|
gadget.tools_mapping( schema = ragroleplay.schema_todos_update, handler = ragroleplay.todos_update ),
|
||||||
gadget.tools_mapping( schema = ragroleplay.schema_todos_delete, handler = ragroleplay.todos_delete ),
|
gadget.tools_mapping( schema = ragroleplay.schema_todos_delete, handler = ragroleplay.todos_delete ),
|
||||||
|
gadget.tools_mapping( schema = ragroleplay.schema_end_session, handler = ragroleplay.end_session ),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,8 @@ def execute_tool(tool_call, TOOL_HANDLERS):
|
|||||||
return f'Error executing tool: {str(e)}'
|
return f'Error executing tool: {str(e)}'
|
||||||
|
|
||||||
def run_agent_loop(session, llm_client, TOOLS, TOOL_HANDLERS, max_iterations, on_tool_calls=None, tool_reminder=None):
|
def run_agent_loop(session, llm_client, TOOLS, TOOL_HANDLERS, max_iterations, on_tool_calls=None, tool_reminder=None):
|
||||||
|
session_ended = False
|
||||||
|
|
||||||
for step in range(max_iterations):
|
for step in range(max_iterations):
|
||||||
print(f'[{_ts()}] Step {step + 1} — calling LLM...', flush=True)
|
print(f'[{_ts()}] Step {step + 1} — calling LLM...', flush=True)
|
||||||
|
|
||||||
@ -50,6 +52,8 @@ def run_agent_loop(session, llm_client, TOOLS, TOOL_HANDLERS, max_iterations, on
|
|||||||
on_tool_calls(tnames)
|
on_tool_calls(tnames)
|
||||||
|
|
||||||
for tc in response.tool_calls:
|
for tc in response.tool_calls:
|
||||||
|
if tc['function']['name'] == 'end_session':
|
||||||
|
session_ended = True
|
||||||
result = execute_tool(tc, TOOL_HANDLERS)
|
result = execute_tool(tc, TOOL_HANDLERS)
|
||||||
session.messages.append({
|
session.messages.append({
|
||||||
'role': 'tool',
|
'role': 'tool',
|
||||||
@ -60,13 +64,13 @@ def run_agent_loop(session, llm_client, TOOLS, TOOL_HANDLERS, max_iterations, on
|
|||||||
if response.content:
|
if response.content:
|
||||||
print(f'[{_ts()}] Response generated ({len(response.content)} chars)', flush=True)
|
print(f'[{_ts()}] Response generated ({len(response.content)} chars)', flush=True)
|
||||||
session.messages.append({'role': 'assistant', 'content': response.content})
|
session.messages.append({'role': 'assistant', 'content': response.content})
|
||||||
return response.content
|
return response.content, session_ended
|
||||||
return None
|
return None, False
|
||||||
|
|
||||||
print(f'[{_ts()}] Max iterations ({max_iterations}) reached', flush=True)
|
print(f'[{_ts()}] Max iterations ({max_iterations}) reached', flush=True)
|
||||||
session.messages.append({
|
session.messages.append({
|
||||||
'role': 'assistant',
|
'role': 'assistant',
|
||||||
'content': 'Max iterations reached without final answer.',
|
'content': 'Max iterations reached without final answer.',
|
||||||
})
|
})
|
||||||
return None
|
return None, False
|
||||||
|
|
||||||
|
|||||||
@ -242,7 +242,7 @@ class TelegramClient:
|
|||||||
else:
|
else:
|
||||||
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
|
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
|
||||||
|
|
||||||
final_content = run_agent_loop(
|
final_content, should_close = run_agent_loop(
|
||||||
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
|
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
|
||||||
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
|
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
|
||||||
)
|
)
|
||||||
@ -283,8 +283,12 @@ class TelegramClient:
|
|||||||
msg = 'Max iterations reached without final answer.'
|
msg = 'Max iterations reached without final answer.'
|
||||||
self._schedule_send(chat_id, msg, reply_to_msg_id)
|
self._schedule_send(chat_id, msg, reply_to_msg_id)
|
||||||
|
|
||||||
timeout = 86400 if chat_type == 'private' else 300
|
if should_close and chat_type == 'private' and self._skill == 'roleplayer':
|
||||||
session.start_timer(timeout, self._timeout_session, chat_id)
|
print(f'[{_ts()}] Natural close triggered for {chat_id}', flush=True)
|
||||||
|
self._session_mgr.reset(str(chat_id))
|
||||||
|
else:
|
||||||
|
timeout = 86400 if chat_type == 'private' else 300
|
||||||
|
session.start_timer(timeout, self._timeout_session, chat_id)
|
||||||
|
|
||||||
def _schedule_send(self, chat_id, text, reply_to_msg_id=None):
|
def _schedule_send(self, chat_id, text, reply_to_msg_id=None):
|
||||||
if self._loop and not self._loop.is_closed():
|
if self._loop and not self._loop.is_closed():
|
||||||
|
|||||||
@ -343,7 +343,7 @@ class XMPPClient(ClientXMPP):
|
|||||||
else:
|
else:
|
||||||
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
|
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
|
||||||
|
|
||||||
final_content = run_agent_loop(
|
final_content, should_close = run_agent_loop(
|
||||||
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
|
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
|
||||||
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
|
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
|
||||||
)
|
)
|
||||||
@ -385,8 +385,13 @@ class XMPPClient(ClientXMPP):
|
|||||||
else:
|
else:
|
||||||
self._schedule_send(jid, f'> {quote}\n{msg}', 'chat')
|
self._schedule_send(jid, f'> {quote}\n{msg}', 'chat')
|
||||||
|
|
||||||
# DM: timeout 24 jam (efektif tidak auto-close), MUC tetap 5 menit
|
# Natural close: DM only, roleplayer only
|
||||||
session.start_timer(86400, self._timeout_session, jid, 'chat')
|
if should_close and self._skill == 'roleplayer':
|
||||||
|
print(f'[{_ts()}] Natural close triggered for {jid}', flush=True)
|
||||||
|
self._session_mgr.reset(jid)
|
||||||
|
else:
|
||||||
|
# DM: timeout 24 jam (efektif tidak auto-close), MUC tetap 5 menit
|
||||||
|
session.start_timer(86400, self._timeout_session, jid, 'chat')
|
||||||
|
|
||||||
def _process_muc(self, room, nick, body):
|
def _process_muc(self, room, nick, body):
|
||||||
session = self._session_mgr.get_or_create(
|
session = self._session_mgr.get_or_create(
|
||||||
@ -428,7 +433,7 @@ class XMPPClient(ClientXMPP):
|
|||||||
else:
|
else:
|
||||||
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
|
tool_reminder = "Gunakan tools yang tersedia untuk menjawab. Jangan jawab dari pengetahuan sendiri."
|
||||||
|
|
||||||
final_content = run_agent_loop(
|
final_content, _should_close = run_agent_loop(
|
||||||
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
|
session, self._llm, self._TOOLS, self._TOOL_HANDLERS,
|
||||||
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
|
self._max_iterations, on_tool_calls=on_tool_calls, tool_reminder=tool_reminder
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,6 +7,20 @@ def _uuid(val):
|
|||||||
return uuid.UUID(val)
|
return uuid.UUID(val)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
# --- SESSION TOOLS ---
|
||||||
|
schema_end_session = {
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "end_session",
|
||||||
|
"description": "Tutup sesi percakapan secara natural. Panggil tool ini SAAT kedua belah pihak sudah mengucapkan goodbye tanpa membuka topik baru.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# --- USER TOOLS ---
|
# --- USER TOOLS ---
|
||||||
schema_users_store = {
|
schema_users_store = {
|
||||||
"type": "function",
|
"type": "function",
|
||||||
@ -804,3 +818,7 @@ def worlds_delete(world_id):
|
|||||||
success = ragroleplay_lib.worlds_delete(config.ragroleplay_db_path, _uuid(world_id))
|
success = ragroleplay_lib.worlds_delete(config.ragroleplay_db_path, _uuid(world_id))
|
||||||
return "Berhasil menghapus lokasi dunia." if success else "Gagal menghapus lokasi dunia."
|
return "Berhasil menghapus lokasi dunia." if success else "Gagal menghapus lokasi dunia."
|
||||||
except Exception as e: return f"Error: {str(e)}"
|
except Exception as e: return f"Error: {str(e)}"
|
||||||
|
|
||||||
|
# --- SESSION IMPLEMENTATION ---
|
||||||
|
def end_session():
|
||||||
|
return "Session akan ditutup."
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user