@openclaw/exa-plugin 2026.11.3 → 2026.11.5-beta.2
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/.setup/{exa-web-search-provider-UdcmLdNp.mjs → exa-web-search-provider-D2HeogPB.mjs} +1 -1
- package/dist/.setup/{exa-web-search-provider.runtime-C73kkrxv.mjs → exa-web-search-provider.runtime-DgICTEId.mjs} +89 -119
- package/dist/.source-module-urls/5cfcb03c5b0024dec174889a3f9c18da47ed3402dc2c1542d3c7152d85411a6d.json +1 -0
- package/dist/index.js +1 -1
- package/dist/web-search-contract-api.js +1 -2
- package/dist/web-search-provider.js +1 -2
- package/package.json +4 -4
package/dist/.setup/{exa-web-search-provider-UdcmLdNp.mjs → exa-web-search-provider-D2HeogPB.mjs}
RENAMED
|
@@ -17,7 +17,7 @@ const EXA_FRESHNESS_VALUES = [
|
|
|
17
17
|
"year"
|
|
18
18
|
];
|
|
19
19
|
const EXA_MAX_SEARCH_COUNT = 100;
|
|
20
|
-
const loadExaWebSearchRuntime = createLazyRuntimeModule(() => import("./exa-web-search-provider.runtime-
|
|
20
|
+
const loadExaWebSearchRuntime = createLazyRuntimeModule(() => import("./exa-web-search-provider.runtime-DgICTEId.mjs"));
|
|
21
21
|
const ExaSearchSchema = {
|
|
22
22
|
type: "object",
|
|
23
23
|
properties: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sha256Hex } from "openclaw/plugin-sdk/node-crypto-runtime";
|
|
2
2
|
import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
3
3
|
import { ProviderHttpError, readProviderResponseErrorText, redactProviderResponseErrorText } from "openclaw/plugin-sdk/provider-http";
|
|
4
|
-
import { DEFAULT_SEARCH_COUNT, buildSearchCacheKey, mergeScopedSearchConfig, parseIsoDateRange, readCachedSearchPayload,
|
|
4
|
+
import { DEFAULT_SEARCH_COUNT, buildSearchCacheKey, externalContentStamp, mergeScopedSearchConfig, parseIsoDateRange, readCachedSearchPayload, readPositiveIntegerParam, readStringParam, readWebSearchApiKey, resolveProviderWebSearchPluginConfig, resolveSearchCacheTtlMs, resolveSearchTimeoutSeconds, resolveSiteName, withTrustedWebSearchEndpoint, wrapWebContent, writeCachedSearchPayload } from "openclaw/plugin-sdk/provider-web-search";
|
|
5
5
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
6
6
|
import { asOptionalObjectRecord, asOptionalRecord, isRecord, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
7
|
//#region extensions/exa/src/exa-web-search-provider.runtime.ts
|
|
@@ -23,23 +23,6 @@ const EXA_FRESHNESS_VALUES = [
|
|
|
23
23
|
const EXA_MAX_SEARCH_COUNT = 100;
|
|
24
24
|
const EXA_ERROR_BODY_LIMIT_BYTES = 8192;
|
|
25
25
|
const EXA_SEARCH_JSON_MAX_BYTES = 16777216;
|
|
26
|
-
async function readExaSearchResults(response) {
|
|
27
|
-
const bytes = await readResponseWithLimit(response, EXA_SEARCH_JSON_MAX_BYTES, { onOverflow: ({ maxBytes: maxBytesLocal }) => /* @__PURE__ */ new Error(`Exa API response exceeds ${maxBytesLocal} bytes`) });
|
|
28
|
-
try {
|
|
29
|
-
const payload = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
30
|
-
const results = asOptionalObjectRecord(payload)?.results;
|
|
31
|
-
return Array.isArray(results) ? results.filter(isRecord) : [];
|
|
32
|
-
} catch (cause) {
|
|
33
|
-
throw new Error("Exa API returned malformed JSON", { cause });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function normalizeExaFreshness(value) {
|
|
37
|
-
const trimmed = normalizeOptionalLowercaseString(value);
|
|
38
|
-
return EXA_FRESHNESS_VALUES.find((freshness) => freshness === trimmed);
|
|
39
|
-
}
|
|
40
|
-
function resolveExaApiKey(exa) {
|
|
41
|
-
return readConfiguredSecretString(exa?.apiKey, "plugins.entries.exa.config.webSearch.apiKey") ?? readProviderEnvValue(["EXA_API_KEY"]);
|
|
42
|
-
}
|
|
43
26
|
function invalidBaseUrlPayload() {
|
|
44
27
|
return {
|
|
45
28
|
error: "invalid_base_url",
|
|
@@ -47,23 +30,6 @@ function invalidBaseUrlPayload() {
|
|
|
47
30
|
docs: "https://docs.openclaw.ai/tools/exa-search"
|
|
48
31
|
};
|
|
49
32
|
}
|
|
50
|
-
function resolveExaSearchEndpoint(exa) {
|
|
51
|
-
const configured = normalizeOptionalString(exa?.baseUrl);
|
|
52
|
-
if (!configured) return { endpoint: EXA_SEARCH_ENDPOINT };
|
|
53
|
-
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(configured) && !/^https?:\/\//i.test(configured)) return invalidBaseUrlPayload();
|
|
54
|
-
const candidate = /^https?:\/\//i.test(configured) ? configured : `https://${configured}`;
|
|
55
|
-
let parsed;
|
|
56
|
-
try {
|
|
57
|
-
parsed = new URL(candidate);
|
|
58
|
-
} catch {
|
|
59
|
-
return invalidBaseUrlPayload();
|
|
60
|
-
}
|
|
61
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return invalidBaseUrlPayload();
|
|
62
|
-
const pathname = parsed.pathname.replace(/\/+$/, "");
|
|
63
|
-
parsed.pathname = pathname.endsWith("/search") ? pathname : `${pathname}/search`;
|
|
64
|
-
parsed.hash = "";
|
|
65
|
-
return { endpoint: parsed.toString() };
|
|
66
|
-
}
|
|
67
33
|
function invalidContentsPayload(message) {
|
|
68
34
|
return {
|
|
69
35
|
error: "invalid_contents",
|
|
@@ -71,92 +37,42 @@ function invalidContentsPayload(message) {
|
|
|
71
37
|
docs: "https://docs.openclaw.ai/tools/web"
|
|
72
38
|
};
|
|
73
39
|
}
|
|
74
|
-
function parseExaContents(rawContents) {
|
|
75
|
-
if (rawContents === void 0) return { value: void 0 };
|
|
76
|
-
if (!isRecord(rawContents)) return invalidContentsPayload("contents must be an object with optional text, highlights, and summary fields.");
|
|
77
|
-
const raw = rawContents;
|
|
78
|
-
const allowedKeys = /* @__PURE__ */ new Set([
|
|
79
|
-
"text",
|
|
80
|
-
"highlights",
|
|
81
|
-
"summary"
|
|
82
|
-
]);
|
|
83
|
-
for (const key of Object.keys(raw)) if (!allowedKeys.has(key)) return invalidContentsPayload(`contents has unknown field "${key}". Only "text", "highlights", and "summary" are allowed.`);
|
|
84
|
-
const parsed = {};
|
|
85
|
-
const fieldsBySection = {
|
|
86
|
-
text: ["maxCharacters"],
|
|
87
|
-
highlights: [
|
|
88
|
-
"maxCharacters",
|
|
89
|
-
"query",
|
|
90
|
-
"numSentences",
|
|
91
|
-
"highlightsPerUrl"
|
|
92
|
-
],
|
|
93
|
-
summary: ["query"]
|
|
94
|
-
};
|
|
95
|
-
for (const section of [
|
|
96
|
-
"text",
|
|
97
|
-
"highlights",
|
|
98
|
-
"summary"
|
|
99
|
-
]) {
|
|
100
|
-
if (!(section in raw)) continue;
|
|
101
|
-
const value = raw[section];
|
|
102
|
-
if (typeof value === "boolean") {
|
|
103
|
-
parsed[section] = value;
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
if (!isRecord(value)) return invalidContentsPayload(`contents.${section} must be a boolean or an object.`);
|
|
107
|
-
const option = value;
|
|
108
|
-
const fields = fieldsBySection[section];
|
|
109
|
-
for (const key of Object.keys(option)) if (!fields.includes(key)) return invalidContentsPayload(`contents.${section} has unknown field "${key}". ${section === "highlights" ? "Allowed fields are \"maxCharacters\", \"query\", \"numSentences\", and \"highlightsPerUrl\"." : `Only "${fields[0]}" is allowed.`}`);
|
|
110
|
-
for (const field of fields) if (field !== "query" && field in option && !(typeof option[field] === "number" && Number.isInteger(option[field]) && option[field] > 0)) return invalidContentsPayload(`contents.${section}.${field} must be a positive integer.`);
|
|
111
|
-
if (section !== "text" && "query" in option && typeof option.query !== "string") return invalidContentsPayload(`contents.${section}.query must be a string.`);
|
|
112
|
-
const normalized = {};
|
|
113
|
-
for (const field of fields) if (field in option) normalized[field] = option[field];
|
|
114
|
-
Object.assign(parsed, { [section]: normalized });
|
|
115
|
-
}
|
|
116
|
-
return { value: parsed };
|
|
117
|
-
}
|
|
118
|
-
function resolveFreshnessStartDate(freshness) {
|
|
119
|
-
const now = /* @__PURE__ */ new Date();
|
|
120
|
-
if (freshness === "day") {
|
|
121
|
-
now.setUTCDate(now.getUTCDate() - 1);
|
|
122
|
-
return now.toISOString();
|
|
123
|
-
}
|
|
124
|
-
if (freshness === "week") {
|
|
125
|
-
now.setUTCDate(now.getUTCDate() - 7);
|
|
126
|
-
return now.toISOString();
|
|
127
|
-
}
|
|
128
|
-
if (freshness === "month") {
|
|
129
|
-
const currentDay = now.getUTCDate();
|
|
130
|
-
now.setUTCDate(1);
|
|
131
|
-
now.setUTCMonth(now.getUTCMonth() - 1);
|
|
132
|
-
const lastDayOfTargetMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 0)).getUTCDate();
|
|
133
|
-
now.setUTCDate(Math.min(currentDay, lastDayOfTargetMonth));
|
|
134
|
-
return now.toISOString();
|
|
135
|
-
}
|
|
136
|
-
now.setUTCFullYear(now.getUTCFullYear() - 1);
|
|
137
|
-
return now.toISOString();
|
|
138
|
-
}
|
|
139
40
|
async function executeExaWebSearchProviderTool(ctx, args, signal) {
|
|
140
41
|
const searchConfig = mergeScopedSearchConfig(ctx.searchConfig, "exa", resolveProviderWebSearchPluginConfig(ctx.config, "exa"));
|
|
141
42
|
const exaConfig = asOptionalRecord(searchConfig?.exa);
|
|
142
|
-
const apiKey =
|
|
43
|
+
const apiKey = readWebSearchApiKey(exaConfig?.apiKey, "plugins.entries.exa.config.webSearch.apiKey", ["EXA_API_KEY"]);
|
|
143
44
|
if (!apiKey) return {
|
|
144
45
|
error: "missing_exa_api_key",
|
|
145
46
|
message: "web_search (exa) needs an Exa API key. Set EXA_API_KEY in the Gateway environment, or configure plugins.entries.exa.config.webSearch.apiKey.",
|
|
146
47
|
docs: "https://docs.openclaw.ai/tools/web"
|
|
147
48
|
};
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
49
|
+
let endpoint = EXA_SEARCH_ENDPOINT;
|
|
50
|
+
const configured = normalizeOptionalString(exaConfig?.baseUrl);
|
|
51
|
+
if (configured) {
|
|
52
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(configured) && !/^https?:\/\//i.test(configured)) return invalidBaseUrlPayload();
|
|
53
|
+
const candidate = /^https?:\/\//i.test(configured) ? configured : `https://${configured}`;
|
|
54
|
+
let parsed;
|
|
55
|
+
try {
|
|
56
|
+
parsed = new URL(candidate);
|
|
57
|
+
} catch {
|
|
58
|
+
return invalidBaseUrlPayload();
|
|
59
|
+
}
|
|
60
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return invalidBaseUrlPayload();
|
|
61
|
+
const pathname = parsed.pathname.replace(/\/+$/, "");
|
|
62
|
+
parsed.pathname = pathname.endsWith("/search") ? pathname : `${pathname}/search`;
|
|
63
|
+
parsed.hash = "";
|
|
64
|
+
endpoint = parsed.toString();
|
|
65
|
+
}
|
|
151
66
|
const query = readStringParam(args, "query", { required: true });
|
|
152
67
|
const rawType = readStringParam(args, "type");
|
|
153
68
|
const type = EXA_SEARCH_TYPES.find((candidate) => candidate === rawType) ?? "auto";
|
|
154
69
|
const count = readPositiveIntegerParam(args, "count", {
|
|
155
70
|
max: EXA_MAX_SEARCH_COUNT,
|
|
156
71
|
message: `count must be an integer from 1 to ${EXA_MAX_SEARCH_COUNT}.`
|
|
157
|
-
}) ?? searchConfig?.maxResults
|
|
72
|
+
}) ?? searchConfig?.maxResults;
|
|
158
73
|
const rawFreshness = readStringParam(args, "freshness");
|
|
159
|
-
const
|
|
74
|
+
const normalizedFreshness = normalizeOptionalLowercaseString(rawFreshness);
|
|
75
|
+
const freshness = EXA_FRESHNESS_VALUES.find((value) => value === normalizedFreshness);
|
|
160
76
|
if (rawFreshness && !freshness) return {
|
|
161
77
|
error: "invalid_freshness",
|
|
162
78
|
message: "freshness must be one of \"day\", \"week\", \"month\", or \"year\".",
|
|
@@ -178,13 +94,53 @@ async function executeExaWebSearchProviderTool(ctx, args, signal) {
|
|
|
178
94
|
});
|
|
179
95
|
if ("error" in parsedDateRange) return parsedDateRange;
|
|
180
96
|
const { dateAfter, dateBefore } = parsedDateRange;
|
|
181
|
-
const parsedContents =
|
|
182
|
-
|
|
183
|
-
|
|
97
|
+
const parsedContents = {};
|
|
98
|
+
const rawContents = args.contents;
|
|
99
|
+
if (rawContents !== void 0) {
|
|
100
|
+
if (!isRecord(rawContents)) return invalidContentsPayload("contents must be an object with optional text, highlights, and summary fields.");
|
|
101
|
+
const allowedKeys = /* @__PURE__ */ new Set([
|
|
102
|
+
"text",
|
|
103
|
+
"highlights",
|
|
104
|
+
"summary"
|
|
105
|
+
]);
|
|
106
|
+
for (const key of Object.keys(rawContents)) if (!allowedKeys.has(key)) return invalidContentsPayload(`contents has unknown field "${key}". Only "text", "highlights", and "summary" are allowed.`);
|
|
107
|
+
const fieldsBySection = {
|
|
108
|
+
text: ["maxCharacters"],
|
|
109
|
+
highlights: [
|
|
110
|
+
"maxCharacters",
|
|
111
|
+
"query",
|
|
112
|
+
"numSentences",
|
|
113
|
+
"highlightsPerUrl"
|
|
114
|
+
],
|
|
115
|
+
summary: ["query"]
|
|
116
|
+
};
|
|
117
|
+
for (const section of [
|
|
118
|
+
"text",
|
|
119
|
+
"highlights",
|
|
120
|
+
"summary"
|
|
121
|
+
]) {
|
|
122
|
+
if (!(section in rawContents)) continue;
|
|
123
|
+
const value = rawContents[section];
|
|
124
|
+
if (typeof value === "boolean") {
|
|
125
|
+
parsedContents[section] = value;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (!isRecord(value)) return invalidContentsPayload(`contents.${section} must be a boolean or an object.`);
|
|
129
|
+
const option = value;
|
|
130
|
+
const fields = fieldsBySection[section];
|
|
131
|
+
for (const key of Object.keys(option)) if (!fields.includes(key)) return invalidContentsPayload(`contents.${section} has unknown field "${key}". ${section === "highlights" ? "Allowed fields are \"maxCharacters\", \"query\", \"numSentences\", and \"highlightsPerUrl\"." : `Only "${fields[0]}" is allowed.`}`);
|
|
132
|
+
for (const field of fields) if (field !== "query" && field in option && !(typeof option[field] === "number" && Number.isInteger(option[field]) && option[field] > 0)) return invalidContentsPayload(`contents.${section}.${field} must be a positive integer.`);
|
|
133
|
+
if (section !== "text" && "query" in option && typeof option.query !== "string") return invalidContentsPayload(`contents.${section}.query must be a string.`);
|
|
134
|
+
const normalized = {};
|
|
135
|
+
for (const field of fields) if (field in option) normalized[field] = option[field];
|
|
136
|
+
Object.assign(parsedContents, { [section]: normalized });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const contents = Object.keys(parsedContents).length > 0 ? parsedContents : void 0;
|
|
184
140
|
const resolvedCount = Math.min(EXA_MAX_SEARCH_COUNT, parseStrictPositiveInteger(count) ?? DEFAULT_SEARCH_COUNT);
|
|
185
141
|
const cacheKey = buildSearchCacheKey([
|
|
186
142
|
"exa",
|
|
187
|
-
|
|
143
|
+
sha256Hex(apiKey),
|
|
188
144
|
endpoint,
|
|
189
145
|
type,
|
|
190
146
|
query,
|
|
@@ -206,7 +162,19 @@ async function executeExaWebSearchProviderTool(ctx, args, signal) {
|
|
|
206
162
|
contents: contents ?? { highlights: true }
|
|
207
163
|
};
|
|
208
164
|
if (dateAfter) body.startPublishedDate = dateAfter;
|
|
209
|
-
else if (freshness)
|
|
165
|
+
else if (freshness) {
|
|
166
|
+
const now = /* @__PURE__ */ new Date();
|
|
167
|
+
if (freshness === "day") now.setUTCDate(now.getUTCDate() - 1);
|
|
168
|
+
else if (freshness === "week") now.setUTCDate(now.getUTCDate() - 7);
|
|
169
|
+
else if (freshness === "month") {
|
|
170
|
+
const currentDay = now.getUTCDate();
|
|
171
|
+
now.setUTCDate(1);
|
|
172
|
+
now.setUTCMonth(now.getUTCMonth() - 1);
|
|
173
|
+
const lastDayOfTargetMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 0)).getUTCDate();
|
|
174
|
+
now.setUTCDate(Math.min(currentDay, lastDayOfTargetMonth));
|
|
175
|
+
} else now.setUTCFullYear(now.getUTCFullYear() - 1);
|
|
176
|
+
body.startPublishedDate = now.toISOString();
|
|
177
|
+
}
|
|
210
178
|
if (dateBefore) body.endPublishedDate = dateBefore;
|
|
211
179
|
const headers = {
|
|
212
180
|
Accept: "application/json",
|
|
@@ -228,7 +196,14 @@ async function executeExaWebSearchProviderTool(ctx, args, signal) {
|
|
|
228
196
|
const detail = await readProviderResponseErrorText(res, EXA_ERROR_BODY_LIMIT_BYTES, headers, signal);
|
|
229
197
|
throw new ProviderHttpError(`Exa API error (${res.status}): ${detail || redactProviderResponseErrorText(res.statusText, headers)}`, { status: res.status });
|
|
230
198
|
}
|
|
231
|
-
|
|
199
|
+
const bytes = await readResponseWithLimit(res, EXA_SEARCH_JSON_MAX_BYTES, { onOverflow: ({ maxBytes: maxBytesLocal }) => /* @__PURE__ */ new Error(`Exa API response exceeds ${maxBytesLocal} bytes`) });
|
|
200
|
+
try {
|
|
201
|
+
const payload = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
202
|
+
const rows = asOptionalObjectRecord(payload)?.results;
|
|
203
|
+
return (Array.isArray(rows) ? rows.filter(isRecord) : []).slice(0, resolvedCount);
|
|
204
|
+
} catch (cause) {
|
|
205
|
+
throw new Error("Exa API returned malformed JSON", { cause });
|
|
206
|
+
}
|
|
232
207
|
});
|
|
233
208
|
signal?.throwIfAborted();
|
|
234
209
|
const payload = {
|
|
@@ -236,12 +211,7 @@ async function executeExaWebSearchProviderTool(ctx, args, signal) {
|
|
|
236
211
|
provider: "exa",
|
|
237
212
|
count: results.length,
|
|
238
213
|
tookMs: Date.now() - start,
|
|
239
|
-
externalContent:
|
|
240
|
-
untrusted: true,
|
|
241
|
-
source: "web_search",
|
|
242
|
-
provider: "exa",
|
|
243
|
-
wrapped: true
|
|
244
|
-
},
|
|
214
|
+
externalContent: externalContentStamp("exa"),
|
|
245
215
|
results: results.map((entry) => {
|
|
246
216
|
const title = typeof entry.title === "string" ? entry.title : "";
|
|
247
217
|
const url = typeof entry.url === "string" ? entry.url : "";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"entries":[{"output":"index.js","source":"extensions/exa/index.ts"},{"output":"web-search-contract-api.js","source":"extensions/exa/web-search-contract-api.ts"},{"output":"web-search-provider.js","source":"extensions/exa/web-search-provider.ts"}],"chunks":[{"output":".setup/exa-web-search-provider-D2HeogPB.mjs","sha256":"0376e59d945efe6e5dbef89207a011a0a51759b809d3bd91528af9a5c1fed5d4","facadeSource":null,"sources":["extensions/exa/src/exa-web-search-provider.ts"]},{"output":".setup/exa-web-search-provider.runtime-DgICTEId.mjs","sha256":"c748c42f12fbd97cba1a6d541950ba07a1618d18e4b314aebb25727b5aeb8439","facadeSource":"extensions/exa/src/exa-web-search-provider.runtime.ts","sources":["extensions/exa/src/exa-web-search-provider.runtime.ts"]},{"output":"index.js","sha256":"703c4ed77aa96f5957c8c49249c31530654d9d746e8c7639641184bdb0a00874","facadeSource":"extensions/exa/index.ts","sources":["extensions/exa/index.ts"]},{"output":"web-search-contract-api.js","sha256":"1971df1282041c8023828af88b4ce58e91c068917b10fd16ded2fd71dbc6ac42","facadeSource":"extensions/exa/web-search-contract-api.ts","sources":[]},{"output":"web-search-provider.js","sha256":"2b368e8fb211191494aaf0db90c8478a66c86bcd99368e2c1f09b75560f96f59","facadeSource":"extensions/exa/web-search-provider.ts","sources":[]}],"unrenderedSources":["extensions/exa/web-search-contract-api.ts","extensions/exa/web-search-provider.ts"]}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createExaWebSearchProvider } from "./.setup/exa-web-search-provider-
|
|
1
|
+
import { t as createExaWebSearchProvider } from "./.setup/exa-web-search-provider-D2HeogPB.mjs";
|
|
2
2
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
3
3
|
//#region extensions/exa/index.ts
|
|
4
4
|
var exa_default = definePluginEntry({
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { createExaWebSearchProvider };
|
|
1
|
+
export { t as createExaWebSearchProvider } from "./.setup/exa-web-search-provider-D2HeogPB.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/exa-plugin",
|
|
3
|
-
"version": "2026.11.
|
|
3
|
+
"version": "2026.11.5-beta.2",
|
|
4
4
|
"description": "OpenClaw Exa plugin.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"minHostVersion": ">=2026.6.8"
|
|
19
19
|
},
|
|
20
20
|
"compat": {
|
|
21
|
-
"pluginApi": ">=2026.11.
|
|
21
|
+
"pluginApi": ">=2026.11.5-beta.2"
|
|
22
22
|
},
|
|
23
23
|
"build": {
|
|
24
|
-
"openclawVersion": "2026.11.
|
|
24
|
+
"openclawVersion": "2026.11.5-beta.2",
|
|
25
25
|
"bundledDist": false
|
|
26
26
|
},
|
|
27
27
|
"release": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"assets/activity.svg"
|
|
41
41
|
],
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"openclaw": ">=2026.11.
|
|
43
|
+
"openclaw": ">=2026.11.5-beta.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"openclaw": {
|