@ljoukov/llm 3.0.1 → 3.0.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.js CHANGED
@@ -136,7 +136,7 @@ function getGeminiProPricing(modelId) {
136
136
  if (modelId.includes("gemini-2.5-pro")) {
137
137
  return GEMINI_2_5_PRO_PRICING;
138
138
  }
139
- if (modelId.includes("gemini-3-pro")) {
139
+ if (modelId.includes("gemini-3-pro") || modelId.includes("gemini-3.1-pro")) {
140
140
  return GEMINI_3_PRO_PREVIEW_PRICING;
141
141
  }
142
142
  return void 0;
@@ -171,9 +171,6 @@ function getOpenAiPricing(modelId) {
171
171
  if (modelId.includes("gpt-5.3-codex")) {
172
172
  return OPENAI_GPT_53_CODEX_PRICING;
173
173
  }
174
- if (modelId.includes("gpt-5-codex")) {
175
- return OPENAI_GPT_53_CODEX_PRICING;
176
- }
177
174
  if (modelId.includes("gpt-5.2")) {
178
175
  return OPENAI_GPT_52_PRICING;
179
176
  }
@@ -336,8 +333,6 @@ function parseEnvLine(line) {
336
333
  // src/openai/chatgpt-auth.ts
337
334
  var CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_URL";
338
335
  var CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_STORE";
339
- var CHATGPT_AUTH_SERVER_URL_ENV = "CHATGPT_AUTH_SERVER_URL";
340
- var CHATGPT_AUTH_SERVER_STORE_ENV = "CHATGPT_AUTH_SERVER_STORE";
341
336
  var CHATGPT_AUTH_API_KEY_ENV = "CHATGPT_AUTH_API_KEY";
342
337
  var CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY";
343
338
  var CHATGPT_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
@@ -469,7 +464,7 @@ async function refreshChatGptOauthToken(refreshToken, fallback) {
469
464
  }
470
465
  async function getChatGptAuthProfile() {
471
466
  loadLocalEnv();
472
- const tokenProviderUrl = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV] ?? process.env[CHATGPT_AUTH_SERVER_URL_ENV];
467
+ const tokenProviderUrl = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV];
473
468
  const tokenProviderKey = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY_ENV] ?? process.env[CHATGPT_AUTH_API_KEY_ENV];
474
469
  if (tokenProviderUrl && tokenProviderUrl.trim().length > 0 && tokenProviderKey && tokenProviderKey.trim().length > 0) {
475
470
  if (cachedProfile && !isExpired(cachedProfile)) {
@@ -480,7 +475,7 @@ async function getChatGptAuthProfile() {
480
475
  }
481
476
  refreshPromise = (async () => {
482
477
  try {
483
- const store = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV] ?? process.env[CHATGPT_AUTH_SERVER_STORE_ENV];
478
+ const store = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV];
484
479
  const profile = await fetchChatGptAuthProfileFromTokenProvider({
485
480
  baseUrl: tokenProviderUrl,
486
481
  apiKey: tokenProviderKey,
@@ -683,22 +678,624 @@ function extractChatGptAccountId(token) {
683
678
  return typeof namespaced === "string" && namespaced.length > 0 ? namespaced : void 0;
684
679
  }
685
680
 
681
+ // src/openai/responses-websocket.ts
682
+ import WebSocket from "ws";
683
+ var OPENAI_BETA_RESPONSES_WEBSOCKETS_V2 = "responses_websockets=2026-02-06";
684
+ var ResponsesWebSocketHttpError = class extends Error {
685
+ status;
686
+ body;
687
+ headers;
688
+ constructor(options) {
689
+ super(options.message);
690
+ this.name = "ResponsesWebSocketHttpError";
691
+ this.status = options.status;
692
+ this.body = options.body;
693
+ this.headers = options.headers;
694
+ }
695
+ };
696
+ var UNSUPPORTED_WEBSOCKET_STATUS_CODES = /* @__PURE__ */ new Set([400, 404, 405, 406, 426, 501]);
697
+ var WEBSOCKET_CONNECT_TIMEOUT_MS = 3e4;
698
+ function parseUnexpectedServerResponseStatus(message) {
699
+ const match = /unexpected server response:\s*(\d+)/i.exec(message);
700
+ if (!match) {
701
+ return null;
702
+ }
703
+ const status = Number(match[1]);
704
+ if (!Number.isFinite(status) || status <= 0) {
705
+ return null;
706
+ }
707
+ return status;
708
+ }
709
+ function supportsUnexpectedResponseEvent() {
710
+ return !("bun" in process.versions);
711
+ }
712
+ function resolveResponsesWebSocketMode(raw, fallback = "auto") {
713
+ const value = raw?.trim().toLowerCase();
714
+ if (value === "auto" || value === "off" || value === "only") {
715
+ return value;
716
+ }
717
+ return fallback;
718
+ }
719
+ function mergeOpenAiBetaHeader(existing, required) {
720
+ const parts = /* @__PURE__ */ new Set();
721
+ for (const part of (existing ?? "").split(",")) {
722
+ const trimmed = part.trim();
723
+ if (trimmed.length > 0) {
724
+ parts.add(trimmed);
725
+ }
726
+ }
727
+ const normalizedRequired = required.trim();
728
+ if (normalizedRequired.length > 0) {
729
+ parts.add(normalizedRequired);
730
+ }
731
+ return Array.from(parts).join(", ");
732
+ }
733
+ function toWebSocketUrl(httpOrHttpsUrl) {
734
+ const parsed = new URL(httpOrHttpsUrl);
735
+ if (parsed.protocol === "https:") {
736
+ parsed.protocol = "wss:";
737
+ } else if (parsed.protocol === "http:") {
738
+ parsed.protocol = "ws:";
739
+ } else if (parsed.protocol !== "ws:" && parsed.protocol !== "wss:") {
740
+ throw new Error(`Unsupported websocket URL protocol: ${parsed.protocol}`);
741
+ }
742
+ return parsed.toString();
743
+ }
744
+ function isResponsesWebSocketUnsupportedError(error) {
745
+ if (error instanceof ResponsesWebSocketHttpError) {
746
+ return UNSUPPORTED_WEBSOCKET_STATUS_CODES.has(error.status);
747
+ }
748
+ const message = error instanceof Error ? error.message.toLowerCase() : "";
749
+ const status = parseUnexpectedServerResponseStatus(message);
750
+ if (status !== null) {
751
+ return UNSUPPORTED_WEBSOCKET_STATUS_CODES.has(status);
752
+ }
753
+ return message.includes("unexpected server response: 426");
754
+ }
755
+ function createAdaptiveResponsesStream(options) {
756
+ let resolved = null;
757
+ let websocketSelected = false;
758
+ let fallbackSelected = false;
759
+ const activateFallback = (error) => {
760
+ options.onWebSocketFallback?.(error);
761
+ fallbackSelected = true;
762
+ websocketSelected = false;
763
+ const fallback = options.createFallbackStream();
764
+ resolved = Promise.resolve(fallback);
765
+ return fallback;
766
+ };
767
+ const getStream = async () => {
768
+ if (resolved) {
769
+ return await resolved;
770
+ }
771
+ resolved = (async () => {
772
+ if (options.mode === "off") {
773
+ fallbackSelected = true;
774
+ return options.createFallbackStream();
775
+ }
776
+ try {
777
+ const stream = await options.createWebSocketStream();
778
+ websocketSelected = true;
779
+ return stream;
780
+ } catch (error) {
781
+ if (options.mode === "only") {
782
+ throw error;
783
+ }
784
+ return activateFallback(error);
785
+ }
786
+ })();
787
+ return await resolved;
788
+ };
789
+ return {
790
+ async *[Symbol.asyncIterator]() {
791
+ const stream = await getStream();
792
+ let yielded = 0;
793
+ try {
794
+ for await (const event of stream) {
795
+ yielded += 1;
796
+ yield event;
797
+ }
798
+ } catch (error) {
799
+ if (options.mode !== "only" && websocketSelected && !fallbackSelected && yielded === 0) {
800
+ const fallback = activateFallback(error);
801
+ for await (const event of fallback) {
802
+ yield event;
803
+ }
804
+ return;
805
+ }
806
+ throw error;
807
+ }
808
+ },
809
+ async finalResponse() {
810
+ const stream = await getStream();
811
+ try {
812
+ return await stream.finalResponse();
813
+ } catch (error) {
814
+ if (options.mode === "only" || !websocketSelected || fallbackSelected) {
815
+ throw error;
816
+ }
817
+ const fallback = activateFallback(error);
818
+ return await fallback.finalResponse();
819
+ }
820
+ },
821
+ close() {
822
+ void getStream().then((stream) => stream.close()).catch(() => {
823
+ });
824
+ }
825
+ };
826
+ }
827
+ async function createResponsesWebSocketStream(options) {
828
+ const completionTypes = new Set(
829
+ options.completionEventTypes ?? ["response.completed", "response.failed", "response.done"]
830
+ );
831
+ const { socket, responseHeaders } = await connectWebSocket({
832
+ url: options.url,
833
+ headers: options.headers,
834
+ signal: options.signal
835
+ });
836
+ const queue = createAsyncQueue();
837
+ let settled = false;
838
+ let finalResponse = null;
839
+ let latestResponse = null;
840
+ let idleTimer = null;
841
+ let resolveFinal = null;
842
+ let rejectFinal = null;
843
+ const finalPromise = new Promise((resolve, reject) => {
844
+ resolveFinal = resolve;
845
+ rejectFinal = reject;
846
+ });
847
+ void finalPromise.catch(() => {
848
+ });
849
+ const clearIdleTimer = () => {
850
+ if (idleTimer) {
851
+ clearTimeout(idleTimer);
852
+ idleTimer = null;
853
+ }
854
+ };
855
+ const closeSocket = () => {
856
+ try {
857
+ if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
858
+ socket.close();
859
+ }
860
+ } catch {
861
+ }
862
+ };
863
+ const complete = (response) => {
864
+ if (settled) {
865
+ return;
866
+ }
867
+ settled = true;
868
+ clearIdleTimer();
869
+ finalResponse = response;
870
+ resolveFinal?.(response);
871
+ queue.close();
872
+ closeSocket();
873
+ };
874
+ const fail = (error) => {
875
+ if (settled) {
876
+ return;
877
+ }
878
+ settled = true;
879
+ clearIdleTimer();
880
+ rejectFinal?.(error);
881
+ queue.fail(error);
882
+ closeSocket();
883
+ };
884
+ const restartIdleTimer = () => {
885
+ clearIdleTimer();
886
+ const idleTimeoutMs = options.idleTimeoutMs;
887
+ if (!idleTimeoutMs || idleTimeoutMs <= 0 || settled) {
888
+ return;
889
+ }
890
+ idleTimer = setTimeout(() => {
891
+ fail(new Error(`Responses WebSocket idle timeout after ${idleTimeoutMs}ms.`));
892
+ }, idleTimeoutMs);
893
+ };
894
+ const onAbort = () => {
895
+ const error = createAbortError(options.signal?.reason);
896
+ fail(error);
897
+ };
898
+ if (options.signal) {
899
+ if (options.signal.aborted) {
900
+ socket.close();
901
+ throw createAbortError(options.signal.reason);
902
+ }
903
+ options.signal.addEventListener("abort", onAbort, { once: true });
904
+ }
905
+ const cleanup = () => {
906
+ clearIdleTimer();
907
+ socket.removeAllListeners();
908
+ if (options.signal) {
909
+ options.signal.removeEventListener("abort", onAbort);
910
+ }
911
+ };
912
+ socket.on("message", (raw) => {
913
+ restartIdleTimer();
914
+ const parsed = parseWebSocketPayload(raw);
915
+ if (!parsed) {
916
+ return;
917
+ }
918
+ const error = mapWebSocketErrorEvent(parsed);
919
+ if (error) {
920
+ fail(error);
921
+ return;
922
+ }
923
+ const event = parsed;
924
+ if (isObjectWithResponse(event)) {
925
+ latestResponse = event.response;
926
+ }
927
+ queue.push(event);
928
+ const type = typeof event.type === "string" ? event.type : "";
929
+ if (completionTypes.has(type)) {
930
+ const completedResponse = normalizeFinalResponse(
931
+ type,
932
+ event.response,
933
+ latestResponse,
934
+ responseHeaders
935
+ );
936
+ complete(completedResponse);
937
+ }
938
+ });
939
+ socket.on("error", (error) => {
940
+ fail(new Error(`Responses WebSocket error: ${error.message}`));
941
+ });
942
+ socket.on("close", (_code, _reason) => {
943
+ if (settled) {
944
+ cleanup();
945
+ return;
946
+ }
947
+ fail(new Error("Responses WebSocket closed before completion."));
948
+ cleanup();
949
+ });
950
+ restartIdleTimer();
951
+ const payload = serializeRequestPayload(options.request);
952
+ await new Promise((resolve, reject) => {
953
+ socket.send(payload, (error) => {
954
+ if (error) {
955
+ reject(error);
956
+ } else {
957
+ resolve();
958
+ }
959
+ });
960
+ }).catch((error) => {
961
+ fail(new Error(`Failed to send Responses WebSocket request: ${errorToMessage(error)}`));
962
+ throw error instanceof Error ? error : new Error(errorToMessage(error));
963
+ });
964
+ return {
965
+ async *[Symbol.asyncIterator]() {
966
+ try {
967
+ for await (const event of queue.iterable) {
968
+ yield event;
969
+ }
970
+ } finally {
971
+ if (!settled) {
972
+ closeSocket();
973
+ }
974
+ }
975
+ },
976
+ async finalResponse() {
977
+ return await finalPromise;
978
+ },
979
+ close() {
980
+ if (settled) {
981
+ return;
982
+ }
983
+ const response = finalResponse ?? latestResponse ?? { status: "cancelled" };
984
+ complete(response);
985
+ cleanup();
986
+ }
987
+ };
988
+ }
989
+ async function connectWebSocket(options) {
990
+ return await new Promise((resolve, reject) => {
991
+ const shouldListenForUnexpectedResponse = supportsUnexpectedResponseEvent();
992
+ const socket = new WebSocket(options.url, {
993
+ headers: options.headers,
994
+ handshakeTimeout: WEBSOCKET_CONNECT_TIMEOUT_MS
995
+ });
996
+ let settled = false;
997
+ let responseBody = "";
998
+ let connectTimeout = setTimeout(() => {
999
+ rejectOnce(
1000
+ new Error(
1001
+ `Responses WebSocket connection timed out after ${WEBSOCKET_CONNECT_TIMEOUT_MS}ms.`
1002
+ )
1003
+ );
1004
+ }, WEBSOCKET_CONNECT_TIMEOUT_MS);
1005
+ const rejectOnce = (error) => {
1006
+ if (settled) {
1007
+ return;
1008
+ }
1009
+ settled = true;
1010
+ cleanup();
1011
+ try {
1012
+ socket.terminate();
1013
+ } catch {
1014
+ }
1015
+ reject(error);
1016
+ };
1017
+ const resolveOnce = (result) => {
1018
+ if (settled) {
1019
+ return;
1020
+ }
1021
+ settled = true;
1022
+ cleanup(false);
1023
+ resolve(result);
1024
+ };
1025
+ const onAbort = () => {
1026
+ rejectOnce(createAbortError(options.signal?.reason));
1027
+ };
1028
+ const cleanup = (removeAbortListener = true) => {
1029
+ if (connectTimeout) {
1030
+ clearTimeout(connectTimeout);
1031
+ connectTimeout = null;
1032
+ }
1033
+ socket.removeListener("open", onOpen);
1034
+ socket.removeListener("error", onError);
1035
+ if (shouldListenForUnexpectedResponse) {
1036
+ socket.removeListener("unexpected-response", onUnexpectedResponse);
1037
+ }
1038
+ if (removeAbortListener && options.signal) {
1039
+ options.signal.removeEventListener("abort", onAbort);
1040
+ }
1041
+ };
1042
+ const onOpen = () => {
1043
+ const headers = normalizeUpgradeHeaders(socket);
1044
+ resolveOnce({ socket, responseHeaders: headers });
1045
+ };
1046
+ const onError = (error) => {
1047
+ rejectOnce(new Error(`Responses WebSocket connection failed: ${error.message}`));
1048
+ };
1049
+ const onUnexpectedResponse = (_request, response) => {
1050
+ if (typeof response.setEncoding === "function") {
1051
+ response.setEncoding("utf8");
1052
+ }
1053
+ response.on("data", (chunk) => {
1054
+ responseBody += typeof chunk === "string" ? chunk : chunk.toString("utf8");
1055
+ });
1056
+ response.on("end", () => {
1057
+ const status = Number(response.statusCode ?? 0);
1058
+ const headers = {};
1059
+ const rawHeaders = response.headers ?? {};
1060
+ for (const [key, value] of Object.entries(rawHeaders)) {
1061
+ if (typeof value === "string") {
1062
+ headers[key] = value;
1063
+ } else if (Array.isArray(value)) {
1064
+ headers[key] = value.join(", ");
1065
+ }
1066
+ }
1067
+ rejectOnce(
1068
+ new ResponsesWebSocketHttpError({
1069
+ status: Number.isFinite(status) && status > 0 ? status : 500,
1070
+ message: `Responses WebSocket upgrade failed${status ? ` (${status})` : ""}.`,
1071
+ body: responseBody || void 0,
1072
+ headers
1073
+ })
1074
+ );
1075
+ });
1076
+ response.on("error", (error) => {
1077
+ rejectOnce(
1078
+ new ResponsesWebSocketHttpError({
1079
+ status: Number(response.statusCode ?? 500),
1080
+ message: `Responses WebSocket upgrade failed: ${error.message}`,
1081
+ body: responseBody || void 0
1082
+ })
1083
+ );
1084
+ });
1085
+ };
1086
+ socket.once("open", onOpen);
1087
+ socket.once("error", onError);
1088
+ if (shouldListenForUnexpectedResponse) {
1089
+ socket.once("unexpected-response", onUnexpectedResponse);
1090
+ }
1091
+ if (options.signal) {
1092
+ if (options.signal.aborted) {
1093
+ onAbort();
1094
+ return;
1095
+ }
1096
+ options.signal.addEventListener("abort", onAbort, { once: true });
1097
+ }
1098
+ });
1099
+ }
1100
+ function normalizeUpgradeHeaders(socket) {
1101
+ const maybeUpgradeResponse = socket._req?.res;
1102
+ const raw = maybeUpgradeResponse?.headers ?? {};
1103
+ const normalized = {};
1104
+ for (const [key, value] of Object.entries(raw)) {
1105
+ if (typeof value === "string") {
1106
+ normalized[key.toLowerCase()] = value;
1107
+ } else if (Array.isArray(value)) {
1108
+ normalized[key.toLowerCase()] = value.join(", ");
1109
+ }
1110
+ }
1111
+ return normalized;
1112
+ }
1113
+ function parseWebSocketPayload(raw) {
1114
+ const text = toUtf8(raw);
1115
+ if (!text) {
1116
+ return null;
1117
+ }
1118
+ try {
1119
+ const parsed = JSON.parse(text);
1120
+ if (parsed && typeof parsed === "object") {
1121
+ return parsed;
1122
+ }
1123
+ } catch {
1124
+ return null;
1125
+ }
1126
+ return null;
1127
+ }
1128
+ function toUtf8(raw) {
1129
+ if (typeof raw === "string") {
1130
+ return raw;
1131
+ }
1132
+ if (raw instanceof ArrayBuffer) {
1133
+ return Buffer.from(raw).toString("utf8");
1134
+ }
1135
+ if (Array.isArray(raw)) {
1136
+ const chunks = raw.map((chunk) => {
1137
+ if (typeof chunk === "string") {
1138
+ return Buffer.from(chunk, "utf8");
1139
+ }
1140
+ return Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1141
+ });
1142
+ return Buffer.concat(chunks).toString("utf8");
1143
+ }
1144
+ return Buffer.isBuffer(raw) ? raw.toString("utf8") : Buffer.from(raw).toString("utf8");
1145
+ }
1146
+ function mapWebSocketErrorEvent(payload) {
1147
+ if (payload.type !== "error") {
1148
+ return null;
1149
+ }
1150
+ const status = resolveNumericStatus(payload.status) ?? resolveNumericStatus(payload.status_code);
1151
+ if (!status || status < 400) {
1152
+ const message = errorToMessage(payload.error) || "Responses WebSocket returned an error event.";
1153
+ return new Error(message);
1154
+ }
1155
+ const headers = mapErrorHeaders(payload.headers);
1156
+ const body = payload.error && typeof payload.error === "object" ? JSON.stringify({ error: payload.error }, null, 2) : void 0;
1157
+ return new ResponsesWebSocketHttpError({
1158
+ status,
1159
+ message: `Responses WebSocket returned status ${status}.`,
1160
+ body,
1161
+ headers
1162
+ });
1163
+ }
1164
+ function mapErrorHeaders(value) {
1165
+ if (!value || typeof value !== "object") {
1166
+ return void 0;
1167
+ }
1168
+ const headers = {};
1169
+ for (const [key, entry] of Object.entries(value)) {
1170
+ if (typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean") {
1171
+ headers[key.toLowerCase()] = String(entry);
1172
+ }
1173
+ }
1174
+ return Object.keys(headers).length > 0 ? headers : void 0;
1175
+ }
1176
+ function resolveNumericStatus(value) {
1177
+ if (typeof value === "number" && Number.isFinite(value)) {
1178
+ return Math.floor(value);
1179
+ }
1180
+ if (typeof value === "string" && value.trim().length > 0) {
1181
+ const parsed = Number(value);
1182
+ if (Number.isFinite(parsed)) {
1183
+ return Math.floor(parsed);
1184
+ }
1185
+ }
1186
+ return null;
1187
+ }
1188
+ function normalizeFinalResponse(eventType, eventResponse, latestResponse, responseHeaders) {
1189
+ const response = eventResponse && typeof eventResponse === "object" ? { ...eventResponse } : latestResponse ? { ...latestResponse } : {};
1190
+ if (typeof response.status !== "string") {
1191
+ if (eventType === "response.failed") {
1192
+ response.status = "failed";
1193
+ } else if (eventType === "response.done") {
1194
+ response.status = "completed";
1195
+ } else if (eventType === "response.completed") {
1196
+ response.status = "completed";
1197
+ }
1198
+ }
1199
+ const upgradeModel = responseHeaders["openai-model"];
1200
+ if (typeof response.model !== "string" && upgradeModel) {
1201
+ response.model = upgradeModel;
1202
+ }
1203
+ return response;
1204
+ }
1205
+ function serializeRequestPayload(request) {
1206
+ if (!request || typeof request !== "object" || Array.isArray(request)) {
1207
+ throw new Error("Responses WebSocket request must be a JSON object.");
1208
+ }
1209
+ const body = request;
1210
+ const payload = typeof body.type === "string" ? body : { type: "response.create", ...body };
1211
+ return JSON.stringify(payload);
1212
+ }
1213
+ function isObjectWithResponse(event) {
1214
+ return Boolean(event.response && typeof event.response === "object");
1215
+ }
1216
+ function errorToMessage(error) {
1217
+ if (error instanceof Error) {
1218
+ return error.message;
1219
+ }
1220
+ if (typeof error === "string") {
1221
+ return error;
1222
+ }
1223
+ try {
1224
+ return JSON.stringify(error);
1225
+ } catch {
1226
+ return String(error);
1227
+ }
1228
+ }
1229
+ function createAbortError(reason) {
1230
+ const error = new Error(
1231
+ reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "Request aborted."
1232
+ );
1233
+ error.name = "AbortError";
1234
+ return error;
1235
+ }
1236
+
686
1237
  // src/openai/chatgpt-codex.ts
687
1238
  var CHATGPT_CODEX_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
1239
+ var CHATGPT_RESPONSES_EXPERIMENTAL_HEADER = "responses=experimental";
1240
+ var cachedResponsesWebSocketMode = null;
1241
+ var chatGptResponsesWebSocketDisabled = false;
688
1242
  async function streamChatGptCodexResponse(options) {
689
1243
  const { access, accountId } = await getChatGptAuthProfile();
690
- const headers = {
691
- Authorization: `Bearer ${access}`,
692
- "chatgpt-account-id": accountId,
693
- "OpenAI-Beta": "responses=experimental",
694
- originator: "llm",
695
- "User-Agent": buildUserAgent(),
696
- Accept: "text/event-stream",
697
- "Content-Type": "application/json"
1244
+ const mode = resolveChatGptResponsesWebSocketMode();
1245
+ const fallbackStreamFactory = () => {
1246
+ const streamPromise = streamChatGptCodexResponseSse({
1247
+ request: options.request,
1248
+ access,
1249
+ accountId,
1250
+ sessionId: options.sessionId,
1251
+ signal: options.signal
1252
+ });
1253
+ return {
1254
+ async *[Symbol.asyncIterator]() {
1255
+ const stream = await streamPromise;
1256
+ for await (const event of stream) {
1257
+ yield event;
1258
+ }
1259
+ },
1260
+ async finalResponse() {
1261
+ return {};
1262
+ },
1263
+ close() {
1264
+ }
1265
+ };
698
1266
  };
699
- if (options.sessionId) {
700
- headers.session_id = options.sessionId;
1267
+ if (mode === "off" || chatGptResponsesWebSocketDisabled) {
1268
+ return fallbackStreamFactory();
701
1269
  }
1270
+ const websocketHeaders = buildChatGptCodexHeaders({
1271
+ access,
1272
+ accountId,
1273
+ sessionId: options.sessionId,
1274
+ useWebSocket: true
1275
+ });
1276
+ return createAdaptiveResponsesStream({
1277
+ mode,
1278
+ createWebSocketStream: async () => await createResponsesWebSocketStream({
1279
+ url: toWebSocketUrl(CHATGPT_CODEX_ENDPOINT),
1280
+ headers: websocketHeaders,
1281
+ request: options.request,
1282
+ signal: options.signal
1283
+ }),
1284
+ createFallbackStream: fallbackStreamFactory,
1285
+ onWebSocketFallback: () => {
1286
+ chatGptResponsesWebSocketDisabled = true;
1287
+ }
1288
+ });
1289
+ }
1290
+ async function streamChatGptCodexResponseSse(options) {
1291
+ const headers = buildChatGptCodexHeaders({
1292
+ access: options.access,
1293
+ accountId: options.accountId,
1294
+ sessionId: options.sessionId,
1295
+ useWebSocket: false
1296
+ });
1297
+ headers.Accept = "text/event-stream";
1298
+ headers["Content-Type"] = "application/json";
702
1299
  const response = await fetch(CHATGPT_CODEX_ENDPOINT, {
703
1300
  method: "POST",
704
1301
  headers,
@@ -715,20 +1312,67 @@ async function streamChatGptCodexResponse(options) {
715
1312
  }
716
1313
  return parseEventStream(body);
717
1314
  }
1315
+ function resolveChatGptResponsesWebSocketMode() {
1316
+ if (cachedResponsesWebSocketMode) {
1317
+ return cachedResponsesWebSocketMode;
1318
+ }
1319
+ cachedResponsesWebSocketMode = resolveResponsesWebSocketMode(
1320
+ process.env.CHATGPT_RESPONSES_WEBSOCKET_MODE ?? process.env.OPENAI_RESPONSES_WEBSOCKET_MODE,
1321
+ "auto"
1322
+ );
1323
+ return cachedResponsesWebSocketMode;
1324
+ }
1325
+ function buildChatGptCodexHeaders(options) {
1326
+ const openAiBeta = options.useWebSocket ? mergeOpenAiBetaHeader(
1327
+ CHATGPT_RESPONSES_EXPERIMENTAL_HEADER,
1328
+ OPENAI_BETA_RESPONSES_WEBSOCKETS_V2
1329
+ ) : CHATGPT_RESPONSES_EXPERIMENTAL_HEADER;
1330
+ const headers = {
1331
+ Authorization: `Bearer ${options.access}`,
1332
+ "chatgpt-account-id": options.accountId,
1333
+ "OpenAI-Beta": openAiBeta,
1334
+ originator: "llm",
1335
+ "User-Agent": buildUserAgent()
1336
+ };
1337
+ if (options.sessionId) {
1338
+ headers.session_id = options.sessionId;
1339
+ }
1340
+ return headers;
1341
+ }
718
1342
  async function collectChatGptCodexResponse(options) {
719
- let stream;
720
- try {
721
- stream = await streamChatGptCodexResponse(options);
722
- } catch (error) {
723
- if (shouldRetryWithoutReasoningSummary(options.request, error)) {
724
- stream = await streamChatGptCodexResponse({
1343
+ let requestForAttempt = options.request;
1344
+ let retriedWithoutReasoningSummary = false;
1345
+ let retriedViaSseFallback = false;
1346
+ while (true) {
1347
+ let sawAnyDelta = false;
1348
+ try {
1349
+ const stream = await streamChatGptCodexResponse({
725
1350
  ...options,
726
- request: removeReasoningSummary(options.request)
1351
+ request: requestForAttempt
727
1352
  });
728
- } else {
1353
+ return await collectChatGptCodexStream({
1354
+ stream,
1355
+ onDelta: (delta) => {
1356
+ sawAnyDelta = true;
1357
+ options.onDelta?.(delta);
1358
+ }
1359
+ });
1360
+ } catch (error) {
1361
+ if (!sawAnyDelta && !retriedViaSseFallback && shouldRetryViaSseFallback(error) && !chatGptResponsesWebSocketDisabled) {
1362
+ chatGptResponsesWebSocketDisabled = true;
1363
+ retriedViaSseFallback = true;
1364
+ continue;
1365
+ }
1366
+ if (!retriedWithoutReasoningSummary && shouldRetryWithoutReasoningSummary(requestForAttempt, error)) {
1367
+ requestForAttempt = removeReasoningSummary(requestForAttempt);
1368
+ retriedWithoutReasoningSummary = true;
1369
+ continue;
1370
+ }
729
1371
  throw error;
730
1372
  }
731
1373
  }
1374
+ }
1375
+ async function collectChatGptCodexStream(options) {
732
1376
  const toolCalls = /* @__PURE__ */ new Map();
733
1377
  const toolCallOrder = [];
734
1378
  const webSearchCalls = /* @__PURE__ */ new Map();
@@ -741,7 +1385,7 @@ async function collectChatGptCodexResponse(options) {
741
1385
  let model;
742
1386
  let status;
743
1387
  let blocked = false;
744
- for await (const event of stream) {
1388
+ for await (const event of options.stream) {
745
1389
  const type = typeof event.type === "string" ? event.type : void 0;
746
1390
  if (type === "response.output_text.delta") {
747
1391
  const delta = typeof event.delta === "string" ? event.delta : "";
@@ -865,6 +1509,16 @@ function shouldRetryWithoutReasoningSummary(request, error) {
865
1509
  const message = error.message.toLowerCase();
866
1510
  return message.includes("unsupported parameter") && message.includes("reasoning.summary");
867
1511
  }
1512
+ function shouldRetryViaSseFallback(error) {
1513
+ if (!(error instanceof Error)) {
1514
+ return false;
1515
+ }
1516
+ if (error.name === "AbortError") {
1517
+ return false;
1518
+ }
1519
+ const message = error.message.toLowerCase();
1520
+ return message.includes("responses websocket");
1521
+ }
868
1522
  function removeReasoningSummary(request) {
869
1523
  const reasoning = request.reasoning;
870
1524
  if (!reasoning?.summary) {
@@ -1112,14 +1766,16 @@ async function runFireworksCall(fn) {
1112
1766
  }
1113
1767
 
1114
1768
  // src/fireworks/models.ts
1115
- var FIREWORKS_MODEL_IDS = ["kimi-k2.5", "glm-5", "minimax-m2.1"];
1769
+ var FIREWORKS_MODEL_IDS = ["kimi-k2.5", "glm-5", "minimax-m2.1", "gpt-oss-120b"];
1116
1770
  var FIREWORKS_DEFAULT_KIMI_MODEL = "kimi-k2.5";
1117
1771
  var FIREWORKS_DEFAULT_GLM_MODEL = "glm-5";
1118
1772
  var FIREWORKS_DEFAULT_MINIMAX_MODEL = "minimax-m2.1";
1773
+ var FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL = "gpt-oss-120b";
1119
1774
  var FIREWORKS_CANONICAL_MODEL_IDS = {
1120
1775
  "kimi-k2.5": "accounts/fireworks/models/kimi-k2p5",
1121
1776
  "glm-5": "accounts/fireworks/models/glm-5",
1122
- "minimax-m2.1": "accounts/fireworks/models/minimax-m2p1"
1777
+ "minimax-m2.1": "accounts/fireworks/models/minimax-m2p1",
1778
+ "gpt-oss-120b": "accounts/fireworks/models/gpt-oss-120b"
1123
1779
  };
1124
1780
  function isFireworksModelId(value) {
1125
1781
  return FIREWORKS_MODEL_IDS.includes(value.trim());
@@ -1198,16 +1854,25 @@ function getGoogleAuthOptions(scopes) {
1198
1854
  }
1199
1855
 
1200
1856
  // src/google/client.ts
1201
- var GEMINI_MODEL_IDS = [
1857
+ var GEMINI_TEXT_MODEL_IDS = [
1202
1858
  "gemini-3-pro-preview",
1859
+ "gemini-3.1-pro-preview",
1203
1860
  "gemini-3-flash-preview",
1204
1861
  "gemini-2.5-pro",
1205
1862
  "gemini-flash-latest",
1206
1863
  "gemini-flash-lite-latest"
1207
1864
  ];
1865
+ var GEMINI_IMAGE_MODEL_IDS = ["gemini-3-pro-image-preview"];
1866
+ var GEMINI_MODEL_IDS = [...GEMINI_TEXT_MODEL_IDS, ...GEMINI_IMAGE_MODEL_IDS];
1208
1867
  function isGeminiModelId(value) {
1209
1868
  return GEMINI_MODEL_IDS.includes(value);
1210
1869
  }
1870
+ function isGeminiTextModelId(value) {
1871
+ return GEMINI_TEXT_MODEL_IDS.includes(value);
1872
+ }
1873
+ function isGeminiImageModelId(value) {
1874
+ return GEMINI_IMAGE_MODEL_IDS.includes(value);
1875
+ }
1211
1876
  var CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
1212
1877
  var DEFAULT_VERTEX_LOCATION = "global";
1213
1878
  var geminiConfiguration = {};
@@ -1466,6 +2131,8 @@ var cachedApiKey2 = null;
1466
2131
  var cachedClient2 = null;
1467
2132
  var cachedFetch2 = null;
1468
2133
  var cachedTimeoutMs2 = null;
2134
+ var openAiResponsesWebSocketMode = null;
2135
+ var openAiResponsesWebSocketDisabled = false;
1469
2136
  var DEFAULT_OPENAI_TIMEOUT_MS = 15 * 6e4;
1470
2137
  function resolveOpenAiTimeoutMs() {
1471
2138
  if (cachedTimeoutMs2 !== null) {
@@ -1493,6 +2160,97 @@ function getOpenAiFetch() {
1493
2160
  });
1494
2161
  return cachedFetch2;
1495
2162
  }
2163
+ function resolveOpenAiBaseUrl() {
2164
+ loadLocalEnv();
2165
+ return process.env.OPENAI_BASE_URL?.trim() || "https://api.openai.com/v1";
2166
+ }
2167
+ function resolveOpenAiResponsesWebSocketMode() {
2168
+ if (openAiResponsesWebSocketMode) {
2169
+ return openAiResponsesWebSocketMode;
2170
+ }
2171
+ loadLocalEnv();
2172
+ openAiResponsesWebSocketMode = resolveResponsesWebSocketMode(
2173
+ process.env.OPENAI_RESPONSES_WEBSOCKET_MODE,
2174
+ "auto"
2175
+ );
2176
+ return openAiResponsesWebSocketMode;
2177
+ }
2178
+ function wrapFallbackStream(stream) {
2179
+ return {
2180
+ async *[Symbol.asyncIterator]() {
2181
+ for await (const event of stream) {
2182
+ yield event;
2183
+ }
2184
+ },
2185
+ async finalResponse() {
2186
+ return await stream.finalResponse();
2187
+ },
2188
+ close() {
2189
+ const maybeClose = stream;
2190
+ if (typeof maybeClose.close === "function") {
2191
+ maybeClose.close();
2192
+ }
2193
+ }
2194
+ };
2195
+ }
2196
+ function buildOpenAiResponsesEndpointUrl() {
2197
+ const base = resolveOpenAiBaseUrl();
2198
+ const normalized = base.endsWith("/") ? base : `${base}/`;
2199
+ return new URL("responses", normalized).toString();
2200
+ }
2201
+ function buildOpenAiResponsesWebSocketHeaders(apiKey) {
2202
+ const headers = {
2203
+ Authorization: `Bearer ${apiKey}`,
2204
+ "OpenAI-Beta": mergeOpenAiBetaHeader(
2205
+ process.env.OPENAI_BETA,
2206
+ OPENAI_BETA_RESPONSES_WEBSOCKETS_V2
2207
+ )
2208
+ };
2209
+ const organization = process.env.OPENAI_ORGANIZATION?.trim();
2210
+ if (organization) {
2211
+ headers["OpenAI-Organization"] = organization;
2212
+ }
2213
+ const project = process.env.OPENAI_PROJECT?.trim();
2214
+ if (project) {
2215
+ headers["OpenAI-Project"] = project;
2216
+ }
2217
+ return headers;
2218
+ }
2219
+ function installResponsesWebSocketTransport(client, apiKey) {
2220
+ const responsesApi = client.responses;
2221
+ const streamMethod = responsesApi?.stream;
2222
+ if (typeof streamMethod !== "function") {
2223
+ return;
2224
+ }
2225
+ const originalStream = streamMethod.bind(client.responses);
2226
+ responsesApi.stream = (request, options) => {
2227
+ const mode = resolveOpenAiResponsesWebSocketMode();
2228
+ const fallbackStreamFactory = () => wrapFallbackStream(originalStream(request, options));
2229
+ if (mode === "off" || openAiResponsesWebSocketDisabled) {
2230
+ return fallbackStreamFactory();
2231
+ }
2232
+ const signal = options && typeof options === "object" ? options.signal ?? void 0 : void 0;
2233
+ const websocketUrl = toWebSocketUrl(buildOpenAiResponsesEndpointUrl());
2234
+ const headers = buildOpenAiResponsesWebSocketHeaders(apiKey);
2235
+ const timeoutMs = resolveOpenAiTimeoutMs();
2236
+ return createAdaptiveResponsesStream({
2237
+ mode,
2238
+ createWebSocketStream: async () => await createResponsesWebSocketStream({
2239
+ url: websocketUrl,
2240
+ headers,
2241
+ request,
2242
+ signal,
2243
+ idleTimeoutMs: timeoutMs
2244
+ }),
2245
+ createFallbackStream: fallbackStreamFactory,
2246
+ onWebSocketFallback: (error) => {
2247
+ if (isResponsesWebSocketUnsupportedError(error)) {
2248
+ openAiResponsesWebSocketDisabled = true;
2249
+ }
2250
+ }
2251
+ });
2252
+ };
2253
+ }
1496
2254
  function getOpenAiApiKey() {
1497
2255
  if (cachedApiKey2 !== null) {
1498
2256
  return cachedApiKey2;
@@ -1510,6 +2268,7 @@ function getOpenAiClient() {
1510
2268
  if (cachedClient2) {
1511
2269
  return cachedClient2;
1512
2270
  }
2271
+ loadLocalEnv();
1513
2272
  const apiKey = getOpenAiApiKey();
1514
2273
  const timeoutMs = resolveOpenAiTimeoutMs();
1515
2274
  cachedClient2 = new OpenAI2({
@@ -1517,6 +2276,7 @@ function getOpenAiClient() {
1517
2276
  fetch: getOpenAiFetch(),
1518
2277
  timeout: timeoutMs
1519
2278
  });
2279
+ installResponsesWebSocketTransport(cachedClient2, apiKey);
1520
2280
  return cachedClient2;
1521
2281
  }
1522
2282
 
@@ -1531,11 +2291,51 @@ async function runOpenAiCall(fn) {
1531
2291
  return scheduler3.run(async () => fn(getOpenAiClient()));
1532
2292
  }
1533
2293
 
2294
+ // src/openai/models.ts
2295
+ var OPENAI_MODEL_IDS = [
2296
+ "gpt-5.3-codex",
2297
+ "gpt-5.3-codex-spark",
2298
+ "gpt-5.2",
2299
+ "gpt-5.1-codex-mini"
2300
+ ];
2301
+ function isOpenAiModelId(value) {
2302
+ return OPENAI_MODEL_IDS.includes(value);
2303
+ }
2304
+ var CHATGPT_MODEL_IDS = [
2305
+ "chatgpt-gpt-5.3-codex",
2306
+ "chatgpt-gpt-5.3-codex-spark",
2307
+ "chatgpt-gpt-5.2",
2308
+ "chatgpt-gpt-5.1-codex-mini"
2309
+ ];
2310
+ function isChatGptModelId(value) {
2311
+ return CHATGPT_MODEL_IDS.includes(value);
2312
+ }
2313
+ function stripChatGptPrefix(model) {
2314
+ return model.slice("chatgpt-".length);
2315
+ }
2316
+
1534
2317
  // src/llm.ts
1535
2318
  var toolCallContextStorage = new AsyncLocalStorage();
1536
2319
  function getCurrentToolCallContext() {
1537
2320
  return toolCallContextStorage.getStore() ?? null;
1538
2321
  }
2322
+ var LLM_TEXT_MODEL_IDS = [
2323
+ ...OPENAI_MODEL_IDS,
2324
+ ...CHATGPT_MODEL_IDS,
2325
+ ...FIREWORKS_MODEL_IDS,
2326
+ ...GEMINI_TEXT_MODEL_IDS
2327
+ ];
2328
+ var LLM_IMAGE_MODEL_IDS = [...GEMINI_IMAGE_MODEL_IDS];
2329
+ var LLM_MODEL_IDS = [...LLM_TEXT_MODEL_IDS, ...LLM_IMAGE_MODEL_IDS];
2330
+ function isLlmTextModelId(value) {
2331
+ return isOpenAiModelId(value) || isChatGptModelId(value) || isFireworksModelId(value) || isGeminiTextModelId(value);
2332
+ }
2333
+ function isLlmImageModelId(value) {
2334
+ return isGeminiImageModelId(value);
2335
+ }
2336
+ function isLlmModelId(value) {
2337
+ return isLlmTextModelId(value) || isLlmImageModelId(value);
2338
+ }
1539
2339
  var LlmJsonCallError = class extends Error {
1540
2340
  constructor(message, attempts) {
1541
2341
  super(message);
@@ -1893,17 +2693,22 @@ function convertLlmContentToGeminiContent(content) {
1893
2693
  };
1894
2694
  }
1895
2695
  function resolveProvider(model) {
1896
- if (model.startsWith("chatgpt-")) {
1897
- return { provider: "chatgpt", model: model.slice("chatgpt-".length) };
2696
+ if (isChatGptModelId(model)) {
2697
+ return { provider: "chatgpt", model: stripChatGptPrefix(model) };
1898
2698
  }
1899
- if (model.startsWith("gemini-")) {
2699
+ if (isGeminiTextModelId(model) || isGeminiImageModelId(model)) {
1900
2700
  return { provider: "gemini", model };
1901
2701
  }
1902
- const fireworksModel = resolveFireworksModelId(model);
1903
- if (fireworksModel) {
1904
- return { provider: "fireworks", model: fireworksModel };
2702
+ if (isFireworksModelId(model)) {
2703
+ const fireworksModel = resolveFireworksModelId(model);
2704
+ if (fireworksModel) {
2705
+ return { provider: "fireworks", model: fireworksModel };
2706
+ }
2707
+ }
2708
+ if (isOpenAiModelId(model)) {
2709
+ return { provider: "openai", model };
1905
2710
  }
1906
- return { provider: "openai", model };
2711
+ throw new Error(`Unsupported text model: ${model}`);
1907
2712
  }
1908
2713
  function isOpenAiCodexModel(modelId) {
1909
2714
  return modelId.includes("codex");
@@ -3090,6 +3895,7 @@ function extractFireworksToolCalls(message) {
3090
3895
  function resolveGeminiThinkingConfig(modelId) {
3091
3896
  switch (modelId) {
3092
3897
  case "gemini-3-pro-preview":
3898
+ case "gemini-3.1-pro-preview":
3093
3899
  return { includeThoughts: true };
3094
3900
  case "gemini-3-flash-preview":
3095
3901
  return { includeThoughts: true, thinkingBudget: 16384 };
@@ -6485,15 +7291,24 @@ function mergeToolSets(base, extra) {
6485
7291
  return merged;
6486
7292
  }
6487
7293
  export {
7294
+ CHATGPT_MODEL_IDS,
6488
7295
  CODEX_APPLY_PATCH_FREEFORM_TOOL_DESCRIPTION,
6489
7296
  CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
6490
7297
  CODEX_APPLY_PATCH_LARK_GRAMMAR,
6491
7298
  FIREWORKS_DEFAULT_GLM_MODEL,
7299
+ FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL,
6492
7300
  FIREWORKS_DEFAULT_KIMI_MODEL,
6493
7301
  FIREWORKS_DEFAULT_MINIMAX_MODEL,
6494
7302
  FIREWORKS_MODEL_IDS,
7303
+ GEMINI_IMAGE_MODEL_IDS,
7304
+ GEMINI_MODEL_IDS,
7305
+ GEMINI_TEXT_MODEL_IDS,
6495
7306
  InMemoryAgentFilesystem,
7307
+ LLM_IMAGE_MODEL_IDS,
7308
+ LLM_MODEL_IDS,
7309
+ LLM_TEXT_MODEL_IDS,
6496
7310
  LlmJsonCallError,
7311
+ OPENAI_MODEL_IDS,
6497
7312
  appendMarkdownSourcesSection,
6498
7313
  applyPatch,
6499
7314
  configureGemini,
@@ -6528,8 +7343,15 @@ export {
6528
7343
  generateText,
6529
7344
  getChatGptAuthProfile,
6530
7345
  getCurrentToolCallContext,
7346
+ isChatGptModelId,
6531
7347
  isFireworksModelId,
7348
+ isGeminiImageModelId,
6532
7349
  isGeminiModelId,
7350
+ isGeminiTextModelId,
7351
+ isLlmImageModelId,
7352
+ isLlmModelId,
7353
+ isLlmTextModelId,
7354
+ isOpenAiModelId,
6533
7355
  loadEnvFromFile,
6534
7356
  loadLocalEnv,
6535
7357
  parseJsonFromLlmText,