@ever-works/valyu-plugin 1.0.0 → 1.0.3
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/index.cjs +356 -0
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +351 -0
- package/package.json +90 -77
- package/LICENSE +0 -661
- package/src/__tests__/valyu.plugin.spec.ts +0 -321
- package/src/index.ts +0 -2
- package/src/valyu.plugin.ts +0 -365
- package/tsconfig.json +0 -22
- package/tsup.config.ts +0 -12
package/dist/index.js
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { Valyu } from 'valyu-js';
|
|
2
|
+
import { isIP } from 'net';
|
|
3
|
+
|
|
4
|
+
// src/valyu.plugin.ts
|
|
5
|
+
function isSafeWebhookUrl(rawUrl) {
|
|
6
|
+
let url;
|
|
7
|
+
try {
|
|
8
|
+
url = new URL(rawUrl);
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
let host = url.hostname.toLowerCase();
|
|
16
|
+
if (host.startsWith("[") && host.endsWith("]")) {
|
|
17
|
+
host = host.slice(1, -1);
|
|
18
|
+
}
|
|
19
|
+
if (CLOUD_METADATA_HOSTNAMES.has(host)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const ipKind = isIP(host);
|
|
23
|
+
if (ipKind === 4 && isPrivateIPv4(host)) return false;
|
|
24
|
+
if (ipKind === 6 && isPrivateIPv6(host)) return false;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
var CLOUD_METADATA_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
28
|
+
// GCP
|
|
29
|
+
"metadata.google.internal",
|
|
30
|
+
"metadata.goog",
|
|
31
|
+
// AWS
|
|
32
|
+
"instance-data",
|
|
33
|
+
"instance-data.ec2.internal",
|
|
34
|
+
// Azure
|
|
35
|
+
"metadata.azure.internal"
|
|
36
|
+
]);
|
|
37
|
+
function isPrivateIPv4(ip) {
|
|
38
|
+
const parts = ip.split(".").map((p) => Number(p));
|
|
39
|
+
if (parts.length !== 4 || parts.some((n) => Number.isNaN(n))) return false;
|
|
40
|
+
const [a, b] = parts;
|
|
41
|
+
if (a === 10) return true;
|
|
42
|
+
if (a === 127) return true;
|
|
43
|
+
if (a === 0) return true;
|
|
44
|
+
if (a === 169 && b === 254) return true;
|
|
45
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
46
|
+
if (a === 192 && b === 168) return true;
|
|
47
|
+
if (a === 192 && b === 0 && parts[2] === 0) return true;
|
|
48
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
49
|
+
if (a >= 224) return true;
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
function isPrivateIPv6(ip) {
|
|
53
|
+
const lower = ip.toLowerCase();
|
|
54
|
+
if (lower === "::1" || lower === "::") return true;
|
|
55
|
+
if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
|
|
56
|
+
const firstHextet = lower.split(":", 1)[0];
|
|
57
|
+
if (/^[0-9a-f]{1,4}$/.test(firstHextet)) {
|
|
58
|
+
const group0 = parseInt(firstHextet, 16);
|
|
59
|
+
if ((group0 & 65472) === 65152) return true;
|
|
60
|
+
}
|
|
61
|
+
if (lower.startsWith("::ffff:")) {
|
|
62
|
+
const v4 = lower.slice("::ffff:".length);
|
|
63
|
+
if (isIP(v4) === 4) return isPrivateIPv4(v4);
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/valyu.plugin.ts
|
|
69
|
+
var ValyuSearchPlugin = class {
|
|
70
|
+
id = "valyu";
|
|
71
|
+
name = "Valyu";
|
|
72
|
+
version = "1.0.0";
|
|
73
|
+
category = "search";
|
|
74
|
+
capabilities = ["search", "content-extractor"];
|
|
75
|
+
providerName = "Valyu";
|
|
76
|
+
settingsSchema = {
|
|
77
|
+
type: "object",
|
|
78
|
+
properties: {
|
|
79
|
+
apiKey: {
|
|
80
|
+
type: "string",
|
|
81
|
+
title: "API Key",
|
|
82
|
+
description: "Your Valyu API key. Get one at https://valyu.ai",
|
|
83
|
+
"x-secret": true,
|
|
84
|
+
"x-envVar": "PLUGIN_VALYU_API_KEY",
|
|
85
|
+
"x-scope": "user"
|
|
86
|
+
},
|
|
87
|
+
responseLength: {
|
|
88
|
+
type: "string",
|
|
89
|
+
title: "Response Length",
|
|
90
|
+
description: "Content volume per result: short (~25k chars), medium (~50k), large (~100k), or max (unlimited)",
|
|
91
|
+
enum: ["short", "medium", "large", "max"],
|
|
92
|
+
default: "medium"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
required: ["apiKey"]
|
|
96
|
+
};
|
|
97
|
+
configurationMode = "hybrid";
|
|
98
|
+
context;
|
|
99
|
+
async search(options) {
|
|
100
|
+
const client = this.getClient(options.settings);
|
|
101
|
+
const startTime = Date.now();
|
|
102
|
+
const maxNumResults = options.limit || 20;
|
|
103
|
+
const responseLength = options.settings?.responseLength || "medium";
|
|
104
|
+
try {
|
|
105
|
+
const searchOptions = {
|
|
106
|
+
searchType: "all",
|
|
107
|
+
maxNumResults,
|
|
108
|
+
responseLength
|
|
109
|
+
};
|
|
110
|
+
if (options.includeDomains && options.includeDomains.length > 0) {
|
|
111
|
+
searchOptions.includedSources = options.includeDomains;
|
|
112
|
+
} else if (options.excludeDomains && options.excludeDomains.length > 0) {
|
|
113
|
+
searchOptions.excludeSources = options.excludeDomains;
|
|
114
|
+
}
|
|
115
|
+
if (options.region) {
|
|
116
|
+
searchOptions.countryCode = options.region.toUpperCase();
|
|
117
|
+
}
|
|
118
|
+
if (options.timeRange && options.timeRange !== "all") {
|
|
119
|
+
const now = /* @__PURE__ */ new Date();
|
|
120
|
+
const start = new Date(now);
|
|
121
|
+
if (options.timeRange === "day") start.setDate(now.getDate() - 1);
|
|
122
|
+
else if (options.timeRange === "week") start.setDate(now.getDate() - 7);
|
|
123
|
+
else if (options.timeRange === "month") start.setMonth(now.getMonth() - 1);
|
|
124
|
+
else if (options.timeRange === "year") start.setFullYear(now.getFullYear() - 1);
|
|
125
|
+
searchOptions.startDate = start.toISOString().split("T")[0];
|
|
126
|
+
searchOptions.endDate = now.toISOString().split("T")[0];
|
|
127
|
+
}
|
|
128
|
+
const response = await client.search(options.query, searchOptions);
|
|
129
|
+
const results = (response.results || []).map((r, index) => ({
|
|
130
|
+
title: r.title,
|
|
131
|
+
url: r.url,
|
|
132
|
+
snippet: typeof r.content === "string" ? r.content : String(r.content),
|
|
133
|
+
position: index + 1,
|
|
134
|
+
publishedDate: r.publication_date,
|
|
135
|
+
metadata: {
|
|
136
|
+
relevanceScore: r.relevance_score,
|
|
137
|
+
source: r.source,
|
|
138
|
+
description: r.description
|
|
139
|
+
}
|
|
140
|
+
}));
|
|
141
|
+
return {
|
|
142
|
+
results,
|
|
143
|
+
query: options.query,
|
|
144
|
+
totalResults: results.length,
|
|
145
|
+
hasMore: false,
|
|
146
|
+
duration: Date.now() - startTime
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
this.context?.logger.error(
|
|
150
|
+
`Valyu search failed: ${error instanceof Error ? error.message : String(error)}`
|
|
151
|
+
);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async isAvailable() {
|
|
156
|
+
if (!this.context) return false;
|
|
157
|
+
const settings = await this.context.getSettings();
|
|
158
|
+
return Boolean(settings?.apiKey);
|
|
159
|
+
}
|
|
160
|
+
async validateConnection(settings) {
|
|
161
|
+
const apiKey = settings.apiKey;
|
|
162
|
+
if (!apiKey) {
|
|
163
|
+
return { success: false, message: "Valyu API key is not configured." };
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const client = this.getClient(settings);
|
|
167
|
+
await client.search("test", { maxNumResults: 1, searchType: "all" });
|
|
168
|
+
return { success: true, message: "Valyu connection verified." };
|
|
169
|
+
} catch (error) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
message: `Valyu connection failed: ${error instanceof Error ? error.message : String(error)}`
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async getRateLimitInfo() {
|
|
177
|
+
return {
|
|
178
|
+
remaining: -1,
|
|
179
|
+
limit: -1,
|
|
180
|
+
period: "month"
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
async extract(options) {
|
|
184
|
+
const client = this.getClient(options.settings);
|
|
185
|
+
const startTime = Date.now();
|
|
186
|
+
if (!isSafeWebhookUrl(options.url)) {
|
|
187
|
+
return {
|
|
188
|
+
success: false,
|
|
189
|
+
url: options.url,
|
|
190
|
+
error: `URL host is not safe to fetch (SSRF guard blocked: ${options.url})`,
|
|
191
|
+
duration: Date.now() - startTime
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const response = await client.contents([options.url]);
|
|
196
|
+
if (!response.results || response.results.length === 0) {
|
|
197
|
+
return {
|
|
198
|
+
success: false,
|
|
199
|
+
url: options.url,
|
|
200
|
+
error: "No content extracted",
|
|
201
|
+
duration: Date.now() - startTime
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const result = response.results[0];
|
|
205
|
+
const content = typeof result.content === "string" ? result.content : String(result.content || "");
|
|
206
|
+
return {
|
|
207
|
+
success: true,
|
|
208
|
+
url: options.url,
|
|
209
|
+
finalUrl: result.url !== options.url ? result.url : void 0,
|
|
210
|
+
title: result.title,
|
|
211
|
+
content,
|
|
212
|
+
markdown: content,
|
|
213
|
+
duration: Date.now() - startTime,
|
|
214
|
+
wordCount: content ? content.split(/\s+/).length : 0
|
|
215
|
+
};
|
|
216
|
+
} catch (error) {
|
|
217
|
+
return {
|
|
218
|
+
success: false,
|
|
219
|
+
url: options.url,
|
|
220
|
+
error: error instanceof Error ? error.message : String(error),
|
|
221
|
+
duration: Date.now() - startTime
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async extractBatch(urls, options) {
|
|
226
|
+
const client = this.getClient(options?.settings);
|
|
227
|
+
const startTime = Date.now();
|
|
228
|
+
const safeUrls = [];
|
|
229
|
+
const blockedResults = [];
|
|
230
|
+
for (const url of urls) {
|
|
231
|
+
if (isSafeWebhookUrl(url)) {
|
|
232
|
+
safeUrls.push(url);
|
|
233
|
+
} else {
|
|
234
|
+
blockedResults.push({
|
|
235
|
+
success: false,
|
|
236
|
+
url,
|
|
237
|
+
error: `URL host is not safe to fetch (SSRF guard blocked: ${url})`,
|
|
238
|
+
duration: Date.now() - startTime
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
const batchSize = 10;
|
|
244
|
+
const allResults = [];
|
|
245
|
+
for (let i = 0; i < safeUrls.length; i += batchSize) {
|
|
246
|
+
const batch = safeUrls.slice(i, i + batchSize);
|
|
247
|
+
const response = await client.contents(batch);
|
|
248
|
+
const results = (response.results || []).map((result, index) => {
|
|
249
|
+
const content = typeof result.content === "string" ? result.content : String(result.content || "");
|
|
250
|
+
const requestedUrl = batch[index] || result.url;
|
|
251
|
+
return {
|
|
252
|
+
success: true,
|
|
253
|
+
url: requestedUrl,
|
|
254
|
+
finalUrl: result.url !== requestedUrl ? result.url : void 0,
|
|
255
|
+
title: result.title,
|
|
256
|
+
content,
|
|
257
|
+
markdown: content,
|
|
258
|
+
duration: Date.now() - startTime,
|
|
259
|
+
wordCount: content ? content.split(/\s+/).length : 0
|
|
260
|
+
};
|
|
261
|
+
});
|
|
262
|
+
allResults.push(...results);
|
|
263
|
+
}
|
|
264
|
+
return [...blockedResults, ...allResults];
|
|
265
|
+
} catch (error) {
|
|
266
|
+
const failed = safeUrls.map((url) => ({
|
|
267
|
+
success: false,
|
|
268
|
+
url,
|
|
269
|
+
error: error instanceof Error ? error.message : String(error),
|
|
270
|
+
duration: Date.now() - startTime
|
|
271
|
+
}));
|
|
272
|
+
return [...blockedResults, ...failed];
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async canExtract(url) {
|
|
276
|
+
return isSafeWebhookUrl(url);
|
|
277
|
+
}
|
|
278
|
+
getSupportedFormats() {
|
|
279
|
+
return ["text", "markdown"];
|
|
280
|
+
}
|
|
281
|
+
getClient(settings) {
|
|
282
|
+
const apiKey = settings?.apiKey;
|
|
283
|
+
if (!apiKey) {
|
|
284
|
+
throw new Error(
|
|
285
|
+
"Valyu API key not configured. Set it in plugin settings or via PLUGIN_VALYU_API_KEY environment variable."
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
return new Valyu(apiKey);
|
|
289
|
+
}
|
|
290
|
+
async onLoad(context) {
|
|
291
|
+
this.context = context;
|
|
292
|
+
context.logger.log("Valyu Plugin loaded");
|
|
293
|
+
}
|
|
294
|
+
async onUnload() {
|
|
295
|
+
this.context = void 0;
|
|
296
|
+
}
|
|
297
|
+
async healthCheck() {
|
|
298
|
+
return {
|
|
299
|
+
status: "healthy",
|
|
300
|
+
message: "Valyu plugin is ready (API key required for operations)",
|
|
301
|
+
checkedAt: Date.now()
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
getManifest() {
|
|
305
|
+
return {
|
|
306
|
+
id: this.id,
|
|
307
|
+
name: this.name,
|
|
308
|
+
version: this.version,
|
|
309
|
+
description: "AI-native search and content extraction across web and proprietary data sources",
|
|
310
|
+
category: this.category,
|
|
311
|
+
capabilities: [...this.capabilities],
|
|
312
|
+
author: { name: "Ever Works Team" },
|
|
313
|
+
license: "AGPL-3.0",
|
|
314
|
+
builtIn: true,
|
|
315
|
+
systemPlugin: false,
|
|
316
|
+
autoEnable: false,
|
|
317
|
+
homepage: "https://valyu.ai",
|
|
318
|
+
icon: {
|
|
319
|
+
type: "svg",
|
|
320
|
+
value: `<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet"><g fill="#1e1d1d" fill-opacity="1"><g transform="translate(-3, 88)"><path d="M 48.3125 1.734375 L 59.78125 1.734375 L 91.5625 -71.453125 L 91.5625 -77.5 L 16.328125 -77.5 L 16.328125 -71.453125 Z M 64.421875 -32.640625 L 54.15625 -7.140625 L 53.609375 -7.140625 L 43.234375 -32.640625 L 27.78125 -68.96875 L 79.984375 -68.96875 Z M 64.421875 -32.640625 "/></g></g></svg>`,
|
|
321
|
+
darkValue: `<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet"><g fill="#ebebeb" fill-opacity="1"><g transform="translate(-3, 88)"><path d="M 48.3125 1.734375 L 59.78125 1.734375 L 91.5625 -71.453125 L 91.5625 -77.5 L 16.328125 -77.5 L 16.328125 -71.453125 Z M 64.421875 -32.640625 L 54.15625 -7.140625 L 53.609375 -7.140625 L 43.234375 -32.640625 L 27.78125 -68.96875 L 79.984375 -68.96875 Z M 64.421875 -32.640625 "/></g></g></svg>`
|
|
322
|
+
},
|
|
323
|
+
readme: [
|
|
324
|
+
"## What does Valyu do?",
|
|
325
|
+
"",
|
|
326
|
+
"Valyu is an AI-native search and content extraction service that searches across web and proprietary data sources. It returns results optimized for AI applications and RAG pipelines, providing the source material that Ever Works uses to generate accurate work items.",
|
|
327
|
+
"",
|
|
328
|
+
"## Why use it?",
|
|
329
|
+
"",
|
|
330
|
+
"- **Multi-source search** \u2014 search across web, proprietary datasets (arXiv, PubMed, financial data), and news",
|
|
331
|
+
"- **AI-optimized results** \u2014 returns content formatted for AI processing with relevance scoring",
|
|
332
|
+
"- **Content extraction** \u2014 pulls clean text and markdown from web pages",
|
|
333
|
+
"- **Domain filtering** \u2014 include or exclude specific websites from search results",
|
|
334
|
+
"- **Date filtering** \u2014 restrict results to specific time periods",
|
|
335
|
+
"",
|
|
336
|
+
"## How it works in Ever Works",
|
|
337
|
+
"",
|
|
338
|
+
"During work generation, the search facade uses Valyu to find information about each item, discover relevant source URLs, and extract content from web pages. This powers automatic descriptions, source URL resolution, and content enrichment across the generation pipeline.",
|
|
339
|
+
"",
|
|
340
|
+
"## Getting started",
|
|
341
|
+
"",
|
|
342
|
+
"1. Create an account at [valyu.ai](https://valyu.ai)",
|
|
343
|
+
"2. Copy your API key from the Valyu dashboard",
|
|
344
|
+
"3. Enter the key in the **API Key** field below",
|
|
345
|
+
"4. Valyu will be used during work generation when selected as the search provider"
|
|
346
|
+
].join("\n")
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
export { ValyuSearchPlugin, ValyuSearchPlugin as default };
|
package/package.json
CHANGED
|
@@ -1,78 +1,91 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
2
|
+
"name": "@ever-works/valyu-plugin",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "Valyu Plugin - Web search and content extraction using Valyu API",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Ever Co. LTD",
|
|
7
|
+
"email": "ever@ever.co",
|
|
8
|
+
"url": "https://ever.co"
|
|
9
|
+
},
|
|
10
|
+
"license": "AGPL-3.0",
|
|
11
|
+
"private": false,
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.cjs",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"require": "./dist/index.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc --noEmit && tsup",
|
|
28
|
+
"dev": "tsup --watch",
|
|
29
|
+
"type-check": "tsc --noEmit",
|
|
30
|
+
"clean": "rm -rf dist",
|
|
31
|
+
"test": "vitest run --passWithNoTests",
|
|
32
|
+
"test:watch": "vitest",
|
|
33
|
+
"test:coverage": "vitest run --coverage"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"valyu-js": "^2.5.4"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@ever-works/plugin": "^1.2.5"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^26.6.4",
|
|
43
|
+
"@ever-works/plugin": "^1.2.5",
|
|
44
|
+
"tsup": "^8.4.0",
|
|
45
|
+
"typescript": "^5.7.3",
|
|
46
|
+
"vitest": "^5.0.5"
|
|
47
|
+
},
|
|
48
|
+
"everworks": {
|
|
49
|
+
"plugin": {
|
|
50
|
+
"id": "valyu",
|
|
51
|
+
"name": "Valyu",
|
|
52
|
+
"version": "1.0.0",
|
|
53
|
+
"category": "search",
|
|
54
|
+
"capabilities": [
|
|
55
|
+
"search",
|
|
56
|
+
"content-extractor"
|
|
57
|
+
],
|
|
58
|
+
"description": "AI-native search and content extraction using the Valyu API. Supports web, proprietary, and news search with optional content extraction from URLs.",
|
|
59
|
+
"author": {
|
|
60
|
+
"name": "Ever Works Team"
|
|
61
|
+
},
|
|
62
|
+
"license": "AGPL-3.0",
|
|
63
|
+
"autoEnable": false,
|
|
64
|
+
"systemPlugin": false,
|
|
65
|
+
"builtIn": true,
|
|
66
|
+
"envVars": [
|
|
67
|
+
{
|
|
68
|
+
"name": "PLUGIN_VALYU_API_KEY",
|
|
69
|
+
"required": false,
|
|
70
|
+
"secret": true,
|
|
71
|
+
"description": "Valyu API key (optional - can be set via admin/user settings)"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"distribution": "registry"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"repository": {
|
|
78
|
+
"type": "git",
|
|
79
|
+
"url": "git+https://github.com/ever-works/ever-works.git",
|
|
80
|
+
"directory": "packages/plugins/valyu"
|
|
81
|
+
},
|
|
82
|
+
"homepage": "https://github.com/ever-works/ever-works/tree/main/packages/plugins/valyu#readme",
|
|
83
|
+
"bugs": {
|
|
84
|
+
"url": "https://github.com/ever-works/ever-works/issues"
|
|
85
|
+
},
|
|
86
|
+
"everworksRelease": {
|
|
87
|
+
"contentHash": "sha256:8c8dea8cf388efe55f03d52a1113baed5d57e56ec7d9a0ddb65c7ab2eda23022",
|
|
88
|
+
"commit": "19905c70cf05be3bc523db030597046067cd322a",
|
|
89
|
+
"source": "https://github.com/ever-works/ever-works/tree/19905c70cf05be3bc523db030597046067cd322a/packages/plugins/valyu"
|
|
90
|
+
}
|
|
91
|
+
}
|