sxng-cli 1.0.9 → 1.1.0
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/commands/graph-add.d.ts.map +1 -1
- package/dist/commands/graph-add.js +9 -1
- package/dist/commands/graph-add.js.map +1 -1
- package/dist/commands/graph-drill.d.ts +11 -0
- package/dist/commands/graph-drill.d.ts.map +1 -0
- package/dist/commands/graph-drill.js +26 -0
- package/dist/commands/graph-drill.js.map +1 -0
- package/dist/commands/graph-explore.d.ts +10 -0
- package/dist/commands/graph-explore.d.ts.map +1 -0
- package/dist/commands/graph-explore.js +32 -0
- package/dist/commands/graph-explore.js.map +1 -0
- package/dist/commands/graph-obfuscate.d.ts +17 -0
- package/dist/commands/graph-obfuscate.d.ts.map +1 -0
- package/dist/commands/graph-obfuscate.js +110 -0
- package/dist/commands/graph-obfuscate.js.map +1 -0
- package/dist/commands/graph-search.d.ts +11 -0
- package/dist/commands/graph-search.d.ts.map +1 -0
- package/dist/commands/graph-search.js +19 -0
- package/dist/commands/graph-search.js.map +1 -0
- package/dist/commands/graph-traverse.d.ts +10 -0
- package/dist/commands/graph-traverse.d.ts.map +1 -0
- package/dist/commands/graph-traverse.js +39 -0
- package/dist/commands/graph-traverse.js.map +1 -0
- package/dist/commands/query-graph.d.ts +2 -0
- package/dist/commands/query-graph.d.ts.map +1 -1
- package/dist/commands/query-graph.js +66 -0
- package/dist/commands/query-graph.js.map +1 -1
- package/dist/deep/co-occurrence.d.ts +50 -0
- package/dist/deep/co-occurrence.d.ts.map +1 -0
- package/dist/deep/co-occurrence.js +95 -0
- package/dist/deep/co-occurrence.js.map +1 -0
- package/dist/deep/degree-utils.d.ts +39 -0
- package/dist/deep/degree-utils.d.ts.map +1 -0
- package/dist/deep/degree-utils.js +42 -0
- package/dist/deep/degree-utils.js.map +1 -0
- package/dist/deep/extractor.d.ts +7 -2
- package/dist/deep/extractor.d.ts.map +1 -1
- package/dist/deep/extractor.js +143 -78
- package/dist/deep/extractor.js.map +1 -1
- package/dist/deep/graph-explore.d.ts +115 -0
- package/dist/deep/graph-explore.d.ts.map +1 -0
- package/dist/deep/graph-explore.js +586 -0
- package/dist/deep/graph-explore.js.map +1 -0
- package/dist/deep/graph-obfuscate.d.ts +51 -0
- package/dist/deep/graph-obfuscate.d.ts.map +1 -0
- package/dist/deep/graph-obfuscate.js +226 -0
- package/dist/deep/graph-obfuscate.js.map +1 -0
- package/dist/deep/graph-preprocess.d.ts +41 -0
- package/dist/deep/graph-preprocess.d.ts.map +1 -0
- package/dist/deep/graph-preprocess.js +32 -0
- package/dist/deep/graph-preprocess.js.map +1 -0
- package/dist/deep/graph-sampling.d.ts +51 -0
- package/dist/deep/graph-sampling.d.ts.map +1 -0
- package/dist/deep/graph-sampling.js +409 -0
- package/dist/deep/graph-sampling.js.map +1 -0
- package/dist/deep/graph.d.ts +24 -1
- package/dist/deep/graph.d.ts.map +1 -1
- package/dist/deep/graph.js +42 -1
- package/dist/deep/graph.js.map +1 -1
- package/dist/deep/iteration-data.d.ts +38 -0
- package/dist/deep/iteration-data.d.ts.map +1 -0
- package/dist/deep/iteration-data.js +48 -0
- package/dist/deep/iteration-data.js.map +1 -0
- package/dist/deep/path-extraction.d.ts +53 -0
- package/dist/deep/path-extraction.d.ts.map +1 -0
- package/dist/deep/path-extraction.js +229 -0
- package/dist/deep/path-extraction.js.map +1 -0
- package/dist/deep/quality-assess.d.ts +45 -0
- package/dist/deep/quality-assess.d.ts.map +1 -0
- package/dist/deep/quality-assess.js +125 -0
- package/dist/deep/quality-assess.js.map +1 -0
- package/dist/deep/query-redundancy.d.ts +39 -0
- package/dist/deep/query-redundancy.d.ts.map +1 -0
- package/dist/deep/query-redundancy.js +109 -0
- package/dist/deep/query-redundancy.js.map +1 -0
- package/dist/deep/query-suggest.d.ts +35 -0
- package/dist/deep/query-suggest.d.ts.map +1 -0
- package/dist/deep/query-suggest.js +98 -0
- package/dist/deep/query-suggest.js.map +1 -0
- package/dist/deep/recovery-analysis.d.ts +61 -0
- package/dist/deep/recovery-analysis.d.ts.map +1 -0
- package/dist/deep/recovery-analysis.js +188 -0
- package/dist/deep/recovery-analysis.js.map +1 -0
- package/dist/deep/search-strategy.d.ts +37 -0
- package/dist/deep/search-strategy.d.ts.map +1 -0
- package/dist/deep/search-strategy.js +99 -0
- package/dist/deep/search-strategy.js.map +1 -0
- package/dist/deep/session.d.ts +2 -0
- package/dist/deep/session.d.ts.map +1 -1
- package/dist/deep/session.js +1 -1
- package/dist/deep/session.js.map +1 -1
- package/dist/deep/simhash.d.ts +5 -0
- package/dist/deep/simhash.d.ts.map +1 -1
- package/dist/deep/simhash.js +16 -0
- package/dist/deep/simhash.js.map +1 -1
- package/dist/deep/tfidf.d.ts +38 -0
- package/dist/deep/tfidf.d.ts.map +1 -0
- package/dist/deep/tfidf.js +103 -0
- package/dist/deep/tfidf.js.map +1 -0
- package/dist/runCli.d.ts +3 -1
- package/dist/runCli.d.ts.map +1 -1
- package/dist/runCli.js +762 -307
- package/dist/runCli.js.map +1 -1
- package/package.json +17 -4
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query redundancy detection via Jaccard similarity.
|
|
3
|
+
*
|
|
4
|
+
* Before executing a new query, compare it against all historical queries
|
|
5
|
+
* in the session. If similarity exceeds a threshold, take action:
|
|
6
|
+
* - warn: output warning, proceed with search
|
|
7
|
+
* - adjust: auto-remove overlapping terms, add differentiation
|
|
8
|
+
* - skip: skip redundant query entirely
|
|
9
|
+
*
|
|
10
|
+
* Short queries (≤3 words) use character-level bigram Jaccard to avoid
|
|
11
|
+
* low similarity from minor word differences. Longer queries use word-level Jaccard.
|
|
12
|
+
*/
|
|
13
|
+
// ── Jaccard computation ───────────────────────────────────────────
|
|
14
|
+
/** Generate character-level bigrams from a string. */
|
|
15
|
+
function charBigrams(s) {
|
|
16
|
+
const bigrams = new Set();
|
|
17
|
+
for (let i = 0; i < s.length - 1; i++) {
|
|
18
|
+
bigrams.add(s.slice(i, i + 2));
|
|
19
|
+
}
|
|
20
|
+
return bigrams;
|
|
21
|
+
}
|
|
22
|
+
/** Compute Jaccard similarity between two sets. */
|
|
23
|
+
function setJaccard(a, b) {
|
|
24
|
+
if (a.size === 0 && b.size === 0)
|
|
25
|
+
return 0;
|
|
26
|
+
let intersection = 0;
|
|
27
|
+
for (const item of a) {
|
|
28
|
+
if (b.has(item))
|
|
29
|
+
intersection++;
|
|
30
|
+
}
|
|
31
|
+
const union = a.size + b.size - intersection;
|
|
32
|
+
return union === 0 ? 0 : intersection / union;
|
|
33
|
+
}
|
|
34
|
+
/** Count words in a string (split by whitespace). */
|
|
35
|
+
function wordCount(s) {
|
|
36
|
+
return s.trim().split(/\s+/).filter(Boolean).length;
|
|
37
|
+
}
|
|
38
|
+
/** Compute Jaccard similarity between two queries.
|
|
39
|
+
* - ≤2 words: character-level bigram Jaccard (case-insensitive)
|
|
40
|
+
* - >2 words: word-level Jaccard (case-insensitive) */
|
|
41
|
+
export function computeJaccard(a, b) {
|
|
42
|
+
const aLower = a.toLowerCase().trim();
|
|
43
|
+
const bLower = b.toLowerCase().trim();
|
|
44
|
+
if (aLower === bLower)
|
|
45
|
+
return aLower.length > 0 ? 1 : 0;
|
|
46
|
+
if (wordCount(a) <= 2 || wordCount(b) <= 2) {
|
|
47
|
+
// Short query: character-level bigram Jaccard
|
|
48
|
+
const bgA = charBigrams(aLower);
|
|
49
|
+
const bgB = charBigrams(bLower);
|
|
50
|
+
if (bgA.size === 0 || bgB.size === 0)
|
|
51
|
+
return 0;
|
|
52
|
+
return setJaccard(bgA, bgB);
|
|
53
|
+
}
|
|
54
|
+
// Long query: word-level Jaccard
|
|
55
|
+
const setA = new Set(aLower.split(/\s+/).filter(Boolean));
|
|
56
|
+
const setB = new Set(bLower.split(/\s+/).filter(Boolean));
|
|
57
|
+
return setJaccard(setA, setB);
|
|
58
|
+
}
|
|
59
|
+
// ── Query adjustment ──────────────────────────────────────────────
|
|
60
|
+
/** Adjust a redundant query by removing overlapping terms and adding differentiation.
|
|
61
|
+
* Returns the adjusted query string, or the original if no adjustment is possible. */
|
|
62
|
+
export function adjustQuery(newQuery, similarQueries) {
|
|
63
|
+
const newWords = newQuery.toLowerCase().split(/\s+/).filter(Boolean);
|
|
64
|
+
// Collect all overlapping words from similar queries
|
|
65
|
+
const overlappingWords = new Set();
|
|
66
|
+
for (const sq of similarQueries) {
|
|
67
|
+
const sqWords = sq.query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
68
|
+
for (const w of sqWords) {
|
|
69
|
+
if (newWords.includes(w)) {
|
|
70
|
+
overlappingWords.add(w);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Keep non-overlapping words
|
|
75
|
+
const keptWords = newQuery.split(/\s+/).filter(w => !overlappingWords.has(w.toLowerCase()));
|
|
76
|
+
if (keptWords.length === 0) {
|
|
77
|
+
// All words overlap — can't adjust, return original
|
|
78
|
+
return newQuery;
|
|
79
|
+
}
|
|
80
|
+
// Add a differentiation marker to signal this is a refined query
|
|
81
|
+
return keptWords.join(' ');
|
|
82
|
+
}
|
|
83
|
+
// ── Main redundancy check ────────────────────────────────────────
|
|
84
|
+
/** Check a new query against session history for redundancy. */
|
|
85
|
+
export function checkQueryRedundancy(newQuery, sessionHistory, config) {
|
|
86
|
+
const similarQueries = [];
|
|
87
|
+
let maxSimilarity = 0;
|
|
88
|
+
for (const pastQuery of sessionHistory) {
|
|
89
|
+
const sim = computeJaccard(newQuery, pastQuery);
|
|
90
|
+
if (sim >= config.jaccardThreshold) {
|
|
91
|
+
similarQueries.push({ query: pastQuery, similarity: sim });
|
|
92
|
+
}
|
|
93
|
+
if (sim > maxSimilarity) {
|
|
94
|
+
maxSimilarity = sim;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const isRedundant = similarQueries.length > 0;
|
|
98
|
+
const result = {
|
|
99
|
+
isRedundant,
|
|
100
|
+
maxSimilarity,
|
|
101
|
+
similarQueries,
|
|
102
|
+
action: config.action,
|
|
103
|
+
};
|
|
104
|
+
if (isRedundant && config.action === 'adjust') {
|
|
105
|
+
result.adjustedQuery = adjustQuery(newQuery, similarQueries);
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=query-redundancy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-redundancy.js","sourceRoot":"","sources":["../../src/deep/query-redundancy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query suggestion data generation for deep search sessions.
|
|
3
|
+
*
|
|
4
|
+
* CLI outputs analysis data (entities, domains, history, quality)
|
|
5
|
+
* for Agent to use when generating follow-up queries.
|
|
6
|
+
* CLI does NOT auto-generate queries — Agent controls LLM interaction.
|
|
7
|
+
*/
|
|
8
|
+
import { DirectedGraph } from 'graphology';
|
|
9
|
+
import { GraphNodeAttrs, GraphEdgeAttrs } from './graph.js';
|
|
10
|
+
import { SessionResult } from './session.js';
|
|
11
|
+
import { QualityScore } from './quality-assess.js';
|
|
12
|
+
export interface TopEntity {
|
|
13
|
+
label: string;
|
|
14
|
+
obfuscatedLabel?: string;
|
|
15
|
+
degree: number;
|
|
16
|
+
frequency: number;
|
|
17
|
+
entityType?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface RoundHistoryEntry {
|
|
20
|
+
round: number;
|
|
21
|
+
query: string;
|
|
22
|
+
resultCount: number;
|
|
23
|
+
}
|
|
24
|
+
export type SearchStage = 'broad_exploration' | 'targeted_deep_dive';
|
|
25
|
+
export interface QuerySuggestionData {
|
|
26
|
+
topEntities: TopEntity[];
|
|
27
|
+
unexploredDomains: string[];
|
|
28
|
+
currentStage: SearchStage;
|
|
29
|
+
roundHistory: RoundHistoryEntry[];
|
|
30
|
+
qualityLastRound?: QualityScore;
|
|
31
|
+
}
|
|
32
|
+
/** Generate query suggestion data from session context.
|
|
33
|
+
* Returns analysis for Agent — CLI does NOT auto-generate queries. */
|
|
34
|
+
export declare function generateQuerySuggestions(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>, sessionResults: SessionResult[], currentStage: SearchStage, qualityLastRound?: QualityScore): QuerySuggestionData;
|
|
35
|
+
//# sourceMappingURL=query-suggest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-suggest.d.ts","sourceRoot":"","sources":["../../src/deep/query-suggest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAInD,MAAM,WAAW,SAAS;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,oBAAoB,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,EAAE,WAAW,CAAC;IAC1B,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,gBAAgB,CAAC,EAAE,YAAY,CAAC;CACnC;AA8BD;uEACuE;AACvE,wBAAgB,wBAAwB,CACpC,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,EACpD,cAAc,EAAE,aAAa,EAAE,EAC/B,YAAY,EAAE,WAAW,EACzB,gBAAgB,CAAC,EAAE,YAAY,GAChC,mBAAmB,CAsBrB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query suggestion data generation for deep search sessions.
|
|
3
|
+
*
|
|
4
|
+
* CLI outputs analysis data (entities, domains, history, quality)
|
|
5
|
+
* for Agent to use when generating follow-up queries.
|
|
6
|
+
* CLI does NOT auto-generate queries — Agent controls LLM interaction.
|
|
7
|
+
*/
|
|
8
|
+
import { getEntityDegree } from './degree-utils.js';
|
|
9
|
+
// ── Domain extraction ─────────────────────────────────────────────
|
|
10
|
+
/** Known specialized domains for deep-dive search */
|
|
11
|
+
const SPECIALIZED_DOMAINS = [
|
|
12
|
+
'arxiv.org',
|
|
13
|
+
'semanticscholar.org',
|
|
14
|
+
'github.com',
|
|
15
|
+
'stackoverflow.com',
|
|
16
|
+
'docs.rs',
|
|
17
|
+
'npmjs.com',
|
|
18
|
+
'pypi.org',
|
|
19
|
+
'crates.io',
|
|
20
|
+
'medium.com',
|
|
21
|
+
'dev.to',
|
|
22
|
+
'reddit.com',
|
|
23
|
+
'hackernews.com',
|
|
24
|
+
];
|
|
25
|
+
function extractDomain(url) {
|
|
26
|
+
try {
|
|
27
|
+
return new URL(url).hostname;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// ── Suggestion generation ─────────────────────────────────────────
|
|
34
|
+
/** Generate query suggestion data from session context.
|
|
35
|
+
* Returns analysis for Agent — CLI does NOT auto-generate queries. */
|
|
36
|
+
export function generateQuerySuggestions(graph, sessionResults, currentStage, qualityLastRound) {
|
|
37
|
+
// Collect top entities sorted by degree × frequency descending
|
|
38
|
+
const topEntities = collectTopEntities(graph);
|
|
39
|
+
// Detect unexplored domains
|
|
40
|
+
const exploredDomains = new Set();
|
|
41
|
+
for (const r of sessionResults) {
|
|
42
|
+
const domain = extractDomain(r.url);
|
|
43
|
+
if (domain)
|
|
44
|
+
exploredDomains.add(domain);
|
|
45
|
+
}
|
|
46
|
+
const unexploredDomains = SPECIALIZED_DOMAINS.filter(d => !exploredDomains.has(d));
|
|
47
|
+
// Build round history from query nodes in graph
|
|
48
|
+
const roundHistory = buildRoundHistory(graph, sessionResults);
|
|
49
|
+
return {
|
|
50
|
+
topEntities,
|
|
51
|
+
unexploredDomains,
|
|
52
|
+
currentStage,
|
|
53
|
+
roundHistory,
|
|
54
|
+
qualityLastRound,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** Collect entity nodes sorted by degree × frequency descending */
|
|
58
|
+
function collectTopEntities(graph) {
|
|
59
|
+
const entities = [];
|
|
60
|
+
graph.forEachNode((node, attrs) => {
|
|
61
|
+
if (attrs.type !== 'entity')
|
|
62
|
+
return;
|
|
63
|
+
const degree = getEntityDegree(graph, node);
|
|
64
|
+
const frequency = attrs.frequency ?? 1;
|
|
65
|
+
entities.push({
|
|
66
|
+
label: attrs.label,
|
|
67
|
+
obfuscatedLabel: attrs.obfuscatedLabel,
|
|
68
|
+
degree,
|
|
69
|
+
frequency,
|
|
70
|
+
entityType: attrs.entityType,
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
// Sort by degree × frequency descending
|
|
74
|
+
return entities.sort((a, b) => (b.degree * b.frequency) - (a.degree * a.frequency));
|
|
75
|
+
}
|
|
76
|
+
/** Build round history from query nodes in graph */
|
|
77
|
+
function buildRoundHistory(graph, sessionResults) {
|
|
78
|
+
const entries = [];
|
|
79
|
+
graph.forEachNode((node, attrs) => {
|
|
80
|
+
if (attrs.type !== 'query' || !attrs.query)
|
|
81
|
+
return;
|
|
82
|
+
// Count results yielded by this query via edges
|
|
83
|
+
let resultCount = 0;
|
|
84
|
+
graph.forEachOutNeighbor(node, (neighbor) => {
|
|
85
|
+
const nAttrs = graph.getNodeAttributes(neighbor);
|
|
86
|
+
if (nAttrs.type === 'result')
|
|
87
|
+
resultCount++;
|
|
88
|
+
});
|
|
89
|
+
entries.push({
|
|
90
|
+
round: attrs.round ?? entries.length + 1,
|
|
91
|
+
query: attrs.query,
|
|
92
|
+
resultCount,
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
// Sort by round number
|
|
96
|
+
return entries.sort((a, b) => a.round - b.round);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=query-suggest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-suggest.js","sourceRoot":"","sources":["../../src/deep/query-suggest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovery analysis for deep search sessions.
|
|
3
|
+
*
|
|
4
|
+
* When search quality is poor, analyze the session and suggest recovery
|
|
5
|
+
* strategies for the Agent. CLI outputs analysis data only — Agent decides.
|
|
6
|
+
*
|
|
7
|
+
* Four recovery strategies:
|
|
8
|
+
* - reformulate: query too specific → remove qualifiers or use broader terms
|
|
9
|
+
* - engine_rotation: current engines not covering sources → try different engines
|
|
10
|
+
* - category_shift: category results poor → switch category
|
|
11
|
+
* - backtrack: ≥2 consecutive poor rounds → return to last successful query direction
|
|
12
|
+
* (uses graph traversal: query→yields→result backtracking)
|
|
13
|
+
*/
|
|
14
|
+
import { DirectedGraph } from 'graphology';
|
|
15
|
+
import { GraphNodeAttrs, GraphEdgeAttrs } from './graph.js';
|
|
16
|
+
import { SessionResult } from './session.js';
|
|
17
|
+
import { QualityScore, QualityThresholds } from './quality-assess.js';
|
|
18
|
+
import { StrategyConfig } from './search-strategy.js';
|
|
19
|
+
export type RecoveryStrategy = 'reformulate' | 'engine_rotation' | 'category_shift' | 'backtrack';
|
|
20
|
+
export interface RecoveryStrategyInfo {
|
|
21
|
+
strategy: RecoveryStrategy;
|
|
22
|
+
reason: string;
|
|
23
|
+
suggestion: string;
|
|
24
|
+
backtrackTo?: {
|
|
25
|
+
round: number;
|
|
26
|
+
query: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface RoundQuality {
|
|
30
|
+
round: number;
|
|
31
|
+
query: string;
|
|
32
|
+
verdict: QualityScore['verdict'];
|
|
33
|
+
failedIndicators: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface RecoveryAnalysis {
|
|
36
|
+
qualityScore: QualityScore;
|
|
37
|
+
recentFailures: number;
|
|
38
|
+
availableStrategies: RecoveryStrategyInfo[];
|
|
39
|
+
lastSuccessfulRound: {
|
|
40
|
+
round: number;
|
|
41
|
+
query: string;
|
|
42
|
+
quality: string;
|
|
43
|
+
} | null;
|
|
44
|
+
roundQualityHistory: RoundQuality[];
|
|
45
|
+
}
|
|
46
|
+
/** Build per-round quality history from the session graph and results.
|
|
47
|
+
* Each query node in the graph represents a round. We assess quality
|
|
48
|
+
* of results yielded by that query against the accumulated results up
|
|
49
|
+
* to that round. */
|
|
50
|
+
export declare function buildRoundQualityHistory(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>, sessionResults: SessionResult[], qualityThresholds?: Partial<QualityThresholds>): RoundQuality[];
|
|
51
|
+
/** Analyze recovery options for a session with poor quality results.
|
|
52
|
+
* Returns available strategies with reasons and suggestions. */
|
|
53
|
+
export declare function analyzeRecoveryOptions(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>, sessionResults: SessionResult[], qualityScore: QualityScore, config?: Partial<StrategyConfig>): RecoveryAnalysis;
|
|
54
|
+
/** Backtrack via graph traversal: find the query node that yielded
|
|
55
|
+
* the most results connected to high-degree entity nodes.
|
|
56
|
+
* Returns the query and round to backtrack to. */
|
|
57
|
+
export declare function backtrackToBestQuery(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>): {
|
|
58
|
+
round: number;
|
|
59
|
+
query: string;
|
|
60
|
+
} | null;
|
|
61
|
+
//# sourceMappingURL=recovery-analysis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-analysis.d.ts","sourceRoot":"","sources":["../../src/deep/recovery-analysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAuB,MAAM,qBAAqB,CAAC;AAC3F,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAItD,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,WAAW,CAAC;AAElG,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD;AAED,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC7B,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,oBAAoB,EAAE,CAAC;IAC5C,mBAAmB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9E,mBAAmB,EAAE,YAAY,EAAE,CAAC;CACvC;AAID;;;qBAGqB;AACrB,wBAAgB,wBAAwB,CACpC,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,EACpD,cAAc,EAAE,aAAa,EAAE,EAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAC/C,YAAY,EAAE,CAgDhB;AAID;iEACiE;AACjE,wBAAgB,sBAAsB,CAClC,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,EACpD,cAAc,EAAE,aAAa,EAAE,EAC/B,YAAY,EAAE,YAAY,EAC1B,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GACjC,gBAAgB,CA8ElB;AAoBD;;mDAEmD;AACnD,wBAAgB,oBAAoB,CAChC,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,GACrD;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAwCzC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovery analysis for deep search sessions.
|
|
3
|
+
*
|
|
4
|
+
* When search quality is poor, analyze the session and suggest recovery
|
|
5
|
+
* strategies for the Agent. CLI outputs analysis data only — Agent decides.
|
|
6
|
+
*
|
|
7
|
+
* Four recovery strategies:
|
|
8
|
+
* - reformulate: query too specific → remove qualifiers or use broader terms
|
|
9
|
+
* - engine_rotation: current engines not covering sources → try different engines
|
|
10
|
+
* - category_shift: category results poor → switch category
|
|
11
|
+
* - backtrack: ≥2 consecutive poor rounds → return to last successful query direction
|
|
12
|
+
* (uses graph traversal: query→yields→result backtracking)
|
|
13
|
+
*/
|
|
14
|
+
import { assessResultQuality } from './quality-assess.js';
|
|
15
|
+
// ── Quality history per round ─────────────────────────────────────
|
|
16
|
+
/** Build per-round quality history from the session graph and results.
|
|
17
|
+
* Each query node in the graph represents a round. We assess quality
|
|
18
|
+
* of results yielded by that query against the accumulated results up
|
|
19
|
+
* to that round. */
|
|
20
|
+
export function buildRoundQualityHistory(graph, sessionResults, qualityThresholds) {
|
|
21
|
+
// Collect query nodes sorted by round
|
|
22
|
+
const queryNodes = [];
|
|
23
|
+
graph.forEachNode((node, attrs) => {
|
|
24
|
+
if (attrs.type === 'query' && attrs.query) {
|
|
25
|
+
queryNodes.push({ id: node, round: attrs.round ?? 0, query: attrs.query });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
queryNodes.sort((a, b) => a.round - b.round);
|
|
29
|
+
if (queryNodes.length === 0)
|
|
30
|
+
return [];
|
|
31
|
+
const history = [];
|
|
32
|
+
const seenUrls = new Set();
|
|
33
|
+
for (const qNode of queryNodes) {
|
|
34
|
+
// Collect result URLs yielded by this query
|
|
35
|
+
const roundResultUrls = new Set();
|
|
36
|
+
graph.forEachOutNeighbor(qNode.id, (neighbor) => {
|
|
37
|
+
const nAttrs = graph.getNodeAttributes(neighbor);
|
|
38
|
+
if (nAttrs.type === 'result' && nAttrs.url) {
|
|
39
|
+
roundResultUrls.add(nAttrs.url);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
// Get SessionResult objects for these URLs
|
|
43
|
+
const roundResults = sessionResults.filter(r => roundResultUrls.has(r.url));
|
|
44
|
+
// Prior results are all results seen before this round
|
|
45
|
+
const priorResults = sessionResults.filter(r => seenUrls.has(r.url));
|
|
46
|
+
// Assess quality of this round's results
|
|
47
|
+
const quality = assessResultQuality(roundResults, priorResults, graph, qualityThresholds);
|
|
48
|
+
history.push({
|
|
49
|
+
round: qNode.round,
|
|
50
|
+
query: qNode.query,
|
|
51
|
+
verdict: quality.verdict,
|
|
52
|
+
failedIndicators: quality.failedIndicators,
|
|
53
|
+
});
|
|
54
|
+
// Mark these URLs as seen for subsequent rounds
|
|
55
|
+
for (const url of roundResultUrls) {
|
|
56
|
+
seenUrls.add(url);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return history;
|
|
60
|
+
}
|
|
61
|
+
// ── Recovery analysis ─────────────────────────────────────────────
|
|
62
|
+
/** Analyze recovery options for a session with poor quality results.
|
|
63
|
+
* Returns available strategies with reasons and suggestions. */
|
|
64
|
+
export function analyzeRecoveryOptions(graph, sessionResults, qualityScore, config) {
|
|
65
|
+
const history = buildRoundQualityHistory(graph, sessionResults);
|
|
66
|
+
// Count consecutive poor/acceptable rounds from the end
|
|
67
|
+
let recentFailures = 0;
|
|
68
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
69
|
+
if (history[i].verdict === 'poor') {
|
|
70
|
+
recentFailures++;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Find last successful round (good verdict)
|
|
77
|
+
const lastSuccessfulRound = findLastSuccessfulRound(history);
|
|
78
|
+
// Build available strategies
|
|
79
|
+
const strategies = [];
|
|
80
|
+
// Reformulate: suggest when resultCount or contentDepth failed
|
|
81
|
+
if (qualityScore.failedIndicators.includes('resultCount') ||
|
|
82
|
+
qualityScore.failedIndicators.includes('contentDepth')) {
|
|
83
|
+
strategies.push({
|
|
84
|
+
strategy: 'reformulate',
|
|
85
|
+
reason: '查询过于具体或范围过窄,可能需要简化',
|
|
86
|
+
suggestion: '移除限定词或尝试更宽泛的表达',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// Engine rotation: suggest when sourceDiversity failed
|
|
90
|
+
if (qualityScore.failedIndicators.includes('sourceDiversity')) {
|
|
91
|
+
strategies.push({
|
|
92
|
+
strategy: 'engine_rotation',
|
|
93
|
+
reason: '当前引擎组合可能未覆盖相关来源',
|
|
94
|
+
suggestion: '尝试不同引擎组合(如从 google 切换到 duckduckgo 或添加专业引擎)',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// Category shift: suggest when novelty or resultCount failed
|
|
98
|
+
if (qualityScore.failedIndicators.includes('novelty') ||
|
|
99
|
+
(qualityScore.failedIndicators.includes('resultCount') && strategies.length < 3)) {
|
|
100
|
+
strategies.push({
|
|
101
|
+
strategy: 'category_shift',
|
|
102
|
+
reason: '当前分类结果不佳或结果重复',
|
|
103
|
+
suggestion: '切换到更宽泛或不同分类(如从 science 切换到 general 或 it)',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Backtrack: suggest when ≥2 consecutive poor rounds
|
|
107
|
+
if (recentFailures >= 2 && lastSuccessfulRound) {
|
|
108
|
+
strategies.push({
|
|
109
|
+
strategy: 'backtrack',
|
|
110
|
+
reason: `连续 ${recentFailures} 轮质量不佳`,
|
|
111
|
+
suggestion: '回到较早成功的查询方向分支',
|
|
112
|
+
backtrackTo: {
|
|
113
|
+
round: lastSuccessfulRound.round,
|
|
114
|
+
query: lastSuccessfulRound.query,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// If no strategies were triggered but verdict is still poor/acceptable,
|
|
119
|
+
// add a generic reformulate strategy
|
|
120
|
+
if (strategies.length === 0 && qualityScore.verdict !== 'good') {
|
|
121
|
+
strategies.push({
|
|
122
|
+
strategy: 'reformulate',
|
|
123
|
+
reason: '搜索结果未达标',
|
|
124
|
+
suggestion: '尝试调整查询表达或更换搜索方向',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
qualityScore,
|
|
129
|
+
recentFailures,
|
|
130
|
+
availableStrategies: strategies,
|
|
131
|
+
lastSuccessfulRound,
|
|
132
|
+
roundQualityHistory: history,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// ── Helpers ───────────────────────────────────────────────────────
|
|
136
|
+
/** Find the last round with 'good' verdict in quality history. */
|
|
137
|
+
function findLastSuccessfulRound(history) {
|
|
138
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
139
|
+
if (history[i].verdict === 'good') {
|
|
140
|
+
return {
|
|
141
|
+
round: history[i].round,
|
|
142
|
+
query: history[i].query,
|
|
143
|
+
quality: 'good',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
/** Backtrack via graph traversal: find the query node that yielded
|
|
150
|
+
* the most results connected to high-degree entity nodes.
|
|
151
|
+
* Returns the query and round to backtrack to. */
|
|
152
|
+
export function backtrackToBestQuery(graph) {
|
|
153
|
+
const queryScores = [];
|
|
154
|
+
graph.forEachNode((node, attrs) => {
|
|
155
|
+
if (attrs.type !== 'query' || !attrs.query)
|
|
156
|
+
return;
|
|
157
|
+
let score = 0;
|
|
158
|
+
let resultCount = 0;
|
|
159
|
+
// Walk query → result → entity and sum entity degrees
|
|
160
|
+
graph.forEachOutNeighbor(node, (resultNode) => {
|
|
161
|
+
const rAttrs = graph.getNodeAttributes(resultNode);
|
|
162
|
+
if (rAttrs.type !== 'result')
|
|
163
|
+
return;
|
|
164
|
+
resultCount++;
|
|
165
|
+
graph.forEachInNeighbor(resultNode, (entityNode) => {
|
|
166
|
+
const eAttrs = graph.getNodeAttributes(entityNode);
|
|
167
|
+
if (eAttrs.type === 'entity') {
|
|
168
|
+
score += graph.inDegree(entityNode) + graph.outDegree(entityNode);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
queryScores.push({
|
|
173
|
+
id: node,
|
|
174
|
+
query: attrs.query,
|
|
175
|
+
round: attrs.round ?? 0,
|
|
176
|
+
score: resultCount > 0 ? score / resultCount : 0,
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
if (queryScores.length === 0)
|
|
180
|
+
return null;
|
|
181
|
+
// Sort by score descending, then by round ascending (prefer earlier on tie)
|
|
182
|
+
queryScores.sort((a, b) => b.score - a.score || a.round - b.round);
|
|
183
|
+
return {
|
|
184
|
+
round: queryScores[0].round,
|
|
185
|
+
query: queryScores[0].query,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=recovery-analysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-analysis.js","sourceRoot":"","sources":["../../src/deep/recovery-analysis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two-stage search strategy (GraphWalker-inspired).
|
|
3
|
+
*
|
|
4
|
+
* Stage 1 — Broad Exploration: general engines, wide scope.
|
|
5
|
+
* Stage 2 — Targeted Deep-Dive: specialized engines, obfuscated queries.
|
|
6
|
+
*
|
|
7
|
+
* Transition signal: entity richness growth rate slows below threshold.
|
|
8
|
+
* CLI only outputs stage recommendation — Agent decides whether to follow.
|
|
9
|
+
*/
|
|
10
|
+
import { DirectedGraph } from 'graphology';
|
|
11
|
+
import { GraphNodeAttrs, GraphEdgeAttrs } from './graph.js';
|
|
12
|
+
import { SearchStage } from './query-suggest.js';
|
|
13
|
+
export interface StrategyConfig {
|
|
14
|
+
broadEngines: string[];
|
|
15
|
+
deepEngines: string[];
|
|
16
|
+
broadRounds: number;
|
|
17
|
+
autoTransition: boolean;
|
|
18
|
+
transitionThreshold: number;
|
|
19
|
+
}
|
|
20
|
+
export interface StrategyInfo {
|
|
21
|
+
currentStage: SearchStage;
|
|
22
|
+
recommendedEngines: string[];
|
|
23
|
+
recommendedCategories: string[];
|
|
24
|
+
roundNumber: number;
|
|
25
|
+
growthRate: number;
|
|
26
|
+
transitionReason?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Compute entity richness growth rate between last two rounds.
|
|
29
|
+
* growthRate = (newEntitiesThisRound - newEntitiesLastRound) / max(newEntitiesLastRound, 1)
|
|
30
|
+
* When growth rate slows below threshold, it signals transition to deep-dive. */
|
|
31
|
+
export declare function computeGrowthRate(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>): number;
|
|
32
|
+
/** Determine current search stage based on session state.
|
|
33
|
+
* Returns the stage recommendation — Agent may choose to ignore. */
|
|
34
|
+
export declare function determineSearchStage(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>, config?: Partial<StrategyConfig>): SearchStage;
|
|
35
|
+
/** Get full strategy info for Agent decision-making. */
|
|
36
|
+
export declare function getStrategyInfo(graph: DirectedGraph<GraphNodeAttrs, GraphEdgeAttrs>, config?: Partial<StrategyConfig>): StrategyInfo;
|
|
37
|
+
//# sourceMappingURL=search-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-strategy.d.ts","sourceRoot":"","sources":["../../src/deep/search-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjD,MAAM,WAAW,cAAc;IAC3B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IACzB,YAAY,EAAE,WAAW,CAAC;IAC1B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AA6CD;;kFAEkF;AAClF,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,GACrD,MAAM,CAgBR;AAED;qEACqE;AACrE,wBAAgB,oBAAoB,CAChC,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,EACpD,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GACjC,WAAW,CAkBb;AAED,wDAAwD;AACxD,wBAAgB,eAAe,CAC3B,KAAK,EAAE,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,EACpD,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GACjC,YAAY,CAmBd"}
|