Remove persistExchange functionality and simplify agent session handling

- Delete persistExchange method from all data sources and DbService
- Remove unused Topic import and MessageExchange type dependencies
- Simplify agent session existence check to validate sessionId directly
- Make getRawTopic required in MessageDataSource interface
This commit is contained in:
suyao 2025-09-22 22:03:47 +08:00
parent 15f216b050
commit 8645fe4ab1
No known key found for this signature in database
5 changed files with 13 additions and 182 deletions

View File

@ -1,10 +1,9 @@
import { loggerService } from '@logger'
import type { Topic } from '@renderer/types'
import type { AgentPersistedMessage } from '@renderer/types/agent'
import type { Message, MessageBlock } from '@renderer/types/newMessage'
import { IpcChannel } from '@shared/IpcChannel'
import type { MessageDataSource, MessageExchange } from './types'
import type { MessageDataSource } from './types'
import { extractSessionId } from './types'
const logger = loggerService.withContext('AgentMessageDataSource')
@ -60,51 +59,7 @@ export class AgentMessageDataSource implements MessageDataSource {
}
// ============ Write Operations ============
async persistExchange(topicId: string, exchange: MessageExchange): Promise<void> {
try {
const sessionId = extractSessionId(topicId)
if (!window.electron?.ipcRenderer) {
logger.warn('IPC renderer not available for persist exchange')
return
}
const payload: any = {
sessionId,
agentSessionId: exchange.agentSessionId || ''
}
// Prepare user payload
if (exchange.user) {
payload.user = {
payload: {
message: exchange.user.message,
blocks: exchange.user.blocks
}
}
}
// Prepare assistant payload
if (exchange.assistant) {
payload.assistant = {
payload: {
message: exchange.assistant.message,
blocks: exchange.assistant.blocks
}
}
}
await window.electron.ipcRenderer.invoke(IpcChannel.AgentMessage_PersistExchange, payload)
logger.info(`Persisted exchange for agent session ${sessionId}`)
} catch (error) {
logger.error(`Failed to persist exchange for agent session ${topicId}:`, error as Error)
throw error
}
}
async appendMessage(topicId: string, message: Message, blocks: MessageBlock[], insertIndex?: number): Promise<void> {
async appendMessage(topicId: string, message: Message, blocks: MessageBlock[], _insertIndex?: number): Promise<void> {
// For agent sessions, we need to save messages immediately
// Don't wait for persistExchange which happens after response completion
const sessionId = extractSessionId(topicId)
@ -239,12 +194,12 @@ export class AgentMessageDataSource implements MessageDataSource {
// ============ Block Operations ============
async updateBlocks(blocks: MessageBlock[]): Promise<void> {
async updateBlocks(_blocks: MessageBlock[]): Promise<void> {
// Blocks are updated through persistExchange for agent sessions
logger.warn('updateBlocks called for agent session, operation not supported individually')
}
async deleteBlocks(blockIds: string[]): Promise<void> {
async deleteBlocks(_blockIds: string[]): Promise<void> {
// Blocks cannot be deleted individually for agent sessions
logger.warn('deleteBlocks called for agent session, operation not supported')
}
@ -277,11 +232,7 @@ export class AgentMessageDataSource implements MessageDataSource {
if (!window.electron?.ipcRenderer) {
return false
}
// Check if session exists by trying to fetch messages
// In a full implementation, you'd have a dedicated endpoint
const messages = await this.fetchMessages(topicId)
return true // If no error thrown, session exists
return sessionId != null
} catch (error) {
return false
}
@ -294,26 +245,6 @@ export class AgentMessageDataSource implements MessageDataSource {
logger.info(`ensureTopic called for agent session ${sessionId}, no action needed`)
}
async fetchTopic(topicId: string): Promise<Topic | undefined> {
try {
const sessionId = extractSessionId(topicId)
// For agent sessions, we construct a synthetic topic
// In a real implementation, you might fetch session metadata from backend
return {
id: topicId,
name: `Session ${sessionId}`,
assistantId: 'agent',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
messages: [] // Messages are fetched separately
} as Topic
} catch (error) {
logger.error(`Failed to fetch topic for agent session ${topicId}:`, error as Error)
throw error
}
}
async getRawTopic(topicId: string): Promise<{ id: string; messages: Message[] } | undefined> {
try {
// For agent sessions, fetch messages from backend and return in raw topic format
@ -330,22 +261,22 @@ export class AgentMessageDataSource implements MessageDataSource {
// ============ Additional Methods for Interface Compatibility ============
async updateSingleBlock(blockId: string, updates: Partial<MessageBlock>): Promise<void> {
async updateSingleBlock(blockId: string, _updates: Partial<MessageBlock>): Promise<void> {
// Agent session blocks are immutable once persisted
logger.warn(`updateSingleBlock called for agent session block ${blockId}, operation not supported`)
}
async bulkAddBlocks(blocks: MessageBlock[]): Promise<void> {
async bulkAddBlocks(_blocks: MessageBlock[]): Promise<void> {
// Agent session blocks are added through persistExchange
logger.warn(`bulkAddBlocks called for agent session, operation not supported individually`)
}
async updateFileCount(fileId: string, delta: number): Promise<void> {
async updateFileCount(fileId: string, _delta: number): Promise<void> {
// Agent sessions don't manage file reference counts locally
logger.warn(`updateFileCount called for agent session file ${fileId}, operation not supported`)
}
async updateFileCounts(files: Array<{ id: string; delta: number }>): Promise<void> {
async updateFileCounts(_files: Array<{ id: string; delta: number }>): Promise<void> {
// Agent sessions don't manage file reference counts locally
logger.warn(`updateFileCounts called for agent session, operation not supported`)
}

View File

@ -1,10 +1,9 @@
import { loggerService } from '@logger'
import type { Topic } from '@renderer/types'
import type { Message, MessageBlock } from '@renderer/types/newMessage'
import { AgentMessageDataSource } from './AgentMessageDataSource'
import { DexieMessageDataSource } from './DexieMessageDataSource'
import type { MessageDataSource, MessageExchange } from './types'
import type { MessageDataSource } from './types'
import { isAgentSessionTopicId } from './types'
const logger = loggerService.withContext('DbService')
@ -62,18 +61,7 @@ class DbService implements MessageDataSource {
return source.fetchMessages(topicId, forceReload)
}
async fetchTopic(topicId: string): Promise<Topic | undefined> {
const source = this.getDataSource(topicId)
return source.fetchTopic(topicId)
}
// ============ Write Operations ============
async persistExchange(topicId: string, exchange: MessageExchange): Promise<void> {
const source = this.getDataSource(topicId)
return source.persistExchange(topicId, exchange)
}
async appendMessage(topicId: string, message: Message, blocks: MessageBlock[], insertIndex?: number): Promise<void> {
const source = this.getDataSource(topicId)
return source.appendMessage(topicId, message, blocks, insertIndex)
@ -141,12 +129,7 @@ class DbService implements MessageDataSource {
async getRawTopic(topicId: string): Promise<{ id: string; messages: Message[] } | undefined> {
const source = this.getDataSource(topicId)
if (source.getRawTopic) {
return source.getRawTopic(topicId)
}
// Fallback: fetch using fetchTopic and extract messages
const topic = await source.fetchTopic(topicId)
return topic ? { id: topic.id, messages: topic.messages } : undefined
return source.getRawTopic(topicId)
}
async updateSingleBlock(blockId: string, updates: Partial<MessageBlock>): Promise<void> {

View File

@ -6,7 +6,7 @@ import { updateTopicUpdatedAt } from '@renderer/store/assistants'
import type { Message, MessageBlock } from '@renderer/types/newMessage'
import { isEmpty } from 'lodash'
import type { MessageDataSource, MessageExchange } from './types'
import type { MessageDataSource } from './types'
const logger = loggerService.withContext('DexieMessageDataSource')
@ -58,61 +58,6 @@ export class DexieMessageDataSource implements MessageDataSource {
}
// ============ Write Operations ============
async persistExchange(topicId: string, exchange: MessageExchange): Promise<void> {
try {
await db.transaction('rw', db.topics, db.message_blocks, async () => {
const topic = await db.topics.get(topicId)
if (!topic) {
throw new Error(`Topic ${topicId} not found`)
}
const updatedMessages = [...topic.messages]
const blocksToSave: MessageBlock[] = []
// Handle user message
if (exchange.user) {
const userIndex = updatedMessages.findIndex((m) => m.id === exchange.user!.message.id)
if (userIndex !== -1) {
updatedMessages[userIndex] = exchange.user.message
} else {
updatedMessages.push(exchange.user.message)
}
if (exchange.user.blocks.length > 0) {
blocksToSave.push(...exchange.user.blocks)
}
}
// Handle assistant message
if (exchange.assistant) {
const assistantIndex = updatedMessages.findIndex((m) => m.id === exchange.assistant!.message.id)
if (assistantIndex !== -1) {
updatedMessages[assistantIndex] = exchange.assistant.message
} else {
updatedMessages.push(exchange.assistant.message)
}
if (exchange.assistant.blocks.length > 0) {
blocksToSave.push(...exchange.assistant.blocks)
}
}
// Save blocks
if (blocksToSave.length > 0) {
await db.message_blocks.bulkPut(blocksToSave)
}
// Update topic with new messages
await db.topics.update(topicId, { messages: updatedMessages })
})
// Update Redux state
store.dispatch(updateTopicUpdatedAt({ topicId }))
} catch (error) {
logger.error(`Failed to persist exchange for topic ${topicId}:`, error as Error)
throw error
}
}
async appendMessage(topicId: string, message: Message, blocks: MessageBlock[], insertIndex?: number): Promise<void> {
try {
await db.transaction('rw', db.topics, db.message_blocks, async () => {

View File

@ -36,14 +36,9 @@ export interface MessageDataSource {
/**
* Get raw topic data (just id and messages)
*/
getRawTopic?(topicId: string): Promise<{ id: string; messages: Message[] } | undefined>
getRawTopic(topicId: string): Promise<{ id: string; messages: Message[] } | undefined>
// ============ Write Operations ============
/**
* Persist a complete message exchange (user + assistant)
*/
persistExchange(topicId: string, exchange: MessageExchange): Promise<void>
/**
* Append a single message with its blocks
*/

View File

@ -204,29 +204,6 @@ export const saveMessageAndBlocksToDBV2 = async (
}
}
/**
* Persist a message exchange (user + assistant messages)
*/
export const persistExchangeV2 = async (
topicId: string,
exchange: {
user?: { message: Message; blocks: MessageBlock[] }
assistant?: { message: Message; blocks: MessageBlock[] }
}
): Promise<void> => {
try {
await dbService.persistExchange(topicId, exchange)
logger.info('Persisted exchange via DbService', {
topicId,
hasUser: !!exchange.user,
hasAssistant: !!exchange.assistant
})
} catch (error) {
logger.error('Failed to persist exchange:', { topicId, error })
throw error
}
}
// Note: sendMessageV2 would be implemented here but it's more complex
// and would require more of the supporting code from messageThunk.ts