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.mjs CHANGED
@@ -1,6 +1,89 @@
1
1
  // src/index.ts
2
2
  import fetch2, { Headers } from "cross-fetch";
3
3
 
4
+ // package.json
5
+ var package_default = {
6
+ name: "exa-js",
7
+ version: "1.9.2",
8
+ description: "Exa SDK for Node.js and the browser",
9
+ publishConfig: {
10
+ access: "public"
11
+ },
12
+ files: [
13
+ "dist"
14
+ ],
15
+ main: "./dist/index.js",
16
+ module: "./dist/index.mjs",
17
+ exports: {
18
+ ".": {
19
+ types: "./dist/index.d.ts",
20
+ require: "./dist/index.js",
21
+ module: "./dist/index.mjs",
22
+ import: "./dist/index.mjs"
23
+ },
24
+ "./package.json": "./package.json"
25
+ },
26
+ types: "./dist/index.d.ts",
27
+ scripts: {
28
+ "build-fast": "tsup src/index.ts --format cjs,esm",
29
+ build: "tsup",
30
+ test: "vitest run",
31
+ typecheck: "tsc --noEmit",
32
+ "typecheck:src": "tsc --noEmit src/**/*.ts",
33
+ "typecheck:examples": "tsc --noEmit examples/**/*.ts",
34
+ "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",
35
+ format: 'prettier --write "src/**/*.ts" "examples/**/*.ts"',
36
+ "format:websets": "prettier --write src/websets/openapi.ts",
37
+ "build:beta": "cross-env NPM_CONFIG_TAG=beta npm run build",
38
+ "version:beta": "npm version prerelease --preid=beta",
39
+ "version:stable": "npm version patch",
40
+ "publish:beta": "npm run version:beta && npm run build:beta && npm publish --tag beta",
41
+ "publish:stable": "npm run version:stable && npm run build && npm publish",
42
+ prepublishOnly: "npm run build"
43
+ },
44
+ license: "MIT",
45
+ devDependencies: {
46
+ "@types/node": "~22.14.0",
47
+ "cross-env": "~7.0.3",
48
+ "openapi-typescript": "~7.6.1",
49
+ prettier: "~3.5.3",
50
+ "ts-node": "~10.9.2",
51
+ tsup: "~8.4.0",
52
+ typescript: "~5.8.3",
53
+ vitest: "~3.1.1"
54
+ },
55
+ dependencies: {
56
+ "cross-fetch": "~4.1.0",
57
+ dotenv: "~16.4.7",
58
+ openai: "^5.0.1",
59
+ zod: "^3.22.0",
60
+ "zod-to-json-schema": "^3.20.0"
61
+ },
62
+ directories: {
63
+ test: "test"
64
+ },
65
+ repository: {
66
+ type: "git",
67
+ url: "git+https://github.com/exa-labs/exa-js.git"
68
+ },
69
+ keywords: [
70
+ "exa",
71
+ "metaphor",
72
+ "search",
73
+ "AI",
74
+ "LLMs",
75
+ "RAG",
76
+ "retrieval",
77
+ "augmented",
78
+ "generation"
79
+ ],
80
+ author: "jeffzwang",
81
+ bugs: {
82
+ url: "https://github.com/exa-labs/exa-js/issues"
83
+ },
84
+ homepage: "https://github.com/exa-labs/exa-js#readme"
85
+ };
86
+
4
87
  // src/errors.ts
