From 812440c56595c4337d306e1e02641a15213ee0ce Mon Sep 17 00:00:00 2001 From: digua Date: Sat, 22 Aug 2026 00:43:06 +0800 Subject: [PATCH] fix(ai): resolve contacts across all history Use the all-history contacts snapshot when translating stable contact references into cross-chat scopes, so older source sessions are not silently excluded from historical analysis. --- .../cross-chat-analysis/service.test.ts | 35 +++++++++++++++++++ .../services/cross-chat-analysis/service.ts | 5 ++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/node-runtime/src/services/cross-chat-analysis/service.test.ts b/packages/node-runtime/src/services/cross-chat-analysis/service.test.ts index 9bbd7d85..10cd0a2e 100644 --- a/packages/node-runtime/src/services/cross-chat-analysis/service.test.ts +++ b/packages/node-runtime/src/services/cross-chat-analysis/service.test.ts @@ -239,6 +239,41 @@ test('entity resolution uses contact keys and resolves per-session member ids wi } }) +test('entity resolution uses the all-history contact snapshot so older source sessions remain searchable', () => { + const { env } = createFixture() + try { + const contactsService: Pick = { + getContactDetail: (_key, options) => + detail( + contact({ + key: 'test:alice', + platformId: 'alice', + displayName: 'Alice', + sourceSessions: + options?.timeRangePreset === 'all' + ? [ + { id: 'private-alice', name: 'Alice private', platform: 'test', type: 'private' }, + { id: 'group-work', name: 'Work group', platform: 'test', type: 'group' }, + ] + : [{ id: 'group-work', name: 'Work group', platform: 'test', type: 'group' }], + }) + ), + } + const service = createCrossChatAnalysisService({ adapter: env.adapter, contactsService }) + + const result = service.resolveEntities([{ type: 'contact', contactKey: 'test:alice', displayName: 'Alice' }]) + + assert.deepEqual( + result.contacts[0]?.sessions.map((session) => session.sessionId), + ['private-alice', 'group-work'] + ) + assert.equal(result.coverage.candidateSessions, 2) + assert.equal(result.coverage.resolvedSessions, 2) + } finally { + env.cleanup() + } +}) + test('scoped search filters by resolved member ids and keeps compound evidence identity', async () => { const { env, contactsService } = createFixture() try { diff --git a/packages/node-runtime/src/services/cross-chat-analysis/service.ts b/packages/node-runtime/src/services/cross-chat-analysis/service.ts index 73c49d08..e8c2d85e 100644 --- a/packages/node-runtime/src/services/cross-chat-analysis/service.ts +++ b/packages/node-runtime/src/services/cross-chat-analysis/service.ts @@ -83,7 +83,10 @@ class DefaultCrossChatAnalysisService implements CrossChatAnalysisService { continue } - const detail = this.deps.contactsService.getContactDetail(ref.contactKey, { acceptStale: true }) + const detail = this.deps.contactsService.getContactDetail(ref.contactKey, { + acceptStale: true, + timeRangePreset: 'all', + }) const contact = detail.contact if (!contact) { contacts.push({