Files
boltun-ai/src/services/assistant/prompts.ts
yunogasai b8f09227b0 Контекст диалога отдельно от архива чата
- Новая таблица dialog_messages: последние DIALOG_LIMIT пар «вопрос — ответ», подкладываются в каждый запрос
- /clear сбрасывает только контекст диалога, архив (включая импорт) не трогает; без подтверждения
- /context показывает контекст и архив по отдельности

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 20:42:14 +02:00

72 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { ChatMember, ChatMessage, ImageAttachment, ImageSource, Persona } from "../../types.js";
import { formatChatMembers } from "./format-chat-members.js";
import { formatChatMessages } from "./format-chat-messages.js";
export interface Question {
chatId: number;
chatTitle: string;
/** Как зовут спрашивающего: имя, фамилия и ник. */
askerName: string;
/** Может быть пустым, если прислали только картинку. */
text: string;
/** Сообщение, на которое ответил спрашивающий, — сразу передаём его как контекст. */
repliedTo?: ChatMessage;
/** Участники, упомянутые в вопросе через @ник или по имени-ссылке. */
mentionedMembers: ChatMember[];
/** Упомянутые ники, которых бот в чате не встречал. */
unknownUsernames: string[];
/** Где в вопросе есть картинки — даже если модели их не отправляем. */
imageSources: ImageSource[];
/** Скачанные картинки для модели; пусто, если модель их не видит или скачать не вышло. */
images: ImageAttachment[];
}
const IMAGE_SOURCES: Record<ImageSource, string> = {
question: "из вопроса",
replied: "из сообщения, на которое ответили",
};
/** Подсказка модели, откуда картинки — или что посмотреть их она не может. */
const imagesNote = ({ imageSources, images }: Question): string | undefined => {
if (imageSources.length === 0) return undefined;
if (images.length === 0) return "К сообщению приложено изображение, но ты не можешь его просмотреть — честно скажи об этом.";
return `Приложены изображения (по порядку): ${images.map((image) => IMAGE_SOURCES[image.source]).join(", ")}.`;
};
const mentionsSection = (question: Question): string | undefined => {
const known = question.mentionedMembers.length > 0 ? `Упомянуты участники:\n${formatChatMembers(question.mentionedMembers)}` : "";
const unknown =
question.unknownUsernames.length > 0
? `Эти ники в чате не встречались: ${question.unknownUsernames.map((u) => `@${u}`).join(", ")}.`
: "";
return [known, unknown].filter(Boolean).join("\n") || undefined;
};
/** Системные правила бота из `prompts/system.md` + личность + контекст конкретного вопроса. */
export const buildInstructions = (systemRules: string, question: Question, persona: Persona): string =>
[
`Твоя личность: ${persona.name}.\n${persona.prompt}`,
systemRules,
`Чат: «${question.chatTitle}». Вопрос задаёт ${question.askerName}.`,
mentionsSection(question),
]
.filter(Boolean)
.join("\n\n");
export const buildPrompt = (question: Question): string => {
const replied = question.repliedTo
? `Вопрос задан в ответ на сообщение:\n${formatChatMessages([question.repliedTo])}`
: undefined;
const asked = question.text || "(текста нет — прислали только изображение, опиши и прокомментируй его)";
return [replied, imagesNote(question), replied ? `Вопрос: ${asked}` : asked].filter(Boolean).join("\n\n");
};
/** Текст реплики пользователя — с именем, потому что в чате боту пишут разные админы. */
export const buildUserText = (question: Question): string => `${question.askerName}:\n${buildPrompt(question)}`;