feat: change user reference from nickname to UUID in memories

- Change user field type from pyarrow.string() to pyarrow.uuid() in
  knowledge_memories and knowledge_scenario schemas
- Convert user to UUID via _uuid() in memories_store()
- Use UUID hex comparison in memories_filter() and memories_latest()
- Rename user to user_id in memories tool schemas with UUID description
- Convert user to UUID in memories tool handlers
- Add User ID (UUID) to User Context in telegram and xmpp clients
- Update roleplayer instructions to use user_id with UUID instead of
  nickname
This commit is contained in:
Dita Aji Pratama 2026-07-12 13:39:39 +07:00
parent 2c65c51ec9
commit 099cab60fb
5 changed files with 16 additions and 14 deletions

View File

@ -67,9 +67,9 @@ Jika user memperkenalkan diri dalam format `!start ... !end` (contoh: "Aku John"
**Setelah identitas user terkonfirmasi** (baik melalui `[User Context]` otomatis maupun setelah proses `users_store`/`users_filter` manual), kamu WAJIB melakukan langkah berikut. Ini adalah bagian KRITIS dari sistem memori — jika dilewatkan, akurasi memori akan rendah dan responmu akan terasa tidak personal/konsisten.
1. **WAJIB Retrieve Recent History**: Panggil `memories_latest(character="<nama-karaktermu>", user="<nickname-user>")` dengan limit 3 untuk mengambil fragmen interaksi terbaru antara character dan user.
- **Parameter Call**: Gunakan nama karaktermu sendiri (sesuai persona/identitasmu) sebagai `character` dan gunakan **Nickname** user yang tertera pada `[User Context]` sebagai `user`.
- **Contoh**: Jika namamu adalah "Lily" dan nickname user adalah "Budi", panggil: `memories_latest(character="Lily", user="Budi", limit=3)`
1. **WAJIB Retrieve Recent History**: Panggil `memories_latest(character="<nama-karaktermu>", user_id="<user-uuid>")` dengan limit 3 untuk mengambil fragmen interaksi terbaru antara character dan user.
- **Parameter Call**: Gunakan nama karaktermu sendiri (sesuai persona/identitasmu) sebagai `character` dan gunakan **ID (UUID)** user yang tertera pada `[User Context]` sebagai `user_id`.
- **Contoh**: Jika namamu adalah "Lily" dan ID user adalah "550e8400-e29b-41d4-a716-446655440000", panggil: `memories_latest(character="Lily", user_id="550e8400-e29b-41d4-a716-446655440000", limit=3)`
2. **Execution Rule**:
- WAJIB lakukan di awal sesi setiap kali user mengirim pesan baru (setelah identitas terkonfirmasi).
- Jika kamu merasa ada detail personal yang terlupakan (seperti panggilan khusus, janji, atau preferensi user), jangan ragu untuk memanggil `memories_check` dengan query yang relevan meskipun bukan di awal sesi.

View File

@ -24,7 +24,7 @@ def _schema_memories(vector_size):
pyarrow.field('id', pyarrow.uuid(), metadata={'description': 'Unique identifier (UUID)'}),
pyarrow.field('timestamp', pyarrow.timestamp('ms'), metadata={'description': 'When record created'}),
pyarrow.field('character', pyarrow.string(), metadata={'description': 'Active Character'}),
pyarrow.field('user', pyarrow.string(), metadata={'description': 'Active User'}),
pyarrow.field('user', pyarrow.uuid(), metadata={'description': 'Active User UUID'}),
pyarrow.field('event', pyarrow.string(), metadata={'description': 'What event'}),
pyarrow.field('category', pyarrow.string(), metadata={'description': 'Event category'}),
pyarrow.field('detail', pyarrow.string(), metadata={'description': 'Event detail'}),
@ -38,7 +38,7 @@ def _schema_scenario(vector_size):
pyarrow.field('id', pyarrow.uuid(), metadata={'description': 'Unique identifier (UUID)'}),
pyarrow.field('timestamp', pyarrow.timestamp('ms'), metadata={'description': 'When record created'}),
pyarrow.field('character', pyarrow.string(), metadata={'description': 'Active Character'}),
pyarrow.field('user', pyarrow.string(), metadata={'description': 'Active User'}),
pyarrow.field('user', pyarrow.uuid(), metadata={'description': 'Active User UUID'}),
pyarrow.field('scenario', pyarrow.string(), metadata={'description': 'Detailed scenario description'}),
pyarrow.field('vector_context', pyarrow.list_(pyarrow.float32(), vector_size), metadata={'description': 'Vector data of scenario'}),
])
@ -241,7 +241,7 @@ def memories_store(db_path, model_url, model_name, character, user, event, categ
"id": uuid.uuid4(),
"timestamp": datetime.now(),
"character": character,
"user": user,
"user": _uuid(user),
"event": event,
"category": category,
"detail": detail,
@ -270,7 +270,7 @@ def memories_filter(db_path, category=None, character=None, user=None):
if character:
filters.append(f"character = '{character}'")
if user:
filters.append(f"user = '{user}'")
filters.append(f"user = X'{_uuid(user).hex}'")
if filters:
query = " AND ".join(filters)
@ -288,7 +288,7 @@ def memories_latest(db_path, character, user, limit=3):
try:
db = lancedb.connect(db_path)
table = db.open_table("knowledge_memories")
query = f"character = '{character}' AND user = '{user}'"
query = f"character = '{character}' AND user = X'{_uuid(user).hex}'"
results = table.search().where(query).to_list()
results.sort(key=lambda x: x['timestamp'], reverse=True)

View File

@ -200,6 +200,7 @@ class TelegramClient:
u = results[0]
context = (
f'[User Context]\n'
f'ID: {u["id"]}\n'
f'Nama: {u["fullname"]} ({u["nickname"]})\n'
f'Alias: {u.get("alias", "-") or "-"}\n'
f'Salutation: {u.get("salutation", "-") or "-"}\n'

View File

@ -304,6 +304,7 @@ class XMPPClient(ClientXMPP):
u = results[0]
context = (
f'[User Context]\n'
f'ID: {u["id"]}\n'
f'Nama: {u["fullname"]} ({u["nickname"]})\n'
f'Alias: {u.get("alias", "-") or "-"}\n'
f'Salutation: {u.get("salutation", "-") or "-"}\n'

View File

@ -111,7 +111,7 @@ schema_memories_store = {
"type": "object",
"properties": {
"character": {"type": "string", "description": "The active character name"},
"user": {"type": "string", "description": "The active user name"},
"user": {"type": "string", "description": "The UUID of the active user"},
"event": {"type": "string", "description": "Brief summary of the event"},
"category": {"type": "string", "description": "Category of the memory (e.g., 'Emotional', 'Physical', 'Relationship')"},
"detail": {"type": "string", "description": "Detailed description of the event"},
@ -133,7 +133,7 @@ schema_memories_filter = {
"properties": {
"category": {"type": "string", "description": "Filter by memory category"},
"character": {"type": "string", "description": "Filter by character name"},
"user": {"type": "string", "description": "Filter by user name"}
"user": {"type": "string", "description": "Filter by user UUID"}
}
}
}
@ -164,7 +164,7 @@ schema_memories_latest = {
"type": "object",
"properties": {
"character": {"type": "string", "description": "The name of the character"},
"user": {"type": "string", "description": "The name of the user"},
"user": {"type": "string", "description": "The UUID of the user"},
"limit": {"type": "integer", "description": "Number of recent memories to retrieve", "default": 3}
},
"required": ["character", "user"]
@ -524,7 +524,7 @@ def memories_store(character, user, event, category, detail, physical, emotional
config.ragroleplay_model_url,
config.ragroleplay_model_name,
character,
user,
_uuid(user),
event,
category,
detail,
@ -540,7 +540,7 @@ def memories_store(character, user, event, category, detail, physical, emotional
def memories_filter(category=None, character=None, user=None):
try:
results = ragroleplay_lib.memories_filter(config.ragroleplay_db_path, category, character, user)
results = ragroleplay_lib.memories_filter(config.ragroleplay_db_path, category, character, _uuid(user) if user else None)
if not results:
return "Tidak ada memori yang sesuai dengan filter tersebut."
@ -574,7 +574,7 @@ def memories_summarize(prompt_text, search_limit=5):
def memories_latest(character, user, limit=3):
try:
results = ragroleplay_lib.memories_latest(config.ragroleplay_db_path, character, user, limit)
results = ragroleplay_lib.memories_latest(config.ragroleplay_db_path, character, _uuid(user), limit)
if not results:
return f"Tidak ada memori terbaru yang ditemukan antara {user} dan {character}."