refactor focus concepts: add focusTerms/focusCharacters and switch character filtering
This commit is contained in:
@@ -319,7 +319,7 @@ async function recallAnchors(queryVector, vectorConfig, metrics) {
|
||||
// 返回 { events, vectorMap }
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async function recallEvents(queryVector, allEvents, vectorConfig, focusEntities, metrics) {
|
||||
async function recallEvents(queryVector, allEvents, vectorConfig, focusCharacters, metrics) {
|
||||
const { chatId } = getContext();
|
||||
if (!chatId || !queryVector?.length || !allEvents?.length) {
|
||||
return { events: [], vectorMap: new Map() };
|
||||
@@ -339,7 +339,7 @@ async function recallEvents(queryVector, allEvents, vectorConfig, focusEntities,
|
||||
return { events: [], vectorMap };
|
||||
}
|
||||
|
||||
const focusSet = new Set((focusEntities || []).map(normalize));
|
||||
const focusSet = new Set((focusCharacters || []).map(normalize));
|
||||
|
||||
const scored = allEvents.map(event => {
|
||||
const v = vectorMap.get(event.id);
|
||||
@@ -381,7 +381,8 @@ async function recallEvents(queryVector, allEvents, vectorConfig, focusEntities,
|
||||
|
||||
if (metrics) {
|
||||
metrics.event.entityFilter = {
|
||||
focusEntities: focusEntities || [],
|
||||
focusCharacters: focusCharacters || [],
|
||||
focusEntities: focusCharacters || [],
|
||||
before: beforeFilter,
|
||||
after: candidates.length,
|
||||
filtered: beforeFilter - candidates.length,
|
||||
@@ -962,6 +963,8 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
l1ByFloor: new Map(),
|
||||
causalChain: [],
|
||||
focusEntities: [],
|
||||
focusTerms: [],
|
||||
focusCharacters: [],
|
||||
elapsed: metrics.timing.total,
|
||||
logText: 'No events.',
|
||||
metrics,
|
||||
@@ -982,9 +985,13 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
const lastMessages = getLastMessages(chat, lastMessagesCount, excludeLastAi);
|
||||
|
||||
const bundle = buildQueryBundle(lastMessages, pendingUserMessage);
|
||||
const focusTerms = bundle.focusTerms || bundle.focusEntities || [];
|
||||
const focusCharacters = bundle.focusCharacters || [];
|
||||
|
||||
metrics.query.buildTime = Math.round(performance.now() - T_Build_Start);
|
||||
metrics.anchor.focusEntities = bundle.focusEntities;
|
||||
metrics.anchor.focusTerms = focusTerms;
|
||||
metrics.anchor.focusEntities = focusTerms; // compat
|
||||
metrics.anchor.focusCharacters = focusCharacters;
|
||||
|
||||
if (metrics.query?.lengths) {
|
||||
metrics.query.lengths.v0Chars = bundle.querySegments.reduce((sum, s) => sum + s.text.length, 0);
|
||||
@@ -993,7 +1000,7 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
}
|
||||
|
||||
xbLog.info(MODULE_ID,
|
||||
`Query Build: focus=[${bundle.focusEntities.join(',')}] segments=${bundle.querySegments.length} lexTerms=[${bundle.lexicalTerms.slice(0, 5).join(',')}]`
|
||||
`Query Build: focus_terms=[${focusTerms.join(',')}] focus_characters=[${focusCharacters.join(',')}] segments=${bundle.querySegments.length} lexTerms=[${bundle.lexicalTerms.slice(0, 5).join(',')}]`
|
||||
);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
@@ -1005,7 +1012,9 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
metrics.timing.total = Math.round(performance.now() - T0);
|
||||
return {
|
||||
events: [], l0Selected: [], l1ByFloor: new Map(), causalChain: [],
|
||||
focusEntities: bundle.focusEntities,
|
||||
focusEntities: focusTerms,
|
||||
focusTerms,
|
||||
focusCharacters,
|
||||
elapsed: metrics.timing.total,
|
||||
logText: 'No query segments.',
|
||||
metrics,
|
||||
@@ -1025,7 +1034,9 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
metrics.timing.total = Math.round(performance.now() - T0);
|
||||
return {
|
||||
events: [], l0Selected: [], l1ByFloor: new Map(), causalChain: [],
|
||||
focusEntities: bundle.focusEntities,
|
||||
focusEntities: focusTerms,
|
||||
focusTerms,
|
||||
focusCharacters,
|
||||
elapsed: metrics.timing.total,
|
||||
logText: 'Embedding failed (round 1, after retry).',
|
||||
metrics,
|
||||
@@ -1037,7 +1048,9 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
metrics.timing.total = Math.round(performance.now() - T0);
|
||||
return {
|
||||
events: [], l0Selected: [], l1ByFloor: new Map(), causalChain: [],
|
||||
focusEntities: bundle.focusEntities,
|
||||
focusEntities: focusTerms,
|
||||
focusTerms,
|
||||
focusCharacters,
|
||||
elapsed: metrics.timing.total,
|
||||
logText: 'Empty query vectors (round 1).',
|
||||
metrics,
|
||||
@@ -1055,7 +1068,9 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
metrics.timing.total = Math.round(performance.now() - T0);
|
||||
return {
|
||||
events: [], l0Selected: [], l1ByFloor: new Map(), causalChain: [],
|
||||
focusEntities: bundle.focusEntities,
|
||||
focusEntities: focusTerms,
|
||||
focusTerms,
|
||||
focusCharacters,
|
||||
elapsed: metrics.timing.total,
|
||||
logText: 'Weighted average produced empty vector.',
|
||||
metrics,
|
||||
@@ -1067,7 +1082,7 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
const r1AnchorTime = Math.round(performance.now() - T_R1_Anchor_Start);
|
||||
|
||||
const T_R1_Event_Start = performance.now();
|
||||
const { events: eventHits_v0 } = await recallEvents(queryVector_v0, allEvents, vectorConfig, bundle.focusEntities, null);
|
||||
const { events: eventHits_v0 } = await recallEvents(queryVector_v0, allEvents, vectorConfig, focusCharacters, null);
|
||||
const r1EventTime = Math.round(performance.now() - T_R1_Event_Start);
|
||||
|
||||
xbLog.info(MODULE_ID,
|
||||
@@ -1089,7 +1104,7 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
}
|
||||
|
||||
xbLog.info(MODULE_ID,
|
||||
`Refinement: focus=[${bundle.focusEntities.join(',')}] hasHints=${!!bundle.hintsSegment} (${metrics.query.refineTime}ms)`
|
||||
`Refinement: focus_terms=[${focusTerms.join(',')}] focus_characters=[${focusCharacters.join(',')}] hasHints=${!!bundle.hintsSegment} (${metrics.query.refineTime}ms)`
|
||||
);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
@@ -1129,7 +1144,7 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
metrics.timing.anchorSearch = Math.round(performance.now() - T_R2_Anchor_Start);
|
||||
|
||||
const T_R2_Event_Start = performance.now();
|
||||
let { events: eventHits, vectorMap: eventVectorMap } = await recallEvents(queryVector_v1, allEvents, vectorConfig, bundle.focusEntities, metrics);
|
||||
let { events: eventHits, vectorMap: eventVectorMap } = await recallEvents(queryVector_v1, allEvents, vectorConfig, focusCharacters, metrics);
|
||||
metrics.timing.eventRetrieval = Math.round(performance.now() - T_R2_Event_Start);
|
||||
|
||||
xbLog.info(MODULE_ID,
|
||||
@@ -1178,7 +1193,7 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
let lexicalEventCount = 0;
|
||||
let lexicalEventFilteredByDense = 0;
|
||||
let l0LinkedCount = 0;
|
||||
const focusSetForLexical = new Set((bundle.focusEntities || []).map(normalize));
|
||||
const focusSetForLexical = new Set((focusCharacters || []).map(normalize));
|
||||
|
||||
for (const eid of lexicalResult.eventIds) {
|
||||
if (existingEventIds.has(eid)) continue;
|
||||
@@ -1351,14 +1366,16 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
metrics.timing.total = Math.round(performance.now() - T0);
|
||||
metrics.event.entityNames = bundle.focusEntities;
|
||||
metrics.event.entitiesUsed = bundle.focusEntities.length;
|
||||
metrics.event.entityNames = focusCharacters;
|
||||
metrics.event.entitiesUsed = focusCharacters.length;
|
||||
metrics.event.focusTermsCount = focusTerms.length;
|
||||
|
||||
console.group('%c[Recall v9]', 'color: #7c3aed; font-weight: bold');
|
||||
console.log(`Total: ${metrics.timing.total}ms`);
|
||||
console.log(`Query Build: ${metrics.query.buildTime}ms | Refine: ${metrics.query.refineTime}ms`);
|
||||
console.log(`R1 weights: [${r1Weights.map(w => w.toFixed(2)).join(', ')}]`);
|
||||
console.log(`Focus: [${bundle.focusEntities.join(', ')}]`);
|
||||
console.log(`Focus terms: [${focusTerms.join(', ')}]`);
|
||||
console.log(`Focus characters: [${focusCharacters.join(', ')}]`);
|
||||
console.log(`Round 2 Anchors: ${anchorHits.length} hits → ${anchorFloors_dense.size} floors`);
|
||||
console.log(`Lexical: chunks=${lexicalResult.chunkIds.length} events=${lexicalResult.eventIds.length} evtMerged=+${lexicalEventCount} evtFiltered=${lexicalEventFilteredByDense} floorFiltered=${metrics.lexical.floorFilteredByDense || 0} (idx=${indexReadyTime}ms search=${lexicalResult.searchTime || 0}ms total=${lexTime}ms)`);
|
||||
console.log(`Fusion (floor, weighted): dense=${metrics.fusion.denseFloors} lex=${metrics.fusion.lexFloors} → cap=${metrics.fusion.afterCap} (${metrics.fusion.time}ms)`);
|
||||
@@ -1373,7 +1390,9 @@ export async function recallMemory(allEvents, vectorConfig, options = {}) {
|
||||
causalChain,
|
||||
l0Selected,
|
||||
l1ByFloor,
|
||||
focusEntities: bundle.focusEntities,
|
||||
focusEntities: focusTerms,
|
||||
focusTerms,
|
||||
focusCharacters,
|
||||
elapsed: metrics.timing.total,
|
||||
metrics,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user