refactor(server,stage-ui): use local first message key
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE "chat_members" DROP CONSTRAINT "chat_members_user_id_user_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "chat_members" DROP CONSTRAINT "chat_members_character_id_characters_id_fk";
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,13 @@
|
||||
"when": 1769186900274,
|
||||
"tag": "0006_gray_stardust",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "7",
|
||||
"when": 1769253946442,
|
||||
"tag": "0007_dazzling_ken_ellis",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,8 +3,6 @@ import type { InferInsertModel, InferSelectModel } from 'drizzle-orm'
|
||||
import { integer, pgTable, text, timestamp } from 'drizzle-orm/pg-core'
|
||||
|
||||
import { nanoid } from '../utils/id'
|
||||
import { user } from './accounts'
|
||||
import { character } from './characters'
|
||||
|
||||
export const media = pgTable(
|
||||
'media',
|
||||
@@ -65,8 +63,8 @@ export const chatMembers = pgTable(
|
||||
id: text('id').primaryKey().$defaultFn(() => nanoid()),
|
||||
chatId: text('chat_id').notNull().references(() => chats.id, { onDelete: 'cascade' }),
|
||||
memberType: text('member_type').notNull().$type<ChatMemberType>(),
|
||||
userId: text('user_id').references(() => user.id, { onDelete: 'cascade' }),
|
||||
characterId: text('character_id').references(() => character.id, { onDelete: 'cascade' }),
|
||||
userId: text('user_id'),
|
||||
characterId: text('character_id'),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { ChatAssistantMessage, ChatSlices, ChatStreamEventContext, Streamin
|
||||
import type { StreamEvent, StreamOptions } from './llm'
|
||||
|
||||
import { createQueue } from '@proj-airi/stream-kit'
|
||||
import { nanoid } from 'nanoid'
|
||||
import { defineStore, storeToRefs } from 'pinia'
|
||||
import { ref, toRaw } from 'vue'
|
||||
|
||||
@@ -112,7 +113,7 @@ export const useChatOrchestratorStore = defineStore('chat-orchestrator', () => {
|
||||
|
||||
const sendingCreatedAt = Date.now()
|
||||
const streamingMessageContext: ChatStreamEventContext = {
|
||||
message: { role: 'user', content: sendingMessage, createdAt: sendingCreatedAt },
|
||||
message: { role: 'user', content: sendingMessage, createdAt: sendingCreatedAt, id: nanoid() },
|
||||
contexts: chatContext.getContextsSnapshot(),
|
||||
composedMessage: [],
|
||||
input: options.input,
|
||||
@@ -127,7 +128,7 @@ export const useChatOrchestratorStore = defineStore('chat-orchestrator', () => {
|
||||
|
||||
const isForegroundSession = () => sessionId === activeSessionId.value
|
||||
|
||||
const buildingMessage: StreamingAssistantMessage = { role: 'assistant', content: '', slices: [], tool_results: [], createdAt: Date.now() }
|
||||
const buildingMessage: StreamingAssistantMessage = { role: 'assistant', content: '', slices: [], tool_results: [], createdAt: Date.now(), id: nanoid() }
|
||||
|
||||
const updateUI = () => {
|
||||
if (isForegroundSession()) {
|
||||
@@ -170,7 +171,7 @@ export const useChatOrchestratorStore = defineStore('chat-orchestrator', () => {
|
||||
return
|
||||
|
||||
const sessionMessagesForSend = chatSession.getSessionMessages(sessionId)
|
||||
sessionMessagesForSend.push({ role: 'user', content: finalContent, createdAt: sendingCreatedAt })
|
||||
sessionMessagesForSend.push({ role: 'user', content: finalContent, createdAt: sendingCreatedAt, id: nanoid() })
|
||||
chatSession.persistSessionMessages(sessionId)
|
||||
|
||||
const categorizer = createStreamingCategorizer(activeProvider.value)
|
||||
|
||||
@@ -72,14 +72,28 @@ export const useChatSessionStore = defineStore('chat-session', () => {
|
||||
return ''
|
||||
}
|
||||
|
||||
function buildMessageId(sessionId: string, message: ChatHistoryItem, index: number) {
|
||||
const createdAt = message.createdAt ?? 0
|
||||
return `${sessionId}:${createdAt}:${index}`
|
||||
function ensureSessionMessageIds(sessionId: string) {
|
||||
const current = sessionMessages.value[sessionId] ?? []
|
||||
let changed = false
|
||||
const next = current.map((message) => {
|
||||
if (message.id)
|
||||
return message
|
||||
changed = true
|
||||
return {
|
||||
...message,
|
||||
id: nanoid(),
|
||||
}
|
||||
})
|
||||
|
||||
if (changed)
|
||||
sessionMessages.value[sessionId] = next
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
function buildSyncMessages(sessionId: string, messages: ChatHistoryItem[]) {
|
||||
return messages.map((message, index) => ({
|
||||
id: buildMessageId(sessionId, message, index),
|
||||
function buildSyncMessages(messages: ChatHistoryItem[]) {
|
||||
return messages.map(message => ({
|
||||
id: message.id ?? nanoid(),
|
||||
role: message.role,
|
||||
content: extractMessageContent(message),
|
||||
createdAt: message.createdAt,
|
||||
@@ -106,13 +120,22 @@ export const useChatSessionStore = defineStore('chat-session', () => {
|
||||
{ type: 'user', userId: userId.value },
|
||||
]
|
||||
|
||||
if (cachedRecord.meta.characterId) {
|
||||
if (cachedRecord.meta.characterId && cachedRecord.meta.characterId !== 'default') {
|
||||
members.push({
|
||||
type: 'character',
|
||||
characterId: cachedRecord.meta.characterId,
|
||||
})
|
||||
}
|
||||
|
||||
const normalizedMessages = cachedRecord.messages.map(message => message.id ? message : { ...message, id: nanoid() })
|
||||
if (normalizedMessages.some((message, index) => cachedRecord?.messages[index]?.id !== message.id)) {
|
||||
cachedRecord = {
|
||||
...cachedRecord,
|
||||
messages: normalizedMessages,
|
||||
}
|
||||
await chatSessionsRepo.saveSession(sessionId, cachedRecord)
|
||||
}
|
||||
|
||||
const res = await client.api.chats.sync.$post({
|
||||
json: {
|
||||
chat: {
|
||||
@@ -123,7 +146,7 @@ export const useChatSessionStore = defineStore('chat-session', () => {
|
||||
updatedAt: cachedRecord.meta.updatedAt,
|
||||
},
|
||||
members,
|
||||
messages: buildSyncMessages(cachedRecord.meta.sessionId, cachedRecord.messages),
|
||||
messages: buildSyncMessages(cachedRecord.messages),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -155,6 +178,7 @@ export const useChatSessionStore = defineStore('chat-session', () => {
|
||||
return {
|
||||
role: 'system',
|
||||
content,
|
||||
id: nanoid(),
|
||||
createdAt: Date.now(),
|
||||
} satisfies ChatHistoryItem
|
||||
}
|
||||
@@ -193,7 +217,7 @@ export const useChatSessionStore = defineStore('chat-session', () => {
|
||||
const meta = sessionMetas.value[sessionId]
|
||||
if (!meta)
|
||||
return
|
||||
const messages = snapshotMessages(sessionMessages.value[sessionId] ?? [])
|
||||
const messages = snapshotMessages(ensureSessionMessageIds(sessionId))
|
||||
const now = Date.now()
|
||||
const updatedMeta = {
|
||||
...meta,
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface ContextMessage extends ContextUpdate<Record<string, unknown>, s
|
||||
createdAt: number
|
||||
}
|
||||
|
||||
export type ChatHistoryItem = (ChatMessage | ErrorMessage) & { context?: ContextMessage } & { createdAt?: number }
|
||||
export type ChatHistoryItem = (ChatMessage | ErrorMessage) & { context?: ContextMessage } & { createdAt?: number, id?: string }
|
||||
|
||||
export interface ChatStreamEventContext {
|
||||
message: ChatHistoryItem
|
||||
@@ -65,4 +65,4 @@ export type ChatStreamEvent
|
||||
| { type: 'assistant-end', message: string, sessionId: string, context: ChatStreamEventContext }
|
||||
| { type: 'assistant-message', message: ChatAssistantMessage, sessionId: string, messageText: string, context: ChatStreamEventContext }
|
||||
|
||||
export type StreamingAssistantMessage = ChatAssistantMessage & { context?: ContextMessage } & { createdAt?: number }
|
||||
export type StreamingAssistantMessage = ChatAssistantMessage & { context?: ContextMessage } & { createdAt?: number, id?: string }
|
||||
|
||||
Reference in New Issue
Block a user