exa-js 1.9.1 → 1.9.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.d.mts +1203 -2466
- package/dist/index.d.ts +1203 -2466
- package/dist/index.js +253 -169
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +253 -169
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -71,6 +71,89 @@ __export(index_exports, {
|
|
|
71
71
|
module.exports = __toCommonJS(index_exports);
|
|
72
72
|
var import_cross_fetch = __toESM(require("cross-fetch"));
|
|
73
73
|
|
|
74
|
+
// package.json
|
|
75
|
+
var package_default = {
|
|
76
|
+
name: "exa-js",
|
|
77
|
+
version: "1.9.3",
|
|
78
|
+
description: "Exa SDK for Node.js and the browser",
|
|
79
|
+
publishConfig: {
|
|
80
|
+
access: "public"
|
|
81
|
+
},
|
|
82
|
+
files: [
|
|
83
|
+
"dist"
|
|
84
|
+
],
|
|
85
|
+
main: "./dist/index.js",
|
|
86
|
+
module: "./dist/index.mjs",
|
|
87
|
+
exports: {
|
|
88
|
+
".": {
|
|
89
|
+
types: "./dist/index.d.ts",
|
|
90
|
+
require: "./dist/index.js",
|
|
91
|
+
module: "./dist/index.mjs",
|
|
92
|
+
import: "./dist/index.mjs"
|
|
93
|
+
},
|
|
94
|
+
"./package.json": "./package.json"
|
|
95
|
+
},
|
|
96
|
+
types: "./dist/index.d.ts",
|
|
97
|
+
scripts: {
|
|
98
|
+
"build-fast": "tsup src/index.ts --format cjs,esm",
|
|
99
|
+
build: "tsup",
|
|
100
|
+
test: "vitest run",
|
|
101
|
+
typecheck: "tsc --noEmit",
|
|
102
|
+
"typecheck:src": "tsc --noEmit src/**/*.ts",
|
|
103
|
+
"typecheck:examples": "tsc --noEmit examples/**/*.ts",
|
|
104
|
+
"generate:types:websets": "openapi-typescript https://raw.githubusercontent.com/exa-labs/openapi-spec/refs/heads/master/exa-websets-spec.yaml --enum --root-types --alphabetize --root-types-no-schema-prefix --output ./src/websets/openapi.ts && npm run format:websets",
|
|
105
|
+
format: 'prettier --write "src/**/*.ts" "examples/**/*.ts"',
|
|
106
|
+
"format:websets": "prettier --write src/websets/openapi.ts",
|
|
107
|
+
"build:beta": "cross-env NPM_CONFIG_TAG=beta npm run build",
|
|
108
|
+
"version:beta": "npm version prerelease --preid=beta",
|
|
109
|
+
"version:stable": "npm version patch",
|
|
110
|
+
"publish:beta": "npm run version:beta && npm run build:beta && npm publish --tag beta",
|
|
111
|
+
"publish:stable": "npm run version:stable && npm run build && npm publish",
|
|
112
|
+
prepublishOnly: "npm run build"
|
|
113
|
+
},
|
|
114
|
+
license: "MIT",
|
|
115
|
+
devDependencies: {
|
|
116
|
+
"@types/node": "~22.14.0",
|
|
117
|
+
"cross-env": "~7.0.3",
|
|
118
|
+
"openapi-typescript": "~7.6.1",
|
|
119
|
+
prettier: "~3.5.3",
|
|
120
|
+
"ts-node": "~10.9.2",
|
|
121
|
+
tsup: "~8.4.0",
|
|
122
|
+
typescript: "~5.8.3",
|
|
123
|
+
vitest: "~3.1.1"
|
|
124
|
+
},
|
|
125
|
+
dependencies: {
|
|
126
|
+
"cross-fetch": "~4.1.0",
|
|
127
|
+
dotenv: "~16.4.7",
|
|
128
|
+
openai: "^5.0.1",
|
|
129
|
+
zod: "^3.22.0",
|
|
130
|
+
"zod-to-json-schema": "^3.20.0"
|
|
131
|
+
},
|
|
132
|
+
directories: {
|
|
133
|
+
test: "test"
|
|
134
|
+
},
|
|
135
|
+
repository: {
|
|
136
|
+
type: "git",
|
|
137
|
+
url: "git+https://github.com/exa-labs/exa-js.git"
|
|
138
|
+
},
|
|
139
|
+
keywords: [
|
|
140
|
+
"exa",
|
|
141
|
+
"metaphor",
|
|
142
|
+
"search",
|
|
143
|
+
"AI",
|
|
144
|
+
"LLMs",
|
|
145
|
+
"RAG",
|
|
146
|
+
"retrieval",
|
|
147
|
+
"augmented",
|
|
148
|
+
"generation"
|
|
149
|
+
],
|
|
150
|
+
author: "jeffzwang",
|
|
151
|
+
bugs: {
|
|
152
|
+
url: "https://github.com/exa-labs/exa-js/issues"
|
|
153
|
+
},
|
|
154
|
+
homepage: "https://github.com/exa-labs/exa-js#readme"
|
|
155
|
+
};
|
|
156
|
+
|
|
74
157
|
// src/errors.ts
|
|
75
158
|
var HttpStatusCode = /* @__PURE__ */ ((HttpStatusCode2) => {
|
|
76
159
|
HttpStatusCode2[HttpStatusCode2["BadRequest"] = 400] = "BadRequest";
|
|
@@ -100,6 +183,173 @@ var ExaError = class extends Error {
|
|
|
100
183
|
}
|
|
101
184
|
};
|
|
102
185
|
|
|
186
|
+
// src/zod-utils.ts
|
|
187
|
+
var import_zod = require("zod");
|
|
188
|
+
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
189
|
+
function isZodSchema(obj) {
|
|
190
|
+
return obj instanceof import_zod.ZodType;
|
|
191
|
+
}
|
|
192
|
+
function zodToJsonSchema(schema) {
|
|
193
|
+
return (0, import_zod_to_json_schema.zodToJsonSchema)(schema, {
|
|
194
|
+
$refStrategy: "none"
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/research/base.ts
|
|
199
|
+
var ResearchBaseClient = class {
|
|
200
|
+
constructor(client) {
|
|
201
|
+
this.client = client;
|
|
202
|
+
}
|
|
203
|
+
async request(endpoint, method = "POST", data, params) {
|
|
204
|
+
return this.client.request(
|
|
205
|
+
`/research/v1${endpoint}`,
|
|
206
|
+
method,
|
|
207
|
+
data,
|
|
208
|
+
params
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
async rawRequest(endpoint, method = "POST", data, params) {
|
|
212
|
+
return this.client.rawRequest(
|
|
213
|
+
`/research/v1${endpoint}`,
|
|
214
|
+
method,
|
|
215
|
+
data,
|
|
216
|
+
params
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
buildPaginationParams(pagination) {
|
|
220
|
+
const params = {};
|
|
221
|
+
if (!pagination) return params;
|
|
222
|
+
if (pagination.cursor) params.cursor = pagination.cursor;
|
|
223
|
+
if (pagination.limit) params.limit = pagination.limit;
|
|
224
|
+
return params;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// src/research/client.ts
|
|
229
|
+
var ResearchClient = class extends ResearchBaseClient {
|
|
230
|
+
constructor(client) {
|
|
231
|
+
super(client);
|
|
232
|
+
}
|
|
233
|
+
async create(params) {
|
|
234
|
+
const { instructions, model, outputSchema } = params;
|
|
235
|
+
let schema = outputSchema;
|
|
236
|
+
if (schema && isZodSchema(schema)) {
|
|
237
|
+
schema = zodToJsonSchema(schema);
|
|
238
|
+
}
|
|
239
|
+
const payload = {
|
|
240
|
+
instructions,
|
|
241
|
+
model: model ?? "exa-research"
|
|
242
|
+
};
|
|
243
|
+
if (schema) {
|
|
244
|
+
payload.outputSchema = schema;
|
|
245
|
+
}
|
|
246
|
+
return this.request("", "POST", payload);
|
|
247
|
+
}
|
|
248
|
+
get(researchId, options) {
|
|
249
|
+
if (options?.stream) {
|
|
250
|
+
const promise = async () => {
|
|
251
|
+
const params = { stream: "true" };
|
|
252
|
+
if (options.events !== void 0) {
|
|
253
|
+
params.events = options.events.toString();
|
|
254
|
+
}
|
|
255
|
+
const resp = await this.rawRequest(
|
|
256
|
+
`/${researchId}`,
|
|
257
|
+
"GET",
|
|
258
|
+
void 0,
|
|
259
|
+
params
|
|
260
|
+
);
|
|
261
|
+
if (!resp.body) {
|
|
262
|
+
throw new Error("No response body for SSE stream");
|
|
263
|
+
}
|
|
264
|
+
const reader = resp.body.getReader();
|
|
265
|
+
const decoder = new TextDecoder();
|
|
266
|
+
let buffer = "";
|
|
267
|
+
function processPart(part) {
|
|
268
|
+
const lines = part.split("\n");
|
|
269
|
+
let data = lines.slice(1).join("\n");
|
|
270
|
+
if (data.startsWith("data:")) {
|
|
271
|
+
data = data.slice(5).trimStart();
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
return JSON.parse(data);
|
|
275
|
+
} catch (e) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async function* streamEvents() {
|
|
280
|
+
while (true) {
|
|
281
|
+
const { done, value } = await reader.read();
|
|
282
|
+
if (done) break;
|
|
283
|
+
buffer += decoder.decode(value, { stream: true });
|
|
284
|
+
let parts = buffer.split("\n\n");
|
|
285
|
+
buffer = parts.pop() ?? "";
|
|
286
|
+
for (const part of parts) {
|
|
287
|
+
const processed = processPart(part);
|
|
288
|
+
if (processed) {
|
|
289
|
+
yield processed;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (buffer.trim()) {
|
|
294
|
+
const processed = processPart(buffer.trim());
|
|
295
|
+
if (processed) {
|
|
296
|
+
yield processed;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return streamEvents();
|
|
301
|
+
};
|
|
302
|
+
return promise();
|
|
303
|
+
} else {
|
|
304
|
+
const params = { stream: "false" };
|
|
305
|
+
if (options?.events !== void 0) {
|
|
306
|
+
params.events = options.events.toString();
|
|
307
|
+
}
|
|
308
|
+
return this.request(
|
|
309
|
+
`/${researchId}`,
|
|
310
|
+
"GET",
|
|
311
|
+
void 0,
|
|
312
|
+
params
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async list(options) {
|
|
317
|
+
const params = this.buildPaginationParams(options);
|
|
318
|
+
return this.request("", "GET", void 0, params);
|
|
319
|
+
}
|
|
320
|
+
async pollUntilFinished(researchId, options) {
|
|
321
|
+
const pollInterval = options?.pollInterval ?? 1e3;
|
|
322
|
+
const timeoutMs = options?.timeoutMs ?? 10 * 60 * 1e3;
|
|
323
|
+
const maxConsecutiveFailures = 5;
|
|
324
|
+
const startTime = Date.now();
|
|
325
|
+
let consecutiveFailures = 0;
|
|
326
|
+
while (true) {
|
|
327
|
+
try {
|
|
328
|
+
const research = await this.get(researchId, {
|
|
329
|
+
events: options?.events
|
|
330
|
+
});
|
|
331
|
+
consecutiveFailures = 0;
|
|
332
|
+
if (research.status === "completed" || research.status === "failed" || research.status === "canceled") {
|
|
333
|
+
return research;
|
|
334
|
+
}
|
|
335
|
+
} catch (err) {
|
|
336
|
+
consecutiveFailures += 1;
|
|
337
|
+
if (consecutiveFailures >= maxConsecutiveFailures) {
|
|
338
|
+
throw new Error(
|
|
339
|
+
`Polling failed ${maxConsecutiveFailures} times in a row for research ${researchId}: ${err}`
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
344
|
+
throw new Error(
|
|
345
|
+
`Polling timeout: Research ${researchId} did not complete within ${timeoutMs}ms`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
|
|
103
353
|
// src/websets/base.ts
|
|
104
354
|
var WebsetsBaseClient = class {
|
|
105
355
|
/**
|
|
@@ -1076,173 +1326,6 @@ var WebsetsClient = class extends WebsetsBaseClient {
|
|
|
1076
1326
|
}
|
|
1077
1327
|
};
|
|
1078
1328
|
|
|
1079
|
-
// src/zod-utils.ts
|
|
1080
|
-
var import_zod = require("zod");
|
|
1081
|
-
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
1082
|
-
function isZodSchema(obj) {
|
|
1083
|
-
return obj instanceof import_zod.ZodType;
|
|
1084
|
-
}
|
|
1085
|
-
function zodToJsonSchema(schema) {
|
|
1086
|
-
return (0, import_zod_to_json_schema.zodToJsonSchema)(schema, {
|
|
1087
|
-
$refStrategy: "none"
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
// src/research/base.ts
|
|
1092
|
-
var ResearchBaseClient = class {
|
|
1093
|
-
constructor(client) {
|
|
1094
|
-
this.client = client;
|
|
1095
|
-
}
|
|
1096
|
-
async request(endpoint, method = "POST", data, params) {
|
|
1097
|
-
return this.client.request(
|
|
1098
|
-
`/research/v1${endpoint}`,
|
|
1099
|
-
method,
|
|
1100
|
-
data,
|
|
1101
|
-
params
|
|
1102
|
-
);
|
|
1103
|
-
}
|
|
1104
|
-
async rawRequest(endpoint, method = "POST", data, params) {
|
|
1105
|
-
return this.client.rawRequest(
|
|
1106
|
-
`/research/v1${endpoint}`,
|
|
1107
|
-
method,
|
|
1108
|
-
data,
|
|
1109
|
-
params
|
|
1110
|
-
);
|
|
1111
|
-
}
|
|
1112
|
-
buildPaginationParams(pagination) {
|
|
1113
|
-
const params = {};
|
|
1114
|
-
if (!pagination) return params;
|
|
1115
|
-
if (pagination.cursor) params.cursor = pagination.cursor;
|
|
1116
|
-
if (pagination.limit) params.limit = pagination.limit;
|
|
1117
|
-
return params;
|
|
1118
|
-
}
|
|
1119
|
-
};
|
|
1120
|
-
|
|
1121
|
-
// src/research/client.ts
|
|
1122
|
-
var ResearchClient = class extends ResearchBaseClient {
|
|
1123
|
-
constructor(client) {
|
|
1124
|
-
super(client);
|
|
1125
|
-
}
|
|
1126
|
-
async create(params) {
|
|
1127
|
-
const { instructions, model, outputSchema } = params;
|
|
1128
|
-
let schema = outputSchema;
|
|
1129
|
-
if (schema && isZodSchema(schema)) {
|
|
1130
|
-
schema = zodToJsonSchema(schema);
|
|
1131
|
-
}
|
|
1132
|
-
const payload = {
|
|
1133
|
-
instructions,
|
|
1134
|
-
model: model ?? "exa-research"
|
|
1135
|
-
};
|
|
1136
|
-
if (schema) {
|
|
1137
|
-
payload.outputSchema = schema;
|
|
1138
|
-
}
|
|
1139
|
-
return this.request("", "POST", payload);
|
|
1140
|
-
}
|
|
1141
|
-
get(researchId, options) {
|
|
1142
|
-
if (options?.stream) {
|
|
1143
|
-
const promise = async () => {
|
|
1144
|
-
const params = { stream: "true" };
|
|
1145
|
-
if (options.events !== void 0) {
|
|
1146
|
-
params.events = options.events.toString();
|
|
1147
|
-
}
|
|
1148
|
-
const resp = await this.rawRequest(
|
|
1149
|
-
`/${researchId}`,
|
|
1150
|
-
"GET",
|
|
1151
|
-
void 0,
|
|
1152
|
-
params
|
|
1153
|
-
);
|
|
1154
|
-
if (!resp.body) {
|
|
1155
|
-
throw new Error("No response body for SSE stream");
|
|
1156
|
-
}
|
|
1157
|
-
const reader = resp.body.getReader();
|
|
1158
|
-
const decoder = new TextDecoder();
|
|
1159
|
-
let buffer = "";
|
|
1160
|
-
function processPart(part) {
|
|
1161
|
-
const lines = part.split("\n");
|
|
1162
|
-
let data = lines.slice(1).join("\n");
|
|
1163
|
-
if (data.startsWith("data:")) {
|
|
1164
|
-
data = data.slice(5).trimStart();
|
|
1165
|
-
}
|
|
1166
|
-
try {
|
|
1167
|
-
return JSON.parse(data);
|
|
1168
|
-
} catch (e) {
|
|
1169
|
-
return null;
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
async function* streamEvents() {
|
|
1173
|
-
while (true) {
|
|
1174
|
-
const { done, value } = await reader.read();
|
|
1175
|
-
if (done) break;
|
|
1176
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1177
|
-
let parts = buffer.split("\n\n");
|
|
1178
|
-
buffer = parts.pop() ?? "";
|
|
1179
|
-
for (const part of parts) {
|
|
1180
|
-
const processed = processPart(part);
|
|
1181
|
-
if (processed) {
|
|
1182
|
-
yield processed;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
if (buffer.trim()) {
|
|
1187
|
-
const processed = processPart(buffer.trim());
|
|
1188
|
-
if (processed) {
|
|
1189
|
-
yield processed;
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
return streamEvents();
|
|
1194
|
-
};
|
|
1195
|
-
return promise();
|
|
1196
|
-
} else {
|
|
1197
|
-
const params = { stream: "false" };
|
|
1198
|
-
if (options?.events !== void 0) {
|
|
1199
|
-
params.events = options.events.toString();
|
|
1200
|
-
}
|
|
1201
|
-
return this.request(
|
|
1202
|
-
`/${researchId}`,
|
|
1203
|
-
"GET",
|
|
1204
|
-
void 0,
|
|
1205
|
-
params
|
|
1206
|
-
);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
async list(options) {
|
|
1210
|
-
const params = this.buildPaginationParams(options);
|
|
1211
|
-
return this.request("", "GET", void 0, params);
|
|
1212
|
-
}
|
|
1213
|
-
async pollUntilFinished(researchId, options) {
|
|
1214
|
-
const pollInterval = options?.pollInterval ?? 1e3;
|
|
1215
|
-
const timeoutMs = options?.timeoutMs ?? 10 * 60 * 1e3;
|
|
1216
|
-
const maxConsecutiveFailures = 5;
|
|
1217
|
-
const startTime = Date.now();
|
|
1218
|
-
let consecutiveFailures = 0;
|
|
1219
|
-
while (true) {
|
|
1220
|
-
try {
|
|
1221
|
-
const research = await this.get(researchId, {
|
|
1222
|
-
events: options?.events
|
|
1223
|
-
});
|
|
1224
|
-
consecutiveFailures = 0;
|
|
1225
|
-
if (research.status === "completed" || research.status === "failed" || research.status === "canceled") {
|
|
1226
|
-
return research;
|
|
1227
|
-
}
|
|
1228
|
-
} catch (err) {
|
|
1229
|
-
consecutiveFailures += 1;
|
|
1230
|
-
if (consecutiveFailures >= maxConsecutiveFailures) {
|
|
1231
|
-
throw new Error(
|
|
1232
|
-
`Polling failed ${maxConsecutiveFailures} times in a row for research ${researchId}: ${err}`
|
|
1233
|
-
);
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
if (Date.now() - startTime > timeoutMs) {
|
|
1237
|
-
throw new Error(
|
|
1238
|
-
`Polling timeout: Research ${researchId} did not complete within ${timeoutMs}ms`
|
|
1239
|
-
);
|
|
1240
|
-
}
|
|
1241
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
};
|
|
1245
|
-
|
|
1246
1329
|
// src/index.ts
|
|
1247
1330
|
var fetchImpl = typeof global !== "undefined" && global.fetch ? global.fetch : import_cross_fetch.default;
|
|
1248
1331
|
var HeadersImpl = typeof global !== "undefined" && global.Headers ? global.Headers : import_cross_fetch.Headers;
|
|
@@ -1311,7 +1394,7 @@ var Exa2 = class {
|
|
|
1311
1394
|
this.headers = new HeadersImpl({
|
|
1312
1395
|
"x-api-key": apiKey,
|
|
1313
1396
|
"Content-Type": "application/json",
|
|
1314
|
-
"User-Agent":
|
|
1397
|
+
"User-Agent": `exa-node ${package_default.version}`
|
|
1315
1398
|
});
|
|
1316
1399
|
this.websets = new WebsetsClient(this);
|
|
1317
1400
|
this.research = new ResearchClient(this);
|
|
@@ -1498,7 +1581,8 @@ var Exa2 = class {
|
|
|
1498
1581
|
text: options?.text ?? false,
|
|
1499
1582
|
model: options?.model ?? "exa",
|
|
1500
1583
|
systemPrompt: options?.systemPrompt,
|
|
1501
|
-
outputSchema
|
|
1584
|
+
outputSchema,
|
|
1585
|
+
userLocation: options?.userLocation
|
|
1502
1586
|
};
|
|
1503
1587
|
return await this.request("/answer", "POST", requestBody);
|
|
1504
1588
|
}
|