feat: init_db on startup, fix users_update UUID, memories_latest limit 6, incremental profile + cross-platform instructions

This commit is contained in:
Dita Aji Pratama 2026-07-12 18:13:08 +07:00
parent 2d87641cfd
commit 1077381a4a
4 changed files with 61 additions and 8 deletions

View File

@ -67,7 +67,7 @@ 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_id="<user-uuid>")` 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 6 untuk mengambil fragmen interaksi terbaru antara character dan user. Gunakan limit 0 untuk mengambil semua memori.
- **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**:
@ -76,6 +76,50 @@ Jika user memperkenalkan diri dalam format `!start ... !end` (contoh: "Aku John"
- JANGAN memanggil `memories_latest` di setiap giliran respon dalam sesi yang sama (cukup sekali di awal sesi).
3. **Immersive Integration**: Gunakan data dari memori tersebut untuk memberikan respon yang personal (contoh: mengingat janji, topik pembicaraan terakhir, atau perasaan yang tertinggal) tanpa menyebutkan bahwa kamu sedang "membaca database".
### Incremental Profile Building
User mungkin tidak langsung memberikan semua info dalam satu percakapan.
Karakter harus proaktif mengumpulkan info secara bertahap melalui percakapan natural.
**Alur pengumpulan data:**
- **Percakapan pertama**: Tanya nama → simpan via `users_store`
- **Percakapan berikutnya**: Jika ada info yang belum lengkap, tanyakan secara natural
- **Urutan ideal**: nickname → fullname → salutation (Mas/Bang/Bro/Pak dll)
**Karakter WAJIB proaktif bertanya** jika ada field yang kosong/kurang di `[User Context]`:
- Belum ada nama lengkap? → Tanya: "Btw nama lengkapmu siapa?"
- Belum ada salutation? → Tanya: "Aku harus panggil kamu apa? Mas, Bang, Kak, atau yang lain?"
- Belum ada persona? → Tanyakan selera/ preferensi user saat topik relevan
- Jangan tanya sekaligus — selingi dengan percakapan natural
**Setiap kali user memberikan info baru tentang dirinya:**
- Cek `[User Context]` — kalau info sudah ada, skip
- Kalau user belum ada di database → `users_store`
- Kalau user sudah ada → `users_update` dengan `user_id` dari context
- **JANGAN** buat user baru kalau profile sudah ada
**Field yang bisa berubah seiring waktu:**
- **Persona** — berubah seiring interaksi. Perbarui kalau kamu mengamati perubahan perilaku/selera user
- **Alias / Salutation** — user mungkin minta dipanggil beda ("Eh panggil aku Mas aja ya" → `users_update`)
- **Nickname / Fullname** — user bisa koreksi ejaan/nama ("Salah, namaku Johny bukan Johnny" → `users_update`)
- Selalu gunakan `users_update`, jangan `users_store`, untuk perubahan apapun pada profile existing
### Cross-Platform Identity Linking
User bisa menggunakan karakter dari multiple platform (Telegram, XMPP, dll).
User mungkin bilang: "Aku John di Telegram, orang yang sama dengan username john@xmpp lho."
Ketika user menyebutkan identitas cross-platform:
1. Cek apakah user dengan ID platform tersebut sudah ada di database (`users_filter`)
2. Kalau sudah ada → itu user yang sama, sambut natural
3. Kalau belum ada → update profile yang sudah ada via `users_update`,
tambahkan platform ID baru ke field yang sesuai
(contoh: `xampp_username: "john@xmpp"`)
4. **JANGAN** buat user baru — cukup update profile existing
Ini memastikan satu user punya satu UUID yang konsisten lintas semua platform,
dan memori karakter bisa diakses dari manapun user menghubungi.
## Penulisan XMPP
- Response roleplay dikirim sebagai pesan chat biasa (plain text langsung dalam karakter).

View File

@ -12,6 +12,7 @@ from services.telegram_client import TelegramClient
from services.llm_client import LLMClient
from lib import gadget, personality
import lib.ragroleplay as ragroleplay_lib
from interfaces.tui import HendrikTUI
@ -78,6 +79,8 @@ def main():
llm_client = LLMClient(config.llm_baseurl, config.llm_model, config.llm_api_key, config.llm_timeout)
ragroleplay_lib.init_db(config.ragroleplay_db_path, config.ragroleplay_vector_size)
services = []
if config.XMPP_ENABLED:

View File

@ -101,10 +101,13 @@ _TABLE_SCHEMAS = {
# ─── Table Management ─────────────────────────────────────────────────────────
def create_table(db_path, vector_size):
def init_db(db_path, vector_size):
db = lancedb.connect(db_path)
existing = db.table_names()
for name, schema_fn in _TABLE_SCHEMAS.items():
db.create_table(name, schema=schema_fn(vector_size))
if name not in existing:
db.create_table(name, schema=schema_fn(vector_size))
print(f"[ragroleplay] Created table: {name}", flush=True)
del db
gc.collect()
@ -209,6 +212,7 @@ def users_update(db_path, model_url, model_name, user_id, **updates):
return False
record = current_record[0]
original_id = record['id']
needs_reembed = 'fullname' in updates
for key, value in updates.items():
@ -218,7 +222,8 @@ def users_update(db_path, model_url, model_name, user_id, **updates):
if needs_reembed:
record['vector_fullname'] = embed_text(model_url, model_name, record['fullname'])
table.delete(f"id = X'{_uuid(record['id']).hex}'")
table.delete(f"id = X'{_uuid(original_id).hex}'")
record['id'] = original_id
table.add([record])
del table
@ -284,7 +289,7 @@ def memories_filter(db_path, category=None, character=None, user=None):
print(f"Error filtering memories: {e}")
return []
def memories_latest(db_path, character, user, limit=3):
def memories_latest(db_path, character, user, limit=6):
try:
db = lancedb.connect(db_path)
table = db.open_table("knowledge_memories")
@ -292,12 +297,13 @@ def memories_latest(db_path, character, user, limit=3):
results = table.search().where(query).to_list()
results.sort(key=lambda x: x['timestamp'], reverse=True)
final_results = results[:limit]
if limit and limit > 0:
results = results[:limit]
del table
del db
gc.collect()
return final_results
return results
except Exception as e:
print(f"Error getting latest memories: {e}")
return []

View File

@ -165,7 +165,7 @@ schema_memories_latest = {
"properties": {
"character": {"type": "string", "description": "The name of the character"},
"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. Use 0 to get all memories.", "default": 6}
},
"required": ["character", "user"]
}