@defai.digital/ax-cli 3.8.7 → 3.8.8
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/README.md +28 -393
- package/config-defaults/settings.yaml +3 -0
- package/dist/agent/llm-agent.d.ts +11 -2
- package/dist/agent/llm-agent.js +73 -104
- package/dist/agent/llm-agent.js.map +1 -1
- package/dist/agent/loop-detector.d.ts +70 -0
- package/dist/agent/loop-detector.js +339 -0
- package/dist/agent/loop-detector.js.map +1 -0
- package/dist/agent/progress-tracker.d.ts +94 -0
- package/dist/agent/progress-tracker.js +222 -0
- package/dist/agent/progress-tracker.js.map +1 -0
- package/dist/agent/status-reporter.js +2 -2
- package/dist/agent/status-reporter.js.map +1 -1
- package/dist/agent/subagent.js +3 -3
- package/dist/agent/subagent.js.map +1 -1
- package/dist/analyzers/git/churn-calculator.js +2 -1
- package/dist/analyzers/git/churn-calculator.js.map +1 -1
- package/dist/checkpoint/storage.js +6 -4
- package/dist/checkpoint/storage.js.map +1 -1
- package/dist/commands/cache.js +8 -6
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/doctor.js +19 -27
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/mcp-migrate.js +6 -5
- package/dist/commands/mcp-migrate.js.map +1 -1
- package/dist/commands/models.js +8 -12
- package/dist/commands/models.js.map +1 -1
- package/dist/commands/plan.js +1 -10
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/setup.js +2 -1
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.js +4 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/constants.d.ts +12 -0
- package/dist/constants.js +16 -4
- package/dist/constants.js.map +1 -1
- package/dist/hooks/hook-runner.d.ts +138 -0
- package/dist/hooks/hook-runner.js +429 -0
- package/dist/hooks/hook-runner.js.map +1 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.js +1 -19
- package/dist/index.js.map +1 -1
- package/dist/llm/tools.js +2 -39
- package/dist/llm/tools.js.map +1 -1
- package/dist/mcp/automatosx-loader.js +2 -1
- package/dist/mcp/automatosx-loader.js.map +1 -1
- package/dist/mcp/config-migrator.js +3 -2
- package/dist/mcp/config-migrator.js.map +1 -1
- package/dist/mcp/config-v2.d.ts +5 -0
- package/dist/mcp/config-v2.js +26 -0
- package/dist/mcp/config-v2.js.map +1 -1
- package/dist/mcp/error-formatter.js +4 -1
- package/dist/mcp/error-formatter.js.map +1 -1
- package/dist/mcp/reconnection.js +2 -1
- package/dist/mcp/reconnection.js.map +1 -1
- package/dist/mcp/registry.js +3 -2
- package/dist/mcp/registry.js.map +1 -1
- package/dist/mcp/resources.js +2 -1
- package/dist/mcp/resources.js.map +1 -1
- package/dist/mcp/validation.js +9 -0
- package/dist/mcp/validation.js.map +1 -1
- package/dist/memory/context-store.js +4 -6
- package/dist/memory/context-store.js.map +1 -1
- package/dist/memory/types.d.ts +2 -0
- package/dist/memory/types.js +4 -1
- package/dist/memory/types.js.map +1 -1
- package/dist/permissions/index.d.ts +6 -0
- package/dist/permissions/index.js +7 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/permissions/permission-manager.d.ts +145 -0
- package/dist/permissions/permission-manager.js +401 -0
- package/dist/permissions/permission-manager.js.map +1 -0
- package/dist/planner/task-planner.js +2 -1
- package/dist/planner/task-planner.js.map +1 -1
- package/dist/schemas/index.d.ts +2 -2
- package/dist/schemas/settings-schemas.d.ts +0 -14
- package/dist/schemas/settings-schemas.js +0 -10
- package/dist/schemas/settings-schemas.js.map +1 -1
- package/dist/schemas/tool-schemas.d.ts +2 -2
- package/dist/schemas/yaml-schemas.d.ts +15 -0
- package/dist/schemas/yaml-schemas.js +3 -0
- package/dist/schemas/yaml-schemas.js.map +1 -1
- package/dist/tools/bash.js +6 -5
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/confirmation-tool.js +3 -2
- package/dist/tools/confirmation-tool.js.map +1 -1
- package/dist/tools/registry.d.ts +1 -1
- package/dist/tools/registry.js +2 -1
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/todo-tool.js +3 -2
- package/dist/tools/todo-tool.js.map +1 -1
- package/dist/ui/components/tool-group-display.js +0 -6
- package/dist/ui/components/tool-group-display.js.map +1 -1
- package/dist/ui/hooks/use-input-handler.js +7 -6
- package/dist/ui/hooks/use-input-handler.js.map +1 -1
- package/dist/ui/hooks/use-input-history.js +4 -4
- package/dist/ui/hooks/use-input-history.js.map +1 -1
- package/dist/ui/utils/tool-grouper.d.ts +1 -2
- package/dist/ui/utils/tool-grouper.js +4 -15
- package/dist/ui/utils/tool-grouper.js.map +1 -1
- package/dist/utils/audit-logger.js +2 -1
- package/dist/utils/audit-logger.js.map +1 -1
- package/dist/utils/config-loader.d.ts +3 -0
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/encryption.js +2 -1
- package/dist/utils/encryption.js.map +1 -1
- package/dist/utils/file-cache.js +4 -2
- package/dist/utils/file-cache.js.map +1 -1
- package/dist/utils/onboarding-manager.js +2 -1
- package/dist/utils/onboarding-manager.js.map +1 -1
- package/dist/utils/path-helpers.js +3 -2
- package/dist/utils/path-helpers.js.map +1 -1
- package/dist/utils/path-security.js +3 -2
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/settings-manager.d.ts +1 -21
- package/dist/utils/settings-manager.js +2 -82
- package/dist/utils/settings-manager.js.map +1 -1
- package/dist/utils/streaming-analyzer.d.ts +2 -13
- package/dist/utils/streaming-analyzer.js +3 -25
- package/dist/utils/streaming-analyzer.js.map +1 -1
- package/dist/utils/token-counter.d.ts +8 -1
- package/dist/utils/token-counter.js +14 -5
- package/dist/utils/token-counter.js.map +1 -1
- package/package.json +3 -2
- package/packages/schemas/README.md +1 -1
- package/packages/schemas/package.json +1 -1
- package/.ax-cli/CUSTOM.md +0 -97
- package/.ax-cli/auto-accept-audit.json +0 -1302
- package/.ax-cli/index.json +0 -43
- package/.ax-cli/memory.json +0 -55
- package/.ax-cli/settings.json +0 -12
- package/ax.config.json +0 -303
- package/dist/tools/web-search/cache.d.ts +0 -62
- package/dist/tools/web-search/cache.js +0 -105
- package/dist/tools/web-search/cache.js.map +0 -1
- package/dist/tools/web-search/engines/crates.d.ts +0 -19
- package/dist/tools/web-search/engines/crates.js +0 -87
- package/dist/tools/web-search/engines/crates.js.map +0 -1
- package/dist/tools/web-search/engines/npm.d.ts +0 -18
- package/dist/tools/web-search/engines/npm.js +0 -86
- package/dist/tools/web-search/engines/npm.js.map +0 -1
- package/dist/tools/web-search/engines/pypi.d.ts +0 -18
- package/dist/tools/web-search/engines/pypi.js +0 -75
- package/dist/tools/web-search/engines/pypi.js.map +0 -1
- package/dist/tools/web-search/engines/stackoverflow.d.ts +0 -30
- package/dist/tools/web-search/engines/stackoverflow.js +0 -130
- package/dist/tools/web-search/engines/stackoverflow.js.map +0 -1
- package/dist/tools/web-search/engines/wikipedia.d.ts +0 -27
- package/dist/tools/web-search/engines/wikipedia.js +0 -112
- package/dist/tools/web-search/engines/wikipedia.js.map +0 -1
- package/dist/tools/web-search/index.d.ts +0 -11
- package/dist/tools/web-search/index.js +0 -11
- package/dist/tools/web-search/index.js.map +0 -1
- package/dist/tools/web-search/router.d.ts +0 -36
- package/dist/tools/web-search/router.js +0 -270
- package/dist/tools/web-search/router.js.map +0 -1
- package/dist/tools/web-search/types.d.ts +0 -45
- package/dist/tools/web-search/types.js +0 -6
- package/dist/tools/web-search/types.js.map +0 -1
- package/dist/tools/web-search/web-search-tool.d.ts +0 -51
- package/dist/tools/web-search/web-search-tool.js +0 -262
- package/dist/tools/web-search/web-search-tool.js.map +0 -1
- package/packages/schemas/dist/index.d.ts +0 -14
- package/packages/schemas/dist/index.d.ts.map +0 -1
- package/packages/schemas/dist/index.js +0 -19
- package/packages/schemas/dist/index.js.map +0 -1
- package/packages/schemas/dist/public/core/brand-types.d.ts +0 -308
- package/packages/schemas/dist/public/core/brand-types.d.ts.map +0 -1
- package/packages/schemas/dist/public/core/brand-types.js +0 -243
- package/packages/schemas/dist/public/core/brand-types.js.map +0 -1
- package/packages/schemas/dist/public/core/enums.d.ts +0 -227
- package/packages/schemas/dist/public/core/enums.d.ts.map +0 -1
- package/packages/schemas/dist/public/core/enums.js +0 -222
- package/packages/schemas/dist/public/core/enums.js.map +0 -1
- package/packages/schemas/dist/public/core/id-types.d.ts +0 -286
- package/packages/schemas/dist/public/core/id-types.d.ts.map +0 -1
- package/packages/schemas/dist/public/core/id-types.js +0 -136
- package/packages/schemas/dist/public/core/id-types.js.map +0 -1
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search Router
|
|
3
|
-
* Detects query intent and routes to appropriate search engines
|
|
4
|
-
*/
|
|
5
|
-
import type { SearchEngine, SearchIntent } from "./types.js";
|
|
6
|
-
export declare class WebSearchRouter {
|
|
7
|
-
private npmEngine;
|
|
8
|
-
private pypiEngine;
|
|
9
|
-
private cratesEngine;
|
|
10
|
-
private stackOverflowEngine;
|
|
11
|
-
private wikipediaEngine;
|
|
12
|
-
private readonly technicalKeywords;
|
|
13
|
-
private readonly codeKeywords;
|
|
14
|
-
private readonly packageKeywords;
|
|
15
|
-
private readonly pythonKeywords;
|
|
16
|
-
private readonly rustKeywords;
|
|
17
|
-
private readonly newsKeywords;
|
|
18
|
-
constructor();
|
|
19
|
-
/**
|
|
20
|
-
* Detect the intent of a search query
|
|
21
|
-
*/
|
|
22
|
-
detectIntent(query: string): SearchIntent;
|
|
23
|
-
/**
|
|
24
|
-
* Select the best search engines for a given intent
|
|
25
|
-
*/
|
|
26
|
-
selectEngines(intent: SearchIntent): SearchEngine[];
|
|
27
|
-
/**
|
|
28
|
-
* Get all available engines
|
|
29
|
-
*/
|
|
30
|
-
getAvailableEngines(): SearchEngine[];
|
|
31
|
-
/**
|
|
32
|
-
* Check if any search engine is available
|
|
33
|
-
* Always returns true because package search engines require no API key
|
|
34
|
-
*/
|
|
35
|
-
hasAvailableEngines(): boolean;
|
|
36
|
-
}
|
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Search Router
|
|
3
|
-
* Detects query intent and routes to appropriate search engines
|
|
4
|
-
*/
|
|
5
|
-
import { NpmSearch } from "./engines/npm.js";
|
|
6
|
-
import { PyPISearch } from "./engines/pypi.js";
|
|
7
|
-
import { CratesSearch } from "./engines/crates.js";
|
|
8
|
-
import { StackOverflowSearch } from "./engines/stackoverflow.js";
|
|
9
|
-
import { WikipediaSearch } from "./engines/wikipedia.js";
|
|
10
|
-
export class WebSearchRouter {
|
|
11
|
-
npmEngine;
|
|
12
|
-
pypiEngine;
|
|
13
|
-
cratesEngine;
|
|
14
|
-
stackOverflowEngine;
|
|
15
|
-
wikipediaEngine;
|
|
16
|
-
// Keywords for intent detection
|
|
17
|
-
technicalKeywords = [
|
|
18
|
-
"error",
|
|
19
|
-
"exception",
|
|
20
|
-
"bug",
|
|
21
|
-
"fix",
|
|
22
|
-
"debug",
|
|
23
|
-
"troubleshoot",
|
|
24
|
-
"code",
|
|
25
|
-
"function",
|
|
26
|
-
"method",
|
|
27
|
-
"class",
|
|
28
|
-
"api",
|
|
29
|
-
"library",
|
|
30
|
-
"framework",
|
|
31
|
-
"npm",
|
|
32
|
-
"package",
|
|
33
|
-
"install",
|
|
34
|
-
"configure",
|
|
35
|
-
"implementation",
|
|
36
|
-
"syntax",
|
|
37
|
-
"typescript",
|
|
38
|
-
"javascript",
|
|
39
|
-
"python",
|
|
40
|
-
"java",
|
|
41
|
-
"rust",
|
|
42
|
-
"go",
|
|
43
|
-
];
|
|
44
|
-
codeKeywords = [
|
|
45
|
-
"code",
|
|
46
|
-
"example",
|
|
47
|
-
"implementation",
|
|
48
|
-
"snippet",
|
|
49
|
-
"sample",
|
|
50
|
-
"github",
|
|
51
|
-
"repository",
|
|
52
|
-
"source",
|
|
53
|
-
"function",
|
|
54
|
-
"class",
|
|
55
|
-
"how to",
|
|
56
|
-
"tutorial",
|
|
57
|
-
];
|
|
58
|
-
packageKeywords = [
|
|
59
|
-
"package",
|
|
60
|
-
"npm",
|
|
61
|
-
"library",
|
|
62
|
-
"module",
|
|
63
|
-
"install",
|
|
64
|
-
"dependency",
|
|
65
|
-
"dependencies",
|
|
66
|
-
"node_modules",
|
|
67
|
-
"yarn",
|
|
68
|
-
"pnpm",
|
|
69
|
-
];
|
|
70
|
-
pythonKeywords = [
|
|
71
|
-
"python",
|
|
72
|
-
"pip",
|
|
73
|
-
"pypi",
|
|
74
|
-
"django",
|
|
75
|
-
"flask",
|
|
76
|
-
"fastapi",
|
|
77
|
-
"pandas",
|
|
78
|
-
"numpy",
|
|
79
|
-
"pytest",
|
|
80
|
-
"virtualenv",
|
|
81
|
-
"conda",
|
|
82
|
-
"poetry",
|
|
83
|
-
];
|
|
84
|
-
rustKeywords = [
|
|
85
|
-
"rust",
|
|
86
|
-
"cargo",
|
|
87
|
-
"crate",
|
|
88
|
-
"crates.io",
|
|
89
|
-
"rustc",
|
|
90
|
-
"tokio",
|
|
91
|
-
"serde",
|
|
92
|
-
"actix",
|
|
93
|
-
"wasm",
|
|
94
|
-
];
|
|
95
|
-
newsKeywords = [
|
|
96
|
-
"news",
|
|
97
|
-
"latest",
|
|
98
|
-
"today",
|
|
99
|
-
"yesterday",
|
|
100
|
-
"recent",
|
|
101
|
-
"update",
|
|
102
|
-
"announcement",
|
|
103
|
-
"release",
|
|
104
|
-
"2025",
|
|
105
|
-
"2024",
|
|
106
|
-
"current",
|
|
107
|
-
"breaking",
|
|
108
|
-
"trending",
|
|
109
|
-
];
|
|
110
|
-
constructor() {
|
|
111
|
-
this.npmEngine = new NpmSearch(); // Always available (no API key)
|
|
112
|
-
this.pypiEngine = new PyPISearch(); // Always available (no API key)
|
|
113
|
-
this.cratesEngine = new CratesSearch(); // Always available (no API key)
|
|
114
|
-
this.stackOverflowEngine = new StackOverflowSearch(); // 300 req/day free
|
|
115
|
-
this.wikipediaEngine = new WikipediaSearch(); // Effectively unlimited
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Detect the intent of a search query
|
|
119
|
-
*/
|
|
120
|
-
detectIntent(query) {
|
|
121
|
-
const lowerQuery = query.toLowerCase();
|
|
122
|
-
const words = lowerQuery.split(/\s+/);
|
|
123
|
-
let technicalScore = 0;
|
|
124
|
-
let codeScore = 0;
|
|
125
|
-
let newsScore = 0;
|
|
126
|
-
let packageScore = 0;
|
|
127
|
-
let pythonScore = 0;
|
|
128
|
-
let rustScore = 0;
|
|
129
|
-
// Count keyword matches
|
|
130
|
-
for (const word of words) {
|
|
131
|
-
if (this.technicalKeywords.some((kw) => word.includes(kw))) {
|
|
132
|
-
technicalScore++;
|
|
133
|
-
}
|
|
134
|
-
if (this.codeKeywords.some((kw) => word.includes(kw))) {
|
|
135
|
-
codeScore++;
|
|
136
|
-
}
|
|
137
|
-
if (this.newsKeywords.some((kw) => word.includes(kw))) {
|
|
138
|
-
newsScore++;
|
|
139
|
-
}
|
|
140
|
-
if (this.packageKeywords.some((kw) => word.includes(kw))) {
|
|
141
|
-
packageScore++;
|
|
142
|
-
}
|
|
143
|
-
if (this.pythonKeywords.some((kw) => word.includes(kw))) {
|
|
144
|
-
pythonScore++;
|
|
145
|
-
}
|
|
146
|
-
if (this.rustKeywords.some((kw) => word.includes(kw))) {
|
|
147
|
-
rustScore++;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
// Determine primary intent
|
|
151
|
-
let type = "general";
|
|
152
|
-
let confidence = 0.5; // Default confidence
|
|
153
|
-
let language = undefined;
|
|
154
|
-
// Detect language first
|
|
155
|
-
if (pythonScore > 0 && pythonScore >= rustScore) {
|
|
156
|
-
language = "python";
|
|
157
|
-
}
|
|
158
|
-
else if (rustScore > 0 && rustScore > pythonScore) {
|
|
159
|
-
language = "rust";
|
|
160
|
-
}
|
|
161
|
-
else if (packageScore > 0) {
|
|
162
|
-
language = "javascript"; // npm implies JavaScript
|
|
163
|
-
}
|
|
164
|
-
// Package search takes priority if npm keywords detected
|
|
165
|
-
if (packageScore > 0 || pythonScore > 0 || rustScore > 0) {
|
|
166
|
-
type = "technical"; // Packages are technical
|
|
167
|
-
confidence = Math.min((packageScore + pythonScore + rustScore) / words.length + 0.6, 1.0);
|
|
168
|
-
}
|
|
169
|
-
else if (newsScore > 0) {
|
|
170
|
-
type = "news";
|
|
171
|
-
confidence = Math.min(newsScore / words.length + 0.5, 1.0);
|
|
172
|
-
}
|
|
173
|
-
else if (codeScore > technicalScore) {
|
|
174
|
-
type = "code";
|
|
175
|
-
confidence = Math.min(codeScore / words.length + 0.5, 1.0);
|
|
176
|
-
}
|
|
177
|
-
else if (technicalScore > 0) {
|
|
178
|
-
type = "technical";
|
|
179
|
-
confidence = Math.min(technicalScore / words.length + 0.5, 1.0);
|
|
180
|
-
}
|
|
181
|
-
return {
|
|
182
|
-
type,
|
|
183
|
-
requiresTechnical: technicalScore > 0 || packageScore > 0 || pythonScore > 0 || rustScore > 0,
|
|
184
|
-
requiresCode: codeScore > 0,
|
|
185
|
-
requiresNews: newsScore > 0,
|
|
186
|
-
confidence,
|
|
187
|
-
language,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Select the best search engines for a given intent
|
|
192
|
-
*/
|
|
193
|
-
selectEngines(intent) {
|
|
194
|
-
const engines = [];
|
|
195
|
-
// Check if query contains package keywords - prioritize language-specific search
|
|
196
|
-
const hasPackageIntent = intent.requiresTechnical && intent.confidence > 0.6;
|
|
197
|
-
// Select engines based on intent type
|
|
198
|
-
switch (intent.type) {
|
|
199
|
-
case "technical":
|
|
200
|
-
case "code":
|
|
201
|
-
// For technical/code queries, Stack Overflow is excellent for "how to" and errors
|
|
202
|
-
if (this.stackOverflowEngine.isAvailable()) {
|
|
203
|
-
engines.push(this.stackOverflowEngine);
|
|
204
|
-
}
|
|
205
|
-
// Route to language-specific package search
|
|
206
|
-
if (hasPackageIntent && intent.language) {
|
|
207
|
-
if (intent.language === "python") {
|
|
208
|
-
engines.push(this.pypiEngine); // Python packages
|
|
209
|
-
}
|
|
210
|
-
else if (intent.language === "rust") {
|
|
211
|
-
engines.push(this.cratesEngine); // Rust crates
|
|
212
|
-
}
|
|
213
|
-
else if (intent.language === "javascript") {
|
|
214
|
-
engines.push(this.npmEngine); // npm packages
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
else if (hasPackageIntent) {
|
|
218
|
-
// Default to npm if language not detected
|
|
219
|
-
engines.push(this.npmEngine);
|
|
220
|
-
}
|
|
221
|
-
break;
|
|
222
|
-
case "news":
|
|
223
|
-
// News queries - use Wikipedia for background context
|
|
224
|
-
engines.push(this.wikipediaEngine);
|
|
225
|
-
break;
|
|
226
|
-
case "general":
|
|
227
|
-
default:
|
|
228
|
-
// General queries - Wikipedia is excellent for "what is" and concepts
|
|
229
|
-
engines.push(this.wikipediaEngine);
|
|
230
|
-
// Also include Stack Overflow for technical general queries
|
|
231
|
-
if (intent.requiresTechnical && this.stackOverflowEngine.isAvailable()) {
|
|
232
|
-
engines.push(this.stackOverflowEngine);
|
|
233
|
-
}
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
// Fallback: ensure we always have at least one engine
|
|
237
|
-
if (engines.length === 0) {
|
|
238
|
-
// Wikipedia is always available and works for most queries
|
|
239
|
-
engines.push(this.wikipediaEngine);
|
|
240
|
-
// npm as secondary fallback for technical queries
|
|
241
|
-
engines.push(this.npmEngine);
|
|
242
|
-
}
|
|
243
|
-
return engines;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Get all available engines
|
|
247
|
-
*/
|
|
248
|
-
getAvailableEngines() {
|
|
249
|
-
const engines = [];
|
|
250
|
-
// Package search engines are always available (no API key required)
|
|
251
|
-
engines.push(this.npmEngine);
|
|
252
|
-
engines.push(this.pypiEngine);
|
|
253
|
-
engines.push(this.cratesEngine);
|
|
254
|
-
// Stack Overflow (300 req/day free, check availability)
|
|
255
|
-
if (this.stackOverflowEngine.isAvailable()) {
|
|
256
|
-
engines.push(this.stackOverflowEngine);
|
|
257
|
-
}
|
|
258
|
-
// Wikipedia is always available (effectively unlimited)
|
|
259
|
-
engines.push(this.wikipediaEngine);
|
|
260
|
-
return engines;
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Check if any search engine is available
|
|
264
|
-
* Always returns true because package search engines require no API key
|
|
265
|
-
*/
|
|
266
|
-
hasAvailableEngines() {
|
|
267
|
-
return true; // npm, PyPI, and crates.io search are always available
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
//# sourceMappingURL=router.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/tools/web-search/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Web Search Types
|
|
3
|
-
* Common interfaces and types for web search functionality
|
|
4
|
-
*/
|
|
5
|
-
export interface WebSearchResult {
|
|
6
|
-
title: string;
|
|
7
|
-
url: string;
|
|
8
|
-
snippet: string;
|
|
9
|
-
source: string;
|
|
10
|
-
relevanceScore?: number;
|
|
11
|
-
publishedDate?: string;
|
|
12
|
-
metadata?: Record<string, any>;
|
|
13
|
-
}
|
|
14
|
-
export interface SearchOptions {
|
|
15
|
-
maxResults?: number;
|
|
16
|
-
includeAnswer?: boolean;
|
|
17
|
-
searchDepth?: "basic" | "advanced";
|
|
18
|
-
freshness?: "day" | "week" | "month" | "year";
|
|
19
|
-
includeDomains?: string[];
|
|
20
|
-
excludeDomains?: string[];
|
|
21
|
-
timeout?: number;
|
|
22
|
-
}
|
|
23
|
-
export interface SearchIntent {
|
|
24
|
-
type: "general" | "technical" | "news" | "code";
|
|
25
|
-
requiresTechnical: boolean;
|
|
26
|
-
requiresCode: boolean;
|
|
27
|
-
requiresNews: boolean;
|
|
28
|
-
confidence: number;
|
|
29
|
-
language?: "javascript" | "python" | "rust";
|
|
30
|
-
}
|
|
31
|
-
export interface SearchEngine {
|
|
32
|
-
name: string;
|
|
33
|
-
search(query: string, options?: SearchOptions): Promise<WebSearchResult[]>;
|
|
34
|
-
isAvailable(): boolean;
|
|
35
|
-
getQuota?(): {
|
|
36
|
-
remaining: number;
|
|
37
|
-
limit: number;
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
export interface SearchEngineResponse {
|
|
41
|
-
results: WebSearchResult[];
|
|
42
|
-
answer?: string;
|
|
43
|
-
totalResults?: number;
|
|
44
|
-
query: string;
|
|
45
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/tools/web-search/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Web Search Tool
|
|
3
|
-
* Main tool for web search functionality in AX CLI
|
|
4
|
-
*/
|
|
5
|
-
import type { ToolResult } from "../../types/index.js";
|
|
6
|
-
import type { SearchOptions } from "./types.js";
|
|
7
|
-
export declare class WebSearchTool {
|
|
8
|
-
private router;
|
|
9
|
-
private cache;
|
|
10
|
-
private readonly DEFAULT_MAX_RESULTS;
|
|
11
|
-
private readonly MAX_RESULTS_LIMIT;
|
|
12
|
-
private readonly MAX_PARALLEL_ENGINES;
|
|
13
|
-
constructor();
|
|
14
|
-
/**
|
|
15
|
-
* Search the web for information
|
|
16
|
-
*/
|
|
17
|
-
search(query: string, options?: SearchOptions): Promise<ToolResult>;
|
|
18
|
-
/**
|
|
19
|
-
* Sanitize search query to prevent injection attacks
|
|
20
|
-
*/
|
|
21
|
-
private sanitizeQuery;
|
|
22
|
-
/**
|
|
23
|
-
* Aggregate and deduplicate results from multiple search engines
|
|
24
|
-
*/
|
|
25
|
-
private aggregateResults;
|
|
26
|
-
/**
|
|
27
|
-
* Get bonus score for specific search engines
|
|
28
|
-
*/
|
|
29
|
-
private getSourceBonus;
|
|
30
|
-
/**
|
|
31
|
-
* Format search results for display
|
|
32
|
-
*/
|
|
33
|
-
private formatResults;
|
|
34
|
-
/**
|
|
35
|
-
* Get cache statistics (for debugging/monitoring)
|
|
36
|
-
*/
|
|
37
|
-
getCacheStats(): {
|
|
38
|
-
keys: number;
|
|
39
|
-
hits: number;
|
|
40
|
-
misses: number;
|
|
41
|
-
hitRate: number;
|
|
42
|
-
};
|
|
43
|
-
/**
|
|
44
|
-
* Clear search cache
|
|
45
|
-
*/
|
|
46
|
-
clearCache(): void;
|
|
47
|
-
/**
|
|
48
|
-
* Check if web search is available
|
|
49
|
-
*/
|
|
50
|
-
isAvailable(): boolean;
|
|
51
|
-
}
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Web Search Tool
|
|
3
|
-
* Main tool for web search functionality in AX CLI
|
|
4
|
-
*/
|
|
5
|
-
import { WebSearchRouter } from "./router.js";
|
|
6
|
-
import { SearchCache } from "./cache.js";
|
|
7
|
-
export class WebSearchTool {
|
|
8
|
-
router;
|
|
9
|
-
cache;
|
|
10
|
-
DEFAULT_MAX_RESULTS = 5;
|
|
11
|
-
MAX_RESULTS_LIMIT = 10;
|
|
12
|
-
MAX_PARALLEL_ENGINES = 3; // Execute up to 3 engines in parallel
|
|
13
|
-
constructor() {
|
|
14
|
-
this.router = new WebSearchRouter();
|
|
15
|
-
this.cache = new SearchCache();
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Search the web for information
|
|
19
|
-
*/
|
|
20
|
-
async search(query, options) {
|
|
21
|
-
try {
|
|
22
|
-
// Validate query
|
|
23
|
-
if (!query || query.trim().length === 0) {
|
|
24
|
-
return {
|
|
25
|
-
success: false,
|
|
26
|
-
error: "Search query cannot be empty",
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
// Sanitize query
|
|
30
|
-
const sanitizedQuery = this.sanitizeQuery(query);
|
|
31
|
-
// Note: hasAvailableEngines() always returns true now because npm, PyPI,
|
|
32
|
-
// and crates.io search are available by default (no API key required).
|
|
33
|
-
// Check cache first
|
|
34
|
-
const cached = this.cache.get(sanitizedQuery);
|
|
35
|
-
if (cached && cached.length > 0) {
|
|
36
|
-
return {
|
|
37
|
-
success: true,
|
|
38
|
-
output: this.formatResults(cached, sanitizedQuery, true),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
// Detect intent and select engines
|
|
42
|
-
const intent = this.router.detectIntent(sanitizedQuery);
|
|
43
|
-
const engines = this.router.selectEngines(intent);
|
|
44
|
-
if (engines.length === 0) {
|
|
45
|
-
return {
|
|
46
|
-
success: false,
|
|
47
|
-
error: "No search engine available",
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
// Prepare search options
|
|
51
|
-
const searchOptions = {
|
|
52
|
-
maxResults: Math.min(options?.maxResults || this.DEFAULT_MAX_RESULTS, this.MAX_RESULTS_LIMIT),
|
|
53
|
-
includeAnswer: options?.includeAnswer ?? true,
|
|
54
|
-
searchDepth: options?.searchDepth || "basic",
|
|
55
|
-
freshness: options?.freshness,
|
|
56
|
-
includeDomains: options?.includeDomains,
|
|
57
|
-
excludeDomains: options?.excludeDomains,
|
|
58
|
-
};
|
|
59
|
-
// Execute searches in parallel across multiple engines
|
|
60
|
-
const parallelCount = Math.min(engines.length, this.MAX_PARALLEL_ENGINES);
|
|
61
|
-
const enginesToUse = engines.slice(0, parallelCount);
|
|
62
|
-
// Execute all searches in parallel
|
|
63
|
-
const searchPromises = enginesToUse.map((engine) => engine
|
|
64
|
-
.search(sanitizedQuery, searchOptions)
|
|
65
|
-
.then((results) => ({ engine: engine.name, results, error: null }))
|
|
66
|
-
.catch((error) => ({
|
|
67
|
-
engine: engine.name,
|
|
68
|
-
results: [],
|
|
69
|
-
error: error.message,
|
|
70
|
-
})));
|
|
71
|
-
const searchResults = await Promise.all(searchPromises);
|
|
72
|
-
const engineErrors = searchResults.filter((r) => r.error);
|
|
73
|
-
// Aggregate and deduplicate results
|
|
74
|
-
const results = this.aggregateResults(searchResults, searchOptions.maxResults || this.DEFAULT_MAX_RESULTS);
|
|
75
|
-
// If every engine failed, surface the errors instead of returning an empty success
|
|
76
|
-
if (results.length === 0 && engineErrors.length === searchResults.length) {
|
|
77
|
-
const errorSummary = engineErrors
|
|
78
|
-
.map((r) => `${r.engine}: ${r.error || 'unknown error'}`)
|
|
79
|
-
.join('; ');
|
|
80
|
-
return {
|
|
81
|
-
success: false,
|
|
82
|
-
error: `All web search engines failed: ${errorSummary}`,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
// Cache results (5 minute TTL)
|
|
86
|
-
if (results.length > 0) {
|
|
87
|
-
this.cache.set(sanitizedQuery, results, 300);
|
|
88
|
-
}
|
|
89
|
-
// Get list of engines that were used
|
|
90
|
-
const enginesUsed = searchResults
|
|
91
|
-
.filter((r) => r.results.length > 0)
|
|
92
|
-
.map((r) => r.engine);
|
|
93
|
-
const engineErrorWarning = engineErrors.length > 0
|
|
94
|
-
? `\n⚠️ Some engines failed: ${engineErrors
|
|
95
|
-
.map((r) => `${r.engine} (${r.error || 'unknown error'})`)
|
|
96
|
-
.join('; ')}`
|
|
97
|
-
: '';
|
|
98
|
-
// Format and return results
|
|
99
|
-
return {
|
|
100
|
-
success: true,
|
|
101
|
-
output: this.formatResults(results, sanitizedQuery, false, intent.type, enginesUsed) + engineErrorWarning,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
// Handle specific error cases
|
|
106
|
-
if (error.message?.includes("timeout")) {
|
|
107
|
-
return {
|
|
108
|
-
success: false,
|
|
109
|
-
error: "Search request timed out. Please try again.",
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
if (error.message?.includes("rate limit")) {
|
|
113
|
-
return {
|
|
114
|
-
success: false,
|
|
115
|
-
error: "Search rate limit exceeded. Please try again later.",
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
if (error.message?.includes("API key")) {
|
|
119
|
-
return {
|
|
120
|
-
success: false,
|
|
121
|
-
error: "Search API authentication failed. Please check your API keys.",
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
// Generic error
|
|
125
|
-
return {
|
|
126
|
-
success: false,
|
|
127
|
-
error: `Web search error: ${error.message}`,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Sanitize search query to prevent injection attacks
|
|
133
|
-
*/
|
|
134
|
-
sanitizeQuery(query) {
|
|
135
|
-
return query
|
|
136
|
-
.replace(/[<>\"\']/g, "") // Remove special characters
|
|
137
|
-
.trim()
|
|
138
|
-
.slice(0, 500); // Max length
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Aggregate and deduplicate results from multiple search engines
|
|
142
|
-
*/
|
|
143
|
-
aggregateResults(searchResults, maxResults) {
|
|
144
|
-
const urlMap = new Map();
|
|
145
|
-
const scores = new Map();
|
|
146
|
-
// Aggregate results from all engines
|
|
147
|
-
for (const { engine, results } of searchResults) {
|
|
148
|
-
results.forEach((result, index) => {
|
|
149
|
-
const url = result.url;
|
|
150
|
-
// Calculate score based on position and source
|
|
151
|
-
// Earlier results and results from multiple engines get higher scores
|
|
152
|
-
const positionScore = maxResults - index;
|
|
153
|
-
const sourceBonus = this.getSourceBonus(engine);
|
|
154
|
-
const score = positionScore + sourceBonus;
|
|
155
|
-
if (!urlMap.has(url)) {
|
|
156
|
-
// New result
|
|
157
|
-
urlMap.set(url, result);
|
|
158
|
-
scores.set(url, score);
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
// Duplicate - boost score (result appears in multiple engines)
|
|
162
|
-
const existingScore = scores.get(url) || 0;
|
|
163
|
-
scores.set(url, existingScore + score * 0.5); // 50% bonus for appearing in multiple sources
|
|
164
|
-
// Merge metadata if the new result has additional info
|
|
165
|
-
const existing = urlMap.get(url);
|
|
166
|
-
if (result.metadata?.answer && !existing.metadata?.answer) {
|
|
167
|
-
existing.metadata = {
|
|
168
|
-
...existing.metadata,
|
|
169
|
-
answer: result.metadata.answer,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
// Sort by score and return top results
|
|
176
|
-
const aggregated = Array.from(urlMap.entries())
|
|
177
|
-
.map(([url, result]) => ({
|
|
178
|
-
result,
|
|
179
|
-
score: scores.get(url) || 0,
|
|
180
|
-
}))
|
|
181
|
-
.sort((a, b) => b.score - a.score)
|
|
182
|
-
.slice(0, maxResults)
|
|
183
|
-
.map(({ result }) => result);
|
|
184
|
-
return aggregated;
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Get bonus score for specific search engines
|
|
188
|
-
*/
|
|
189
|
-
getSourceBonus(engine) {
|
|
190
|
-
// Prioritize certain engines based on reliability
|
|
191
|
-
switch (engine) {
|
|
192
|
-
case "npm":
|
|
193
|
-
case "pypi":
|
|
194
|
-
case "crates.io":
|
|
195
|
-
return 2; // Package registries are authoritative for packages
|
|
196
|
-
default:
|
|
197
|
-
return 0;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Format search results for display
|
|
202
|
-
*/
|
|
203
|
-
formatResults(results, query, fromCache, intentType, enginesUsed) {
|
|
204
|
-
if (results.length === 0) {
|
|
205
|
-
return `No web search results found for "${query}".`;
|
|
206
|
-
}
|
|
207
|
-
let output = `Web search results for "${query}"`;
|
|
208
|
-
// Add cache indicator
|
|
209
|
-
if (fromCache) {
|
|
210
|
-
output += " (cached)";
|
|
211
|
-
}
|
|
212
|
-
// Add intent indicator if available
|
|
213
|
-
if (intentType && intentType !== "general") {
|
|
214
|
-
output += ` [${intentType}]`;
|
|
215
|
-
}
|
|
216
|
-
// Add engines used indicator (for parallel search)
|
|
217
|
-
if (enginesUsed && enginesUsed.length > 1) {
|
|
218
|
-
output += ` [sources: ${enginesUsed.join(", ")}]`;
|
|
219
|
-
}
|
|
220
|
-
output += ":\n\n";
|
|
221
|
-
// Format each result
|
|
222
|
-
results.forEach((result, index) => {
|
|
223
|
-
output += `${index + 1}. **${result.title}**\n`;
|
|
224
|
-
output += ` URL: ${result.url}\n`;
|
|
225
|
-
output += ` ${result.snippet}\n`;
|
|
226
|
-
// Add published date if available
|
|
227
|
-
if (result.publishedDate) {
|
|
228
|
-
output += ` Published: ${result.publishedDate}\n`;
|
|
229
|
-
}
|
|
230
|
-
// Add source indicator
|
|
231
|
-
output += ` Source: ${result.source}\n`;
|
|
232
|
-
output += "\n";
|
|
233
|
-
});
|
|
234
|
-
// Add result count
|
|
235
|
-
if (results.length >= this.MAX_RESULTS_LIMIT) {
|
|
236
|
-
output += `Showing ${results.length} results (maximum). Refine your query for more specific results.\n`;
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
output += `Found ${results.length} result${results.length === 1 ? "" : "s"}.\n`;
|
|
240
|
-
}
|
|
241
|
-
return output.trim();
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Get cache statistics (for debugging/monitoring)
|
|
245
|
-
*/
|
|
246
|
-
getCacheStats() {
|
|
247
|
-
return this.cache.getStats();
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Clear search cache
|
|
251
|
-
*/
|
|
252
|
-
clearCache() {
|
|
253
|
-
this.cache.clear();
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Check if web search is available
|
|
257
|
-
*/
|
|
258
|
-
isAvailable() {
|
|
259
|
-
return this.router.hasAvailableEngines();
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
//# sourceMappingURL=web-search-tool.js.map
|