@indexnetwork/protocol 1.12.4-rc.168.1 → 1.12.5-rc.171.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.
@@ -1 +1 @@
1
- {"version":3,"file":"opportunity.graph.d.ts","sourceRoot":"","sources":["../../src/opportunity/opportunity.graph.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"opportunity.graph.d.ts","sourceRoot":"","sources":["../../src/opportunity/opportunity.graph.ts"],"names":[],"mappings":"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"}
@@ -591,12 +591,18 @@ export class OpportunityGraphFactory {
591
591
  // Similarity threshold for recall (0.30 = 30% similarity)
592
592
  const minScore = 0.3;
593
593
  if (state.discoverySource === 'profile') {
594
- // Profile-context discovery: HyDE (when search query exists) + premise-to-premise.
595
- // Profile-embedding direct search (Path B) has been removed all semantic
596
- // matching goes through HyDE embeddings or premise-to-premise similarity.
594
+ const embedding = state.sourceProfile?.embedding ?? null;
595
+ const vector = Array.isArray(embedding) && embedding.length > 0 && typeof embedding[0] === 'number'
596
+ ? embedding
597
+ : Array.isArray(embedding) && Array.isArray(embedding[0])
598
+ ? embedding[0]
599
+ : null;
600
+ // ALWAYS run query-based HyDE when we have a search query (e.g., "looking for investors")
601
+ // This ensures we use the right strategies (investor, mentor, etc.) not just mirror
597
602
  if (state.searchQuery?.trim()) {
598
- logger.verbose('[Graph:Discovery] Profile source with searchQuery → running query HyDE + premise paths', {
603
+ logger.verbose('[Graph:Discovery] Profile source with searchQuery → running query HyDE path for broader search', {
599
604
  searchQuery: state.searchQuery.trim().substring(0, 80),
605
+ hasProfileVector: !!vector,
600
606
  });
601
607
  const queryCandidates = await runQueryHydeDiscovery();
602
608
  logger.verbose('[Graph:Discovery] Query HyDE path complete', { candidatesFound: queryCandidates.length });
@@ -652,6 +658,59 @@ export class OpportunityGraphFactory {
652
658
  model: getModelName("hydeGenerator"),
653
659
  },
654
660
  });
661
+ // If we also have a profile vector, merge with profile-based results
662
+ if (vector && vector.length > 0) {
663
+ const profileCandidates = [];
664
+ for (const targetIndex of state.targetNetworks) {
665
+ const results = await this.embedder.searchWithProfileEmbedding(vector, {
666
+ indexScope: [targetIndex.networkId],
667
+ excludeUserId: discoveryUserId,
668
+ limitPerStrategy: Math.floor(limitPerStrategy / 2),
669
+ limit: Math.floor(perIndexLimit / 2),
670
+ minScore,
671
+ });
672
+ for (const result of results) {
673
+ profileCandidates.push({
674
+ candidateUserId: result.userId,
675
+ candidateIntentId: result.type === 'intent' ? result.id : undefined,
676
+ networkId: targetIndex.networkId,
677
+ similarity: result.score,
678
+ lens: result.matchedVia,
679
+ candidatePayload: '',
680
+ candidateSummary: undefined,
681
+ discoverySource: 'profile-similarity',
682
+ });
683
+ }
684
+ }
685
+ // Merge and dedupe - keep both intent and profile candidates per user
686
+ const byKey = new Map();
687
+ for (const c of [...queryCandidates, ...profileCandidates]) {
688
+ const key = `${c.candidateUserId}:${c.networkId}:${c.candidateIntentId ?? 'profile'}:${c.discoverySource ?? 'unknown'}`;
689
+ if (!byKey.has(key) || c.similarity > (byKey.get(key)?.similarity ?? 0)) {
690
+ byKey.set(key, c);
691
+ }
692
+ }
693
+ const merged = Array.from(byKey.values());
694
+ logger.verbose('[Graph:Discovery] Merged HyDE + profile candidates', {
695
+ hydeCandidates: queryCandidates.length,
696
+ profileCandidates: profileCandidates.length,
697
+ merged: merged.length
698
+ });
699
+ traceEntries.push({
700
+ node: "discovery",
701
+ detail: `+ Profile search → ${profileCandidates.length} additional, merged to ${merged.length}`,
702
+ data: {
703
+ profileCandidates: profileCandidates.length,
704
+ merged: merged.length,
705
+ },
706
+ });
707
+ const premiseCands = await runPremiseDiscovery();
708
+ const withPremises = mergePremiseCandidates(merged, premiseCands);
709
+ if (premiseCands.length > 0) {
710
+ traceEntries.push({ node: "discovery", detail: `+ Premise search → ${premiseCands.length} candidate(s), merged to ${withPremises.length}` });
711
+ }
712
+ return { candidates: filterByTarget(withPremises), trace: traceEntries };
713
+ }
655
714
  const premiseCands = await runPremiseDiscovery();
656
715
  const withPremises = mergePremiseCandidates(queryCandidates, premiseCands);
657
716
  if (premiseCands.length > 0) {
@@ -659,15 +718,122 @@ export class OpportunityGraphFactory {
659
718
  }
660
719
  return { candidates: filterByTarget(withPremises), trace: traceEntries };
661
720
  }
662
- // No search query — premise-to-premise discovery only
721
+ // No search query - use profile embedding directly (mirror-only)
722
+ if (!vector || vector.length === 0) {
723
+ // Still attempt premise-based discovery even without a profile vector
724
+ const premiseCands = await runPremiseDiscovery();
725
+ if (premiseCands.length > 0) {
726
+ return {
727
+ candidates: filterByTarget(premiseCands),
728
+ trace: [{ node: "discovery", detail: `No profile vector; premise search → ${premiseCands.length} candidate(s)` }],
729
+ };
730
+ }
731
+ return { candidates: [] };
732
+ }
733
+ const allCandidates = [];
734
+ for (const targetIndex of state.targetNetworks) {
735
+ const results = await this.embedder.searchWithProfileEmbedding(vector, {
736
+ indexScope: [targetIndex.networkId],
737
+ excludeUserId: discoveryUserId,
738
+ limitPerStrategy,
739
+ limit: perIndexLimit,
740
+ minScore,
741
+ });
742
+ for (const result of results) {
743
+ if (result.type === 'intent') {
744
+ allCandidates.push({
745
+ candidateUserId: result.userId,
746
+ candidateIntentId: result.id,
747
+ networkId: targetIndex.networkId,
748
+ similarity: result.score,
749
+ lens: result.matchedVia,
750
+ candidatePayload: '',
751
+ candidateSummary: undefined,
752
+ discoverySource: 'profile-similarity',
753
+ });
754
+ }
755
+ else {
756
+ allCandidates.push({
757
+ candidateUserId: result.userId,
758
+ networkId: targetIndex.networkId,
759
+ similarity: result.score,
760
+ lens: result.matchedVia,
761
+ candidatePayload: '',
762
+ candidateSummary: undefined,
763
+ discoverySource: 'profile-similarity',
764
+ });
765
+ }
766
+ }
767
+ }
768
+ const byUserAndIndex = new Map();
769
+ for (const c of allCandidates) {
770
+ const key = `${c.candidateUserId}:${c.networkId}:${c.candidateIntentId ?? 'profile'}`;
771
+ if (!byUserAndIndex.has(key) || c.similarity > (byUserAndIndex.get(key)?.similarity ?? 0)) {
772
+ byUserAndIndex.set(key, c);
773
+ }
774
+ }
775
+ const candidates = Array.from(byUserAndIndex.values());
776
+ logger.verbose('[Graph:Discovery] Profile-as-source discovery complete', { candidatesFound: candidates.length });
777
+ // Build trace with individual candidate similarity scores
778
+ const traceEntries = [];
779
+ // Show what the profile search is based on
780
+ const profileBio = state.sourceProfile?.identity?.bio;
781
+ const profileContext = state.sourceProfile?.narrative?.context;
782
+ const profileSummary = profileBio || profileContext || '(profile embedding)';
783
+ // Compute per-lens stats from deduped candidates
784
+ const lensStats = {};
785
+ for (const c of candidates) {
786
+ const s = c.lens || 'unknown';
787
+ if (!lensStats[s])
788
+ lensStats[s] = { count: 0, avgSimilarity: 0 };
789
+ lensStats[s].count++;
790
+ lensStats[s].avgSimilarity += c.similarity;
791
+ }
792
+ for (const s of Object.values(lensStats)) {
793
+ s.avgSimilarity = s.count > 0 ? Math.round((s.avgSimilarity / s.count) * 1000) / 1000 : 0;
794
+ }
795
+ traceEntries.push({
796
+ node: "discovery",
797
+ detail: `Profile-based search → ${candidates.length} candidate(s)`,
798
+ data: {
799
+ source: "profile",
800
+ candidateCount: candidates.length,
801
+ byLens: lensStats,
802
+ durationMs: Date.now() - startTime,
803
+ },
804
+ });
805
+ traceEntries.push({
806
+ node: "search_query",
807
+ detail: `Searching for matches to: "${profileSummary.slice(0, 150)}${profileSummary.length > 150 ? '...' : ''}"`,
808
+ data: {
809
+ type: "profile_embedding",
810
+ bio: profileBio,
811
+ context: profileContext,
812
+ },
813
+ });
814
+ // Add top candidates with similarity scores
815
+ const sortedCandidates = [...candidates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
816
+ for (const c of sortedCandidates) {
817
+ traceEntries.push({
818
+ node: "match",
819
+ detail: `Similarity ${Math.round(c.similarity * 100)}% via ${c.lens}`,
820
+ data: {
821
+ userId: c.candidateUserId,
822
+ similarity: Math.round(c.similarity * 100),
823
+ lens: c.lens,
824
+ hasIntent: !!c.candidateIntentId,
825
+ },
826
+ });
827
+ }
663
828
  const premiseCands = await runPremiseDiscovery();
829
+ const withPremises = mergePremiseCandidates(candidates, premiseCands);
664
830
  if (premiseCands.length > 0) {
665
- return {
666
- candidates: filterByTarget(premiseCands),
667
- trace: [{ node: "discovery", detail: `No search query; premise search → ${premiseCands.length} candidate(s)` }],
668
- };
831
+ traceEntries.push({ node: "discovery", detail: `+ Premise search → ${premiseCands.length} candidate(s), merged to ${withPremises.length}` });
669
832
  }
670
- return { candidates: [] };
833
+ return {
834
+ candidates: filterByTarget(withPremises),
835
+ trace: traceEntries,
836
+ };
671
837
  }
672
838
  async function runQueryHydeDiscovery() {
673
839
  const searchText = state.searchQuery?.trim() ?? '';
@@ -1095,7 +1261,7 @@ export class OpportunityGraphFactory {
1095
1261
  const batchToEvaluate = dedupedCandidates.slice(0, EVAL_BATCH_SIZE);
1096
1262
  const remaining = dedupedCandidates.slice(EVAL_BATCH_SIZE);
1097
1263
  // Early termination: if search was query-driven and no query-sourced candidates remain,
1098
- // clear remaining to prevent pointless pagination through non-query leftovers
1264
+ // clear remaining to prevent pointless pagination through profile-similarity leftovers
1099
1265
  const isQueryDriven = !!state.searchQuery?.trim();
1100
1266
  const queryRemaining = remaining.filter((c) => c.discoverySource === 'query' || c.discoverySource == null);
1101
1267
  const effectiveRemaining = isQueryDriven && queryRemaining.length === 0 ? [] : remaining;