diff --git a/src/main/assistant/supervisor-service.test.ts b/src/main/assistant/supervisor-service.test.ts index 58fdb03e..bf6a55fb 100644 --- a/src/main/assistant/supervisor-service.test.ts +++ b/src/main/assistant/supervisor-service.test.ts @@ -52,13 +52,16 @@ const output = { } describe('SupervisorService', () => { - it('rejects a source alias when it identifies more than one input fragment', async () => { + it('expands a source alias to all matching bounded input fragments', async () => { const fragments = [0, 1].map(index => ({ ...evidence[0]!, id: `fragment-${index}`, locator: { source: 'message:shared', start: index, end: index + 1 } })) + const save = vi.fn() const service = new SupervisorService({ collect: async () => fragments }, { summarize: async () => ({ ...output, entities: [], events: [{ ...output.events[0], entityIds: [], sourceReferenceIds: ['message:shared'] }] - }) }, { save: vi.fn() }) - await expect(service.run(request)).rejects.toThrow('本次范围之外') + }) }, { save }) + const result = await service.run(request) + expect(result.output.events[0]!.sourceReferenceIds).toEqual(['fragment-0', 'fragment-1']) + expect(save).toHaveBeenCalledWith(result) }) it('rejects invented persisted identities even when a local model id matches', async () => { const id = '00000000-0000-4000-8000-000000000001' diff --git a/src/main/assistant/supervisor-service.ts b/src/main/assistant/supervisor-service.ts index 8ff21a59..dc84d92c 100644 --- a/src/main/assistant/supervisor-service.ts +++ b/src/main/assistant/supervisor-service.ts @@ -137,11 +137,11 @@ function validateReferences( for (const item of [...output.events, ...output.entities, ...output.entityChanges, ...output.relations]) { item.sourceReferenceIds = [...new Set(item.sourceReferenceIds.map(id => { if (evidenceIds.has(id)) return id - // Providers also copy the supplied locator.source. Resolve it only when this - // node contains exactly one fragment of that source, never to an entire message. + // Providers may copy the supplied locator.source. Expand it to the matching + // bounded fragments so a multi-fragment source never becomes an unbounded citation. const matches = evidence.filter(source => source.locator?.source === id) - return matches.length === 1 ? matches[0]!.id : id - }))] + return matches.length ? matches.map(source => source.id) : [id] + }).flat())] } const references = [ ...output.events.flatMap((item) => item.sourceReferenceIds),