Compare commits
4 Commits
feat/mcp-u
...
feature/pe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
630c8e4d38 | ||
|
|
3fd53572dd | ||
|
|
3aec08d650 | ||
|
|
7328664edf |
@@ -998,6 +998,7 @@
|
||||
},
|
||||
"memory": {
|
||||
"actions": "Actions",
|
||||
"active_memory_user": "Active Memory User",
|
||||
"add_failed": "Failed to add memory",
|
||||
"add_first_memory": "Add Your First Memory",
|
||||
"add_memory": "Add Memory",
|
||||
|
||||
@@ -998,6 +998,7 @@
|
||||
},
|
||||
"memory": {
|
||||
"actions": "アクション",
|
||||
"active_memory_user": "アクティブメモリユーザー",
|
||||
"add_failed": "メモリーの追加に失敗しました",
|
||||
"add_first_memory": "最初のメモリを追加",
|
||||
"add_memory": "メモリーを追加",
|
||||
|
||||
@@ -998,6 +998,7 @@
|
||||
},
|
||||
"memory": {
|
||||
"actions": "Действия",
|
||||
"active_memory_user": "Активный пользователь памяти",
|
||||
"add_failed": "Не удалось добавить память",
|
||||
"add_first_memory": "Добавить первое воспоминание",
|
||||
"add_memory": "Добавить память",
|
||||
|
||||
@@ -998,6 +998,7 @@
|
||||
},
|
||||
"memory": {
|
||||
"actions": "操作",
|
||||
"active_memory_user": "活跃记忆用户",
|
||||
"add_failed": "添加记忆失败",
|
||||
"add_first_memory": "添加您的第一条记忆",
|
||||
"add_memory": "添加记忆",
|
||||
|
||||
@@ -998,6 +998,7 @@
|
||||
},
|
||||
"memory": {
|
||||
"actions": "操作",
|
||||
"active_memory_user": "活躍記憶使用者",
|
||||
"add_failed": "新增記憶失敗",
|
||||
"add_first_memory": "新增您的第一個記憶",
|
||||
"add_memory": "新增記憶",
|
||||
|
||||
@@ -3,9 +3,9 @@ import { loggerService } from '@logger'
|
||||
import { Box } from '@renderer/components/Layout'
|
||||
import MemoriesSettingsModal from '@renderer/pages/memory/settings-modal'
|
||||
import MemoryService from '@renderer/services/MemoryService'
|
||||
import { selectGlobalMemoryEnabled, selectMemoryConfig } from '@renderer/store/memory'
|
||||
import { selectCurrentUserId, selectGlobalMemoryEnabled, selectMemoryConfig } from '@renderer/store/memory'
|
||||
import { Assistant, AssistantSettings } from '@renderer/types'
|
||||
import { Alert, Button, Card, Space, Switch, Tooltip, Typography } from 'antd'
|
||||
import { Alert, Button, Card, Select, Space, Switch, Tooltip, Typography } from 'antd'
|
||||
import { useForm } from 'antd/es/form/Form'
|
||||
import { Settings2 } from 'lucide-react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
@@ -28,19 +28,36 @@ const AssistantMemorySettings: React.FC<Props> = ({ assistant, updateAssistant,
|
||||
const { t } = useTranslation()
|
||||
const memoryConfig = useSelector(selectMemoryConfig)
|
||||
const globalMemoryEnabled = useSelector(selectGlobalMemoryEnabled)
|
||||
const currentUserId = useSelector(selectCurrentUserId)
|
||||
const [memoryStats, setMemoryStats] = useState<{ count: number; loading: boolean }>({
|
||||
count: 0,
|
||||
loading: true
|
||||
})
|
||||
const [availableUsers, setAvailableUsers] = useState<
|
||||
{ userId: string; memoryCount: number; lastMemoryDate: string }[]
|
||||
>([])
|
||||
const [settingsModalVisible, setSettingsModalVisible] = useState(false)
|
||||
const memoryService = MemoryService.getInstance()
|
||||
const form = useForm()
|
||||
|
||||
// Load available memory users
|
||||
const loadUsers = useCallback(async () => {
|
||||
try {
|
||||
const users = await memoryService.getUsersList()
|
||||
setAvailableUsers(users)
|
||||
} catch (error) {
|
||||
logger.error('Failed to load memory users:', error as Error)
|
||||
setAvailableUsers([])
|
||||
}
|
||||
}, [memoryService])
|
||||
|
||||
// Load memory statistics for this assistant
|
||||
const loadMemoryStats = useCallback(async () => {
|
||||
setMemoryStats((prev) => ({ ...prev, loading: true }))
|
||||
try {
|
||||
const effectiveUserId = memoryService.getEffectiveUserId(assistant, currentUserId)
|
||||
const result = await memoryService.list({
|
||||
userId: effectiveUserId,
|
||||
agentId: assistant.id,
|
||||
limit: 1000
|
||||
})
|
||||
@@ -49,16 +66,25 @@ const AssistantMemorySettings: React.FC<Props> = ({ assistant, updateAssistant,
|
||||
logger.error('Failed to load memory stats:', error as Error)
|
||||
setMemoryStats({ count: 0, loading: false })
|
||||
}
|
||||
}, [assistant.id, memoryService])
|
||||
}, [assistant, currentUserId, memoryService])
|
||||
|
||||
useEffect(() => {
|
||||
loadUsers()
|
||||
loadMemoryStats()
|
||||
}, [loadMemoryStats])
|
||||
}, [loadUsers, loadMemoryStats])
|
||||
|
||||
const handleMemoryToggle = (enabled: boolean) => {
|
||||
updateAssistant({ ...assistant, enableMemory: enabled })
|
||||
}
|
||||
|
||||
const handleMemoryUserChange = (value: string) => {
|
||||
// 'global' means use global default (undefined)
|
||||
const memoryUserId = value === 'global' ? undefined : value
|
||||
updateAssistant({ ...assistant, memoryUserId })
|
||||
// Reload stats after changing user
|
||||
setTimeout(() => loadMemoryStats(), 100)
|
||||
}
|
||||
|
||||
const handleNavigateToMemory = () => {
|
||||
// Close current modal/page first
|
||||
if (onClose) {
|
||||
@@ -70,6 +96,8 @@ const AssistantMemorySettings: React.FC<Props> = ({ assistant, updateAssistant,
|
||||
|
||||
const isMemoryConfigured = memoryConfig.embedderApiClient && memoryConfig.llmApiClient
|
||||
const isMemoryEnabled = globalMemoryEnabled && isMemoryConfigured
|
||||
const effectiveUserId = memoryService.getEffectiveUserId(assistant, currentUserId)
|
||||
const currentMemoryUser = assistant.memoryUserId || 'global'
|
||||
|
||||
return (
|
||||
<Container>
|
||||
@@ -124,12 +152,41 @@ const AssistantMemorySettings: React.FC<Props> = ({ assistant, updateAssistant,
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Memory User Selection */}
|
||||
{assistant.enableMemory && isMemoryEnabled && (
|
||||
<Card size="small" style={{ marginBottom: 16 }}>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<div>
|
||||
<Text strong>{t('memory.active_memory_user')}: </Text>
|
||||
<Select
|
||||
value={currentMemoryUser}
|
||||
onChange={handleMemoryUserChange}
|
||||
style={{ width: 200, marginLeft: 8 }}
|
||||
disabled={!assistant.enableMemory}>
|
||||
<Select.Option value="global">
|
||||
{t('memory.default_user')} ({currentUserId})
|
||||
</Select.Option>
|
||||
{availableUsers.map((user) => (
|
||||
<Select.Option key={user.userId} value={user.userId}>
|
||||
{user.userId} ({user.memoryCount} memories)
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Card size="small" style={{ marginBottom: 16 }}>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<div>
|
||||
<Text strong>{t('memory.stored_memories')}: </Text>
|
||||
<Text>{memoryStats.loading ? t('common.loading') : memoryStats.count}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text strong>{t('memory.active_memory_user')}: </Text>
|
||||
<Text code>{effectiveUserId}</Text>
|
||||
</div>
|
||||
{memoryConfig.embedderApiClient && (
|
||||
<div>
|
||||
<Text strong>{t('memory.embedding_model')}: </Text>
|
||||
|
||||
@@ -458,7 +458,7 @@ const MemorySettings = () => {
|
||||
try {
|
||||
// Create the user by adding an initial memory with the userId
|
||||
// This implicitly creates the user in the system
|
||||
await memoryService.setCurrentUser(userId)
|
||||
memoryService.setCurrentUser(userId)
|
||||
await memoryService.add(t('memory.initial_memory_content'), { userId })
|
||||
|
||||
// Refresh the users list from the database to persist the new user
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import CustomTag from '@renderer/components/CustomTag'
|
||||
import { HStack } from '@renderer/components/Layout'
|
||||
import { useAssistants } from '@renderer/hooks/useAssistant'
|
||||
import { Avatar, Button, Select, Space, Tooltip } from 'antd'
|
||||
import { UserRoundPlus } from 'lucide-react'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
@@ -15,23 +17,50 @@ interface UserSelectorProps {
|
||||
|
||||
const UserSelector: React.FC<UserSelectorProps> = ({ currentUser, uniqueUsers, onUserSwitch, onAddUser }) => {
|
||||
const { t } = useTranslation()
|
||||
const { assistants } = useAssistants()
|
||||
|
||||
const getUserAvatar = useCallback((user: string) => {
|
||||
return user === DEFAULT_USER_ID ? user.slice(0, 1).toUpperCase() : user.slice(0, 2).toUpperCase()
|
||||
}, [])
|
||||
|
||||
// Get assistants linked to a specific memory user
|
||||
const getAssistantsForUser = useCallback(
|
||||
(userId: string) => {
|
||||
return assistants.filter(
|
||||
(assistant) =>
|
||||
// Assistant uses this user if either:
|
||||
// 1. memoryUserId explicitly matches
|
||||
// 2. memoryUserId is undefined and this is the current global user
|
||||
assistant.memoryUserId === userId || (!assistant.memoryUserId && userId === currentUser)
|
||||
)
|
||||
},
|
||||
[assistants, currentUser]
|
||||
)
|
||||
|
||||
const renderLabel = useCallback(
|
||||
(userId: string, userName: string) => {
|
||||
const linkedAssistants = getAssistantsForUser(userId)
|
||||
|
||||
return (
|
||||
<HStack alignItems="center" gap={10}>
|
||||
<HStack alignItems="center" justifyContent="space-between" style={{ width: '100%' }}>
|
||||
<HStack alignItems="center" gap={8} style={{ minWidth: 0 }}>
|
||||
<Avatar size={20} style={{ background: 'var(--color-primary)' }}>
|
||||
{getUserAvatar(userId)}
|
||||
</Avatar>
|
||||
<span>{userName}</span>
|
||||
<span style={{ whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }}>{userName}</span>
|
||||
</HStack>
|
||||
{linkedAssistants.length > 0 && (
|
||||
<CustomTag
|
||||
color="#8c8c8c"
|
||||
size={10}
|
||||
tooltip={`Linked Assistants: ${linkedAssistants.map((a) => a.name).join(', ')}`}>
|
||||
{linkedAssistants.length}
|
||||
</CustomTag>
|
||||
)}
|
||||
</HStack>
|
||||
)
|
||||
},
|
||||
[getUserAvatar]
|
||||
[getUserAvatar, getAssistantsForUser]
|
||||
)
|
||||
|
||||
const options = useMemo(() => {
|
||||
|
||||
@@ -67,6 +67,7 @@ import {
|
||||
} from './AssistantService'
|
||||
import { processKnowledgeSearch } from './KnowledgeService'
|
||||
import { MemoryProcessor } from './MemoryProcessor'
|
||||
import MemoryService from './MemoryService'
|
||||
import {
|
||||
filterContextMessages,
|
||||
filterEmptyMessages,
|
||||
@@ -232,10 +233,12 @@ async function fetchExternalTool(
|
||||
}
|
||||
|
||||
if (memoryConfig.llmApiClient && memoryConfig.embedderApiClient) {
|
||||
const currentUserId = selectCurrentUserId(store.getState())
|
||||
// Search for relevant memories
|
||||
const processorConfig = MemoryProcessor.getProcessorConfig(memoryConfig, assistant.id, currentUserId)
|
||||
logger.info(`Searching for relevant memories with content: ${content}`)
|
||||
const globalUserId = selectCurrentUserId(store.getState())
|
||||
const memoryService = MemoryService.getInstance()
|
||||
const effectiveUserId = memoryService.getEffectiveUserId(assistant, globalUserId)
|
||||
// Search for relevant memories using effective user ID
|
||||
const processorConfig = MemoryProcessor.getProcessorConfig(memoryConfig, assistant.id, effectiveUserId)
|
||||
logger.info(`Searching for relevant memories with content: ${content} for effective user: ${effectiveUserId}`)
|
||||
const memoryProcessor = new MemoryProcessor()
|
||||
const relevantMemories = await memoryProcessor.searchRelevantMemories(
|
||||
content,
|
||||
@@ -557,7 +560,9 @@ async function processConversationMemory(messages: Message[], assistant: Assista
|
||||
// return
|
||||
// }
|
||||
|
||||
const currentUserId = selectCurrentUserId(store.getState())
|
||||
const globalUserId = selectCurrentUserId(store.getState())
|
||||
const memoryService = MemoryService.getInstance()
|
||||
const effectiveUserId = memoryService.getEffectiveUserId(assistant, globalUserId)
|
||||
|
||||
// Create updated memory config with resolved models
|
||||
const updatedMemoryConfig = {
|
||||
@@ -582,7 +587,7 @@ async function processConversationMemory(messages: Message[], assistant: Assista
|
||||
const processorConfig = MemoryProcessor.getProcessorConfig(
|
||||
updatedMemoryConfig,
|
||||
assistant.id,
|
||||
currentUserId,
|
||||
effectiveUserId,
|
||||
lastUserMessage?.id
|
||||
)
|
||||
|
||||
|
||||
@@ -238,12 +238,10 @@ export class MemoryProcessor {
|
||||
limit
|
||||
})
|
||||
|
||||
logger.debug(
|
||||
`Searching memories with query: ${query} for user: ${userId} and assistant: ${assistantId} result: ${result}`
|
||||
)
|
||||
logger.debug('Searching memories successful', { query, userId, assistantId, result })
|
||||
return result.results
|
||||
} catch (error) {
|
||||
logger.error('Error searching memories:', error as Error)
|
||||
logger.error('Searching memories error:', { error })
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { loggerService } from '@logger'
|
||||
import type { RootState } from '@renderer/store'
|
||||
import store from '@renderer/store'
|
||||
import { selectMemoryConfig } from '@renderer/store/memory'
|
||||
import { selectCurrentUserId, selectMemoryConfig } from '@renderer/store/memory'
|
||||
import {
|
||||
AddMemoryOptions,
|
||||
Assistant,
|
||||
AssistantMessage,
|
||||
MemoryHistoryItem,
|
||||
MemoryListOptions,
|
||||
@@ -10,6 +12,8 @@ import {
|
||||
MemorySearchResult
|
||||
} from '@types'
|
||||
|
||||
import { getAssistantById } from './AssistantService'
|
||||
|
||||
const logger = loggerService.withContext('MemoryService')
|
||||
|
||||
// Main process SearchResult type (matches what the IPC actually returns)
|
||||
@@ -26,8 +30,10 @@ interface SearchResult {
|
||||
class MemoryService {
|
||||
private static instance: MemoryService | null = null
|
||||
private currentUserId: string = 'default-user'
|
||||
private getStateFunction: () => RootState
|
||||
|
||||
constructor() {
|
||||
constructor(getStateFunction: () => RootState = () => store.getState()) {
|
||||
this.getStateFunction = getStateFunction
|
||||
this.init()
|
||||
}
|
||||
|
||||
@@ -68,6 +74,37 @@ class MemoryService {
|
||||
return this.currentUserId
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the effective memory user ID for an assistant using dependency injection
|
||||
* Falls back to global currentUserId when assistant has no specific memoryUserId
|
||||
* @param assistant - The assistant object containing memoryUserId
|
||||
* @param globalUserId - The global user ID to fall back to
|
||||
* @returns The effective user ID to use for memory operations
|
||||
*/
|
||||
public getEffectiveUserId(assistant: Assistant, globalUserId: string): string {
|
||||
return assistant.memoryUserId || globalUserId
|
||||
}
|
||||
|
||||
/**
|
||||
* Private helper to resolve user ID for context operations
|
||||
* @param assistant - Optional assistant object to determine effective user ID
|
||||
* @returns The resolved user ID to use for memory operations
|
||||
*/
|
||||
private resolveUserId(assistant?: Assistant): string {
|
||||
let globalUserId = this.currentUserId
|
||||
|
||||
if (this.getStateFunction) {
|
||||
try {
|
||||
globalUserId = selectCurrentUserId(this.getStateFunction())
|
||||
} catch (error) {
|
||||
logger.warn('Failed to get state, falling back to internal currentUserId:', error as Error)
|
||||
globalUserId = this.currentUserId
|
||||
}
|
||||
}
|
||||
|
||||
return assistant ? this.getEffectiveUserId(assistant, globalUserId) : globalUserId
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all stored memories
|
||||
* @param config - Optional configuration for filtering memories
|
||||
@@ -110,13 +147,33 @@ class MemoryService {
|
||||
* @returns Promise resolving to search results of added memories
|
||||
*/
|
||||
public async add(messages: string | AssistantMessage[], options: AddMemoryOptions): Promise<MemorySearchResult> {
|
||||
options.userId = this.currentUserId
|
||||
const result: SearchResult = await window.api.memory.add(messages, options)
|
||||
const optionsWithUser = {
|
||||
...options,
|
||||
userId: this.currentUserId
|
||||
}
|
||||
|
||||
try {
|
||||
const result: SearchResult = await window.api.memory.add(messages, optionsWithUser)
|
||||
|
||||
// Handle error responses from main process
|
||||
if (result.error) {
|
||||
logger.error(`Memory service error: ${result.error}`)
|
||||
throw new Error(result.error)
|
||||
}
|
||||
|
||||
// Convert SearchResult to MemorySearchResult for consistency
|
||||
return {
|
||||
results: result.memories,
|
||||
results: result.memories || [],
|
||||
relations: []
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to add memories:', error as Error)
|
||||
// Return empty result on error to prevent UI crashes
|
||||
return {
|
||||
results: [],
|
||||
relations: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,13 +183,43 @@ class MemoryService {
|
||||
* @returns Promise resolving to search results matching the query
|
||||
*/
|
||||
public async search(query: string, options: MemorySearchOptions): Promise<MemorySearchResult> {
|
||||
options.userId = this.currentUserId
|
||||
const result: SearchResult = await window.api.memory.search(query, options)
|
||||
const optionsWithUser = {
|
||||
...options,
|
||||
userId: this.currentUserId
|
||||
}
|
||||
|
||||
// If agentId is provided, resolve userId from assistant's memoryUserId
|
||||
if (optionsWithUser.agentId) {
|
||||
const assistant = getAssistantById(optionsWithUser.agentId)
|
||||
if (assistant) {
|
||||
optionsWithUser.userId = assistant.memoryUserId || this.currentUserId
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug('Searching memories start with options', { query: query, options: optionsWithUser })
|
||||
|
||||
try {
|
||||
const result: SearchResult = await window.api.memory.search(query, optionsWithUser)
|
||||
|
||||
// Handle error responses from main process
|
||||
if (result.error) {
|
||||
logger.error(`Memory service error: ${result.error}`)
|
||||
throw new Error(result.error)
|
||||
}
|
||||
|
||||
// Convert SearchResult to MemorySearchResult for consistency
|
||||
return {
|
||||
results: result.memories,
|
||||
results: result.memories || [],
|
||||
relations: []
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to search memories:', error as Error)
|
||||
// Return empty result on error to prevent UI crashes
|
||||
return {
|
||||
results: [],
|
||||
relations: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,12 +284,13 @@ class MemoryService {
|
||||
*/
|
||||
public async updateConfig(): Promise<void> {
|
||||
try {
|
||||
if (!store || !store.getState) {
|
||||
logger.warn('Store not available, skipping memory config update')
|
||||
if (!this.getStateFunction) {
|
||||
logger.warn('State function not available, skipping memory config update')
|
||||
return
|
||||
}
|
||||
|
||||
const memoryConfig = selectMemoryConfig(store.getState())
|
||||
const state = this.getStateFunction()
|
||||
const memoryConfig = selectMemoryConfig(state)
|
||||
const embedderApiClient = memoryConfig.embedderApiClient
|
||||
const llmApiClient = memoryConfig.llmApiClient
|
||||
|
||||
@@ -218,6 +306,138 @@ class MemoryService {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Enhanced methods with assistant context support
|
||||
|
||||
/**
|
||||
* Lists stored memories with assistant context support
|
||||
* Automatically resolves the effective user ID based on assistant's memoryUserId
|
||||
* @param config - Configuration for filtering memories
|
||||
* @param assistant - Optional assistant object to determine effective user ID
|
||||
* @returns Promise resolving to search results containing filtered memories
|
||||
*/
|
||||
public async listWithContext(
|
||||
config?: Omit<MemoryListOptions, 'userId'>,
|
||||
assistant?: Assistant
|
||||
): Promise<MemorySearchResult> {
|
||||
const effectiveUserId = this.resolveUserId(assistant)
|
||||
|
||||
const configWithUser = {
|
||||
...config,
|
||||
userId: effectiveUserId
|
||||
}
|
||||
|
||||
try {
|
||||
const result: SearchResult = await window.api.memory.list(configWithUser)
|
||||
|
||||
// Handle error responses from main process
|
||||
if (result.error) {
|
||||
logger.error(`Memory service error: ${result.error}`)
|
||||
throw new Error(result.error)
|
||||
}
|
||||
|
||||
// Convert SearchResult to MemorySearchResult for consistency
|
||||
return {
|
||||
results: result.memories || [],
|
||||
relations: []
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to list memories with context:', error as Error)
|
||||
// Return empty result on error to prevent UI crashes
|
||||
return {
|
||||
results: [],
|
||||
relations: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new memory entries with assistant context support
|
||||
* Automatically resolves the effective user ID based on assistant's memoryUserId
|
||||
* @param messages - String content or array of assistant messages to store as memory
|
||||
* @param options - Configuration options for adding memory (without userId)
|
||||
* @param assistant - Optional assistant object to determine effective user ID
|
||||
* @returns Promise resolving to search results of added memories
|
||||
*/
|
||||
public async addWithContext(
|
||||
messages: string | AssistantMessage[],
|
||||
options: Omit<AddMemoryOptions, 'userId'>,
|
||||
assistant?: Assistant
|
||||
): Promise<MemorySearchResult> {
|
||||
const effectiveUserId = this.resolveUserId(assistant)
|
||||
|
||||
const optionsWithUser = {
|
||||
...options,
|
||||
userId: effectiveUserId
|
||||
}
|
||||
|
||||
try {
|
||||
const result: SearchResult = await window.api.memory.add(messages, optionsWithUser)
|
||||
|
||||
// Handle error responses from main process
|
||||
if (result.error) {
|
||||
logger.error(`Memory service error: ${result.error}`)
|
||||
throw new Error(result.error)
|
||||
}
|
||||
|
||||
// Convert SearchResult to MemorySearchResult for consistency
|
||||
return {
|
||||
results: result.memories || [],
|
||||
relations: []
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to add memories with context:', error as Error)
|
||||
// Return empty result on error to prevent UI crashes
|
||||
return {
|
||||
results: [],
|
||||
relations: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches stored memories with assistant context support
|
||||
* Automatically resolves the effective user ID based on assistant's memoryUserId
|
||||
* @param query - Search query string to find relevant memories
|
||||
* @param options - Configuration options for memory search (without userId)
|
||||
* @param assistant - Optional assistant object to determine effective user ID
|
||||
* @returns Promise resolving to search results matching the query
|
||||
*/
|
||||
public async searchWithContext(
|
||||
query: string,
|
||||
options: Omit<MemorySearchOptions, 'userId'>,
|
||||
assistant?: Assistant
|
||||
): Promise<MemorySearchResult> {
|
||||
const effectiveUserId = this.resolveUserId(assistant)
|
||||
|
||||
const optionsWithUser = {
|
||||
...options,
|
||||
userId: effectiveUserId
|
||||
}
|
||||
|
||||
try {
|
||||
const result: SearchResult = await window.api.memory.search(query, optionsWithUser)
|
||||
|
||||
// Handle error responses from main process
|
||||
if (result.error) {
|
||||
logger.error(`Memory service error: ${result.error}`)
|
||||
throw new Error(result.error)
|
||||
}
|
||||
|
||||
// Convert SearchResult to MemorySearchResult for consistency
|
||||
return {
|
||||
results: result.memories || [],
|
||||
relations: []
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to search memories with context:', error as Error)
|
||||
// Return empty result on error to prevent UI crashes
|
||||
return {
|
||||
results: [],
|
||||
relations: []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MemoryService
|
||||
|
||||
@@ -51,7 +51,7 @@ export function createStreamProcessor(callbacks: StreamProcessorCallbacks = {})
|
||||
return (chunk: Chunk) => {
|
||||
try {
|
||||
const data = chunk
|
||||
logger.debug('data: ', data)
|
||||
logger.silly('data: ', data)
|
||||
switch (data.type) {
|
||||
case ChunkType.BLOCK_COMPLETE: {
|
||||
if (callbacks.onComplete) callbacks.onComplete(AssistantMessageStatus.SUCCESS, data?.response)
|
||||
|
||||
@@ -32,6 +32,7 @@ export type Assistant = {
|
||||
regularPhrases?: QuickPhrase[] // Added for regular phrase
|
||||
tags?: string[] // 助手标签
|
||||
enableMemory?: boolean
|
||||
memoryUserId?: string // 绑定的记忆用户ID,当未指定时使用全局记忆用户
|
||||
}
|
||||
|
||||
export type TranslateAssistant = Assistant & {
|
||||
|
||||
Reference in New Issue
Block a user