@indexnetwork/protocol 1.19.0-rc.186.1 → 1.20.0-rc.187.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/context/context.generator.d.ts +61 -0
- package/dist/context/context.generator.d.ts.map +1 -0
- package/dist/context/context.generator.js +85 -0
- package/dist/context/context.generator.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/opportunity/opportunity.graph.d.ts +59 -0
- package/dist/opportunity/opportunity.graph.d.ts.map +1 -1
- package/dist/opportunity/opportunity.graph.js +185 -35
- package/dist/opportunity/opportunity.graph.js.map +1 -1
- package/dist/opportunity/opportunity.state.d.ts +18 -2
- package/dist/opportunity/opportunity.state.d.ts.map +1 -1
- package/dist/opportunity/opportunity.state.js +5 -0
- package/dist/opportunity/opportunity.state.js.map +1 -1
- package/dist/shared/agent/model.config.d.ts +5 -0
- package/dist/shared/agent/model.config.d.ts.map +1 -1
- package/dist/shared/agent/model.config.js +1 -0
- package/dist/shared/agent/model.config.js.map +1 -1
- package/dist/shared/hyde/hyde.graph.d.ts +6 -6
- package/dist/shared/hyde/hyde.state.d.ts +3 -3
- package/dist/shared/hyde/hyde.state.d.ts.map +1 -1
- package/dist/shared/hyde/hyde.state.js +1 -1
- package/dist/shared/hyde/hyde.state.js.map +1 -1
- package/dist/shared/interfaces/database.interface.d.ts +55 -3
- package/dist/shared/interfaces/database.interface.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -198,14 +198,26 @@ export class OpportunityGraphFactory {
|
|
|
198
198
|
premiseId: p.id,
|
|
199
199
|
embedding: p.embedding,
|
|
200
200
|
}));
|
|
201
|
+
const contextToIntentEnabled = process.env.DISCOVERY_CONTEXT_TO_INTENT !== '0';
|
|
202
|
+
const rawContexts = contextToIntentEnabled
|
|
203
|
+
? await this.database.getUserContexts(discoveryUserId)
|
|
204
|
+
: [];
|
|
205
|
+
const sourceContexts = rawContexts
|
|
206
|
+
.filter((c) => c.embedding && c.embedding.length > 0 && userNetworkIds.includes(c.networkId))
|
|
207
|
+
.map((c) => ({
|
|
208
|
+
contextId: c.id,
|
|
209
|
+
networkId: c.networkId,
|
|
210
|
+
embedding: c.embedding,
|
|
211
|
+
}));
|
|
201
212
|
return {
|
|
202
213
|
userNetworks: userNetworkIds,
|
|
203
214
|
indexedIntents,
|
|
204
215
|
sourceProfile,
|
|
205
216
|
sourcePremises,
|
|
217
|
+
sourceContexts,
|
|
206
218
|
trace: [{
|
|
207
219
|
node: "prep",
|
|
208
|
-
detail: `${userNetworkIds.length} network(s), ${intents.length} intent(s), ${sourcePremises.length} premise(s), ${profile ? 'profile loaded' : 'no profile'}`,
|
|
220
|
+
detail: `${userNetworkIds.length} network(s), ${intents.length} intent(s), ${sourcePremises.length} premise(s), ${sourceContexts.length} context(s), ${profile ? 'profile loaded' : 'no profile'}`,
|
|
209
221
|
}],
|
|
210
222
|
};
|
|
211
223
|
}, { context: { userId: state.userId }, logOutput: true }).catch((error) => {
|
|
@@ -649,20 +661,38 @@ export class OpportunityGraphFactory {
|
|
|
649
661
|
model: getModelName("hydeGenerator"),
|
|
650
662
|
},
|
|
651
663
|
});
|
|
652
|
-
const premiseCands = await
|
|
653
|
-
|
|
664
|
+
const [premiseCands, contextCands] = await Promise.all([
|
|
665
|
+
runPremiseDiscovery(),
|
|
666
|
+
runContextToIntentDiscovery(),
|
|
667
|
+
]);
|
|
668
|
+
const withPremisesAndContext = mergeStrategyCandidates(queryCandidates, premiseCands, contextCands);
|
|
654
669
|
if (premiseCands.length > 0) {
|
|
655
|
-
traceEntries.push({ node: "
|
|
670
|
+
traceEntries.push({ node: "strategy", detail: `premise-to-premise → ${premiseCands.length} candidate(s)` });
|
|
671
|
+
}
|
|
672
|
+
if (contextCands.length > 0) {
|
|
673
|
+
traceEntries.push({ node: "strategy", detail: `context-to-intent → ${contextCands.length} candidate(s)` });
|
|
656
674
|
}
|
|
657
|
-
return { candidates: filterByTarget(
|
|
675
|
+
return { candidates: filterByTarget(withPremisesAndContext), trace: traceEntries };
|
|
658
676
|
}
|
|
659
|
-
// No search query — premise-to-premise discovery
|
|
660
|
-
const premiseCands = await
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
677
|
+
// No search query — premise-to-premise + context-to-intent discovery
|
|
678
|
+
const [premiseCands, contextCands] = await Promise.all([
|
|
679
|
+
runPremiseDiscovery(),
|
|
680
|
+
runContextToIntentDiscovery(),
|
|
681
|
+
]);
|
|
682
|
+
if (premiseCands.length > 0 || contextCands.length > 0) {
|
|
683
|
+
const merged = mergeStrategyCandidates(premiseCands, contextCands);
|
|
684
|
+
const traceEntries = [];
|
|
685
|
+
if (premiseCands.length > 0) {
|
|
686
|
+
traceEntries.push({ node: "strategy", detail: `premise-to-premise → ${premiseCands.length} candidate(s)` });
|
|
687
|
+
}
|
|
688
|
+
if (contextCands.length > 0) {
|
|
689
|
+
traceEntries.push({ node: "strategy", detail: `context-to-intent → ${contextCands.length} candidate(s)` });
|
|
690
|
+
}
|
|
691
|
+
traceEntries.push({
|
|
692
|
+
node: "discovery",
|
|
693
|
+
detail: `${[premiseCands.length > 0 && 'premise-to-premise', contextCands.length > 0 && 'context-to-intent'].filter(Boolean).length} strategies → ${premiseCands.length + contextCands.length} raw, ${merged.length} after dedup`,
|
|
694
|
+
});
|
|
695
|
+
return { candidates: filterByTarget(merged), trace: traceEntries };
|
|
666
696
|
}
|
|
667
697
|
return { candidates: [] };
|
|
668
698
|
}
|
|
@@ -807,20 +837,126 @@ export class OpportunityGraphFactory {
|
|
|
807
837
|
return deduped;
|
|
808
838
|
}
|
|
809
839
|
/**
|
|
810
|
-
*
|
|
811
|
-
*
|
|
840
|
+
* Context-to-intent discovery: searches intents using context HyDE embeddings.
|
|
841
|
+
* When HyDE documents exist for a context, uses optimised hypothetical-document
|
|
842
|
+
* embeddings via searchWithHydeEmbeddings. Falls back to raw context embedding
|
|
843
|
+
* via searchIntentsByContextEmbedding when no HyDE docs are available.
|
|
812
844
|
*/
|
|
813
|
-
function
|
|
814
|
-
if (
|
|
815
|
-
return
|
|
845
|
+
async function runContextToIntentDiscovery() {
|
|
846
|
+
if (!state.sourceContexts?.length)
|
|
847
|
+
return [];
|
|
848
|
+
const contextToIntentEnabled = process.env.DISCOVERY_CONTEXT_TO_INTENT !== '0';
|
|
849
|
+
if (!contextToIntentEnabled)
|
|
850
|
+
return [];
|
|
851
|
+
const targetNetworkIds = state.targetNetworks.map(t => t.networkId);
|
|
852
|
+
if (targetNetworkIds.length === 0)
|
|
853
|
+
return [];
|
|
854
|
+
logger.verbose('[Graph:Discovery] runContextToIntentDiscovery start', {
|
|
855
|
+
contextCount: state.sourceContexts.length,
|
|
856
|
+
targetNetworks: targetNetworkIds.length,
|
|
857
|
+
});
|
|
858
|
+
const contextCandidates = [];
|
|
859
|
+
for (const ctx of state.sourceContexts.filter(c => targetNetworkIds.includes(c.networkId))) {
|
|
860
|
+
// Attempt HyDE-enhanced search first
|
|
861
|
+
const hydeDocs = await self.database.getHydeDocumentsForSource('context', ctx.contextId);
|
|
862
|
+
const lensEmbeddings = hydeDocs
|
|
863
|
+
.filter(d => d.hydeEmbedding?.length > 0)
|
|
864
|
+
.map(d => ({
|
|
865
|
+
lens: d.strategy,
|
|
866
|
+
corpus: (d.targetCorpus === 'intents' ? 'intents' : d.targetCorpus === 'premises' ? 'premises' : 'intents'),
|
|
867
|
+
embedding: d.hydeEmbedding,
|
|
868
|
+
}));
|
|
869
|
+
if (lensEmbeddings.length > 0) {
|
|
870
|
+
// HyDE-enhanced search: same path as query HyDE, scoped to this context's network
|
|
871
|
+
const results = await self.embedder.searchWithHydeEmbeddings(lensEmbeddings, {
|
|
872
|
+
indexScope: [ctx.networkId],
|
|
873
|
+
excludeUserId: discoveryUserId,
|
|
874
|
+
limitPerStrategy: limitPerStrategy,
|
|
875
|
+
limit: 20,
|
|
876
|
+
minScore,
|
|
877
|
+
});
|
|
878
|
+
for (const r of results.filter(r => r.type === 'intent')) {
|
|
879
|
+
contextCandidates.push({
|
|
880
|
+
candidateUserId: r.userId,
|
|
881
|
+
candidateIntentId: r.id,
|
|
882
|
+
networkId: ctx.networkId,
|
|
883
|
+
similarity: r.score,
|
|
884
|
+
lens: r.matchedVia,
|
|
885
|
+
candidatePayload: '',
|
|
886
|
+
candidateSummary: undefined,
|
|
887
|
+
discoverySource: 'context-to-intent',
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
// Fallback: raw context embedding search (no HyDE docs yet)
|
|
893
|
+
const results = await self.database.searchIntentsByContextEmbedding({
|
|
894
|
+
embedding: ctx.embedding,
|
|
895
|
+
networkIds: [ctx.networkId],
|
|
896
|
+
excludeUserId: discoveryUserId,
|
|
897
|
+
limit: 20,
|
|
898
|
+
minScore: minScore,
|
|
899
|
+
});
|
|
900
|
+
for (const r of results) {
|
|
901
|
+
contextCandidates.push({
|
|
902
|
+
candidateUserId: r.userId,
|
|
903
|
+
candidateIntentId: r.intentId,
|
|
904
|
+
networkId: r.networkId,
|
|
905
|
+
similarity: typeof r.similarity === 'number' ? r.similarity : parseFloat(String(r.similarity)),
|
|
906
|
+
lens: 'context_match',
|
|
907
|
+
candidatePayload: r.payload ?? '',
|
|
908
|
+
candidateSummary: r.summary ?? undefined,
|
|
909
|
+
discoverySource: 'context-to-intent',
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
const byKey = new Map();
|
|
915
|
+
for (const c of contextCandidates) {
|
|
916
|
+
const key = `${c.candidateUserId}:${c.candidateIntentId ?? 'none'}:${c.networkId}`;
|
|
917
|
+
if (!byKey.has(key) || c.similarity > (byKey.get(key)?.similarity ?? 0)) {
|
|
918
|
+
byKey.set(key, c);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
const deduped = Array.from(byKey.values());
|
|
922
|
+
logger.verbose('[Graph:Discovery] runContextToIntentDiscovery complete', {
|
|
923
|
+
rawCount: contextCandidates.length,
|
|
924
|
+
dedupedCount: deduped.length,
|
|
925
|
+
});
|
|
926
|
+
return deduped;
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Merge candidates from multiple strategies. Deduplicates by userId + networkId + entityId,
|
|
930
|
+
* keeps the highest similarity, tracks which strategies found each candidate,
|
|
931
|
+
* and applies a multi-strategy boost (+0.05 per additional strategy, boost capped at 0.15,
|
|
932
|
+
* final similarity capped at 1.0).
|
|
933
|
+
*/
|
|
934
|
+
function mergeStrategyCandidates(...groups) {
|
|
816
935
|
const merged = new Map();
|
|
817
|
-
for (const
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
936
|
+
for (const group of groups) {
|
|
937
|
+
for (const c of group) {
|
|
938
|
+
const entityId = c.candidateIntentId ?? c.candidatePremiseId ?? 'none';
|
|
939
|
+
const key = `${c.candidateUserId}:${c.networkId}:${entityId}`;
|
|
940
|
+
const existing = merged.get(key);
|
|
941
|
+
if (!existing) {
|
|
942
|
+
merged.set(key, { ...c, _strategies: new Set([c.discoverySource ?? 'unknown']) });
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
existing._strategies.add(c.discoverySource ?? 'unknown');
|
|
946
|
+
if (c.similarity > existing.similarity) {
|
|
947
|
+
Object.assign(existing, c);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
821
950
|
}
|
|
822
951
|
}
|
|
823
|
-
return Array.from(merged.values())
|
|
952
|
+
return Array.from(merged.values()).map(({ _strategies, ...c }) => {
|
|
953
|
+
const boost = Math.min((_strategies.size - 1) * 0.05, 0.15);
|
|
954
|
+
return {
|
|
955
|
+
...c,
|
|
956
|
+
similarity: Math.min(c.similarity + boost, 1.0),
|
|
957
|
+
matchedStrategies: Array.from(_strategies),
|
|
958
|
+
};
|
|
959
|
+
});
|
|
824
960
|
}
|
|
825
961
|
const resolvedIntent = state.resolvedTriggerIntentId
|
|
826
962
|
? state.indexedIntents.find((i) => i.intentId === state.resolvedTriggerIntentId)
|
|
@@ -828,11 +964,15 @@ export class OpportunityGraphFactory {
|
|
|
828
964
|
const searchText = state.searchQuery ?? resolvedIntent?.payload ?? '';
|
|
829
965
|
if (!searchText) {
|
|
830
966
|
logger.warn('[Graph:Discovery] No search text available for intent path');
|
|
831
|
-
const premiseCands = await
|
|
832
|
-
|
|
967
|
+
const [premiseCands, contextCands] = await Promise.all([
|
|
968
|
+
runPremiseDiscovery(),
|
|
969
|
+
runContextToIntentDiscovery(),
|
|
970
|
+
]);
|
|
971
|
+
const merged = mergeStrategyCandidates(premiseCands, contextCands);
|
|
972
|
+
if (merged.length > 0) {
|
|
833
973
|
return {
|
|
834
|
-
candidates: filterByTarget(
|
|
835
|
-
trace: [{ node: "discovery", detail: `No search text; premise
|
|
974
|
+
candidates: filterByTarget(merged),
|
|
975
|
+
trace: [{ node: "discovery", detail: `No search text; premise → ${premiseCands.length}, context → ${contextCands.length}, merged → ${merged.length} candidate(s)` }],
|
|
836
976
|
};
|
|
837
977
|
}
|
|
838
978
|
return { candidates: [] };
|
|
@@ -851,12 +991,16 @@ export class OpportunityGraphFactory {
|
|
|
851
991
|
const hydeEmbeddings = hydeResult.hydeEmbeddings;
|
|
852
992
|
const lenses = hydeResult.lenses ?? [];
|
|
853
993
|
if (!hydeEmbeddings || Object.keys(hydeEmbeddings).length === 0) {
|
|
854
|
-
const premiseCands = await
|
|
855
|
-
|
|
994
|
+
const [premiseCands, contextCands] = await Promise.all([
|
|
995
|
+
runPremiseDiscovery(),
|
|
996
|
+
runContextToIntentDiscovery(),
|
|
997
|
+
]);
|
|
998
|
+
const merged = mergeStrategyCandidates(premiseCands, contextCands);
|
|
999
|
+
if (merged.length > 0) {
|
|
856
1000
|
return {
|
|
857
1001
|
hydeEmbeddings: {},
|
|
858
|
-
candidates: filterByTarget(
|
|
859
|
-
trace: [{ node: "discovery", detail: `No HyDE embeddings; premise
|
|
1002
|
+
candidates: filterByTarget(merged),
|
|
1003
|
+
trace: [{ node: "discovery", detail: `No HyDE embeddings; premise → ${premiseCands.length}, context → ${contextCands.length}, merged → ${merged.length} candidate(s)` }],
|
|
860
1004
|
};
|
|
861
1005
|
}
|
|
862
1006
|
return { hydeEmbeddings: {}, candidates: [] };
|
|
@@ -986,14 +1130,20 @@ export class OpportunityGraphFactory {
|
|
|
986
1130
|
},
|
|
987
1131
|
});
|
|
988
1132
|
}
|
|
989
|
-
const premiseCands = await
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1133
|
+
const [premiseCands, contextCands] = await Promise.all([
|
|
1134
|
+
runPremiseDiscovery(),
|
|
1135
|
+
runContextToIntentDiscovery(),
|
|
1136
|
+
]);
|
|
1137
|
+
const allStrategies = mergeStrategyCandidates(candidates, premiseCands, contextCands);
|
|
1138
|
+
if (premiseCands.length > 0 || contextCands.length > 0) {
|
|
1139
|
+
traceEntries.push({
|
|
1140
|
+
node: "discovery",
|
|
1141
|
+
detail: `+ Premise → ${premiseCands.length}, Context → ${contextCands.length}, merged to ${allStrategies.length} candidate(s)`,
|
|
1142
|
+
});
|
|
993
1143
|
}
|
|
994
1144
|
return {
|
|
995
1145
|
hydeEmbeddings: hydeEmbeddings,
|
|
996
|
-
candidates: filterByTarget(
|
|
1146
|
+
candidates: filterByTarget(allStrategies),
|
|
997
1147
|
trace: traceEntries,
|
|
998
1148
|
};
|
|
999
1149
|
}
|