pi-all-search 1.0.9 → 1.0.11
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/package.json +1 -1
- package/src/config.ts +20 -9
- package/src/router.ts +19 -17
- package/src/web-search.ts +8 -7
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
import { PROVIDERS } from "./providers/index.js";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
|
|
6
|
+
const CONFIG_PATH = join(homedir(), ".pi", "web-search.json");
|
|
2
7
|
|
|
3
8
|
export interface SearchConfig {
|
|
4
9
|
apiKeys: Record<string, string>;
|
|
5
|
-
routing?: {
|
|
6
|
-
finance?: string;
|
|
7
|
-
academic?: string;
|
|
8
|
-
general?: string;
|
|
9
|
-
};
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function loadConfig(): SearchConfig {
|
|
13
|
-
const env = process.env;
|
|
14
13
|
const apiKeys: Record<string, string> = {};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const config = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
|
|
17
|
+
for (const meta of PROVIDERS) {
|
|
18
|
+
const key = config[meta.name + "ApiKey"];
|
|
19
|
+
if (key) apiKeys[meta.name] = key;
|
|
20
|
+
}
|
|
21
|
+
} catch {
|
|
22
|
+
// fallback to env vars
|
|
23
|
+
const env = process.env;
|
|
24
|
+
for (const meta of PROVIDERS) {
|
|
25
|
+
const key = env[meta.envVar];
|
|
26
|
+
if (key) apiKeys[meta.name] = key;
|
|
27
|
+
}
|
|
18
28
|
}
|
|
29
|
+
|
|
19
30
|
return { apiKeys };
|
|
20
31
|
}
|
|
21
32
|
|
package/src/router.ts
CHANGED
|
@@ -10,23 +10,21 @@ export interface RoutingConfig {
|
|
|
10
10
|
|
|
11
11
|
export function classifyIntent(query: string): SearchIntent {
|
|
12
12
|
const q = query.toLowerCase();
|
|
13
|
-
|
|
14
13
|
if (/\b(stock|price|ticker|forex|crypto|market|trade|earnings|fund|etf|ipo)\b/.test(q)) return "finance";
|
|
15
14
|
if (/\b(paper|research|journal|doi|arxiv|scholar|academic|study|thesis)\b/.test(q)) return "academic";
|
|
16
15
|
if (/\b(doc|docs|documentation|library|framework|api|sdk|how to|example|syntax|function|method|class|component)\b/.test(q)) return "docs";
|
|
17
16
|
if (/\b(code|github|repo|repository|pull request|commit|branch|merge)\b/.test(q)) return "technical";
|
|
18
17
|
if (/\b(news|latest|today|breaking|announced|update|release|happened)\b/.test(q)) return "news";
|
|
19
|
-
|
|
20
18
|
return "general";
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
const INTENT_PROVIDERS: Record<SearchIntent,
|
|
24
|
-
finance:
|
|
25
|
-
academic:
|
|
26
|
-
docs:
|
|
27
|
-
technical:
|
|
28
|
-
news:
|
|
29
|
-
general:
|
|
21
|
+
const INTENT_PROVIDERS: Record<SearchIntent, string[]> = {
|
|
22
|
+
finance: ["anysearch", "exa", "tavily"],
|
|
23
|
+
academic: ["exa", "anysearch", "tavily"],
|
|
24
|
+
docs: ["context7", "exa", "tavily"],
|
|
25
|
+
technical: ["firecrawl", "exa", "tavily"],
|
|
26
|
+
news: ["tavily", "anysearch", "exa"],
|
|
27
|
+
general: ["tavily", "anysearch", "exa", "firecrawl"],
|
|
30
28
|
};
|
|
31
29
|
|
|
32
30
|
export function routeIntent(
|
|
@@ -35,20 +33,24 @@ export function routeIntent(
|
|
|
35
33
|
requestedProvider?: string,
|
|
36
34
|
): RoutingConfig {
|
|
37
35
|
if (requestedProvider && providers.has(requestedProvider)) {
|
|
36
|
+
const secondary = [...providers.keys()].filter((k) => k !== requestedProvider);
|
|
37
|
+
return { primary: requestedProvider, secondary, intent };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const candidates = INTENT_PROVIDERS[intent];
|
|
41
|
+
const available = candidates.filter((p) => providers.has(p));
|
|
42
|
+
|
|
43
|
+
if (available.length === 0) {
|
|
44
|
+
const allAvailable = [...providers.keys()];
|
|
38
45
|
return {
|
|
39
|
-
primary:
|
|
40
|
-
secondary:
|
|
46
|
+
primary: allAvailable[0] ?? "tavily",
|
|
47
|
+
secondary: allAvailable.slice(1),
|
|
41
48
|
intent,
|
|
42
49
|
};
|
|
43
50
|
}
|
|
44
51
|
|
|
45
|
-
const config = INTENT_PROVIDERS[intent];
|
|
46
|
-
const available = config.primary === "anysearch" && !providers.has("anysearch")
|
|
47
|
-
? config.secondary.filter((p) => providers.has(p))
|
|
48
|
-
: [config.primary, ...config.secondary].filter((p) => providers.has(p));
|
|
49
|
-
|
|
50
52
|
return {
|
|
51
|
-
primary: available[0]
|
|
53
|
+
primary: available[0],
|
|
52
54
|
secondary: available.slice(1),
|
|
53
55
|
intent,
|
|
54
56
|
};
|
package/src/web-search.ts
CHANGED
|
@@ -121,18 +121,19 @@ export function registerWebSearchTool(pi: ExtensionAPI): void {
|
|
|
121
121
|
name: "web_search",
|
|
122
122
|
label: "Web Search",
|
|
123
123
|
description:
|
|
124
|
-
"Search the web with
|
|
124
|
+
"Search the web with 5 providers (exa, tavily, anysearch, firecrawl, context7). Choose the right provider based on query type. Falls back automatically if the primary provider fails. Use web_fetch for full page content. Use queries (plural) for parallel multi-angle research.",
|
|
125
125
|
promptSnippet:
|
|
126
126
|
"Search the web with automatic or custom routing (set provider='exa' for papers, provider='anysearch' for finance, provider='tavily' for general, provider='context7' for docs).",
|
|
127
127
|
get promptGuidelines() {
|
|
128
128
|
return [
|
|
129
129
|
"Use web_search for information beyond your training data — current events, recent docs, live data.",
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
130
|
+
"Choose the right provider based on the query type:",
|
|
131
|
+
" • context7 — library/framework/API documentation, code examples, how-to guides, syntax questions",
|
|
132
|
+
" • exa — academic research papers, journals, DOIs, scholarly articles, theses",
|
|
133
|
+
" • anysearch — stock prices, tickers, forex, crypto, CVE vulnerabilities, financial data",
|
|
134
|
+
" • firecrawl — scraping-heavy sites, code repos, GitHub content, when others fail",
|
|
135
|
+
" • tavily — general web search, news, programming guides, fast results (default)",
|
|
136
|
+
"Set provider='auto' to let the local intent router decide automatically.",
|
|
136
137
|
"After answering, include a \"Sources:\" section with markdown hyperlinks: [Title](URL).",
|
|
137
138
|
"Use web_fetch after web_search to read full page content — web_search returns snippets only.",
|
|
138
139
|
"Use {queries:[...]} with 2-4 varied angles for broader coverage.",
|