@opengeni/sdk 0.25.0 → 0.25.5

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
@@ -2,30 +2,64 @@
2
2
  var OpenGeniApiError = class extends Error {
3
3
  status;
4
4
  code;
5
+ retryable;
6
+ correlationId;
7
+ /** True only when an uncontrolled transport failed after a mutation may have been accepted. */
8
+ outcomeUnknown;
5
9
  body;
6
- constructor(status, body) {
10
+ constructor(status, body, options = {}) {
7
11
  const decoded = decodeApiErrorBody(body);
8
- super(`OpenGeni API ${status}: ${decoded.message ?? (body || "(empty body)")}`);
12
+ const correlationId = decoded?.requestId ?? boundedCorrelationId(options.correlationId);
13
+ const gatewayFailure = status >= 502 && status <= 504;
14
+ const fromResponse = options.mutation !== void 0;
15
+ const message = decoded?.message ?? (fromResponse ? "Request failed." : body || "(empty body)");
16
+ const displayMessage = options.displayMessage ?? (gatewayFailure && fromResponse ? "OpenGeni is temporarily unavailable \u2014 retry." : `OpenGeni API ${status}: ${message}`);
17
+ super(correlationId ? `${displayMessage} Reference: ${correlationId}.` : displayMessage);
9
18
  this.name = "OpenGeniApiError";
10
19
  this.status = status;
11
- this.code = decoded.code;
12
- this.body = body;
20
+ this.code = options.code ?? decoded?.code ?? (gatewayFailure && fromResponse ? "upstream_unavailable" : void 0);
21
+ this.retryable = options.retryable ?? decoded?.retryable ?? retryableApiStatus(status);
22
+ this.correlationId = correlationId;
23
+ this.outcomeUnknown = options.outcomeUnknown ?? (gatewayFailure && !!options.mutation && !decoded);
24
+ this.body = !fromResponse || decoded ? body : "";
13
25
  }
14
26
  };
15
27
  function decodeApiErrorBody(body) {
16
- if (!body) return {};
28
+ if (!body) return null;
17
29
  try {
18
30
  const decoded = JSON.parse(body);
19
- if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) return {};
31
+ if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) return null;
20
32
  const record = decoded;
33
+ const nested = record.error && typeof record.error === "object" && !Array.isArray(record.error) ? record.error : record;
34
+ const code = boundedApiField(nested.code);
35
+ const message = boundedApiField(nested.message);
36
+ const requestId = boundedCorrelationId(nested.requestId);
37
+ const retryable = typeof nested.retryable === "boolean" ? nested.retryable : void 0;
38
+ if (!code && !message && !requestId && retryable === void 0) return null;
21
39
  return {
22
- ...typeof record.code === "string" && record.code ? { code: record.code } : {},
23
- ...typeof record.message === "string" && record.message ? { message: record.message } : {}
40
+ code,
41
+ message,
42
+ requestId,
43
+ retryable
24
44
  };
25
45
  } catch {
26
- return {};
46
+ return null;
27
47
  }
28
48
  }
49
+ function boundedApiField(value) {
50
+ if (typeof value !== "string") return;
51
+ const bytes = new TextEncoder().encode(value);
52
+ return bytes.byteLength <= 512 ? value : new TextDecoder().decode(bytes.slice(0, 512));
53
+ }
54
+ function retryableApiStatus(status) {
55
+ return status === 408 || status === 409 || status === 425 || status === 429 || status >= 500;
56
+ }
57
+ function boundedCorrelationId(value) {
58
+ if (typeof value !== "string" || value.length > 128 || !/^[\w.:-]+$/.test(value)) {
59
+ return;
60
+ }
61
+ return value;
62
+ }
29
63
  var OpenGeniSessionListCursorError = class extends OpenGeniApiError {
30
64
  };
