chat-agent-toolkit 1.2.32 → 1.2.34
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/research-agent.cjs.js +1 -1
- package/dist/research-agent.cjs.js.map +1 -1
- package/dist/research-agent.es.js +1 -1
- package/dist/research-agent.es.js.map +1 -1
- package/package.json +1 -1
- package/src/config/config-manager.ts +295 -295
- package/src/config/config-types.ts +65 -65
- package/src/config/environment-variables.ts +16 -16
- package/src/config/index.ts +26 -26
- package/src/config/language-models-database.ts +1434 -1434
- package/src/config/mcp-server-registry.ts +24 -24
- package/src/config/model-registry.ts +271 -271
- package/src/config/model-tester.ts +211 -211
- package/src/config/model-utils.ts +193 -193
- package/src/config/provider-ui-config.ts +196 -196
- package/src/connectors/open-connector.json +130 -130
- package/src/index.ts +26 -26
- package/src/memory/ARCHITECTURE.md +302 -302
- package/src/memory/README.md +224 -224
- package/src/memory/agent-memory-manager.ts +416 -416
- package/src/memory/example.ts +343 -343
- package/src/memory/index.ts +47 -47
- package/src/memory/mastra-integration.ts +604 -604
- package/src/memory/storage/drizzle-storage.ts +236 -236
- package/src/memory/storage/in-memory-storage.ts +551 -551
- package/src/memory/storage/storage-interface.ts +68 -68
- package/src/memory/types.ts +125 -125
- package/src/models/types.ts +4 -4
- package/src/provider-logos/01-ai.png +0 -0
- package/src/provider-logos/anthropic.png +0 -0
- package/src/provider-logos/aws-bedrock.png +0 -0
- package/src/provider-logos/aws-sagemaker.png +0 -0
- package/src/provider-logos/azure-openai-service.png +0 -0
- package/src/provider-logos/chatglm.png +0 -0
- package/src/provider-logos/cohere.png +0 -0
- package/src/provider-logos/gemini.png +0 -0
- package/src/provider-logos/groqcloud.png +0 -0
- package/src/provider-logos/huggingface.png +0 -0
- package/src/provider-logos/jina.png +0 -0
- package/src/provider-logos/localai.png +0 -0
- package/src/provider-logos/mistral-ai.png +0 -0
- package/src/provider-logos/moonshot-ai.png +0 -0
- package/src/provider-logos/ollama.png +0 -0
- package/src/provider-logos/openai.png +0 -0
- package/src/provider-logos/openllm.png +0 -0
- package/src/provider-logos/openrouter.png +0 -0
- package/src/provider-logos/replicate.png +0 -0
- package/src/provider-logos/together-ai.png +0 -0
- package/src/provider-logos/tongyi.png +0 -0
- package/src/provider-logos/xorbits-inference.png +0 -0
- package/src/provider-logos/zhipu-ai.png +0 -0
- package/src/tools/index.ts +13 -13
- package/src/tools/open-connector-mastra.ts +270 -270
- package/src/tools/open-connector-mcp.ts +170 -170
- package/src/tools/qwksearch-api-tools.ts +326 -326
- package/src/tools/search/doc-utils.ts +139 -139
- package/src/tools/search/document.ts +47 -47
- package/src/tools/search/index.ts +14 -14
- package/src/tools/search/link-summarizer.ts +112 -112
- package/src/tools/search/meta-search-types.ts +62 -62
- package/src/tools/search/metaSearchAgent.ts +465 -465
- package/src/tools/search/search-handlers.ts +97 -97
- package/src/tools/search/suggestionGeneratorAgent.ts +56 -56
- package/src/types.d.ts +137 -137
- package/src/utils/index.ts +2 -2
- package/src/utils/markdown-to-html.ts +53 -53
- package/src/utils/outputParser.ts +73 -73
|
@@ -1,327 +1,327 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Specialized tools for AI agents to interact with the QwkSearch API.
|
|
3
|
-
* Provides web search, content extraction, and AI response generation.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// @ts-nocheck
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
import * as QwkSearch from 'qwksearch-api-client'; // Update this path to match your QwkSearch module location
|
|
9
|
-
|
|
10
|
-
// Configuration for QwkSearch API
|
|
11
|
-
const QWKSEARCH_CONFIG = {
|
|
12
|
-
baseURL: typeof process !== "undefined" && process?.env.QWKSEARCH_URL || 'https://app.qwksearch.com/api',
|
|
13
|
-
apiKey: typeof process !== "undefined" && process?.env.QWKSEARCH_API_KEY || null,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* List of tools available for agent usage, including their schemas and implementation.
|
|
18
|
-
*/
|
|
19
|
-
export const AGENT_TOOLS = [
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
name: "web_search",
|
|
23
|
-
description:
|
|
24
|
-
"Search the web for information on any topic using QwkSearch API. Input: search query string and optional category. Returns relevant search results with titles, descriptions, and URLs from 100+ sources via SearXNG metasearch engine.",
|
|
25
|
-
schema: z.object({
|
|
26
|
-
query: z.string(),
|
|
27
|
-
category: z.enum(["general", "news", "videos", "images", "science", "files", "it"]).optional().default("general"),
|
|
28
|
-
recency: z.enum(["none", "day", "week", "month", "year"]).optional().default("none"),
|
|
29
|
-
page: z.number().optional().default(1),
|
|
30
|
-
language: z.string().optional().default("en-US"),
|
|
31
|
-
public: z.boolean().optional().default(false),
|
|
32
|
-
timeout: z.number().optional().default(10),
|
|
33
|
-
baseURL: z.string().optional(),
|
|
34
|
-
apiKey: z.string().optional()
|
|
35
|
-
}),
|
|
36
|
-
func: async ({ query, category = "general", recency = "none", page = 1, language = "en-US", public: isPublic = false, timeout = 10, baseURL, apiKey }) => {
|
|
37
|
-
try {
|
|
38
|
-
// Use provided config or fall back to environment/defaults
|
|
39
|
-
const baseUrl = baseURL || QWKSEARCH_CONFIG.baseURL;
|
|
40
|
-
const headers = apiKey || QWKSEARCH_CONFIG.apiKey ? { 'x-api-key': apiKey || QWKSEARCH_CONFIG.apiKey } : undefined;
|
|
41
|
-
|
|
42
|
-
const result = await QwkSearch.searchWeb({
|
|
43
|
-
query: {
|
|
44
|
-
q: query,
|
|
45
|
-
cat: category,
|
|
46
|
-
recency: recency,
|
|
47
|
-
page: page,
|
|
48
|
-
lang: language,
|
|
49
|
-
public: isPublic,
|
|
50
|
-
timeout: timeout
|
|
51
|
-
},
|
|
52
|
-
baseUrl: baseUrl,
|
|
53
|
-
...(headers && { headers })
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
if (!result.data || !result.data.results || result.data.results.length === 0) {
|
|
57
|
-
return `No search results found for "${query}". Please try a different search term.`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let resultText = `Web search results for "${query}" (${category} category):\n\n`;
|
|
61
|
-
|
|
62
|
-
result.data.results.forEach((searchResult, index) => {
|
|
63
|
-
resultText += `${index + 1}. ${searchResult.title}\n`;
|
|
64
|
-
resultText += ` URL: ${searchResult.url}\n`;
|
|
65
|
-
if (searchResult.domain) {
|
|
66
|
-
resultText += ` Domain: ${searchResult.domain}\n`;
|
|
67
|
-
}
|
|
68
|
-
if (searchResult.snippet) {
|
|
69
|
-
resultText += ` Description: ${searchResult.snippet}\n`;
|
|
70
|
-
}
|
|
71
|
-
if (searchResult.engines && searchResult.engines.length > 0) {
|
|
72
|
-
resultText += ` Sources: ${searchResult.engines.join(", ")}\n`;
|
|
73
|
-
}
|
|
74
|
-
resultText += `\n`;
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
resultText += `Found ${result.data.results.length} results from multiple search engines. This is the complete search information.`;
|
|
78
|
-
|
|
79
|
-
return resultText;
|
|
80
|
-
} catch (error) {
|
|
81
|
-
return `Unable to perform web search for "${query}". Error: ${error.message}`;
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: "extract_page",
|
|
87
|
-
description:
|
|
88
|
-
"Extract and summarize content from a web page using QwkSearch API. Supports articles, PDFs, and YouTube videos. Uses Mozilla Readability and Postlight Mercury algorithms with 100+ custom adapters for major sites. Input: URL of the page to extract. Returns structured content with citation information.",
|
|
89
|
-
schema: z.object({
|
|
90
|
-
url: z.string().url(),
|
|
91
|
-
images: z.boolean().optional().default(true),
|
|
92
|
-
links: z.boolean().optional().default(true),
|
|
93
|
-
formatting: z.boolean().optional().default(true),
|
|
94
|
-
absoluteURLs: z.boolean().optional().default(true),
|
|
95
|
-
timeout: z.number().min(1).max(30).optional().default(10),
|
|
96
|
-
baseURL: z.string().optional(),
|
|
97
|
-
apiKey: z.string().optional()
|
|
98
|
-
}),
|
|
99
|
-
func: async ({ url, images = true, links = true, formatting = true, absoluteURLs = true, timeout = 10, baseURL, apiKey }) => {
|
|
100
|
-
try {
|
|
101
|
-
// Use provided config or fall back to environment/defaults
|
|
102
|
-
const baseUrl = baseURL || QWKSEARCH_CONFIG.baseURL;
|
|
103
|
-
const headers = apiKey || QWKSEARCH_CONFIG.apiKey ? { 'x-api-key': apiKey || QWKSEARCH_CONFIG.apiKey } : undefined;
|
|
104
|
-
|
|
105
|
-
const result = await QwkSearch.extractContent({
|
|
106
|
-
query: {
|
|
107
|
-
url: url,
|
|
108
|
-
images: images,
|
|
109
|
-
links: links,
|
|
110
|
-
formatting: formatting,
|
|
111
|
-
absoluteURLs: absoluteURLs,
|
|
112
|
-
timeout: timeout
|
|
113
|
-
},
|
|
114
|
-
baseUrl: baseUrl,
|
|
115
|
-
...(headers && { headers })
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (!result.data) {
|
|
119
|
-
return `No content could be extracted from "${url}". Please check the URL and try again.`;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const data = result.data;
|
|
123
|
-
|
|
124
|
-
let resultText = `Content extracted from: ${data.url || url}\n\n`;
|
|
125
|
-
|
|
126
|
-
if (data.title) {
|
|
127
|
-
resultText += `Title: ${data.title}\n\n`;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (data.author) {
|
|
131
|
-
resultText += `Author: ${data.author}\n`;
|
|
132
|
-
if (data.author_cite) {
|
|
133
|
-
resultText += `Author (Citation Format): ${data.author_cite}\n`;
|
|
134
|
-
}
|
|
135
|
-
if (data.author_type) {
|
|
136
|
-
resultText += `Author Type: ${data.author_type}\n`;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (data.date) {
|
|
141
|
-
resultText += `Publication Date: ${data.date}\n`;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (data.source) {
|
|
145
|
-
resultText += `Source: ${data.source}\n`;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (data.word_count) {
|
|
149
|
-
resultText += `Word Count: ${data.word_count}\n`;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (data.cite) {
|
|
153
|
-
resultText += `\nCitation (APA Format): ${data.cite}\n`;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (data.html) {
|
|
157
|
-
resultText += `\nContent:\n${data.html}\n\n`;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
resultText += `This is the complete page extraction information.`;
|
|
161
|
-
|
|
162
|
-
return resultText;
|
|
163
|
-
} catch (error) {
|
|
164
|
-
return `Unable to extract content from "${url}". Error: ${error.message}`;
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
name: "generate_ai_response",
|
|
170
|
-
description:
|
|
171
|
-
"Generate AI language model responses using QwkSearch API with various agent templates. Supports multiple providers (Groq, OpenAI, Anthropic, etc.) and agent types for different tasks like summarization, question answering, and content generation.",
|
|
172
|
-
schema: z.object({
|
|
173
|
-
provider: z.enum(["groq", "openai", "anthropic", "together", "xai", "google", "perplexity", "cloudflare"]),
|
|
174
|
-
key: z.string().optional(),
|
|
175
|
-
agent: z.enum([
|
|
176
|
-
"question",
|
|
177
|
-
"summarize-bullets",
|
|
178
|
-
"summarize",
|
|
179
|
-
"suggest-followups",
|
|
180
|
-
"answer-cite-sources",
|
|
181
|
-
"query-resolution",
|
|
182
|
-
"knowledge-graph-nodes",
|
|
183
|
-
"summary-longtext"
|
|
184
|
-
]).optional().default("question"),
|
|
185
|
-
model: z.string().optional().default("meta-llama/llama-4-maverick-17b-128e-instruct"),
|
|
186
|
-
temperature: z.number().min(0).max(2).optional().default(0.7),
|
|
187
|
-
html: z.boolean().optional().default(true),
|
|
188
|
-
query: z.string().optional(),
|
|
189
|
-
chat_history: z.string().optional(),
|
|
190
|
-
article: z.string().optional(),
|
|
191
|
-
baseURL: z.string().optional(),
|
|
192
|
-
apiKey: z.string().optional()
|
|
193
|
-
}),
|
|
194
|
-
func: async ({ provider, key, agent = "question", model = "meta-llama/llama-4-maverick-17b-128e-instruct", temperature = 0.7, html = true, query, chat_history, article, baseURL, apiKey }) => {
|
|
195
|
-
try {
|
|
196
|
-
// Use provided config or fall back to environment/defaults
|
|
197
|
-
const baseUrl = baseURL || QWKSEARCH_CONFIG.baseURL;
|
|
198
|
-
const headers = apiKey || QWKSEARCH_CONFIG.apiKey ? { 'x-api-key': apiKey || QWKSEARCH_CONFIG.apiKey } : undefined;
|
|
199
|
-
|
|
200
|
-
const requestBody = {
|
|
201
|
-
agent,
|
|
202
|
-
provider,
|
|
203
|
-
model,
|
|
204
|
-
html,
|
|
205
|
-
temperature
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
if (key) {
|
|
209
|
-
requestBody.key = key;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (query) {
|
|
213
|
-
requestBody.query = query;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (chat_history) {
|
|
217
|
-
requestBody.chat_history = chat_history;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (article) {
|
|
221
|
-
requestBody.article = article;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const result = await QwkSearch.writeLanguage({
|
|
225
|
-
body: requestBody,
|
|
226
|
-
baseUrl: baseUrl,
|
|
227
|
-
...(headers && { headers })
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
if (!result.data) {
|
|
231
|
-
return `No response generated. Please check your input parameters and try again.`;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
let resultText = `AI Response (${agent} agent, ${provider} provider):\n\n`;
|
|
235
|
-
|
|
236
|
-
if (result.data.content) {
|
|
237
|
-
resultText += result.data.content;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (result.data.extract) {
|
|
241
|
-
resultText += `\n\nStructured Extract:\n${JSON.stringify(result.data.extract, null, 2)}`;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
resultText += `\n\nThis is the complete AI-generated response.`;
|
|
245
|
-
|
|
246
|
-
return resultText;
|
|
247
|
-
} catch (error) {
|
|
248
|
-
return `Unable to generate AI response. Error: ${error.message}`;
|
|
249
|
-
}
|
|
250
|
-
},
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
name: "render_page_with_javascript",
|
|
254
|
-
description:
|
|
255
|
-
"Render a web page with JavaScript execution using Cloudflare Browser Rendering. Use this for JavaScript-heavy sites (SPAs, React apps), pages behind bot protection (Cloudflare, reCAPTCHA), or when extract_page fails. Returns fully rendered HTML with JavaScript executed. Slower but more complete than extract_page.",
|
|
256
|
-
schema: z.object({
|
|
257
|
-
url: z.string().url(),
|
|
258
|
-
blockImages: z.boolean().optional().default(true),
|
|
259
|
-
wait: z.number().min(0).max(10000).optional().default(0),
|
|
260
|
-
timeout: z.number().min(1000).max(60000).optional().default(30000),
|
|
261
|
-
waitUntil: z.enum(["domcontentloaded", "load", "networkidle0", "networkidle2"]).optional().default("networkidle2"),
|
|
262
|
-
bypassCaptcha: z.boolean().optional().default(true),
|
|
263
|
-
sessionId: z.string().optional().default("default"),
|
|
264
|
-
format: z.enum(["html", "json"]).optional().default("html"),
|
|
265
|
-
scraperUrl: z.string().optional(),
|
|
266
|
-
scraperApiKey: z.string().optional()
|
|
267
|
-
}),
|
|
268
|
-
func: async ({ url, blockImages = true, wait = 0, timeout = 30000, waitUntil = "networkidle2", bypassCaptcha = true, sessionId = "default", format = "html", scraperUrl, scraperApiKey }) => {
|
|
269
|
-
try {
|
|
270
|
-
const scraperEndpoint = scraperUrl || (typeof process !== "undefined" && process?.env?.SCRAPER_URL) || 'https://scraper.qwksearch.workers.dev';
|
|
271
|
-
const apiKey = scraperApiKey || (typeof process !== "undefined" && process?.env?.SCRAPER_API_KEY);
|
|
272
|
-
|
|
273
|
-
const requestUrl = new URL('/api/render', scraperEndpoint);
|
|
274
|
-
|
|
275
|
-
const body = {
|
|
276
|
-
url,
|
|
277
|
-
blockImages,
|
|
278
|
-
wait,
|
|
279
|
-
timeout,
|
|
280
|
-
waitUntil,
|
|
281
|
-
bypassCaptcha,
|
|
282
|
-
sessionId,
|
|
283
|
-
format
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const headers: Record<string, string> = {
|
|
287
|
-
'Content-Type': 'application/json',
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
if (apiKey) {
|
|
291
|
-
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const response = await fetch(requestUrl.toString(), {
|
|
295
|
-
method: 'POST',
|
|
296
|
-
headers,
|
|
297
|
-
body: JSON.stringify(body),
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
if (!response.ok) {
|
|
301
|
-
const errorText = await response.text();
|
|
302
|
-
return `Failed to render page: ${errorText}`;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (format === 'json') {
|
|
306
|
-
const data = await response.json();
|
|
307
|
-
let resultText = `Page rendered successfully: ${data.url}\n\n`;
|
|
308
|
-
if (data.title) {
|
|
309
|
-
resultText += `Title: ${data.title}\n`;
|
|
310
|
-
}
|
|
311
|
-
resultText += `Load Time: ${data.loadTime}ms\n`;
|
|
312
|
-
if (data.challengeBypassed) {
|
|
313
|
-
resultText += `Challenge Bypassed: Yes (${data.retryCount} retries)\n`;
|
|
314
|
-
}
|
|
315
|
-
resultText += `\nRendered HTML Content:\n${data.html}\n\n`;
|
|
316
|
-
resultText += `This is the complete rendered page content.`;
|
|
317
|
-
return resultText;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const html = await response.text();
|
|
321
|
-
return `Page rendered successfully.\n\nHTML Content:\n${html}`;
|
|
322
|
-
} catch (error) {
|
|
323
|
-
return `Unable to render page "${url}". Error: ${error.message}`;
|
|
324
|
-
}
|
|
325
|
-
},
|
|
326
|
-
},
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Specialized tools for AI agents to interact with the QwkSearch API.
|
|
3
|
+
* Provides web search, content extraction, and AI response generation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// @ts-nocheck
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import * as QwkSearch from 'qwksearch-api-client'; // Update this path to match your QwkSearch module location
|
|
9
|
+
|
|
10
|
+
// Configuration for QwkSearch API
|
|
11
|
+
const QWKSEARCH_CONFIG = {
|
|
12
|
+
baseURL: typeof process !== "undefined" && process?.env.QWKSEARCH_URL || 'https://app.qwksearch.com/api',
|
|
13
|
+
apiKey: typeof process !== "undefined" && process?.env.QWKSEARCH_API_KEY || null,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* List of tools available for agent usage, including their schemas and implementation.
|
|
18
|
+
*/
|
|
19
|
+
export const AGENT_TOOLS = [
|
|
20
|
+
|
|
21
|
+
{
|
|
22
|
+
name: "web_search",
|
|
23
|
+
description:
|
|
24
|
+
"Search the web for information on any topic using QwkSearch API. Input: search query string and optional category. Returns relevant search results with titles, descriptions, and URLs from 100+ sources via SearXNG metasearch engine.",
|
|
25
|
+
schema: z.object({
|
|
26
|
+
query: z.string(),
|
|
27
|
+
category: z.enum(["general", "news", "videos", "images", "science", "files", "it"]).optional().default("general"),
|
|
28
|
+
recency: z.enum(["none", "day", "week", "month", "year"]).optional().default("none"),
|
|
29
|
+
page: z.number().optional().default(1),
|
|
30
|
+
language: z.string().optional().default("en-US"),
|
|
31
|
+
public: z.boolean().optional().default(false),
|
|
32
|
+
timeout: z.number().optional().default(10),
|
|
33
|
+
baseURL: z.string().optional(),
|
|
34
|
+
apiKey: z.string().optional()
|
|
35
|
+
}),
|
|
36
|
+
func: async ({ query, category = "general", recency = "none", page = 1, language = "en-US", public: isPublic = false, timeout = 10, baseURL, apiKey }) => {
|
|
37
|
+
try {
|
|
38
|
+
// Use provided config or fall back to environment/defaults
|
|
39
|
+
const baseUrl = baseURL || QWKSEARCH_CONFIG.baseURL;
|
|
40
|
+
const headers = apiKey || QWKSEARCH_CONFIG.apiKey ? { 'x-api-key': apiKey || QWKSEARCH_CONFIG.apiKey } : undefined;
|
|
41
|
+
|
|
42
|
+
const result = await QwkSearch.searchWeb({
|
|
43
|
+
query: {
|
|
44
|
+
q: query,
|
|
45
|
+
cat: category,
|
|
46
|
+
recency: recency,
|
|
47
|
+
page: page,
|
|
48
|
+
lang: language,
|
|
49
|
+
public: isPublic,
|
|
50
|
+
timeout: timeout
|
|
51
|
+
},
|
|
52
|
+
baseUrl: baseUrl,
|
|
53
|
+
...(headers && { headers })
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!result.data || !result.data.results || result.data.results.length === 0) {
|
|
57
|
+
return `No search results found for "${query}". Please try a different search term.`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let resultText = `Web search results for "${query}" (${category} category):\n\n`;
|
|
61
|
+
|
|
62
|
+
result.data.results.forEach((searchResult, index) => {
|
|
63
|
+
resultText += `${index + 1}. ${searchResult.title}\n`;
|
|
64
|
+
resultText += ` URL: ${searchResult.url}\n`;
|
|
65
|
+
if (searchResult.domain) {
|
|
66
|
+
resultText += ` Domain: ${searchResult.domain}\n`;
|
|
67
|
+
}
|
|
68
|
+
if (searchResult.snippet) {
|
|
69
|
+
resultText += ` Description: ${searchResult.snippet}\n`;
|
|
70
|
+
}
|
|
71
|
+
if (searchResult.engines && searchResult.engines.length > 0) {
|
|
72
|
+
resultText += ` Sources: ${searchResult.engines.join(", ")}\n`;
|
|
73
|
+
}
|
|
74
|
+
resultText += `\n`;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
resultText += `Found ${result.data.results.length} results from multiple search engines. This is the complete search information.`;
|
|
78
|
+
|
|
79
|
+
return resultText;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
return `Unable to perform web search for "${query}". Error: ${error.message}`;
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "extract_page",
|
|
87
|
+
description:
|
|
88
|
+
"Extract and summarize content from a web page using QwkSearch API. Supports articles, PDFs, and YouTube videos. Uses Mozilla Readability and Postlight Mercury algorithms with 100+ custom adapters for major sites. Input: URL of the page to extract. Returns structured content with citation information.",
|
|
89
|
+
schema: z.object({
|
|
90
|
+
url: z.string().url(),
|
|
91
|
+
images: z.boolean().optional().default(true),
|
|
92
|
+
links: z.boolean().optional().default(true),
|
|
93
|
+
formatting: z.boolean().optional().default(true),
|
|
94
|
+
absoluteURLs: z.boolean().optional().default(true),
|
|
95
|
+
timeout: z.number().min(1).max(30).optional().default(10),
|
|
96
|
+
baseURL: z.string().optional(),
|
|
97
|
+
apiKey: z.string().optional()
|
|
98
|
+
}),
|
|
99
|
+
func: async ({ url, images = true, links = true, formatting = true, absoluteURLs = true, timeout = 10, baseURL, apiKey }) => {
|
|
100
|
+
try {
|
|
101
|
+
// Use provided config or fall back to environment/defaults
|
|
102
|
+
const baseUrl = baseURL || QWKSEARCH_CONFIG.baseURL;
|
|
103
|
+
const headers = apiKey || QWKSEARCH_CONFIG.apiKey ? { 'x-api-key': apiKey || QWKSEARCH_CONFIG.apiKey } : undefined;
|
|
104
|
+
|
|
105
|
+
const result = await QwkSearch.extractContent({
|
|
106
|
+
query: {
|
|
107
|
+
url: url,
|
|
108
|
+
images: images,
|
|
109
|
+
links: links,
|
|
110
|
+
formatting: formatting,
|
|
111
|
+
absoluteURLs: absoluteURLs,
|
|
112
|
+
timeout: timeout
|
|
113
|
+
},
|
|
114
|
+
baseUrl: baseUrl,
|
|
115
|
+
...(headers && { headers })
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (!result.data) {
|
|
119
|
+
return `No content could be extracted from "${url}". Please check the URL and try again.`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const data = result.data;
|
|
123
|
+
|
|
124
|
+
let resultText = `Content extracted from: ${data.url || url}\n\n`;
|
|
125
|
+
|
|
126
|
+
if (data.title) {
|
|
127
|
+
resultText += `Title: ${data.title}\n\n`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (data.author) {
|
|
131
|
+
resultText += `Author: ${data.author}\n`;
|
|
132
|
+
if (data.author_cite) {
|
|
133
|
+
resultText += `Author (Citation Format): ${data.author_cite}\n`;
|
|
134
|
+
}
|
|
135
|
+
if (data.author_type) {
|
|
136
|
+
resultText += `Author Type: ${data.author_type}\n`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (data.date) {
|
|
141
|
+
resultText += `Publication Date: ${data.date}\n`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (data.source) {
|
|
145
|
+
resultText += `Source: ${data.source}\n`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (data.word_count) {
|
|
149
|
+
resultText += `Word Count: ${data.word_count}\n`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (data.cite) {
|
|
153
|
+
resultText += `\nCitation (APA Format): ${data.cite}\n`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (data.html) {
|
|
157
|
+
resultText += `\nContent:\n${data.html}\n\n`;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
resultText += `This is the complete page extraction information.`;
|
|
161
|
+
|
|
162
|
+
return resultText;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
return `Unable to extract content from "${url}". Error: ${error.message}`;
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "generate_ai_response",
|
|
170
|
+
description:
|
|
171
|
+
"Generate AI language model responses using QwkSearch API with various agent templates. Supports multiple providers (Groq, OpenAI, Anthropic, etc.) and agent types for different tasks like summarization, question answering, and content generation.",
|
|
172
|
+
schema: z.object({
|
|
173
|
+
provider: z.enum(["groq", "openai", "anthropic", "together", "xai", "google", "perplexity", "cloudflare"]),
|
|
174
|
+
key: z.string().optional(),
|
|
175
|
+
agent: z.enum([
|
|
176
|
+
"question",
|
|
177
|
+
"summarize-bullets",
|
|
178
|
+
"summarize",
|
|
179
|
+
"suggest-followups",
|
|
180
|
+
"answer-cite-sources",
|
|
181
|
+
"query-resolution",
|
|
182
|
+
"knowledge-graph-nodes",
|
|
183
|
+
"summary-longtext"
|
|
184
|
+
]).optional().default("question"),
|
|
185
|
+
model: z.string().optional().default("meta-llama/llama-4-maverick-17b-128e-instruct"),
|
|
186
|
+
temperature: z.number().min(0).max(2).optional().default(0.7),
|
|
187
|
+
html: z.boolean().optional().default(true),
|
|
188
|
+
query: z.string().optional(),
|
|
189
|
+
chat_history: z.string().optional(),
|
|
190
|
+
article: z.string().optional(),
|
|
191
|
+
baseURL: z.string().optional(),
|
|
192
|
+
apiKey: z.string().optional()
|
|
193
|
+
}),
|
|
194
|
+
func: async ({ provider, key, agent = "question", model = "meta-llama/llama-4-maverick-17b-128e-instruct", temperature = 0.7, html = true, query, chat_history, article, baseURL, apiKey }) => {
|
|
195
|
+
try {
|
|
196
|
+
// Use provided config or fall back to environment/defaults
|
|
197
|
+
const baseUrl = baseURL || QWKSEARCH_CONFIG.baseURL;
|
|
198
|
+
const headers = apiKey || QWKSEARCH_CONFIG.apiKey ? { 'x-api-key': apiKey || QWKSEARCH_CONFIG.apiKey } : undefined;
|
|
199
|
+
|
|
200
|
+
const requestBody = {
|
|
201
|
+
agent,
|
|
202
|
+
provider,
|
|
203
|
+
model,
|
|
204
|
+
html,
|
|
205
|
+
temperature
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
if (key) {
|
|
209
|
+
requestBody.key = key;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (query) {
|
|
213
|
+
requestBody.query = query;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (chat_history) {
|
|
217
|
+
requestBody.chat_history = chat_history;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (article) {
|
|
221
|
+
requestBody.article = article;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const result = await QwkSearch.writeLanguage({
|
|
225
|
+
body: requestBody,
|
|
226
|
+
baseUrl: baseUrl,
|
|
227
|
+
...(headers && { headers })
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (!result.data) {
|
|
231
|
+
return `No response generated. Please check your input parameters and try again.`;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let resultText = `AI Response (${agent} agent, ${provider} provider):\n\n`;
|
|
235
|
+
|
|
236
|
+
if (result.data.content) {
|
|
237
|
+
resultText += result.data.content;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (result.data.extract) {
|
|
241
|
+
resultText += `\n\nStructured Extract:\n${JSON.stringify(result.data.extract, null, 2)}`;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
resultText += `\n\nThis is the complete AI-generated response.`;
|
|
245
|
+
|
|
246
|
+
return resultText;
|
|
247
|
+
} catch (error) {
|
|
248
|
+
return `Unable to generate AI response. Error: ${error.message}`;
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: "render_page_with_javascript",
|
|
254
|
+
description:
|
|
255
|
+
"Render a web page with JavaScript execution using Cloudflare Browser Rendering. Use this for JavaScript-heavy sites (SPAs, React apps), pages behind bot protection (Cloudflare, reCAPTCHA), or when extract_page fails. Returns fully rendered HTML with JavaScript executed. Slower but more complete than extract_page.",
|
|
256
|
+
schema: z.object({
|
|
257
|
+
url: z.string().url(),
|
|
258
|
+
blockImages: z.boolean().optional().default(true),
|
|
259
|
+
wait: z.number().min(0).max(10000).optional().default(0),
|
|
260
|
+
timeout: z.number().min(1000).max(60000).optional().default(30000),
|
|
261
|
+
waitUntil: z.enum(["domcontentloaded", "load", "networkidle0", "networkidle2"]).optional().default("networkidle2"),
|
|
262
|
+
bypassCaptcha: z.boolean().optional().default(true),
|
|
263
|
+
sessionId: z.string().optional().default("default"),
|
|
264
|
+
format: z.enum(["html", "json"]).optional().default("html"),
|
|
265
|
+
scraperUrl: z.string().optional(),
|
|
266
|
+
scraperApiKey: z.string().optional()
|
|
267
|
+
}),
|
|
268
|
+
func: async ({ url, blockImages = true, wait = 0, timeout = 30000, waitUntil = "networkidle2", bypassCaptcha = true, sessionId = "default", format = "html", scraperUrl, scraperApiKey }) => {
|
|
269
|
+
try {
|
|
270
|
+
const scraperEndpoint = scraperUrl || (typeof process !== "undefined" && process?.env?.SCRAPER_URL) || 'https://scraper.qwksearch.workers.dev';
|
|
271
|
+
const apiKey = scraperApiKey || (typeof process !== "undefined" && process?.env?.SCRAPER_API_KEY);
|
|
272
|
+
|
|
273
|
+
const requestUrl = new URL('/api/render', scraperEndpoint);
|
|
274
|
+
|
|
275
|
+
const body = {
|
|
276
|
+
url,
|
|
277
|
+
blockImages,
|
|
278
|
+
wait,
|
|
279
|
+
timeout,
|
|
280
|
+
waitUntil,
|
|
281
|
+
bypassCaptcha,
|
|
282
|
+
sessionId,
|
|
283
|
+
format
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const headers: Record<string, string> = {
|
|
287
|
+
'Content-Type': 'application/json',
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
if (apiKey) {
|
|
291
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const response = await fetch(requestUrl.toString(), {
|
|
295
|
+
method: 'POST',
|
|
296
|
+
headers,
|
|
297
|
+
body: JSON.stringify(body),
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
if (!response.ok) {
|
|
301
|
+
const errorText = await response.text();
|
|
302
|
+
return `Failed to render page: ${errorText}`;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (format === 'json') {
|
|
306
|
+
const data = await response.json();
|
|
307
|
+
let resultText = `Page rendered successfully: ${data.url}\n\n`;
|
|
308
|
+
if (data.title) {
|
|
309
|
+
resultText += `Title: ${data.title}\n`;
|
|
310
|
+
}
|
|
311
|
+
resultText += `Load Time: ${data.loadTime}ms\n`;
|
|
312
|
+
if (data.challengeBypassed) {
|
|
313
|
+
resultText += `Challenge Bypassed: Yes (${data.retryCount} retries)\n`;
|
|
314
|
+
}
|
|
315
|
+
resultText += `\nRendered HTML Content:\n${data.html}\n\n`;
|
|
316
|
+
resultText += `This is the complete rendered page content.`;
|
|
317
|
+
return resultText;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const html = await response.text();
|
|
321
|
+
return `Page rendered successfully.\n\nHTML Content:\n${html}`;
|
|
322
|
+
} catch (error) {
|
|
323
|
+
return `Unable to render page "${url}". Error: ${error.message}`;
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
327
|
];
|