You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
3.4 KiB
TypeScript

import {
router,
publicProcedure,
createCallerFactory,
} from "../../trpc/server";
import { MODEL_NAME } from "./provider.js";
import { generateObject, generateText, jsonSchema } from "ai";
import type { DraftMessage } from "../../types.js";
const runningSummarySystemPrompt = ({
previousRunningSummary,
}: {
previousRunningSummary: string;
}) => `You are an expert at summarizing conversations.
You will be given a summary of a conversation, and the messages exchanged since that summary was produced.
Your task is to produce a new summary of the conversation.
* The user should be referred to as "the user" in the summary.
* The user's pronouns should be either he or she, NOT "they" or "them", because this summary will be read by an AI assistant to give it context; and excessive use of "they" or "them" will make what they refer to unclear or ambiguous.
* The assistant should be referred to as "I" or "me", because this summary will be read by an AI assistant to give it context.
* The new summary may omit details present in the old summary, provided that the messages that were exchanged since that summary was produced indictae that those details are becoming less relevant to the continuation of the conversation.
<running_summary>
${previousRunningSummary}
</running_summary>
`;
const runningSummaryUserPrompt = ({
messagesSincePreviousRunningSummary,
mainResponseContent,
}: {
messagesSincePreviousRunningSummary: Array<DraftMessage>;
mainResponseContent: string;
}) =>
`${messagesSincePreviousRunningSummary.map(
(message) =>
`<${message.role}_message>${message.parts
.filter((p) => p.type === "text")
.map((p) => p.text)
.join("\n")}</${message.role}_message>`
)}
<assistant_response>
${mainResponseContent}
</assistant_response>
Generate a new running summary of the conversation.`;
export const messages = router({
fetchByConversationId: publicProcedure
.input((x) => x as { conversationId: string })
.query(async ({ input: { conversationId }, ctx: { db } }) => {
return await db.messages.findByConversationId(conversationId);
}),
deleteOne: publicProcedure
.input((x) => x as { id: string })
.mutation(async ({ input: { id }, ctx: { db } }) => {
await db.messages.delete(id);
return { success: true };
}),
generateRunningSummary: publicProcedure
.input(
(x) =>
x as {
previousRunningSummary: string;
messagesSincePreviousRunningSummary: Array<DraftMessage>;
mainResponseContent: string;
}
)
.mutation(
async ({
input: {
previousRunningSummary,
messagesSincePreviousRunningSummary,
mainResponseContent,
},
ctx: { openrouter },
}) => {
const runningSummaryResponse = await generateText({
model: openrouter(MODEL_NAME),
messages: [
{
role: "system" as const,
content: runningSummarySystemPrompt({
previousRunningSummary,
}),
},
{
role: "user" as const,
content: runningSummaryUserPrompt({
messagesSincePreviousRunningSummary,
mainResponseContent,
}),
},
],
tools: undefined,
});
return runningSummaryResponse;
}
),
});
export const createCaller = createCallerFactory(messages);