31
65
  var OpenGeniApiContractMismatchError = class extends Error {
@@ -48,9 +82,7 @@ function isAbortError(error) {
48
82
  return error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
49
83
  }
50
84
  function isRetryableStreamError(error) {
51
- if (error instanceof OpenGeniApiError) {
52
- return error.status === 408 || error.status === 409 || error.status === 425 || error.status === 429 || error.status >= 500;
53
- }
85
+ if (error instanceof OpenGeniApiError) return error.retryable;
54
86
  return error instanceof TypeError;
55
87
  }
56
88
 
@@ -391,6 +423,7 @@ var SESSION_EVENT_TYPES = [
391
423
  "terminal.pty.exited",
392
424
  "session.title_set",
393
425
  "session.mcp.approval_policy.updated",
426
+ "session.tool_policy.updated",
394
427
  // Multi-account Codex (P1): the session's inference account changed.
395
428
  "codex.account.switched",
396
429
  // credential allocator metadata-only per-turn credential selection audit.
@@ -472,6 +505,7 @@ var KNOWN_PERMISSIONS = [
472
505
  ];
473
506
  var OPENGENI_API_CONTRACT_REVISION = "2026-07-turn-instructions-v1";
474
507
  var OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract";
508
+ var OPENGENI_CORRELATION_HEADER = "x-opengeni-correlation-id";
475
509
  var RETAINED_OUTPUT_DEFAULT_PAGE_BYTES = 256 * 1024;
476
510
  var RETAINED_OUTPUT_MAX_PAGE_BYTES = 1024 * 1024;
477
511
  var KNOWN_USAGE_EVENT_TYPES = [
@@ -540,6 +574,14 @@ var OpenGeniClient = class {
540
574
  request
541
575
  );
542
576
  }
577
+ /** Replace the durable tool policy or explicitly adopt workspace defaults. */
578
+ async updateSessionToolPolicy(workspaceId, sessionId, request) {
579
+ return await this.requestJson(
580
+ "PUT",
581
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/tool-policy`,
582
+ request
583
+ );
584
+ }
543
585
  /**
544
586
  * Replace one attached MCP server's approval policy. The change is captured
545
587
  * by the next claimed attempt; already-claimed work keeps its immutable
@@ -583,7 +625,13 @@ var OpenGeniClient = class {
583
625
  );
584
626
  } catch (error) {
585
627
  if (error instanceof OpenGeniApiError && error.status === 410) {
586
- throw new OpenGeniSessionListCursorError(error.status, error.body);
628
+ throw new OpenGeniSessionListCursorError(error.status, error.body, {
629
+ ...error.code ? { code: error.code } : {},
630
+ retryable: error.retryable,
631
+ ...error.correlationId ? { correlationId: error.correlationId } : {},
632
+ outcomeUnknown: error.outcomeUnknown,
633
+ displayMessage: "The session list changed \u2014 refresh and try again."
634
+ });
587
635
  }
588
636
  throw error;
589
637
  }
@@ -758,6 +806,7 @@ var OpenGeniClient = class {
758
806
  throw new TypeError("resultMode=compact requires latest");
759
807
  }
760
808
  const listOptions = options.resultMode === "compact" ? null : options;
809
+ const correlationId = crypto.randomUUID();
761
810
  const response = await this.fetchImpl(
762
811
  this.url(`/v1/workspaces/${workspaceId}/sessions/${sessionId}/events`, {
763
812
  ...listOptions?.after !== void 0 ? { after: String(listOptions.after) } : {},
@@ -776,11 +825,14 @@ var OpenGeniClient = class {
776
825
  }),
777
826
  {
778
827
  method: "GET",
779
- headers: { ...this.headers(), Accept: "application/json" }
828
+ headers: { ...this.headers(correlationId), Accept: "application/json" }
780
829
  }
781
830
  );
782
831
  assertApiContractResponse(response);
783
- if (!response.ok) throw new OpenGeniApiError(response.status, await safeText(response));
832
+ if (!response.ok) {
833
+ throw await apiErrorFromResponse(response, { method: "GET", correlationId });
834
+ }
835
+ await assertJsonResponse(response, { method: "GET", correlationId });
784
836
  const body = await response.json();
785
837
  if (options.resultMode === "compact") {
786
838
  return body;
@@ -908,14 +960,15 @@ var OpenGeniClient = class {
908
960
  const url = this.url(`/v1/workspaces/${workspaceId}/sessions/${sessionId}/events/stream`, {
909
961
  after: String(options.after ?? 0)
910
962
  });
963
+ const correlationId = crypto.randomUUID();
911
964
  const response = await this.fetchImpl(url, {
912
965
  method: "GET",
913
- headers: { ...this.headers(), Accept: "text/event-stream" },
966
+ headers: { ...this.headers(correlationId), Accept: "text/event-stream" },
914
967
  ...options.signal ? { signal: options.signal } : {}
915
968
  });
916
969
  assertApiContractResponse(response);
917
970
  if (!response.ok) {
918
- throw new OpenGeniApiError(response.status, await safeText(response));
971
+ throw await apiErrorFromResponse(response, { method: "GET", correlationId });
919
972
  }
920
973
  if (!response.body) {
921
974
  throw new OpenGeniApiError(response.status, "SSE response did not include a readable body");
@@ -997,6 +1050,7 @@ var OpenGeniClient = class {
997
1050
  }
998
1051
  /** Count/byte-bounded page plus an explicit continuation cursor. */
999
1052
  async listWorkspaceControlEventPage(workspaceId, options = {}) {
1053
+ const correlationId = crypto.randomUUID();
1000
1054
  const response = await this.fetchImpl(
1001
1055
  this.url(`/v1/workspaces/${workspaceId}/control-events`, {
1002
1056
  ...options.after !== void 0 ? { after: String(options.after) } : {},
@@ -1004,13 +1058,14 @@ var OpenGeniClient = class {
1004
1058
  }),
1005
1059
  {
1006
1060
  method: "GET",
1007
- headers: { ...this.headers(), Accept: "application/json" }
1061
+ headers: { ...this.headers(correlationId), Accept: "application/json" }
1008
1062
  }
1009
1063
  );
1010
1064
  assertApiContractResponse(response);
1011
1065
  if (!response.ok) {
1012
- throw new OpenGeniApiError(response.status, await safeText(response));
1066
+ throw await apiErrorFromResponse(response, { method: "GET", correlationId });
1013
1067
  }
1068
+ await assertJsonResponse(response, { method: "GET", correlationId });
1014
1069
  const events = await response.json();
1015
1070
  const bytesHeader = response.headers.get("X-OpenGeni-Page-Bytes");
1016
1071
  const nextHeader = response.headers.get("X-OpenGeni-Next-After");
@@ -1035,18 +1090,21 @@ var OpenGeniClient = class {
1035
1090
  };
1036
1091
  }
1037
1092
  async openWorkspaceControlEventStream(workspaceId, options = {}) {
1093
+ const correlationId = crypto.randomUUID();
1038
1094
  const response = await this.fetchImpl(
1039
1095
  this.url(`/v1/workspaces/${workspaceId}/control-events/stream`, {
1040
1096
  after: String(options.after ?? 0)
1041
1097
  }),
1042
1098
  {
1043
1099
  method: "GET",
1044
- headers: { ...this.headers(), Accept: "text/event-stream" },
1100
+ headers: { ...this.headers(correlationId), Accept: "text/event-stream" },
1045
1101
  ...options.signal ? { signal: options.signal } : {}
1046
1102
  }
1047
1103
  );
1048
1104
  assertApiContractResponse(response);
1049
- if (!response.ok) throw new OpenGeniApiError(response.status, await safeText(response));
1105
+ if (!response.ok) {
1106
+ throw await apiErrorFromResponse(response, { method: "GET", correlationId });
1107
+ }
1050
1108
  if (!response.body) {
1051
1109
  throw new OpenGeniApiError(response.status, "SSE response did not include a readable body");
1052
1110
  }
@@ -1684,7 +1742,7 @@ var OpenGeniClient = class {
1684
1742
  body
1685
1743
  });
1686
1744
  if (!putResponse.ok) {
1687
- throw new OpenGeniApiError(putResponse.status, await safeText(putResponse));
1745
+ throw await apiErrorFromResponse(putResponse, { method: "PUT" });
1688
1746
  }
1689
1747
  return await this.completeFileUpload(workspaceId, upload.uploadId);
1690
1748
  }
@@ -1709,12 +1767,13 @@ var OpenGeniClient = class {
1709
1767
  if (options.range && (options.range.length > 128 || /[^\x20-\x7e]/.test(options.range))) {
1710
1768
  throw new RangeError("retained artifact range must be at most 128 printable ASCII bytes");
1711
1769
  }
1770
+ const correlationId = crypto.randomUUID();
1712
1771
  const response = await this.fetchImpl(
1713
1772
  this.url(`/v1/workspaces/${workspaceId}/artifacts/${artifactId}/content`),
1714
1773
  {
1715
1774
  method: "GET",
1716
1775
  headers: {
1717
- ...this.headers(),
1776
+ ...this.headers(correlationId),
1718
1777
  Accept: "application/octet-stream",
1719
1778
  ...options.range ? { Range: options.range } : {}
1720
1779
  },
@@ -1728,7 +1787,7 @@ var OpenGeniClient = class {
1728
1787
  throw error;
1729
1788
  }
1730
1789
  if (!response.ok) {
1731
- throw new OpenGeniApiError(response.status, await safeBoundedText(response));
1790
+ throw await apiErrorFromResponse(response, { method: "GET", correlationId });
1732
1791
  }
1733
1792
  if (response.status !== 200 && response.status !== 206) {
1734
1793
  await cancelResponseBody(response, "unexpected retained artifact response status");
@@ -1800,6 +1859,30 @@ var OpenGeniClient = class {
1800
1859
  `/v1/workspaces/${workspaceId}/document-bases/${baseId}/documents`
1801
1860
  );
1802
1861
  }
1862
+ /**
1863
+ * Drop raw text or an already-uploaded file into the workspace's Default
1864
+ * base. When curation is enabled, it may name, summarize, categorize, and
1865
+ * (confidence permitting) file the document into the best-matching base;
1866
+ * provider=none leaves caller metadata and Default placement unchanged.
1867
+ */
1868
+ async createKnowledgeDrop(workspaceId, request) {
1869
+ return await this.requestJson(
1870
+ "POST",
1871
+ `/v1/workspaces/${workspaceId}/knowledge/drops`,
1872
+ request
1873
+ );
1874
+ }
1875
+ /**
1876
+ * Move a document (and its indexed chunks) to another base. With no
1877
+ * targetBaseId, applies the document's stored curation suggestion.
1878
+ */
1879
+ async moveDocument(workspaceId, documentId, request = {}) {
1880
+ return await this.requestJson(
1881
+ "POST",
1882
+ `/v1/workspaces/${workspaceId}/documents/${documentId}/move`,
1883
+ request
1884
+ );
1885
+ }
1803
1886
  /** Retry indexing for a failed document. */
1804
1887
  async reindexDocument(workspaceId, baseId, documentId) {
1805
1888
  return await this.requestJson(
@@ -2010,14 +2093,11 @@ var OpenGeniClient = class {
2010
2093
  return logoAssetPath ? `${this.baseUrl}/v1/${logoAssetPath}` : null;
2011
2094
  }
2012
2095
  // --- GitHub ----------------------------------------------------------------------------------
2013
- /** GitHub App configuration status; install/link URLs are null while new binding is disabled. */
2096
+ /** GitHub App server configuration plus truthful workspace binding status. */
2014
2097
  async getGitHubApp(workspaceId) {
2015
2098
  return await this.requestJson("GET", `/v1/workspaces/${workspaceId}/github/app`);
2016
2099
  }
2017
- /**
2018
- * Compatibility URL for previously issued state. New installation binding is
2019
- * disabled, so the endpoint validates state and terminates with HTTP 410.
2020
- */
2100
+ /** Build the GitHub owner-consent entry URL for fresh workspace-bound state. */
2021
2101
  githubConnectUrl(workspaceId, state) {
2022
2102
  return this.url(`/v1/workspaces/${workspaceId}/github/connect`, { state });
2023
2103
  }
@@ -2099,12 +2179,13 @@ var OpenGeniClient = class {
2099
2179
  return await this.requestJson("POST", "/v1/billing/checkout", request);
2100
2180
  }
2101
2181
  // --- Internals -------------------------------------------------------------
2102
- headers() {
2182
+ headers(correlationId) {
2103
2183
  const extra = typeof this.options.headers === "function" ? this.options.headers() : this.options.headers;
2104
2184
  return {
2105
2185
  ...this.options.apiKey ? { Authorization: `Bearer ${this.options.apiKey}` } : {},
2106
2186
  ...extra,
2107
- [OPENGENI_API_CONTRACT_HEADER]: OPENGENI_API_CONTRACT_REVISION
2187
+ [OPENGENI_API_CONTRACT_HEADER]: OPENGENI_API_CONTRACT_REVISION,
2188
+ ...correlationId ? { [OPENGENI_CORRELATION_HEADER]: correlationId } : {}
2108
2189
  };
2109
2190
  }
2110
2191
  url(path, query = {}) {
@@ -2220,36 +2301,62 @@ var OpenGeniClient = class {
2220
2301
  );
2221
2302
  }
2222
2303
  async requestJson(method, path, body, query = {}, options = {}) {
2223
- const response = await this.fetchImpl(this.url(path, query), {
2224
- method,
2225
- headers: {
2226
- ...this.headers(),
2227
- Accept: "application/json",
2228
- ...body !== void 0 ? { "Content-Type": "application/json" } : {}
2229
- },
2230
- ...body !== void 0 ? { body: JSON.stringify(body) } : {},
2231
- ...options.signal ? { signal: options.signal } : {}
2232
- });
2304
+ const correlationId = crypto.randomUUID();
2305
+ let response;
2306
+ try {
2307
+ response = await this.fetchImpl(this.url(path, query), {
2308
+ method,
2309
+ headers: {
2310
+ ...this.headers(correlationId),
2311
+ Accept: "application/json",
2312
+ ...body !== void 0 ? { "Content-Type": "application/json" } : {}
2313
+ },
2314
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {},
2315
+ ...options.signal ? { signal: options.signal } : {}
2316
+ });
2317
+ } catch (error) {
2318
+ if (isMutationMethod(method)) {
2319
+ throw mutationTransportError(correlationId);
2320
+ }
2321
+ throw error;
2322
+ }
2233
2323
  assertApiContractResponse(response);
2234
2324
  if (!response.ok) {
2235
- throw new OpenGeniApiError(response.status, await safeText(response));
2325
+ throw await apiErrorFromResponse(response, { method, correlationId });
2326
+ }
2327
+ await assertJsonResponse(response, { method, correlationId });
2328
+ try {
2329
+ return await response.json();
2330
+ } catch (error) {
2331
+ if (isMutationMethod(method)) {
2332
+ throw mutationTransportError(correlationId);
2333
+ }
2334
+ throw error;
2236
2335
  }
2237
- return await response.json();
2238
2336
  }
2239
2337
  /** Like `requestJson` for endpoints that respond with no body (204). */
2240
2338
  async requestVoid(method, path, body) {
2241
- const response = await this.fetchImpl(this.url(path), {
2242
- method,
2243
- headers: {
2244
- ...this.headers(),
2245
- Accept: "application/json",
2246
- ...body !== void 0 ? { "Content-Type": "application/json" } : {}
2247
- },
2248
- ...body !== void 0 ? { body: JSON.stringify(body) } : {}
2249
- });
2339
+ const correlationId = crypto.randomUUID();
2340
+ let response;
2341
+ try {
2342
+ response = await this.fetchImpl(this.url(path), {
2343
+ method,
2344
+ headers: {
2345
+ ...this.headers(correlationId),
2346
+ Accept: "application/json",
2347
+ ...body !== void 0 ? { "Content-Type": "application/json" } : {}
2348
+ },
2349
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
2350
+ });
2351
+ } catch (error) {
2352
+ if (isMutationMethod(method)) {
2353
+ throw mutationTransportError(correlationId);
2354
+ }
2355
+ throw error;
2356
+ }
2250
2357
  assertApiContractResponse(response);
2251
2358
  if (!response.ok) {
2252
- throw new OpenGeniApiError(response.status, await safeText(response));
2359
+ throw await apiErrorFromResponse(response, { method, correlationId });
2253
2360
  }
2254
2361
  }
2255
2362
  };
@@ -2259,25 +2366,62 @@ function assertApiContractResponse(response) {
2259
2366
  throw new OpenGeniApiContractMismatchError(OPENGENI_API_CONTRACT_REVISION, actual);
2260
2367
  }
2261
2368
  }
2262
- async function sha256ForUpload(body) {
2263
- const bytes = typeof body === "string" ? new TextEncoder().encode(body) : body instanceof Blob ? new Uint8Array(await body.arrayBuffer()) : new Uint8Array(body);
2264
- const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
2265
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
2369
+ var API_ERROR_MAX_BYTES = 16 * 1024;
2370
+ async function apiErrorFromResponse(response, context) {
2371
+ return new OpenGeniApiError(response.status, await readBoundedJsonErrorBody(response), {
2372
+ correlationId: response.headers.get(OPENGENI_CORRELATION_HEADER) ?? context.correlationId,
2373
+ mutation: isMutationMethod(context.method)
2374
+ });
2266
2375
  }
2267
- async function safeText(response) {
2268
- try {
2269
- return await response.text();
2270
- } catch {
2376
+ async function assertJsonResponse(response, context) {
2377
+ if (isJsonContentType(response.headers.get("content-type"))) return;
2378
+ await cancelResponseBody(response, "unexpected non-JSON API response");
2379
+ throw new OpenGeniApiError(502, "", {
2380
+ code: "upstream_unavailable",
2381
+ retryable: true,
2382
+ correlationId: response.headers.get(OPENGENI_CORRELATION_HEADER) ?? context.correlationId,
2383
+ outcomeUnknown: isMutationMethod(context.method),
2384
+ displayMessage: "OpenGeni is temporarily unavailable \u2014 retry."
2385
+ });
2386
+ }
2387
+ async function readBoundedJsonErrorBody(response) {
2388
+ if (!isJsonContentType(response.headers.get("content-type"))) {
2389
+ await cancelResponseBody(response, "discarding API error body");
2390
+ return "";
2391
+ }
2392
+ if (Number(response.headers.get("content-length")) > API_ERROR_MAX_BYTES) {
2393
+ await cancelResponseBody(response, "discarding API error body");
2271
2394
  return "";
2272
2395
  }
2273
- }
2274
- async function safeBoundedText(response) {
2275
2396
  try {
2276
- return new TextDecoder().decode(await readBoundedResponseBytes(response, 64 * 1024, null));
2397
+ return new TextDecoder().decode(
2398
+ await readBoundedResponseBytes(response, API_ERROR_MAX_BYTES, null)
2399
+ );
2277
2400
  } catch {
2278
2401
  return "";
2279
2402
  }
2280
2403
  }
2404
+ function isJsonContentType(value) {
2405
+ return /^(application\/json|[^;]+\+json)\s*(;|$)/i.test(value ?? "");
2406
+ }
2407
+ function isMutationMethod(method) {
2408
+ return method !== "GET" && method !== "HEAD" && method !== "OPTIONS";
2409
+ }
2410
+ function mutationTransportError(correlationId) {
2411
+ return new OpenGeniApiError(0, "", {
2412
+ code: "network_error",
2413
+ retryable: true,
2414
+ correlationId,
2415
+ outcomeUnknown: true,
2416
+ mutation: true,
2417
+ displayMessage: "OpenGeni could not confirm the request \u2014 reconcile before retrying."
2418
+ });
2419
+ }
2420
+ async function sha256ForUpload(body) {
2421
+ const bytes = typeof body === "string" ? new TextEncoder().encode(body) : body instanceof Blob ? new Uint8Array(await body.arrayBuffer()) : new Uint8Array(body);
2422
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
2423
+ return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
2424
+ }
2281
2425
  async function cancelResponseBody(response, reason) {
2282
2426
  await response.body?.cancel(reason).catch(() => void 0);
2283
2427
  }
@@ -2729,6 +2873,7 @@ export {
2729
2873
  KNOWN_USAGE_EVENT_TYPES,
2730
2874
  OPENGENI_API_CONTRACT_HEADER,
2731
2875
  OPENGENI_API_CONTRACT_REVISION,
2876
+ OPENGENI_CORRELATION_HEADER,
2732
2877
  OpenGeniApiContractMismatchError,
2733
2878
  OpenGeniApiError,
2734
2879
  OpenGeniClient,