Контекст диалога отдельно от архива чата
- Новая таблица dialog_messages: последние DIALOG_LIMIT пар «вопрос — ответ», подкладываются в каждый запрос - /clear сбрасывает только контекст диалога, архив (включая импорт) не трогает; без подтверждения - /context показывает контекст и архив по отдельности Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import { Agent } from "@mastra/core/agent";
|
||||
import { RequestContext } from "@mastra/core/request-context";
|
||||
import { readPrompt } from "../../libs/prompts.js";
|
||||
import type { Persona } from "../../types.js";
|
||||
import type { DialogTurn, Persona } from "../../types.js";
|
||||
import type { ChatHistoryService } from "../chat-history-service.js";
|
||||
import type { ChatMemberService } from "../chat-member-service.js";
|
||||
import { buildInstructions, buildPrompt, type Question } from "./prompts.js";
|
||||
import type { DialogService } from "../dialog-service.js";
|
||||
import { buildInstructions, buildUserText, type Question } from "./prompts.js";
|
||||
import { createListChatMembersTool } from "./tools/list-chat-members-tool.js";
|
||||
import { createReadChatMessagesTool } from "./tools/read-chat-messages-tool.js";
|
||||
import { createReadMemberMessagesTool } from "./tools/read-member-messages-tool.js";
|
||||
@@ -18,6 +19,7 @@ interface AssistantServiceDeps {
|
||||
imageInput: boolean;
|
||||
chatHistoryService: ChatHistoryService;
|
||||
chatMemberService: ChatMemberService;
|
||||
dialogService: DialogService;
|
||||
}
|
||||
|
||||
const MAX_AGENT_STEPS = 6;
|
||||
@@ -26,16 +28,23 @@ const MAX_AGENT_STEPS = 6;
|
||||
const buildUserMessage = (question: Question) => ({
|
||||
role: "user" as const,
|
||||
content: [
|
||||
{ type: "text" as const, text: buildPrompt(question) },
|
||||
{ type: "text" as const, text: buildUserText(question) },
|
||||
...question.images.map((image) => ({ type: "image" as const, image: image.data, mimeType: image.mimeType })),
|
||||
],
|
||||
});
|
||||
|
||||
/** Реплика прошлого диалога в формате сообщений Mastra (роль должна быть литералом). */
|
||||
const toModelMessage = (turn: DialogTurn) =>
|
||||
turn.role === "user"
|
||||
? { role: "user" as const, content: turn.content }
|
||||
: { role: "assistant" as const, content: turn.content };
|
||||
|
||||
export const createAssistantService = ({
|
||||
model,
|
||||
imageInput,
|
||||
chatHistoryService,
|
||||
chatMemberService,
|
||||
dialogService,
|
||||
}: AssistantServiceDeps) => {
|
||||
const systemRules = readPrompt("system.md");
|
||||
|
||||
@@ -51,19 +60,29 @@ export const createAssistantService = ({
|
||||
},
|
||||
});
|
||||
|
||||
/** Ответ на вопрос в образе личности; агент сам решает, какую историю чата подгрузить. */
|
||||
/**
|
||||
* Ответ на вопрос в образе личности. Контекст диалога (прошлые вопросы и ответы) подкладываем сами,
|
||||
* архив чата агент подгружает инструментами, когда нужно.
|
||||
*/
|
||||
const answer = async (question: Question, persona: Persona): Promise<string> => {
|
||||
const requestContext = new RequestContext<AssistantRequestContext>();
|
||||
|
||||
requestContext.set("chatId", question.chatId);
|
||||
|
||||
const result = await agent.generate([buildUserMessage(question)], {
|
||||
const history = dialogService.recent(question.chatId).map(toModelMessage);
|
||||
|
||||
const result = await agent.generate([...history, buildUserMessage(question)], {
|
||||
instructions: buildInstructions(systemRules, question, persona),
|
||||
requestContext,
|
||||
maxSteps: MAX_AGENT_STEPS,
|
||||
});
|
||||
|
||||
return result.text.trim();
|
||||
const text = result.text.trim();
|
||||
|
||||
// Картинки в контекст не кладём — только текст вопроса; пустой ответ не запоминаем.
|
||||
if (text) dialogService.remember(question.chatId, buildUserText(question), text);
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
/** Боту стоит скачивать фото, только если модель умеет их смотреть. */
|
||||
|
||||
Reference in New Issue
Block a user