exa-js 1.9.1 → 1.9.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/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.2",
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": "exa-node 1.4.0"
1397
+ "User-Agent": `exa-node ${package_default.version}`
1315
1398
  });
1316
1399
  this.websets = new WebsetsClient(this);
1317
1400
  this.research = new ResearchClient(this);