5
88
  var HttpStatusCode = /* @__PURE__ */ ((HttpStatusCode2) => {
6
89
  HttpStatusCode2[HttpStatusCode2["BadRequest"] = 400] = "BadRequest";
@@ -30,6 +113,173 @@ var ExaError = class extends Error {
30
113
  }
31
114
  };
32
115
 
116
+ // src/zod-utils.ts
117
+ import { ZodType } from "zod";
118
+ import { zodToJsonSchema as convertZodToJsonSchema } from "zod-to-json-schema";
119
+ function isZodSchema(obj) {
120
+ return obj instanceof ZodType;
121
+ }
122
+ function zodToJsonSchema(schema) {
123
+ return convertZodToJsonSchema(schema, {
124
+ $refStrategy: "none"
125
+ });
126
+ }
127
+
128
+ // src/research/base.ts
129
+ var ResearchBaseClient = class {
130
+ constructor(client) {
131
+ this.client = client;
132
+ }
133
+ async request(endpoint, method = "POST", data, params) {
134
+ return this.client.request(
135
+ `/research/v1${endpoint}`,
136
+ method,
137
+ data,
138
+ params
139
+ );
140
+ }
141
+ async rawRequest(endpoint, method = "POST", data, params) {
142
+ return this.client.rawRequest(
143
+ `/research/v1${endpoint}`,
144
+ method,
145
+ data,
146
+ params
147
+ );
148
+ }
149
+ buildPaginationParams(pagination) {
150
+ const params = {};
151
+ if (!pagination) return params;
152
+ if (pagination.cursor) params.cursor = pagination.cursor;
153
+ if (pagination.limit) params.limit = pagination.limit;
154
+ return params;
155
+ }
156
+ };
157
+
158
+ // src/research/client.ts
159
+ var ResearchClient = class extends ResearchBaseClient {
160
+ constructor(client) {
161
+ super(client);
162
+ }
163
+ async create(params) {
164
+ const { instructions, model, outputSchema } = params;
165
+ let schema = outputSchema;
166
+ if (schema && isZodSchema(schema)) {
167
+ schema = zodToJsonSchema(schema);
168
+ }
169
+ const payload = {
170
+ instructions,
171
+ model: model ?? "exa-research"
172
+ };
173
+ if (schema) {
174
+ payload.outputSchema = schema;
175
+ }
176
+ return this.request("", "POST", payload);
177
+ }
178
+ get(researchId, options) {
179
+ if (options?.stream) {
180
+ const promise = async () => {
181
+ const params = { stream: "true" };
182
+ if (options.events !== void 0) {
183
+ params.events = options.events.toString();
184
+ }
185
+ const resp = await this.rawRequest(
186
+ `/${researchId}`,
187
+ "GET",
188
+ void 0,
189
+ params
190
+ );
191
+ if (!resp.body) {
192
+ throw new Error("No response body for SSE stream");
193
+ }
194
+ const reader = resp.body.getReader();
195
+ const decoder = new TextDecoder();
196
+ let buffer = "";
197
+ function processPart(part) {
198
+ const lines = part.split("\n");
199
+ let data = lines.slice(1).join("\n");
200
+ if (data.startsWith("data:")) {
201
+ data = data.slice(5).trimStart();
202
+ }
203
+ try {
204
+ return JSON.parse(data);
205
+ } catch (e) {
206
+ return null;
207
+ }
208
+ }
209
+ async function* streamEvents() {
210
+ while (true) {
211
+ const { done, value } = await reader.read();
212
+ if (done) break;
213
+ buffer += decoder.decode(value, { stream: true });
214
+ let parts = buffer.split("\n\n");
215
+ buffer = parts.pop() ?? "";
216
+ for (const part of parts) {
217
+ const processed = processPart(part);
218
+ if (processed) {
219
+ yield processed;
220
+ }
221
+ }
222
+ }
223
+ if (buffer.trim()) {
224
+ const processed = processPart(buffer.trim());
225
+ if (processed) {
226
+ yield processed;
227
+ }
228
+ }
229
+ }
230
+ return streamEvents();
231
+ };
232
+ return promise();
233
+ } else {
234
+ const params = { stream: "false" };
235
+ if (options?.events !== void 0) {
236
+ params.events = options.events.toString();
237
+ }
238
+ return this.request(
239
+ `/${researchId}`,
240
+ "GET",
241
+ void 0,
242
+ params
243
+ );
244
+ }
245
+ }
246
+ async list(options) {
247
+ const params = this.buildPaginationParams(options);
248
+ return this.request("", "GET", void 0, params);
249
+ }
250
+ async pollUntilFinished(researchId, options) {
251
+ const pollInterval = options?.pollInterval ?? 1e3;
252
+ const timeoutMs = options?.timeoutMs ?? 10 * 60 * 1e3;
253
+ const maxConsecutiveFailures = 5;
254
+ const startTime = Date.now();
255
+ let consecutiveFailures = 0;
256
+ while (true) {
257
+ try {
258
+ const research = await this.get(researchId, {
259
+ events: options?.events
260
+ });
261
+ consecutiveFailures = 0;
262
+ if (research.status === "completed" || research.status === "failed" || research.status === "canceled") {
263
+ return research;
264
+ }
265
+ } catch (err) {
266
+ consecutiveFailures += 1;
267
+ if (consecutiveFailures >= maxConsecutiveFailures) {
268
+ throw new Error(
269
+ `Polling failed ${maxConsecutiveFailures} times in a row for research ${researchId}: ${err}`
270
+ );
271
+ }
272
+ }
273
+ if (Date.now() - startTime > timeoutMs) {
274
+ throw new Error(
275
+ `Polling timeout: Research ${researchId} did not complete within ${timeoutMs}ms`
276
+ );
277
+ }
278
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
279
+ }
280
+ }
281
+ };
282
+
33
283
  // src/websets/base.ts
34
284
  var WebsetsBaseClient = class {
35
285
  /**
@@ -1006,173 +1256,6 @@ var WebsetsClient = class extends WebsetsBaseClient {
1006
1256
  }
1007
1257
  };
1008
1258
 
1009
- // src/zod-utils.ts
1010
- import { ZodType } from "zod";
1011
- import { zodToJsonSchema as convertZodToJsonSchema } from "zod-to-json-schema";
1012
- function isZodSchema(obj) {
1013
- return obj instanceof ZodType;
1014
- }
1015
- function zodToJsonSchema(schema) {
1016
- return convertZodToJsonSchema(schema, {
1017
- $refStrategy: "none"
1018
- });
1019
- }
1020
-
1021
- // src/research/base.ts
1022
- var ResearchBaseClient = class {
1023
- constructor(client) {
1024
- this.client = client;
1025
- }
1026
- async request(endpoint, method = "POST", data, params) {
1027
- return this.client.request(
1028
- `/research/v1${endpoint}`,
1029
- method,
1030
- data,
1031
- params
1032
- );
1033
- }
1034
- async rawRequest(endpoint, method = "POST", data, params) {
1035
- return this.client.rawRequest(
1036
- `/research/v1${endpoint}`,
1037
- method,
1038
- data,
1039
- params
1040
- );
1041
- }
1042
- buildPaginationParams(pagination) {
1043
- const params = {};
1044
- if (!pagination) return params;
1045
- if (pagination.cursor) params.cursor = pagination.cursor;
1046
- if (pagination.limit) params.limit = pagination.limit;
1047
- return params;
1048
- }
1049
- };
1050
-
1051
- // src/research/client.ts
1052
- var ResearchClient = class extends ResearchBaseClient {
1053
- constructor(client) {
1054
- super(client);
1055
- }
1056
- async create(params) {
1057
- const { instructions, model, outputSchema } = params;
1058
- let schema = outputSchema;
1059
- if (schema && isZodSchema(schema)) {
1060
- schema = zodToJsonSchema(schema);
1061
- }
1062
- const payload = {
1063
- instructions,
1064
- model: model ?? "exa-research"
1065
- };
1066
- if (schema) {
1067
- payload.outputSchema = schema;
1068
- }
1069
- return this.request("", "POST", payload);
1070
- }
1071
- get(researchId, options) {
1072
- if (options?.stream) {
1073
- const promise = async () => {
1074
- const params = { stream: "true" };
1075
- if (options.events !== void 0) {
1076
- params.events = options.events.toString();
1077
- }
1078
- const resp = await this.rawRequest(
1079
- `/${researchId}`,
1080
- "GET",
1081
- void 0,
1082
- params
1083
- );
1084
- if (!resp.body) {
1085
- throw new Error("No response body for SSE stream");
1086
- }
1087
- const reader = resp.body.getReader();
1088
- const decoder = new TextDecoder();
1089
- let buffer = "";
1090
- function processPart(part) {
1091
- const lines = part.split("\n");
1092
- let data = lines.slice(1).join("\n");
1093
- if (data.startsWith("data:")) {
1094
- data = data.slice(5).trimStart();
1095
- }
1096
- try {
1097
- return JSON.parse(data);
1098
- } catch (e) {
1099
- return null;
1100
- }
1101
- }
1102
- async function* streamEvents() {
1103
- while (true) {
1104
- const { done, value } = await reader.read();
1105
- if (done) break;
1106
- buffer += decoder.decode(value, { stream: true });
1107
- let parts = buffer.split("\n\n");
1108
- buffer = parts.pop() ?? "";
1109
- for (const part of parts) {
1110
- const processed = processPart(part);
1111
- if (processed) {
1112
- yield processed;
1113
- }
1114
- }
1115
- }
1116
- if (buffer.trim()) {
1117
- const processed = processPart(buffer.trim());
1118
- if (processed) {
1119
- yield processed;
1120
- }
1121
- }
1122
- }
1123
- return streamEvents();
1124
- };
1125
- return promise();
1126
- } else {
1127
- const params = { stream: "false" };
1128
- if (options?.events !== void 0) {
1129
- params.events = options.events.toString();
1130
- }
1131
- return this.request(
1132
- `/${researchId}`,
1133
- "GET",
1134
- void 0,
1135
- params
1136
- );
1137
- }
1138
- }
1139
- async list(options) {
1140
- const params = this.buildPaginationParams(options);
1141
- return this.request("", "GET", void 0, params);
1142
- }
1143
- async pollUntilFinished(researchId, options) {
1144
- const pollInterval = options?.pollInterval ?? 1e3;
1145
- const timeoutMs = options?.timeoutMs ?? 10 * 60 * 1e3;
1146
- const maxConsecutiveFailures = 5;
1147
- const startTime = Date.now();
1148
- let consecutiveFailures = 0;
1149
- while (true) {
1150
- try {
1151
- const research = await this.get(researchId, {
1152
- events: options?.events
1153
- });
1154
- consecutiveFailures = 0;
1155
- if (research.status === "completed" || research.status === "failed" || research.status === "canceled") {
1156
- return research;
1157
- }
1158
- } catch (err) {
1159
- consecutiveFailures += 1;
1160
- if (consecutiveFailures >= maxConsecutiveFailures) {
1161
- throw new Error(
1162
- `Polling failed ${maxConsecutiveFailures} times in a row for research ${researchId}: ${err}`
1163
- );
1164
- }
1165
- }
1166
- if (Date.now() - startTime > timeoutMs) {
1167
- throw new Error(
1168
- `Polling timeout: Research ${researchId} did not complete within ${timeoutMs}ms`
1169
- );
1170
- }
1171
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
1172
- }
1173
- }
1174
- };
1175
-
1176
1259
  // src/index.ts
1177
1260
  var fetchImpl = typeof global !== "undefined" && global.fetch ? global.fetch : fetch2;
1178
1261
  var HeadersImpl = typeof global !== "undefined" && global.Headers ? global.Headers : Headers;
@@ -1241,7 +1324,7 @@ var Exa2 = class {
1241
1324
  this.headers = new HeadersImpl({
1242
1325
  "x-api-key": apiKey,
1243
1326
  "Content-Type": "application/json",
1244
- "User-Agent": "exa-node 1.4.0"
1327
+ "User-Agent": `exa-node ${package_default.version}`
1245
1328
  });
1246
1329
  this.websets = new WebsetsClient(this);
1247
1330
  this.research = new ResearchClient(this);