Files
ChatLab/tests/global-ai-memory-loop.test.ts
T
digua c69a927615 fix(ai): keep global memory always enabled
Remove the proactive-memory preference and its cross-platform runtime plumbing so memory behavior has one clear contract. Normalize away the obsolete setting and keep source type limited to provenance.
2026-08-24 22:35:47 +08:00

96 lines
3.3 KiB
TypeScript

import assert from 'node:assert/strict'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { it } from 'node:test'
import { AIMemoryService, buildGlobalMemoryPrompt } from '../packages/node-runtime/src/ai/memory'
import type { CrossChatSearchRequest, CrossChatSearchResult } from '@openchatlab/shared-types'
import { ChatType } from '@openchatlab/shared-types'
import {
memoryReadTool,
memoryWriteTool,
searchMessagesGloballyTool,
type CrossChatAnalysisToolService,
type CrossChatToolExecutionContext,
} from '../packages/tools/src'
const sqliteNativeBinding = process.env.CHATLAB_TEST_SQLITE_NATIVE_BINDING
it('recalls a durable preference in a new global AI conversation before querying chat data', async () => {
const dir = mkdtempSync(join(tmpdir(), 'chatlab-global-memory-loop-'))
const memoryService = new AIMemoryService(dir, { nativeBinding: sqliteNativeBinding })
let capturedSearch: CrossChatSearchRequest | null = null
const analysisService = {
searchMessages: async (request: CrossChatSearchRequest): Promise<CrossChatSearchResult> => {
capturedSearch = request
return {
messages: [
{
sessionId: 'private-1',
sessionName: 'Alice',
sessionType: ChatType.PRIVATE,
platform: 'test',
lastMessageTs: 100,
messageId: 1,
senderId: 1,
senderName: 'Me',
senderPlatformId: 'owner',
content: '我最近在看房',
timestamp: 100,
messageType: 0,
},
],
totalMatches: 1,
appliedFilters: { startTs: null, endTs: null, recentDays: request.recentDays ?? null, sender: 'owner' },
coverage: {
candidateSessions: 1,
scannedSessions: 1,
matchedSessions: 1,
failedSessions: 0,
truncated: false,
truncatedReasons: [],
},
}
},
} as unknown as CrossChatAnalysisToolService
const createContext = (aiChatId: string): CrossChatToolExecutionContext => ({
locale: 'zh-CN',
analysisService,
memoryService,
aiChatId,
preprocessMessagesBySession: (_sessionId, messages) => messages,
preprocessSummariesBySession: (_sessionId, summaries) => summaries,
preprocessModelLabel: (value) => value,
})
try {
await memoryWriteTool.handler(
{
scope_type: 'global',
content: '用户所说的“最近”默认指最近 90 天',
source_type: 'user',
},
createContext('global-chat-write')
)
const prompt = buildGlobalMemoryPrompt(memoryService.list({ scopeType: 'global', scopeId: null }), 'zh-CN')
assert.match(prompt, /最近 90 天/)
const secondConversation = createContext('global-chat-read')
const recalled = await memoryReadTool.handler({ scope_type: 'global' }, secondConversation)
const rememberedDays = Number(recalled.content.match(/最近 (\d+) 天/)?.[1])
assert.equal(rememberedDays, 90)
await searchMessagesGloballyTool.handler(
{ keywords: ['买房'], recent_days: rememberedDays, sender: 'owner' },
secondConversation
)
assert.equal(capturedSearch?.recentDays, 90)
assert.equal(capturedSearch?.sender, 'owner')
} finally {
memoryService.close()
rmSync(dir, { recursive: true, force: true })
}
})