feat(characters): support character-scoped conversations

This commit is contained in:
2026-07-17 11:42:31 +08:00
parent 93efcb6604
commit 2796010971
85 changed files with 1645 additions and 251 deletions
+15 -10
View File
@@ -4,7 +4,7 @@ import { ExceptionHandler } from "@/core/errors";
import { MessageQueue } from "@/core/net/message-queue";
import type { ChatSendResponse } from "@/data/dto/chat";
import { loadChatRepository } from "@/data/repositories/chat_repository_loader";
import { resolveChatCacheOwnerKey } from "@/data/repositories/chat_cache_identity";
import { resolveChatConversationKey } from "@/data/repositories/chat_cache_identity";
import { Logger } from "@/utils/logger";
import { Result } from "@/utils/result";
@@ -17,18 +17,22 @@ type UiMessage = import("@/data/dto/chat").UiMessage;
export const sendMessageHttpActor = fromPromise<
{ response: ChatSendResponse; reply: UiMessage | null },
{ content: string }
{ characterId: string; content: string }
>(async ({ input }) => {
return sendMessageViaHttp(input.content);
return sendMessageViaHttp(input.characterId, input.content);
});
export const httpMessageQueueActor = fromCallback<ChatEvent>(
({ sendBack, receive }) => {
return createMessageQueueActor(sendBack, receive);
export const httpMessageQueueActor = fromCallback<
ChatEvent,
{ characterId: string }
>(
({ input, sendBack, receive }) => {
return createMessageQueueActor(input.characterId, sendBack, receive);
},
);
function createMessageQueueActor(
characterId: string,
sendBack: (event: ChatEvent) => void,
receive: (listener: (event: ChatEvent) => void) => void,
): () => void {
@@ -37,7 +41,7 @@ function createMessageQueueActor(
queue.setConsumer(async (content) => {
sendBack({ type: "ChatQueuedSendStarted" });
try {
const output = await sendMessageViaHttp(content);
const output = await sendMessageViaHttp(characterId, content);
sendBack({ type: "ChatQueuedHttpDone", output });
} catch (error) {
const errorMessage = ExceptionHandler.message(error);
@@ -62,13 +66,13 @@ function createMessageQueueActor(
return () => queue.dispose();
}
async function sendMessageViaHttp(content: string): Promise<{
async function sendMessageViaHttp(characterId: string, content: string): Promise<{
response: ChatSendResponse;
reply: UiMessage | null;
}> {
const chatRepo = await loadChatRepository();
const cacheIdentityResult = await resolveChatCacheOwnerKey();
const result = await chatRepo.sendMessage(content);
const cacheIdentityResult = await resolveChatConversationKey(characterId);
const result = await chatRepo.sendMessage(characterId, content);
if (Result.isErr(result)) {
log.error("[chat-machine] sendMessageHttpActor failed", {
error: result.error,
@@ -78,6 +82,7 @@ async function sendMessageViaHttp(content: string): Promise<{
if (Result.isOk(cacheIdentityResult)) {
void chatRepo.prefetchMediaForSendResponse(
result.data,
characterId,
cacheIdentityResult.data,
);
}