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. **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. 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 **Nickname** user yang tertera pada `[User Context]` sebagai `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 nickname user adalah "Budi", panggil: `memories_latest(character="Lily", user="Budi", limit=3)` - **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**: 2. **Execution Rule**:
- WAJIB lakukan di awal sesi setiap kali user mengirim pesan baru (setelah identitas terkonfirmasi). - 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. - 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('id', pyarrow.uuid(), metadata={'description': 'Unique identifier (UUID)'}),
pyarrow.field('timestamp', pyarrow.timestamp('ms'), metadata={'description': 'When record created'}), pyarrow.field('timestamp', pyarrow.timestamp('ms'), metadata={'description': 'When record created'}),
pyarrow.field('character', pyarrow.string(), metadata={'description': 'Active Character'}), 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('event', pyarrow.string(), metadata={'description': 'What event'}),
pyarrow.field('category', pyarrow.string(), metadata={'description': 'Event category'}), pyarrow.field('category', pyarrow.string(), metadata={'description': 'Event category'}),
pyarrow.field('detail', pyarrow.string(), metadata={'description': 'Event detail'}), 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('id', pyarrow.uuid(), metadata={'description': 'Unique identifier (UUID)'}),
pyarrow.field('timestamp', pyarrow.timestamp('ms'), metadata={'description': 'When record created'}), pyarrow.field('timestamp', pyarrow.timestamp('ms'), metadata={'description': 'When record created'}),
pyarrow.field('character', pyarrow.string(), metadata={'description': 'Active Character'}), 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('scenario', pyarrow.string(), metadata={'description': 'Detailed scenario description'}),
pyarrow.field('vector_context', pyarrow.list_(pyarrow.float32(), vector_size), metadata={'description': 'Vector data of scenario'}), 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(), "id": uuid.uuid4(),
"timestamp": datetime.now(), "timestamp": datetime.now(),
"character": character, "character": character,
"user": user, "user": _uuid(user),
"event": event, "event": event,
"category": category, "category": category,
"detail": detail, "detail": detail,
@ -270,7 +270,7 @@ def memories_filter(db_path, category=None, character=None, user=None):
if character: if character:
filters.append(f"character = '{character}'") filters.append(f"character = '{character}'")
if user: if user:
filters.append(f"user = '{user}'") filters.append(f"user = X'{_uuid(user).hex}'")
if filters: if filters:
query = " AND ".join(filters) query = " AND ".join(filters)
@ -288,7 +288,7 @@ def memories_latest(db_path, character, user, limit=3):
try: try:
db = lancedb.connect(db_path) db = lancedb.connect(db_path)
table = db.open_table("knowledge_memories") 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 = table.search().where(query).to_list()
results.sort(key=lambda x: x['timestamp'], reverse=True) results.sort(key=lambda x: x['timestamp'], reverse=True)

View File

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

View File

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

View File

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