Участники чата, промпты в файлах, личности только из кода
- Бот запоминает участников (имя, фамилия, ник, активность) и ID автора каждого сообщения - Упоминания в вопросе (@ник и по имени-ссылке) передаются модели с данными участника - Новые инструменты агента: list_chat_members, read_member_messages (поиск по нику/имени) - Бот обращается к людям по имени - Промпты вынесены в prompts/system.md и prompts/personas/<id>.md - Личности больше не редактируются из чата: скрипт seed синхронизирует их с БД при старте - Оставлена одна личность boltun (Dirty D) - Миграция старых баз: колонка messages.user_id Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
60
src/repositories/chat-member-repository.ts
Normal file
60
src/repositories/chat-member-repository.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { Db } from "../libs/db.js";
|
||||
import type { ChatMember, MemberProfile } from "../types.js";
|
||||
|
||||
interface ChatMemberRow {
|
||||
chat_id: number;
|
||||
user_id: number;
|
||||
username: string | null;
|
||||
first_name: string;
|
||||
last_name: string | null;
|
||||
message_count: number;
|
||||
last_seen: number;
|
||||
}
|
||||
|
||||
const toMember = (row: ChatMemberRow): ChatMember => ({
|
||||
chatId: row.chat_id,
|
||||
userId: row.user_id,
|
||||
username: row.username,
|
||||
firstName: row.first_name,
|
||||
lastName: row.last_name,
|
||||
messageCount: row.message_count,
|
||||
lastSeen: row.last_seen,
|
||||
});
|
||||
|
||||
export const createChatMemberRepository = (db: Db) => {
|
||||
const statements = {
|
||||
upsert: db.prepare(`
|
||||
INSERT INTO chat_members (chat_id, user_id, username, first_name, last_name, message_count, last_seen)
|
||||
VALUES (@chatId, @userId, @username, @firstName, @lastName, @messages, @seenAt)
|
||||
ON CONFLICT(chat_id, user_id) DO UPDATE SET
|
||||
username = excluded.username,
|
||||
first_name = excluded.first_name,
|
||||
last_name = excluded.last_name,
|
||||
message_count = message_count + excluded.message_count,
|
||||
last_seen = MAX(last_seen, excluded.last_seen)
|
||||
`),
|
||||
listByChat: db.prepare("SELECT * FROM chat_members WHERE chat_id = ? ORDER BY last_seen DESC"),
|
||||
findById: db.prepare("SELECT * FROM chat_members WHERE chat_id = ? AND user_id = ?"),
|
||||
};
|
||||
|
||||
/**
|
||||
* Сохраняет актуальные имя и ник участника.
|
||||
* `messages` добавляется к счётчику сообщений, `seenAt` сдвигает время последней активности вперёд.
|
||||
*/
|
||||
const upsert = (chatId: number, profile: MemberProfile, activity: { messages: number; seenAt: number }): void => {
|
||||
statements.upsert.run({ chatId, ...profile, ...activity });
|
||||
};
|
||||
|
||||
const listByChat = (chatId: number): ChatMember[] =>
|
||||
(statements.listByChat.all(chatId) as ChatMemberRow[]).map(toMember);
|
||||
|
||||
const findById = (chatId: number, userId: number): ChatMember | undefined => {
|
||||
const row = statements.findById.get(chatId, userId) as ChatMemberRow | undefined;
|
||||
|
||||
return row && toMember(row);
|
||||
};
|
||||
|
||||
return { upsert, listByChat, findById };
|
||||
};
|
||||
|
||||
export type ChatMemberRepository = ReturnType<typeof createChatMemberRepository>;
|
||||
Reference in New Issue
Block a user