@openclaw/exa-plugin 2026.8.1-beta.3 → 2026.9.1-beta.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/dist/{exa-web-search-provider-BJD3zsL0.js → exa-web-search-provider-Du2L8CNV.js} +30 -2
- package/dist/{exa-web-search-provider.runtime-Uysj-tWk.js → exa-web-search-provider.runtime-C29VmLqm.js} +27 -47
- package/dist/index.js +1 -1
- package/dist/web-search-contract-api.js +2 -9
- package/dist/web-search-provider.js +1 -1
- package/package.json +4 -4
- package/dist/exa-web-search-provider.shared-CWlikD_3.js +0 -30
|
@@ -1,5 +1,33 @@
|
|
|
1
|
-
import { t as createExaWebSearchProviderBase } from "./exa-web-search-provider.shared-CWlikD_3.js";
|
|
2
1
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
2
|
+
import { createWebSearchProviderContractFields } from "openclaw/plugin-sdk/provider-web-search-contract";
|
|
3
|
+
//#region extensions/exa/src/exa-web-search-provider.shared.ts
|
|
4
|
+
const EXA_CREDENTIAL_PATH = "plugins.entries.exa.config.webSearch.apiKey";
|
|
5
|
+
const EXA_ONBOARDING_SCOPES = ["text-inference"];
|
|
6
|
+
function createExaWebSearchProviderBase() {
|
|
7
|
+
return {
|
|
8
|
+
id: "exa",
|
|
9
|
+
label: "Exa Search",
|
|
10
|
+
hint: "Neural + keyword search with date filters and content extraction",
|
|
11
|
+
onboardingScopes: [...EXA_ONBOARDING_SCOPES],
|
|
12
|
+
credentialLabel: "Exa API key",
|
|
13
|
+
envVars: ["EXA_API_KEY"],
|
|
14
|
+
placeholder: "exa-...",
|
|
15
|
+
signupUrl: "https://exa.ai/",
|
|
16
|
+
docsUrl: "https://docs.openclaw.ai/tools/web",
|
|
17
|
+
autoDetectOrder: 65,
|
|
18
|
+
credentialPath: EXA_CREDENTIAL_PATH,
|
|
19
|
+
...createWebSearchProviderContractFields({
|
|
20
|
+
credentialPath: EXA_CREDENTIAL_PATH,
|
|
21
|
+
searchCredential: {
|
|
22
|
+
type: "scoped",
|
|
23
|
+
scopeId: "exa"
|
|
24
|
+
},
|
|
25
|
+
configuredCredential: { pluginId: "exa" },
|
|
26
|
+
selectionPluginId: "exa"
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
3
31
|
//#region extensions/exa/src/exa-web-search-provider.ts
|
|
4
32
|
const EXA_SEARCH_TYPES = [
|
|
5
33
|
"auto",
|
|
@@ -16,7 +44,7 @@ const EXA_FRESHNESS_VALUES = [
|
|
|
16
44
|
"year"
|
|
17
45
|
];
|
|
18
46
|
const EXA_MAX_SEARCH_COUNT = 100;
|
|
19
|
-
const loadExaWebSearchRuntime = createLazyRuntimeModule(() => import("./exa-web-search-provider.runtime-
|
|
47
|
+
const loadExaWebSearchRuntime = createLazyRuntimeModule(() => import("./exa-web-search-provider.runtime-C29VmLqm.js"));
|
|
20
48
|
const ExaSearchSchema = {
|
|
21
49
|
type: "object",
|
|
22
50
|
properties: {
|
|
@@ -108,58 +108,38 @@ function parseExaContents(rawContents) {
|
|
|
108
108
|
]);
|
|
109
109
|
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.`);
|
|
110
110
|
const parsed = {};
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const obj = value;
|
|
115
|
-
for (const key of Object.keys(obj)) if (key !== "maxCharacters") return invalidContentsPayload(`contents.text has unknown field "${key}". Only "maxCharacters" is allowed.`);
|
|
116
|
-
if ("maxCharacters" in obj && parsePositiveInteger(obj.maxCharacters) === void 0) return invalidContentsPayload("contents.text.maxCharacters must be a positive integer.");
|
|
117
|
-
return parsePositiveInteger(obj.maxCharacters) ? { maxCharacters: parsePositiveInteger(obj.maxCharacters) } : {};
|
|
118
|
-
};
|
|
119
|
-
const parseHighlights = (value) => {
|
|
120
|
-
if (typeof value === "boolean") return value;
|
|
121
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return invalidContentsPayload("contents.highlights must be a boolean or an object.");
|
|
122
|
-
const obj = value;
|
|
123
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
111
|
+
const fieldsBySection = {
|
|
112
|
+
text: ["maxCharacters"],
|
|
113
|
+
highlights: [
|
|
124
114
|
"maxCharacters",
|
|
125
115
|
"query",
|
|
126
116
|
"numSentences",
|
|
127
117
|
"highlightsPerUrl"
|
|
128
|
-
]
|
|
129
|
-
|
|
130
|
-
if ("maxCharacters" in obj && parsePositiveInteger(obj.maxCharacters) === void 0) return invalidContentsPayload("contents.highlights.maxCharacters must be a positive integer.");
|
|
131
|
-
if ("numSentences" in obj && parsePositiveInteger(obj.numSentences) === void 0) return invalidContentsPayload("contents.highlights.numSentences must be a positive integer.");
|
|
132
|
-
if ("highlightsPerUrl" in obj && parsePositiveInteger(obj.highlightsPerUrl) === void 0) return invalidContentsPayload("contents.highlights.highlightsPerUrl must be a positive integer.");
|
|
133
|
-
if ("query" in obj && typeof obj.query !== "string") return invalidContentsPayload("contents.highlights.query must be a string.");
|
|
134
|
-
return {
|
|
135
|
-
...parsePositiveInteger(obj.maxCharacters) ? { maxCharacters: parsePositiveInteger(obj.maxCharacters) } : {},
|
|
136
|
-
...typeof obj.query === "string" ? { query: obj.query } : {},
|
|
137
|
-
...parsePositiveInteger(obj.numSentences) ? { numSentences: parsePositiveInteger(obj.numSentences) } : {},
|
|
138
|
-
...parsePositiveInteger(obj.highlightsPerUrl) ? { highlightsPerUrl: parsePositiveInteger(obj.highlightsPerUrl) } : {}
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
|
-
const parseSummary = (value) => {
|
|
142
|
-
if (typeof value === "boolean") return value;
|
|
143
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return invalidContentsPayload("contents.summary must be a boolean or an object.");
|
|
144
|
-
const obj = value;
|
|
145
|
-
for (const key of Object.keys(obj)) if (key !== "query") return invalidContentsPayload(`contents.summary has unknown field "${key}". Only "query" is allowed.`);
|
|
146
|
-
if ("query" in obj && typeof obj.query !== "string") return invalidContentsPayload("contents.summary.query must be a string.");
|
|
147
|
-
return typeof obj.query === "string" ? { query: obj.query } : {};
|
|
118
|
+
],
|
|
119
|
+
summary: ["query"]
|
|
148
120
|
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
121
|
+
for (const section of [
|
|
122
|
+
"text",
|
|
123
|
+
"highlights",
|
|
124
|
+
"summary"
|
|
125
|
+
]) {
|
|
126
|
+
if (!(section in raw)) continue;
|
|
127
|
+
const value = raw[section];
|
|
128
|
+
if (typeof value === "boolean") {
|
|
129
|
+
parsed[section] = value;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return invalidContentsPayload(`contents.${section} must be a boolean or an object.`);
|
|
133
|
+
const option = value;
|
|
134
|
+
const fields = fieldsBySection[section] ?? [];
|
|
135
|
+
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.`}`);
|
|
136
|
+
for (const field of fields) if (field !== "query" && field in option && parsePositiveInteger(option[field]) === void 0) return invalidContentsPayload(`contents.${section}.${field} must be a positive integer.`);
|
|
137
|
+
if (section !== "text" && "query" in option && typeof option.query !== "string") return invalidContentsPayload(`contents.${section}.query must be a string.`);
|
|
138
|
+
const normalized = {};
|
|
139
|
+
for (const field of fields) if (field === "query") {
|
|
140
|
+
if (typeof option.query === "string") normalized.query = option.query;
|
|
141
|
+
} else if (parsePositiveInteger(option[field])) normalized[field] = parsePositiveInteger(option[field]);
|
|
142
|
+
Object.assign(parsed, { [section]: normalized });
|
|
163
143
|
}
|
|
164
144
|
return { value: parsed };
|
|
165
145
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createExaWebSearchProvider } from "./exa-web-search-provider-
|
|
1
|
+
import { t as createExaWebSearchProvider } from "./exa-web-search-provider-Du2L8CNV.js";
|
|
2
2
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
3
3
|
//#region extensions/exa/index.ts
|
|
4
4
|
var exa_default = definePluginEntry({
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
|
|
3
|
-
function createExaWebSearchProvider() {
|
|
4
|
-
return {
|
|
5
|
-
...createExaWebSearchProviderBase(),
|
|
6
|
-
createTool: () => null
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
//#endregion
|
|
1
|
+
import { t as createExaWebSearchProvider } from "./exa-web-search-provider-Du2L8CNV.js";
|
|
2
|
+
import "./web-search-provider.js";
|
|
10
3
|
export { createExaWebSearchProvider };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createExaWebSearchProvider } from "./exa-web-search-provider-
|
|
1
|
+
import { t as createExaWebSearchProvider } from "./exa-web-search-provider-Du2L8CNV.js";
|
|
2
2
|
export { createExaWebSearchProvider };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/exa-plugin",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.9.1-beta.1",
|
|
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.
|
|
21
|
+
"pluginApi": ">=2026.9.1-beta.1"
|
|
22
22
|
},
|
|
23
23
|
"build": {
|
|
24
|
-
"openclawVersion": "2026.
|
|
24
|
+
"openclawVersion": "2026.9.1-beta.1",
|
|
25
25
|
"bundledDist": false
|
|
26
26
|
},
|
|
27
27
|
"release": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"README.md"
|
|
39
39
|
],
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"openclaw": ">=2026.
|
|
41
|
+
"openclaw": ">=2026.9.1-beta.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependenciesMeta": {
|
|
44
44
|
"openclaw": {
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { createWebSearchProviderContractFields } from "openclaw/plugin-sdk/provider-web-search-contract";
|
|
2
|
-
//#region extensions/exa/src/exa-web-search-provider.shared.ts
|
|
3
|
-
const EXA_CREDENTIAL_PATH = "plugins.entries.exa.config.webSearch.apiKey";
|
|
4
|
-
const EXA_ONBOARDING_SCOPES = ["text-inference"];
|
|
5
|
-
function createExaWebSearchProviderBase() {
|
|
6
|
-
return {
|
|
7
|
-
id: "exa",
|
|
8
|
-
label: "Exa Search",
|
|
9
|
-
hint: "Neural + keyword search with date filters and content extraction",
|
|
10
|
-
onboardingScopes: [...EXA_ONBOARDING_SCOPES],
|
|
11
|
-
credentialLabel: "Exa API key",
|
|
12
|
-
envVars: ["EXA_API_KEY"],
|
|
13
|
-
placeholder: "exa-...",
|
|
14
|
-
signupUrl: "https://exa.ai/",
|
|
15
|
-
docsUrl: "https://docs.openclaw.ai/tools/web",
|
|
16
|
-
autoDetectOrder: 65,
|
|
17
|
-
credentialPath: EXA_CREDENTIAL_PATH,
|
|
18
|
-
...createWebSearchProviderContractFields({
|
|
19
|
-
credentialPath: EXA_CREDENTIAL_PATH,
|
|
20
|
-
searchCredential: {
|
|
21
|
-
type: "scoped",
|
|
22
|
-
scopeId: "exa"
|
|
23
|
-
},
|
|
24
|
-
configuredCredential: { pluginId: "exa" },
|
|
25
|
-
selectionPluginId: "exa"
|
|
26
|
-
})
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { createExaWebSearchProviderBase as t };
|