@qzhike/agent-search 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +123 -0
- package/dist/adapters/brave-config.js +46 -0
- package/dist/adapters/brave.js +83 -0
- package/dist/adapters/deeproute-mirror.js +31 -0
- package/dist/adapters/exa-config.js +35 -0
- package/dist/adapters/exa.js +91 -0
- package/dist/adapters/jina-config.js +102 -0
- package/dist/adapters/jina-reader.js +83 -0
- package/dist/adapters/jina.js +90 -0
- package/dist/adapters/kimi.js +196 -0
- package/dist/adapters/metaso-config.js +35 -0
- package/dist/adapters/metaso.js +102 -0
- package/dist/adapters/minimax-config.js +54 -0
- package/dist/adapters/minimax.js +85 -0
- package/dist/adapters/provider-auth.js +18 -0
- package/dist/adapters/ragflow-config.js +63 -0
- package/dist/adapters/ragflow.js +170 -0
- package/dist/adapters/searxng-config.js +40 -0
- package/dist/adapters/searxng.js +86 -0
- package/dist/adapters/serper-config.js +35 -0
- package/dist/adapters/serper.js +80 -0
- package/dist/adapters/tavily-config.js +46 -0
- package/dist/adapters/tavily.js +98 -0
- package/dist/adapters/zai-config.js +39 -0
- package/dist/adapters/zai.js +91 -0
- package/dist/config-schema.js +221 -0
- package/dist/http.js +49 -0
- package/dist/index.js +84 -0
- package/dist/plugin-meta.js +11 -0
- package/dist/read-url.js +38 -0
- package/dist/result.js +326 -0
- package/dist/run-provider.js +42 -0
- package/dist/search-concurrent.js +23 -0
- package/dist/search-fallback.js +14 -0
- package/dist/search.js +43 -0
- package/dist/types.js +2 -0
- package/openclaw.plugin.json +547 -0
- package/package.json +25 -0
- package/skills/qzhike-agent-search/SKILL.md +90 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
const DEEPROUTE_ORIGIN = "deeproute: Console API origin only (e.g. http://host:20316); plugin appends /api/mirror/{provider}. Legacy full mirror paths still work.";
|
|
3
|
+
const providerEnabled = Type.Optional(Type.Boolean({
|
|
4
|
+
description: "Set false to disable a configured provider. Omitted providers are disabled.",
|
|
5
|
+
}));
|
|
6
|
+
export const searxngProviderSchema = Type.Object({
|
|
7
|
+
enabled: providerEnabled,
|
|
8
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
9
|
+
description: "direct: SearXNG instance baseUrl. deeproute: Bearer sk to Console /api/mirror/searxng.",
|
|
10
|
+
})),
|
|
11
|
+
baseUrl: Type.Optional(Type.String({
|
|
12
|
+
description: `direct: SearXNG root, e.g. http://127.0.0.1:8888. ${DEEPROUTE_ORIGIN}`,
|
|
13
|
+
})),
|
|
14
|
+
apiKey: Type.Optional(Type.String({
|
|
15
|
+
description: "deeproute only: New API user sk (Bearer).",
|
|
16
|
+
})),
|
|
17
|
+
categories: Type.Optional(Type.String({ description: "SearXNG categories, e.g. general" })),
|
|
18
|
+
language: Type.Optional(Type.String({ description: "SearXNG language code" })),
|
|
19
|
+
});
|
|
20
|
+
export const kimiProviderSchema = Type.Object({
|
|
21
|
+
enabled: providerEnabled,
|
|
22
|
+
baseUrl: Type.Optional(Type.String({
|
|
23
|
+
description: "OpenAI-compatible base URL, e.g. https://new-api.example.com/v1 (New API).",
|
|
24
|
+
})),
|
|
25
|
+
apiKey: Type.Optional(Type.String({
|
|
26
|
+
description: "Bearer token for Authorization header (required to enable).",
|
|
27
|
+
})),
|
|
28
|
+
model: Type.Optional(Type.String({
|
|
29
|
+
description: "Model id for chat/completions, default kimi-k2.6",
|
|
30
|
+
})),
|
|
31
|
+
});
|
|
32
|
+
export const braveProviderSchema = Type.Object({
|
|
33
|
+
enabled: providerEnabled,
|
|
34
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
35
|
+
description: "direct: Brave X-Subscription-Token (default). deeproute: Bearer user sk to Console /api/mirror/brave.",
|
|
36
|
+
})),
|
|
37
|
+
apiKey: Type.Optional(Type.String({
|
|
38
|
+
description: "direct: Brave subscription token. deeproute: New API user sk (Console injects Brave key).",
|
|
39
|
+
})),
|
|
40
|
+
baseUrl: Type.Optional(Type.String({
|
|
41
|
+
description: `direct: default https://api.search.brave.com. ${DEEPROUTE_ORIGIN}`,
|
|
42
|
+
})),
|
|
43
|
+
country: Type.Optional(Type.String({
|
|
44
|
+
description: "Brave country filter (ISO 3166-1 alpha-2), e.g. US.",
|
|
45
|
+
})),
|
|
46
|
+
freshness: Type.Optional(Type.String({
|
|
47
|
+
description: 'Brave result freshness: "pd" (day), "pw", "pm", or "py".',
|
|
48
|
+
})),
|
|
49
|
+
});
|
|
50
|
+
export const jinaProviderSchema = Type.Object({
|
|
51
|
+
enabled: providerEnabled,
|
|
52
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
53
|
+
description: "direct: POST https://s.jina.ai/ with Jina API key. deeproute: POST {baseUrl}/mirror/jina/s with user sk; Console must store valid Jina API key.",
|
|
54
|
+
})),
|
|
55
|
+
apiKey: Type.Optional(Type.String({
|
|
56
|
+
description: "direct: Jina API key (required). deeproute: New API user sk; vendor Jina key must be in Console 扩展服务.",
|
|
57
|
+
})),
|
|
58
|
+
baseUrl: Type.Optional(Type.String({
|
|
59
|
+
description: `deeproute: ${DEEPROUTE_ORIGIN} direct: default https://s.jina.ai.`,
|
|
60
|
+
})),
|
|
61
|
+
});
|
|
62
|
+
export const minimaxProviderSchema = Type.Object({
|
|
63
|
+
enabled: providerEnabled,
|
|
64
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
65
|
+
description: "direct: Bearer Token Plan key. deeproute: Bearer user sk; Console injects minimax key and region.",
|
|
66
|
+
})),
|
|
67
|
+
apiKey: Type.Optional(Type.String({
|
|
68
|
+
description: "direct: MiniMax Token Plan key. deeproute: New API user sk (Console injects minimax credentials).",
|
|
69
|
+
})),
|
|
70
|
+
baseUrl: Type.Optional(Type.String({
|
|
71
|
+
description: `deeproute: ${DEEPROUTE_ORIGIN} direct: api.minimax.io or api.minimaxi.com.`,
|
|
72
|
+
})),
|
|
73
|
+
region: Type.Optional(Type.String({
|
|
74
|
+
description: 'direct only: "global" (default) or "cn" for upstream host.',
|
|
75
|
+
})),
|
|
76
|
+
});
|
|
77
|
+
export const ragflowProviderSchema = Type.Object({
|
|
78
|
+
enabled: providerEnabled,
|
|
79
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
80
|
+
description: "direct: Bearer RAGFlow API key + datasetIds in config. deeproute: Bearer user sk; Console injects RAGFlow key and dataset_ids.",
|
|
81
|
+
})),
|
|
82
|
+
baseUrl: Type.Optional(Type.String({
|
|
83
|
+
description: `direct: RAGFlow service root. ${DEEPROUTE_ORIGIN}`,
|
|
84
|
+
})),
|
|
85
|
+
apiKey: Type.Optional(Type.String({
|
|
86
|
+
description: "direct: RAGFlow API key. deeproute: New API user sk (Console injects RAGFlow key).",
|
|
87
|
+
})),
|
|
88
|
+
datasetIds: Type.Optional(Type.String({
|
|
89
|
+
description: "direct only: comma-separated RAGFlow dataset IDs (deeproute: configured in Console 扩展服务).",
|
|
90
|
+
})),
|
|
91
|
+
similarityThreshold: Type.Optional(Type.Number({ description: "RAGFlow similarity_threshold, default 0.2." })),
|
|
92
|
+
pageSize: Type.Optional(Type.Number({ description: "RAGFlow page_size, default 30." })),
|
|
93
|
+
topK: Type.Optional(Type.Number({ description: "RAGFlow top_k." })),
|
|
94
|
+
timeoutSeconds: Type.Optional(Type.Number({
|
|
95
|
+
description: "RAGFlow HTTP timeout (seconds), default 120, max 120.",
|
|
96
|
+
minimum: 1,
|
|
97
|
+
maximum: 120,
|
|
98
|
+
})),
|
|
99
|
+
});
|
|
100
|
+
export const serperProviderSchema = Type.Object({
|
|
101
|
+
enabled: providerEnabled,
|
|
102
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
103
|
+
description: "direct: X-API-KEY to google.serper.dev. deeproute: Bearer user sk; Console injects Serper key.",
|
|
104
|
+
})),
|
|
105
|
+
apiKey: Type.Optional(Type.String({
|
|
106
|
+
description: "direct: Serper API key. deeproute: New API user sk (Console injects Serper key).",
|
|
107
|
+
})),
|
|
108
|
+
baseUrl: Type.Optional(Type.String({
|
|
109
|
+
description: `direct: default https://google.serper.dev. ${DEEPROUTE_ORIGIN}`,
|
|
110
|
+
})),
|
|
111
|
+
});
|
|
112
|
+
export const metasoProviderSchema = Type.Object({
|
|
113
|
+
enabled: providerEnabled,
|
|
114
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
115
|
+
description: "direct: Bearer Metaso key. deeproute: Bearer user sk; Console injects Metaso key.",
|
|
116
|
+
})),
|
|
117
|
+
apiKey: Type.Optional(Type.String({
|
|
118
|
+
description: "direct: Metaso API key. deeproute: New API user sk (Console injects Metaso key).",
|
|
119
|
+
})),
|
|
120
|
+
baseUrl: Type.Optional(Type.String({
|
|
121
|
+
description: `direct: default https://metaso.cn. ${DEEPROUTE_ORIGIN}`,
|
|
122
|
+
})),
|
|
123
|
+
});
|
|
124
|
+
export const zaiProviderSchema = Type.Object({
|
|
125
|
+
enabled: providerEnabled,
|
|
126
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
127
|
+
description: "direct: Bearer Zhipu key. deeproute: Bearer user sk; Console injects Zhipu key.",
|
|
128
|
+
})),
|
|
129
|
+
apiKey: Type.Optional(Type.String({
|
|
130
|
+
description: "direct: Zhipu API key. deeproute: New API user sk (Console injects Zhipu key).",
|
|
131
|
+
})),
|
|
132
|
+
baseUrl: Type.Optional(Type.String({
|
|
133
|
+
description: `direct: default https://open.bigmodel.cn. ${DEEPROUTE_ORIGIN}`,
|
|
134
|
+
})),
|
|
135
|
+
searchEngine: Type.Optional(Type.String({
|
|
136
|
+
description: 'Zhipu search_engine parameter, default "search_pro".',
|
|
137
|
+
})),
|
|
138
|
+
});
|
|
139
|
+
export const exaProviderSchema = Type.Object({
|
|
140
|
+
enabled: providerEnabled,
|
|
141
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
142
|
+
description: "direct: x-api-key to api.exa.ai. deeproute: Bearer user sk; Console injects Exa key.",
|
|
143
|
+
})),
|
|
144
|
+
apiKey: Type.Optional(Type.String({
|
|
145
|
+
description: "direct: Exa API key. deeproute: New API user sk (Console injects Exa key).",
|
|
146
|
+
})),
|
|
147
|
+
baseUrl: Type.Optional(Type.String({
|
|
148
|
+
description: `direct: default https://api.exa.ai. ${DEEPROUTE_ORIGIN}`,
|
|
149
|
+
})),
|
|
150
|
+
});
|
|
151
|
+
export const tavilyProviderSchema = Type.Object({
|
|
152
|
+
enabled: providerEnabled,
|
|
153
|
+
auth: Type.Optional(Type.Union([Type.Literal("direct"), Type.Literal("deeproute")], {
|
|
154
|
+
description: "direct: Tavily api_key in POST body. deeproute: Bearer sk; Console injects Tavily key.",
|
|
155
|
+
})),
|
|
156
|
+
apiKey: Type.Optional(Type.String({
|
|
157
|
+
description: "direct: Tavily API key. deeproute: New API user sk (Console injects Tavily key).",
|
|
158
|
+
})),
|
|
159
|
+
baseUrl: Type.Optional(Type.String({
|
|
160
|
+
description: `direct: default https://api.tavily.com. ${DEEPROUTE_ORIGIN}`,
|
|
161
|
+
})),
|
|
162
|
+
searchDepth: Type.Optional(Type.Union([Type.Literal("basic"), Type.Literal("advanced")], {
|
|
163
|
+
description: "Tavily search depth.",
|
|
164
|
+
})),
|
|
165
|
+
includeAnswer: Type.Optional(Type.Boolean({
|
|
166
|
+
description: "Include Tavily synthesized answer when available.",
|
|
167
|
+
})),
|
|
168
|
+
});
|
|
169
|
+
const searchProviderIdSchema = Type.Union([
|
|
170
|
+
Type.Literal("ragflow"),
|
|
171
|
+
Type.Literal("serper"),
|
|
172
|
+
Type.Literal("metaso"),
|
|
173
|
+
Type.Literal("zai"),
|
|
174
|
+
Type.Literal("exa"),
|
|
175
|
+
Type.Literal("searxng"),
|
|
176
|
+
Type.Literal("kimi"),
|
|
177
|
+
Type.Literal("brave"),
|
|
178
|
+
Type.Literal("tavily"),
|
|
179
|
+
Type.Literal("jina"),
|
|
180
|
+
Type.Literal("minimax"),
|
|
181
|
+
]);
|
|
182
|
+
export const pluginConfigSchema = Type.Object({
|
|
183
|
+
searchMode: Type.Optional(Type.Union([Type.Literal("fallback"), Type.Literal("concurrent")], {
|
|
184
|
+
description: 'Search strategy: "fallback" = linear try order; "concurrent" = parallel calls. Default fallback.',
|
|
185
|
+
})),
|
|
186
|
+
fallback: Type.Optional(Type.Array(searchProviderIdSchema, {
|
|
187
|
+
description: "Fallback mode: strict try order. Only listed configured providers run.",
|
|
188
|
+
})),
|
|
189
|
+
concurrent: Type.Optional(Type.Array(searchProviderIdSchema, {
|
|
190
|
+
description: "Concurrent mode: providers to call in parallel (capped by concurrentMaxProviders).",
|
|
191
|
+
})),
|
|
192
|
+
concurrentMaxProviders: Type.Optional(Type.Number({
|
|
193
|
+
description: "Max parallel providers in concurrent mode (1-10). Default 3.",
|
|
194
|
+
minimum: 1,
|
|
195
|
+
maximum: 10,
|
|
196
|
+
})),
|
|
197
|
+
timeoutSeconds: Type.Optional(Type.Number({
|
|
198
|
+
description: "HTTP timeout per request (seconds).",
|
|
199
|
+
minimum: 1,
|
|
200
|
+
maximum: 120,
|
|
201
|
+
})),
|
|
202
|
+
maxResults: Type.Optional(Type.Number({
|
|
203
|
+
description: "Default max structured results (1-10).",
|
|
204
|
+
minimum: 1,
|
|
205
|
+
maximum: 10,
|
|
206
|
+
})),
|
|
207
|
+
providers: Type.Optional(Type.Object({
|
|
208
|
+
ragflow: Type.Optional(ragflowProviderSchema),
|
|
209
|
+
serper: Type.Optional(serperProviderSchema),
|
|
210
|
+
metaso: Type.Optional(metasoProviderSchema),
|
|
211
|
+
zai: Type.Optional(zaiProviderSchema),
|
|
212
|
+
exa: Type.Optional(exaProviderSchema),
|
|
213
|
+
searxng: Type.Optional(searxngProviderSchema),
|
|
214
|
+
kimi: Type.Optional(kimiProviderSchema),
|
|
215
|
+
brave: Type.Optional(braveProviderSchema),
|
|
216
|
+
tavily: Type.Optional(tavilyProviderSchema),
|
|
217
|
+
jina: Type.Optional(jinaProviderSchema),
|
|
218
|
+
minimax: Type.Optional(minimaxProviderSchema),
|
|
219
|
+
})),
|
|
220
|
+
});
|
|
221
|
+
//# sourceMappingURL=config-schema.js.map
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export async function fetchJson(url, options) {
|
|
2
|
+
const controller = new AbortController();
|
|
3
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutSeconds * 1000);
|
|
4
|
+
const signals = [controller.signal];
|
|
5
|
+
if (options.signal) {
|
|
6
|
+
signals.push(options.signal);
|
|
7
|
+
}
|
|
8
|
+
try {
|
|
9
|
+
const init = {
|
|
10
|
+
method: options.method ?? (options.body !== undefined ? "POST" : "GET"),
|
|
11
|
+
headers: options.headers,
|
|
12
|
+
signal: signals.length > 1 ? AbortSignal.any(signals) : controller.signal,
|
|
13
|
+
};
|
|
14
|
+
if (options.body !== undefined) {
|
|
15
|
+
init.body =
|
|
16
|
+
typeof options.body === "string"
|
|
17
|
+
? options.body
|
|
18
|
+
: JSON.stringify(options.body);
|
|
19
|
+
init.headers = {
|
|
20
|
+
"Content-Type": "application/json",
|
|
21
|
+
...options.headers,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const response = await fetch(url, init);
|
|
25
|
+
const text = await response.text();
|
|
26
|
+
let data;
|
|
27
|
+
try {
|
|
28
|
+
data = text ? JSON.parse(text) : {};
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new Error(`Invalid JSON response (${response.status}): ${text.slice(0, 500)}`);
|
|
32
|
+
}
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new Error(`HTTP ${response.status}: ${text.slice(0, 500) || response.statusText}`);
|
|
35
|
+
}
|
|
36
|
+
return { status: response.status, data, text };
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function trimTrailingSlashes(url) {
|
|
43
|
+
return url.replace(/\/+$/, "");
|
|
44
|
+
}
|
|
45
|
+
export function configString(value) {
|
|
46
|
+
const trimmed = value?.trim();
|
|
47
|
+
return trimmed ? trimmed : undefined;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=http.js.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { defineToolPlugin } from "openclaw/plugin-sdk/tool-plugin";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import { pluginConfigSchema } from "./config-schema.js";
|
|
4
|
+
import { PLUGIN_DISPLAY_NAME, PLUGIN_ID, TOOL_READ_URL, TOOL_SEARCH, } from "./plugin-meta.js";
|
|
5
|
+
import { executeReadUrl } from "./read-url.js";
|
|
6
|
+
import { executeDeepSearch } from "./search.js";
|
|
7
|
+
const providerIdSchema = Type.Optional(Type.Union([
|
|
8
|
+
Type.Literal("ragflow"),
|
|
9
|
+
Type.Literal("serper"),
|
|
10
|
+
Type.Literal("metaso"),
|
|
11
|
+
Type.Literal("zai"),
|
|
12
|
+
Type.Literal("exa"),
|
|
13
|
+
Type.Literal("searxng"),
|
|
14
|
+
Type.Literal("kimi"),
|
|
15
|
+
Type.Literal("brave"),
|
|
16
|
+
Type.Literal("tavily"),
|
|
17
|
+
Type.Literal("jina"),
|
|
18
|
+
Type.Literal("minimax"),
|
|
19
|
+
], {
|
|
20
|
+
description: "Force a single backend instead of configured fallback chain.",
|
|
21
|
+
}));
|
|
22
|
+
export default defineToolPlugin({
|
|
23
|
+
id: PLUGIN_ID,
|
|
24
|
+
name: PLUGIN_DISPLAY_NAME,
|
|
25
|
+
description: "Multi-backend search (RAGFlow KB, Serper, Metaso, Zhipu, Exa, SearXNG, Kimi, Brave, Tavily, Jina, MiniMax) with fallback/concurrent modes, plus Jina Reader URL fetch. DeepRoute mirror support.",
|
|
26
|
+
configSchema: pluginConfigSchema,
|
|
27
|
+
tools: (tool) => [
|
|
28
|
+
tool({
|
|
29
|
+
name: TOOL_SEARCH,
|
|
30
|
+
label: "Qzhike Search",
|
|
31
|
+
description: "Search knowledge bases (RAGFlow) and the web using configured backends with fallback or concurrent mode. Prefer this over web_search when this plugin is installed.",
|
|
32
|
+
parameters: Type.Object({
|
|
33
|
+
query: Type.String({ description: "Search query." }),
|
|
34
|
+
count: Type.Optional(Type.Number({
|
|
35
|
+
description: "Max results for structured providers (1-10).",
|
|
36
|
+
minimum: 1,
|
|
37
|
+
maximum: 10,
|
|
38
|
+
})),
|
|
39
|
+
searchMode: Type.Optional(Type.Union([Type.Literal("fallback"), Type.Literal("concurrent")], {
|
|
40
|
+
description: "Override config searchMode for this call (fallback = linear try order, concurrent = parallel).",
|
|
41
|
+
})),
|
|
42
|
+
provider: providerIdSchema,
|
|
43
|
+
country: Type.Optional(Type.String({
|
|
44
|
+
description: "Brave only: ISO 3166-1 alpha-2 country filter (overrides config).",
|
|
45
|
+
})),
|
|
46
|
+
freshness: Type.Optional(Type.String({
|
|
47
|
+
description: "Brave only: freshness pd|pw|pm|py (overrides config).",
|
|
48
|
+
})),
|
|
49
|
+
searchDepth: Type.Optional(Type.Union([Type.Literal("basic"), Type.Literal("advanced")], {
|
|
50
|
+
description: "Tavily only: search depth (overrides config).",
|
|
51
|
+
})),
|
|
52
|
+
includeAnswer: Type.Optional(Type.Boolean({
|
|
53
|
+
description: "Tavily only: include synthesized answer (overrides config).",
|
|
54
|
+
})),
|
|
55
|
+
}),
|
|
56
|
+
async execute(params, config, context) {
|
|
57
|
+
context.signal?.throwIfAborted();
|
|
58
|
+
return executeDeepSearch(config, {
|
|
59
|
+
query: params.query,
|
|
60
|
+
count: params.count,
|
|
61
|
+
searchMode: params.searchMode,
|
|
62
|
+
provider: params.provider,
|
|
63
|
+
country: params.country,
|
|
64
|
+
freshness: params.freshness,
|
|
65
|
+
searchDepth: params.searchDepth,
|
|
66
|
+
includeAnswer: params.includeAnswer,
|
|
67
|
+
}, context.signal);
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
tool({
|
|
71
|
+
name: TOOL_READ_URL,
|
|
72
|
+
label: "Qzhike Read URL",
|
|
73
|
+
description: "Fetch readable page content via Jina Reader (GET r.jina.ai or DeepRoute /api/mirror/jina/r/…). Use when you have a URL and need full page text.",
|
|
74
|
+
parameters: Type.Object({
|
|
75
|
+
url: Type.String({ description: "Absolute HTTP(S) URL to read." }),
|
|
76
|
+
}),
|
|
77
|
+
async execute(params, config, context) {
|
|
78
|
+
context.signal?.throwIfAborted();
|
|
79
|
+
return executeReadUrl(config, { url: params.url }, context.signal);
|
|
80
|
+
},
|
|
81
|
+
}),
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** OpenClaw plugin id (also used as plugins.entries key). */
|
|
2
|
+
export const PLUGIN_ID = "qzhike-agent-search";
|
|
3
|
+
export const PLUGIN_DISPLAY_NAME = "Qzhike Agent Search";
|
|
4
|
+
export const TOOL_SEARCH = "qzhike_search";
|
|
5
|
+
export const TOOL_READ_URL = "qzhike_read_url";
|
|
6
|
+
export const EXTERNAL_CONTENT_SOURCE = "qzhike_agent_search";
|
|
7
|
+
export function pluginConfigPath(suffix = "") {
|
|
8
|
+
const base = `plugins.entries.${PLUGIN_ID}.config`;
|
|
9
|
+
return suffix ? `${base}.${suffix}` : base;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=plugin-meta.js.map
|
package/dist/read-url.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Internal Jina Reader fetch for qzhike_read_url. */
|
|
2
|
+
import { readUrlWithJina } from "./adapters/jina-reader.js";
|
|
3
|
+
import { pluginConfigPath, TOOL_READ_URL } from "./plugin-meta.js";
|
|
4
|
+
import { isJinaReaderConfigured } from "./result.js";
|
|
5
|
+
export async function executeReadUrl(config, params, signal) {
|
|
6
|
+
const url = params.url.trim();
|
|
7
|
+
if (!url) {
|
|
8
|
+
return { error: "missing_url", message: "url is required." };
|
|
9
|
+
}
|
|
10
|
+
if (!isJinaReaderConfigured(config)) {
|
|
11
|
+
return {
|
|
12
|
+
error: "reader_not_configured",
|
|
13
|
+
message: `Jina Reader is not configured. Set ${pluginConfigPath("providers.jina")} ` +
|
|
14
|
+
"(direct: optional apiKey; deeproute: baseUrl + user apiKey sk).",
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const outcome = await readUrlWithJina(config, url, signal);
|
|
18
|
+
if (!outcome.ok) {
|
|
19
|
+
return {
|
|
20
|
+
error: outcome.error,
|
|
21
|
+
message: outcome.message,
|
|
22
|
+
provider: outcome.provider,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
url: outcome.url,
|
|
27
|
+
provider: outcome.provider,
|
|
28
|
+
tookMs: outcome.tookMs,
|
|
29
|
+
title: outcome.title,
|
|
30
|
+
content: outcome.content,
|
|
31
|
+
externalContent: {
|
|
32
|
+
untrusted: true,
|
|
33
|
+
source: TOOL_READ_URL,
|
|
34
|
+
provider: outcome.provider,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=read-url.js.map
|