@indexnetwork/protocol 3.0.0 → 3.1.0-rc.247.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/intent/intent.indexer.d.ts +3 -3
- package/dist/intent/intent.reconciler.d.ts +6 -6
- package/dist/network/indexer/indexer.graph.d.ts +22 -11
- package/dist/network/indexer/indexer.graph.d.ts.map +1 -1
- package/dist/network/indexer/indexer.graph.js +47 -44
- package/dist/network/indexer/indexer.graph.js.map +1 -1
- package/dist/network/indexer/indexer.state.d.ts +3 -3
- package/dist/opportunity/opportunity.evaluator.d.ts +27 -9
- package/dist/opportunity/opportunity.evaluator.d.ts.map +1 -1
- package/dist/opportunity/opportunity.evaluator.js +9 -1
- package/dist/opportunity/opportunity.evaluator.js.map +1 -1
- package/dist/opportunity/opportunity.evidence.d.ts +22 -0
- package/dist/opportunity/opportunity.evidence.d.ts.map +1 -0
- package/dist/opportunity/opportunity.evidence.js +72 -0
- package/dist/opportunity/opportunity.evidence.js.map +1 -0
- package/dist/opportunity/opportunity.graph.d.ts +8 -7
- package/dist/opportunity/opportunity.graph.d.ts.map +1 -1
- package/dist/opportunity/opportunity.graph.js +74 -28
- package/dist/opportunity/opportunity.graph.js.map +1 -1
- package/dist/opportunity/opportunity.state.d.ts +10 -2
- package/dist/opportunity/opportunity.state.d.ts.map +1 -1
- package/dist/opportunity/opportunity.state.js.map +1 -1
- package/dist/premise/premise.graph.d.ts +14 -2
- package/dist/premise/premise.graph.d.ts.map +1 -1
- package/dist/premise/premise.graph.js +49 -20
- package/dist/premise/premise.graph.js.map +1 -1
- package/dist/premise/premise.indexer.d.ts +2 -2
- package/dist/premise/premise.state.d.ts +2 -0
- package/dist/premise/premise.state.d.ts.map +1 -1
- package/dist/premise/premise.state.js +8 -0
- package/dist/premise/premise.state.js.map +1 -1
- package/dist/shared/assignment/network-assignment.policy.d.ts +59 -0
- package/dist/shared/assignment/network-assignment.policy.d.ts.map +1 -0
- package/dist/shared/assignment/network-assignment.policy.js +101 -0
- package/dist/shared/assignment/network-assignment.policy.js.map +1 -0
- package/dist/shared/hyde/hyde.graph.d.ts +6 -6
- package/dist/shared/hyde/hyde.state.d.ts +2 -2
- package/dist/shared/interfaces/database.interface.d.ts +31 -17
- package/dist/shared/interfaces/database.interface.d.ts.map +1 -1
- package/dist/shared/interfaces/database.interface.js.map +1 -1
- package/dist/shared/schemas/network-assignment.schema.d.ts +135 -0
- package/dist/shared/schemas/network-assignment.schema.d.ts.map +1 -0
- package/dist/shared/schemas/network-assignment.schema.js +55 -0
- package/dist/shared/schemas/network-assignment.schema.js.map +1 -0
- package/dist/shared/schemas/question.schema.d.ts +2 -2
- package/package.json +1 -1
|
@@ -28,6 +28,7 @@ import { protocolLogger, withCallLogging } from '../shared/observability/protoco
|
|
|
28
28
|
import { timed } from '../shared/observability/performance.js';
|
|
29
29
|
import { renderNetworkContext } from '../shared/network/metadata.renderer.js';
|
|
30
30
|
import { requestContext } from "../shared/observability/request-context.js";
|
|
31
|
+
import { mergeOpportunityEvidence, withCandidateEvidence, withMatchedStrategies, } from './opportunity.evidence.js';
|
|
31
32
|
const logger = protocolLogger('OpportunityGraph');
|
|
32
33
|
/** Time window for persist-node dedup. Parallel jobs arrive within seconds; 10 min catches those while allowing new opportunities for long-connected pairs. */
|
|
33
34
|
const DEDUP_WINDOW_MS = 10 * 60 * 1000;
|
|
@@ -43,6 +44,13 @@ function getSourcePremiseDiscoveryLimit() {
|
|
|
43
44
|
const parsed = Number.parseInt(raw, 10);
|
|
44
45
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : DEFAULT_SOURCE_PREMISE_DISCOVERY_LIMIT;
|
|
45
46
|
}
|
|
47
|
+
function buildEvaluatorEvidenceKey(candidate) {
|
|
48
|
+
return [
|
|
49
|
+
candidate.candidateUserId,
|
|
50
|
+
candidate.networkId,
|
|
51
|
+
candidate.candidateIntentId ?? candidate.candidatePremiseId ?? candidate.sourceContextId ?? 'profile',
|
|
52
|
+
].join(':');
|
|
53
|
+
}
|
|
46
54
|
/**
|
|
47
55
|
* Builds a compact text summary of the discoverer's profile and active intents
|
|
48
56
|
* for use as profileContext in HyDE generation.
|
|
@@ -210,7 +218,7 @@ export class OpportunityGraphFactory {
|
|
|
210
218
|
// BACKEND-5: thousands of parallel vector searches for premise-rich users.
|
|
211
219
|
const sourcePremises = [];
|
|
212
220
|
const contextToIntentEnabled = process.env.DISCOVERY_CONTEXT_TO_INTENT !== '0';
|
|
213
|
-
const rawContexts = contextToIntentEnabled
|
|
221
|
+
const rawContexts = contextToIntentEnabled && typeof this.database.getUserContexts === 'function'
|
|
214
222
|
? await this.database.getUserContexts(discoveryUserId)
|
|
215
223
|
: [];
|
|
216
224
|
const sourceContexts = rawContexts
|
|
@@ -573,7 +581,7 @@ export class OpportunityGraphFactory {
|
|
|
573
581
|
const intentNetworkIds = await this.database.getNetworkIdsForIntent(intent.id);
|
|
574
582
|
const overlapping = sharedIndexIds.filter(id => intentNetworkIds.includes(id));
|
|
575
583
|
for (const networkId of overlapping) {
|
|
576
|
-
directCandidates.push({
|
|
584
|
+
directCandidates.push(withCandidateEvidence({
|
|
577
585
|
candidateUserId: state.targetUserId,
|
|
578
586
|
candidateIntentId: intent.id,
|
|
579
587
|
networkId,
|
|
@@ -582,22 +590,21 @@ export class OpportunityGraphFactory {
|
|
|
582
590
|
candidatePayload: intent.payload,
|
|
583
591
|
candidateSummary: intent.summary ?? undefined,
|
|
584
592
|
discoverySource: 'query',
|
|
585
|
-
});
|
|
593
|
+
}));
|
|
586
594
|
}
|
|
587
595
|
}
|
|
588
596
|
}
|
|
589
597
|
// Always add a profile-level candidate (so evaluation runs even without intents)
|
|
590
598
|
if (directCandidates.length === 0) {
|
|
591
|
-
directCandidates.push({
|
|
599
|
+
directCandidates.push(withCandidateEvidence({
|
|
592
600
|
candidateUserId: state.targetUserId,
|
|
593
|
-
candidateIntentId: undefined,
|
|
594
601
|
networkId: sharedIndexIds[0],
|
|
595
602
|
similarity: 1.0,
|
|
596
603
|
lens: 'explicit_mention',
|
|
597
604
|
candidatePayload: '',
|
|
598
605
|
candidateSummary: undefined,
|
|
599
606
|
discoverySource: 'query',
|
|
600
|
-
});
|
|
607
|
+
}));
|
|
601
608
|
}
|
|
602
609
|
logger.verbose('[Graph:Discovery] Direct candidates constructed', {
|
|
603
610
|
count: directCandidates.length,
|
|
@@ -766,7 +773,7 @@ export class OpportunityGraphFactory {
|
|
|
766
773
|
minScore,
|
|
767
774
|
});
|
|
768
775
|
for (const r of results.filter((x) => x.type === 'intent')) {
|
|
769
|
-
all.push({
|
|
776
|
+
all.push(withCandidateEvidence({
|
|
770
777
|
candidateUserId: r.userId,
|
|
771
778
|
candidateIntentId: r.id,
|
|
772
779
|
networkId: targetIndex.networkId,
|
|
@@ -775,10 +782,10 @@ export class OpportunityGraphFactory {
|
|
|
775
782
|
candidatePayload: '',
|
|
776
783
|
candidateSummary: undefined,
|
|
777
784
|
discoverySource: 'query',
|
|
778
|
-
});
|
|
785
|
+
}));
|
|
779
786
|
}
|
|
780
787
|
for (const r of results.filter((x) => x.type === 'premise')) {
|
|
781
|
-
all.push({
|
|
788
|
+
all.push(withCandidateEvidence({
|
|
782
789
|
candidateUserId: r.userId,
|
|
783
790
|
candidatePremiseId: r.id,
|
|
784
791
|
networkId: targetIndex.networkId,
|
|
@@ -787,7 +794,7 @@ export class OpportunityGraphFactory {
|
|
|
787
794
|
candidatePayload: '',
|
|
788
795
|
candidateSummary: undefined,
|
|
789
796
|
discoverySource: 'query',
|
|
790
|
-
});
|
|
797
|
+
}));
|
|
791
798
|
}
|
|
792
799
|
}));
|
|
793
800
|
const intentCount = all.filter((c) => c.candidateIntentId).length;
|
|
@@ -847,23 +854,27 @@ export class OpportunityGraphFactory {
|
|
|
847
854
|
excludeUserId: discoveryUserId,
|
|
848
855
|
limitPerSource: PREMISE_MATCH_LIMIT_PER_SOURCE,
|
|
849
856
|
})
|
|
850
|
-
: (await Promise.all(sourcePremises.map(sp =>
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
857
|
+
: (await Promise.all(sourcePremises.map(async (sp) => {
|
|
858
|
+
const results = await self.database.searchPremisesBySimilarity({
|
|
859
|
+
embedding: sp.embedding,
|
|
860
|
+
networkIds: targetNetworkIds,
|
|
861
|
+
excludeUserId: discoveryUserId,
|
|
862
|
+
limit: PREMISE_MATCH_LIMIT_PER_SOURCE,
|
|
863
|
+
});
|
|
864
|
+
return results.map((r) => ({ ...r, sourcePremiseId: sp.premiseId }));
|
|
865
|
+
}))).flat();
|
|
856
866
|
const premiseCandidates = [];
|
|
857
867
|
for (const r of rawResults) {
|
|
858
|
-
premiseCandidates.push({
|
|
868
|
+
premiseCandidates.push(withCandidateEvidence({
|
|
859
869
|
candidateUserId: r.userId,
|
|
870
|
+
sourcePremiseId: r.sourcePremiseId,
|
|
860
871
|
candidatePremiseId: r.premiseId,
|
|
861
872
|
networkId: r.networkId,
|
|
862
873
|
similarity: typeof r.similarity === 'number' ? r.similarity : parseFloat(String(r.similarity)),
|
|
863
874
|
lens: 'premise_match',
|
|
864
875
|
candidatePayload: r.assertionText ?? '',
|
|
865
876
|
discoverySource: 'premise-similarity',
|
|
866
|
-
});
|
|
877
|
+
}));
|
|
867
878
|
}
|
|
868
879
|
// Dedup by userId + premiseId + networkId (a premise can appear in multiple networks)
|
|
869
880
|
const byKey = new Map();
|
|
@@ -921,16 +932,17 @@ export class OpportunityGraphFactory {
|
|
|
921
932
|
minScore,
|
|
922
933
|
});
|
|
923
934
|
for (const r of results.filter(r => r.type === 'intent')) {
|
|
924
|
-
contextCandidates.push({
|
|
935
|
+
contextCandidates.push(withCandidateEvidence({
|
|
925
936
|
candidateUserId: r.userId,
|
|
926
937
|
candidateIntentId: r.id,
|
|
938
|
+
sourceContextId: ctx.contextId,
|
|
927
939
|
networkId: ctx.networkId,
|
|
928
940
|
similarity: r.score,
|
|
929
941
|
lens: r.matchedVia,
|
|
930
942
|
candidatePayload: '',
|
|
931
943
|
candidateSummary: undefined,
|
|
932
944
|
discoverySource: 'context-to-intent',
|
|
933
|
-
});
|
|
945
|
+
}));
|
|
934
946
|
}
|
|
935
947
|
}
|
|
936
948
|
else {
|
|
@@ -943,16 +955,17 @@ export class OpportunityGraphFactory {
|
|
|
943
955
|
minScore: minScore,
|
|
944
956
|
});
|
|
945
957
|
for (const r of results) {
|
|
946
|
-
contextCandidates.push({
|
|
958
|
+
contextCandidates.push(withCandidateEvidence({
|
|
947
959
|
candidateUserId: r.userId,
|
|
948
960
|
candidateIntentId: r.intentId,
|
|
961
|
+
sourceContextId: ctx.contextId,
|
|
949
962
|
networkId: r.networkId,
|
|
950
963
|
similarity: typeof r.similarity === 'number' ? r.similarity : parseFloat(String(r.similarity)),
|
|
951
964
|
lens: 'context_match',
|
|
952
965
|
candidatePayload: r.payload ?? '',
|
|
953
966
|
candidateSummary: r.summary ?? undefined,
|
|
954
967
|
discoverySource: 'context-to-intent',
|
|
955
|
-
});
|
|
968
|
+
}));
|
|
956
969
|
}
|
|
957
970
|
}
|
|
958
971
|
}
|
|
@@ -988,18 +1001,24 @@ export class OpportunityGraphFactory {
|
|
|
988
1001
|
}
|
|
989
1002
|
else {
|
|
990
1003
|
existing._strategies.add(c.discoverySource ?? 'unknown');
|
|
1004
|
+
const mergedEvidence = mergeOpportunityEvidence(existing.evidence, c.evidence);
|
|
991
1005
|
if (c.similarity > existing.similarity) {
|
|
992
|
-
Object.assign(existing, c);
|
|
1006
|
+
Object.assign(existing, { ...c, evidence: mergedEvidence });
|
|
1007
|
+
}
|
|
1008
|
+
else {
|
|
1009
|
+
existing.evidence = mergedEvidence;
|
|
993
1010
|
}
|
|
994
1011
|
}
|
|
995
1012
|
}
|
|
996
1013
|
}
|
|
997
1014
|
return Array.from(merged.values()).map(({ _strategies, ...c }) => {
|
|
1015
|
+
const matchedStrategies = Array.from(_strategies);
|
|
998
1016
|
const boost = Math.min((_strategies.size - 1) * 0.05, 0.15);
|
|
999
1017
|
return {
|
|
1000
1018
|
...c,
|
|
1001
1019
|
similarity: Math.min(c.similarity + boost, 1.0),
|
|
1002
|
-
matchedStrategies
|
|
1020
|
+
matchedStrategies,
|
|
1021
|
+
evidence: withMatchedStrategies(mergeOpportunityEvidence(c.evidence), matchedStrategies),
|
|
1003
1022
|
};
|
|
1004
1023
|
});
|
|
1005
1024
|
}
|
|
@@ -1068,7 +1087,7 @@ export class OpportunityGraphFactory {
|
|
|
1068
1087
|
minScore,
|
|
1069
1088
|
});
|
|
1070
1089
|
for (const result of results.filter((r) => r.type === 'intent')) {
|
|
1071
|
-
allCandidates.push({
|
|
1090
|
+
allCandidates.push(withCandidateEvidence({
|
|
1072
1091
|
candidateUserId: result.userId,
|
|
1073
1092
|
candidateIntentId: result.id,
|
|
1074
1093
|
networkId: targetIndex.networkId,
|
|
@@ -1077,10 +1096,10 @@ export class OpportunityGraphFactory {
|
|
|
1077
1096
|
candidatePayload: '',
|
|
1078
1097
|
candidateSummary: undefined,
|
|
1079
1098
|
discoverySource: 'query',
|
|
1080
|
-
});
|
|
1099
|
+
}));
|
|
1081
1100
|
}
|
|
1082
1101
|
for (const result of results.filter((r) => r.type === 'premise')) {
|
|
1083
|
-
allCandidates.push({
|
|
1102
|
+
allCandidates.push(withCandidateEvidence({
|
|
1084
1103
|
candidateUserId: result.userId,
|
|
1085
1104
|
candidatePremiseId: result.id,
|
|
1086
1105
|
networkId: targetIndex.networkId,
|
|
@@ -1089,7 +1108,7 @@ export class OpportunityGraphFactory {
|
|
|
1089
1108
|
candidatePayload: '',
|
|
1090
1109
|
candidateSummary: undefined,
|
|
1091
1110
|
discoverySource: 'query',
|
|
1092
|
-
});
|
|
1111
|
+
}));
|
|
1093
1112
|
}
|
|
1094
1113
|
}));
|
|
1095
1114
|
const byUserAndIndex = new Map();
|
|
@@ -1299,6 +1318,7 @@ export class OpportunityGraphFactory {
|
|
|
1299
1318
|
summary: i.summary,
|
|
1300
1319
|
})),
|
|
1301
1320
|
networkId: '', // Placeholder — overwritten per-pairing below
|
|
1321
|
+
evidenceKey: `${discoveryUserId}::source`,
|
|
1302
1322
|
ragScore: undefined,
|
|
1303
1323
|
matchedVia: undefined,
|
|
1304
1324
|
};
|
|
@@ -1313,6 +1333,7 @@ export class OpportunityGraphFactory {
|
|
|
1313
1333
|
intentSummary = intent.summary ?? undefined;
|
|
1314
1334
|
}
|
|
1315
1335
|
}
|
|
1336
|
+
const evidenceKey = buildEvaluatorEvidenceKey(c);
|
|
1316
1337
|
return {
|
|
1317
1338
|
userId: c.candidateUserId,
|
|
1318
1339
|
profile: {
|
|
@@ -1327,14 +1348,35 @@ export class OpportunityGraphFactory {
|
|
|
1327
1348
|
? [{ intentId: c.candidateIntentId, payload: intentPayload ?? '', summary: intentSummary }]
|
|
1328
1349
|
: undefined,
|
|
1329
1350
|
networkId: c.networkId,
|
|
1351
|
+
evidenceKey,
|
|
1330
1352
|
ragScore: c.similarity * 100,
|
|
1331
1353
|
matchedVia: c.lens,
|
|
1354
|
+
evidence: c.evidence,
|
|
1332
1355
|
};
|
|
1333
1356
|
}));
|
|
1334
1357
|
const userIdToIndexId = new Map();
|
|
1358
|
+
const evidenceByEntityKey = new Map();
|
|
1359
|
+
const entityKeysByUserId = new Map();
|
|
1335
1360
|
for (const e of candidateEntities) {
|
|
1336
1361
|
if (!userIdToIndexId.has(e.userId))
|
|
1337
1362
|
userIdToIndexId.set(e.userId, e.networkId);
|
|
1363
|
+
if (e.evidenceKey) {
|
|
1364
|
+
evidenceByEntityKey.set(e.evidenceKey, mergeOpportunityEvidence(evidenceByEntityKey.get(e.evidenceKey), e.evidence));
|
|
1365
|
+
entityKeysByUserId.set(e.userId, [...(entityKeysByUserId.get(e.userId) ?? []), e.evidenceKey]);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
function evidenceForActor(actor) {
|
|
1369
|
+
if (actor.evidenceKey)
|
|
1370
|
+
return evidenceByEntityKey.get(actor.evidenceKey);
|
|
1371
|
+
const keys = entityKeysByUserId.get(actor.userId) ?? [];
|
|
1372
|
+
const intentKey = actor.intentId ? keys.find((key) => key.endsWith(`:${actor.intentId}`)) : undefined;
|
|
1373
|
+
if (intentKey)
|
|
1374
|
+
return evidenceByEntityKey.get(intentKey);
|
|
1375
|
+
// Avoid leaking unrelated resource evidence when the evaluator collapsed multiple
|
|
1376
|
+
// candidates for the same user into a profile-only actor.
|
|
1377
|
+
if (keys.length === 1)
|
|
1378
|
+
return evidenceByEntityKey.get(keys[0]);
|
|
1379
|
+
return undefined;
|
|
1338
1380
|
}
|
|
1339
1381
|
// Lower default threshold to 50 for better recall
|
|
1340
1382
|
const minScore = state.options.minScore ?? 50;
|
|
@@ -1495,6 +1537,7 @@ export class OpportunityGraphFactory {
|
|
|
1495
1537
|
const evaluatedOpportunities = pairwiseOpportunities.map((op) => ({
|
|
1496
1538
|
reasoning: op.reasoning,
|
|
1497
1539
|
score: op.score,
|
|
1540
|
+
evidence: mergeOpportunityEvidence(...op.actors.map(evidenceForActor)),
|
|
1498
1541
|
actors: op.actors.map((a) => {
|
|
1499
1542
|
const isSource = a.userId === discoveryUserId;
|
|
1500
1543
|
if (isSource) {
|
|
@@ -2682,6 +2725,9 @@ export class OpportunityGraphFactory {
|
|
|
2682
2725
|
},
|
|
2683
2726
|
confidence: String(evaluated.score / 100),
|
|
2684
2727
|
status: initialStatus,
|
|
2728
|
+
metadata: {
|
|
2729
|
+
evidence: evaluated.evidence ?? [],
|
|
2730
|
+
},
|
|
2685
2731
|
};
|
|
2686
2732
|
}
|
|
2687
2733
|
try {
|