@ljoukov/llm 3.0.1 → 3.0.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.cjs CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION: () => CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
35
35
  CODEX_APPLY_PATCH_LARK_GRAMMAR: () => CODEX_APPLY_PATCH_LARK_GRAMMAR,
36
36
  FIREWORKS_DEFAULT_GLM_MODEL: () => FIREWORKS_DEFAULT_GLM_MODEL,
37
+ FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL: () => FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL,
37
38
  FIREWORKS_DEFAULT_KIMI_MODEL: () => FIREWORKS_DEFAULT_KIMI_MODEL,
38
39
  FIREWORKS_DEFAULT_MINIMAX_MODEL: () => FIREWORKS_DEFAULT_MINIMAX_MODEL,
39
40
  FIREWORKS_MODEL_IDS: () => FIREWORKS_MODEL_IDS,
@@ -227,7 +228,7 @@ function getGeminiProPricing(modelId) {
227
228
  if (modelId.includes("gemini-2.5-pro")) {
228
229
  return GEMINI_2_5_PRO_PRICING;
229
230
  }
230
- if (modelId.includes("gemini-3-pro")) {
231
+ if (modelId.includes("gemini-3-pro") || modelId.includes("gemini-3.1-pro")) {
231
232
  return GEMINI_3_PRO_PREVIEW_PRICING;
232
233
  }
233
234
  return void 0;
@@ -427,8 +428,6 @@ function parseEnvLine(line) {
427
428
  // src/openai/chatgpt-auth.ts
428
429
  var CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_URL";
429
430
  var CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_STORE";
430
- var CHATGPT_AUTH_SERVER_URL_ENV = "CHATGPT_AUTH_SERVER_URL";
431
- var CHATGPT_AUTH_SERVER_STORE_ENV = "CHATGPT_AUTH_SERVER_STORE";
432
431
  var CHATGPT_AUTH_API_KEY_ENV = "CHATGPT_AUTH_API_KEY";
433
432
  var CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY_ENV = "CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY";
434
433
  var CHATGPT_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
@@ -560,7 +559,7 @@ async function refreshChatGptOauthToken(refreshToken, fallback) {
560
559
  }
561
560
  async function getChatGptAuthProfile() {
562
561
  loadLocalEnv();
563
- const tokenProviderUrl = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV] ?? process.env[CHATGPT_AUTH_SERVER_URL_ENV];
562
+ const tokenProviderUrl = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV];
564
563
  const tokenProviderKey = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY_ENV] ?? process.env[CHATGPT_AUTH_API_KEY_ENV];
565
564
  if (tokenProviderUrl && tokenProviderUrl.trim().length > 0 && tokenProviderKey && tokenProviderKey.trim().length > 0) {
566
565
  if (cachedProfile && !isExpired(cachedProfile)) {
@@ -571,7 +570,7 @@ async function getChatGptAuthProfile() {
571
570
  }
572
571
  refreshPromise = (async () => {
573
572
  try {
574
- const store = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV] ?? process.env[CHATGPT_AUTH_SERVER_STORE_ENV];
573
+ const store = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV];
575
574
  const profile = await fetchChatGptAuthProfileFromTokenProvider({
576
575
  baseUrl: tokenProviderUrl,
577
576
  apiKey: tokenProviderKey,
@@ -774,22 +773,588 @@ function extractChatGptAccountId(token) {
774
773
  return typeof namespaced === "string" && namespaced.length > 0 ? namespaced : void 0;
775
774
  }
776
775
 
776
+ // src/openai/responses-websocket.ts
777
+ var import_ws = __toESM(require("ws"), 1);
778
+ var OPENAI_BETA_RESPONSES_WEBSOCKETS_V2 = "responses_websockets=2026-02-06";
779
+ var ResponsesWebSocketHttpError = class extends Error {
780
+ status;
781
+ body;
782
+ headers;
783
+ constructor(options) {
784
+ super(options.message);
785
+ this.name = "ResponsesWebSocketHttpError";
786
+ this.status = options.status;
787
+ this.body = options.body;
788
+ this.headers = options.headers;
789
+ }
790
+ };
791
+ function resolveResponsesWebSocketMode(raw, fallback = "auto") {
792
+ const value = raw?.trim().toLowerCase();
793
+ if (value === "auto" || value === "off" || value === "only") {
794
+ return value;
795
+ }
796
+ return fallback;
797
+ }
798
+ function mergeOpenAiBetaHeader(existing, required) {
799
+ const parts = /* @__PURE__ */ new Set();
800
+ for (const part of (existing ?? "").split(",")) {
801
+ const trimmed = part.trim();
802
+ if (trimmed.length > 0) {
803
+ parts.add(trimmed);
804
+ }
805
+ }
806
+ const normalizedRequired = required.trim();
807
+ if (normalizedRequired.length > 0) {
808
+ parts.add(normalizedRequired);
809
+ }
810
+ return Array.from(parts).join(", ");
811
+ }
812
+ function toWebSocketUrl(httpOrHttpsUrl) {
813
+ const parsed = new URL(httpOrHttpsUrl);
814
+ if (parsed.protocol === "https:") {
815
+ parsed.protocol = "wss:";
816
+ } else if (parsed.protocol === "http:") {
817
+ parsed.protocol = "ws:";
818
+ } else if (parsed.protocol !== "ws:" && parsed.protocol !== "wss:") {
819
+ throw new Error(`Unsupported websocket URL protocol: ${parsed.protocol}`);
820
+ }
821
+ return parsed.toString();
822
+ }
823
+ function isResponsesWebSocketUnsupportedError(error) {
824
+ if (error instanceof ResponsesWebSocketHttpError) {
825
+ return [400, 404, 405, 406, 426, 501].includes(error.status);
826
+ }
827
+ const message = error instanceof Error ? error.message.toLowerCase() : "";
828
+ return message.includes("unexpected server response: 426");
829
+ }
830
+ function createAdaptiveResponsesStream(options) {
831
+ let resolved = null;
832
+ let websocketSelected = false;
833
+ let fallbackSelected = false;
834
+ const activateFallback = (error) => {
835
+ options.onWebSocketFallback?.(error);
836
+ fallbackSelected = true;
837
+ websocketSelected = false;
838
+ const fallback = options.createFallbackStream();
839
+ resolved = Promise.resolve(fallback);
840
+ return fallback;
841
+ };
842
+ const getStream = async () => {
843
+ if (resolved) {
844
+ return await resolved;
845
+ }
846
+ resolved = (async () => {
847
+ if (options.mode === "off") {
848
+ fallbackSelected = true;
849
+ return options.createFallbackStream();
850
+ }
851
+ try {
852
+ const stream = await options.createWebSocketStream();
853
+ websocketSelected = true;
854
+ return stream;
855
+ } catch (error) {
856
+ if (options.mode === "only") {
857
+ throw error;
858
+ }
859
+ return activateFallback(error);
860
+ }
861
+ })();
862
+ return await resolved;
863
+ };
864
+ return {
865
+ async *[Symbol.asyncIterator]() {
866
+ const stream = await getStream();
867
+ let yielded = 0;
868
+ try {
869
+ for await (const event of stream) {
870
+ yielded += 1;
871
+ yield event;
872
+ }
873
+ } catch (error) {
874
+ if (options.mode !== "only" && websocketSelected && !fallbackSelected && yielded === 0) {
875
+ const fallback = activateFallback(error);
876
+ for await (const event of fallback) {
877
+ yield event;
878
+ }
879
+ return;
880
+ }
881
+ throw error;
882
+ }
883
+ },
884
+ async finalResponse() {
885
+ const stream = await getStream();
886
+ try {
887
+ return await stream.finalResponse();
888
+ } catch (error) {
889
+ if (options.mode === "only" || !websocketSelected || fallbackSelected) {
890
+ throw error;
891
+ }
892
+ const fallback = activateFallback(error);
893
+ return await fallback.finalResponse();
894
+ }
895
+ },
896
+ close() {
897
+ void getStream().then((stream) => stream.close()).catch(() => {
898
+ });
899
+ }
900
+ };
901
+ }
902
+ async function createResponsesWebSocketStream(options) {
903
+ const completionTypes = new Set(
904
+ options.completionEventTypes ?? ["response.completed", "response.failed", "response.done"]
905
+ );
906
+ const { socket, responseHeaders } = await connectWebSocket({
907
+ url: options.url,
908
+ headers: options.headers,
909
+ signal: options.signal
910
+ });
911
+ const queue = createAsyncQueue();
912
+ let settled = false;
913
+ let finalResponse = null;
914
+ let latestResponse = null;
915
+ let idleTimer = null;
916
+ let resolveFinal = null;
917
+ let rejectFinal = null;
918
+ const finalPromise = new Promise((resolve, reject) => {
919
+ resolveFinal = resolve;
920
+ rejectFinal = reject;
921
+ });
922
+ void finalPromise.catch(() => {
923
+ });
924
+ const clearIdleTimer = () => {
925
+ if (idleTimer) {
926
+ clearTimeout(idleTimer);
927
+ idleTimer = null;
928
+ }
929
+ };
930
+ const closeSocket = () => {
931
+ try {
932
+ if (socket.readyState === import_ws.default.OPEN || socket.readyState === import_ws.default.CONNECTING) {
933
+ socket.close();
934
+ }
935
+ } catch {
936
+ }
937
+ };
938
+ const complete = (response) => {
939
+ if (settled) {
940
+ return;
941
+ }
942
+ settled = true;
943
+ clearIdleTimer();
944
+ finalResponse = response;
945
+ resolveFinal?.(response);
946
+ queue.close();
947
+ closeSocket();
948
+ };
949
+ const fail = (error) => {
950
+ if (settled) {
951
+ return;
952
+ }
953
+ settled = true;
954
+ clearIdleTimer();
955
+ rejectFinal?.(error);
956
+ queue.fail(error);
957
+ closeSocket();
958
+ };
959
+ const restartIdleTimer = () => {
960
+ clearIdleTimer();
961
+ const idleTimeoutMs = options.idleTimeoutMs;
962
+ if (!idleTimeoutMs || idleTimeoutMs <= 0 || settled) {
963
+ return;
964
+ }
965
+ idleTimer = setTimeout(() => {
966
+ fail(new Error(`Responses WebSocket idle timeout after ${idleTimeoutMs}ms.`));
967
+ }, idleTimeoutMs);
968
+ };
969
+ const onAbort = () => {
970
+ const error = createAbortError(options.signal?.reason);
971
+ fail(error);
972
+ };
973
+ if (options.signal) {
974
+ if (options.signal.aborted) {
975
+ socket.close();
976
+ throw createAbortError(options.signal.reason);
977
+ }
978
+ options.signal.addEventListener("abort", onAbort, { once: true });
979
+ }
980
+ const cleanup = () => {
981
+ clearIdleTimer();
982
+ socket.removeAllListeners();
983
+ if (options.signal) {
984
+ options.signal.removeEventListener("abort", onAbort);
985
+ }
986
+ };
987
+ socket.on("message", (raw) => {
988
+ restartIdleTimer();
989
+ const parsed = parseWebSocketPayload(raw);
990
+ if (!parsed) {
991
+ return;
992
+ }
993
+ const error = mapWebSocketErrorEvent(parsed);
994
+ if (error) {
995
+ fail(error);
996
+ return;
997
+ }
998
+ const event = parsed;
999
+ if (isObjectWithResponse(event)) {
1000
+ latestResponse = event.response;
1001
+ }
1002
+ queue.push(event);
1003
+ const type = typeof event.type === "string" ? event.type : "";
1004
+ if (completionTypes.has(type)) {
1005
+ const completedResponse = normalizeFinalResponse(
1006
+ type,
1007
+ event.response,
1008
+ latestResponse,
1009
+ responseHeaders
1010
+ );
1011
+ complete(completedResponse);
1012
+ }
1013
+ });
1014
+ socket.on("error", (error) => {
1015
+ fail(new Error(`Responses WebSocket error: ${error.message}`));
1016
+ });
1017
+ socket.on("close", (_code, _reason) => {
1018
+ if (settled) {
1019
+ cleanup();
1020
+ return;
1021
+ }
1022
+ fail(new Error("Responses WebSocket closed before completion."));
1023
+ cleanup();
1024
+ });
1025
+ restartIdleTimer();
1026
+ const payload = serializeRequestPayload(options.request);
1027
+ await new Promise((resolve, reject) => {
1028
+ socket.send(payload, (error) => {
1029
+ if (error) {
1030
+ reject(error);
1031
+ } else {
1032
+ resolve();
1033
+ }
1034
+ });
1035
+ }).catch((error) => {
1036
+ fail(new Error(`Failed to send Responses WebSocket request: ${errorToMessage(error)}`));
1037
+ throw error instanceof Error ? error : new Error(errorToMessage(error));
1038
+ });
1039
+ return {
1040
+ async *[Symbol.asyncIterator]() {
1041
+ try {
1042
+ for await (const event of queue.iterable) {
1043
+ yield event;
1044
+ }
1045
+ } finally {
1046
+ if (!settled) {
1047
+ closeSocket();
1048
+ }
1049
+ }
1050
+ },
1051
+ async finalResponse() {
1052
+ return await finalPromise;
1053
+ },
1054
+ close() {
1055
+ if (settled) {
1056
+ return;
1057
+ }
1058
+ const response = finalResponse ?? latestResponse ?? { status: "cancelled" };
1059
+ complete(response);
1060
+ cleanup();
1061
+ }
1062
+ };
1063
+ }
1064
+ async function connectWebSocket(options) {
1065
+ return await new Promise((resolve, reject) => {
1066
+ const socket = new import_ws.default(options.url, {
1067
+ headers: options.headers,
1068
+ handshakeTimeout: 3e4
1069
+ });
1070
+ let settled = false;
1071
+ let responseBody = "";
1072
+ const rejectOnce = (error) => {
1073
+ if (settled) {
1074
+ return;
1075
+ }
1076
+ settled = true;
1077
+ cleanup();
1078
+ try {
1079
+ socket.terminate();
1080
+ } catch {
1081
+ }
1082
+ reject(error);
1083
+ };
1084
+ const resolveOnce = (result) => {
1085
+ if (settled) {
1086
+ return;
1087
+ }
1088
+ settled = true;
1089
+ cleanup(false);
1090
+ resolve(result);
1091
+ };
1092
+ const onAbort = () => {
1093
+ rejectOnce(createAbortError(options.signal?.reason));
1094
+ };
1095
+ const cleanup = (removeAbortListener = true) => {
1096
+ socket.removeListener("open", onOpen);
1097
+ socket.removeListener("error", onError);
1098
+ socket.removeListener("unexpected-response", onUnexpectedResponse);
1099
+ if (removeAbortListener && options.signal) {
1100
+ options.signal.removeEventListener("abort", onAbort);
1101
+ }
1102
+ };
1103
+ const onOpen = () => {
1104
+ const headers = normalizeUpgradeHeaders(socket);
1105
+ resolveOnce({ socket, responseHeaders: headers });
1106
+ };
1107
+ const onError = (error) => {
1108
+ rejectOnce(new Error(`Responses WebSocket connection failed: ${error.message}`));
1109
+ };
1110
+ const onUnexpectedResponse = (_request, response) => {
1111
+ if (typeof response.setEncoding === "function") {
1112
+ response.setEncoding("utf8");
1113
+ }
1114
+ response.on("data", (chunk) => {
1115
+ responseBody += typeof chunk === "string" ? chunk : chunk.toString("utf8");
1116
+ });
1117
+ response.on("end", () => {
1118
+ const status = Number(response.statusCode ?? 0);
1119
+ const headers = {};
1120
+ const rawHeaders = response.headers ?? {};
1121
+ for (const [key, value] of Object.entries(rawHeaders)) {
1122
+ if (typeof value === "string") {
1123
+ headers[key] = value;
1124
+ } else if (Array.isArray(value)) {
1125
+ headers[key] = value.join(", ");
1126
+ }
1127
+ }
1128
+ rejectOnce(
1129
+ new ResponsesWebSocketHttpError({
1130
+ status: Number.isFinite(status) && status > 0 ? status : 500,
1131
+ message: `Responses WebSocket upgrade failed${status ? ` (${status})` : ""}.`,
1132
+ body: responseBody || void 0,
1133
+ headers
1134
+ })
1135
+ );
1136
+ });
1137
+ response.on("error", (error) => {
1138
+ rejectOnce(
1139
+ new ResponsesWebSocketHttpError({
1140
+ status: Number(response.statusCode ?? 500),
1141
+ message: `Responses WebSocket upgrade failed: ${error.message}`,
1142
+ body: responseBody || void 0
1143
+ })
1144
+ );
1145
+ });
1146
+ };
1147
+ socket.once("open", onOpen);
1148
+ socket.once("error", onError);
1149
+ socket.once("unexpected-response", onUnexpectedResponse);
1150
+ if (options.signal) {
1151
+ if (options.signal.aborted) {
1152
+ onAbort();
1153
+ return;
1154
+ }
1155
+ options.signal.addEventListener("abort", onAbort, { once: true });
1156
+ }
1157
+ });
1158
+ }
1159
+ function normalizeUpgradeHeaders(socket) {
1160
+ const maybeUpgradeResponse = socket._req?.res;
1161
+ const raw = maybeUpgradeResponse?.headers ?? {};
1162
+ const normalized = {};
1163
+ for (const [key, value] of Object.entries(raw)) {
1164
+ if (typeof value === "string") {
1165
+ normalized[key.toLowerCase()] = value;
1166
+ } else if (Array.isArray(value)) {
1167
+ normalized[key.toLowerCase()] = value.join(", ");
1168
+ }
1169
+ }
1170
+ return normalized;
1171
+ }
1172
+ function parseWebSocketPayload(raw) {
1173
+ const text = toUtf8(raw);
1174
+ if (!text) {
1175
+ return null;
1176
+ }
1177
+ try {
1178
+ const parsed = JSON.parse(text);
1179
+ if (parsed && typeof parsed === "object") {
1180
+ return parsed;
1181
+ }
1182
+ } catch {
1183
+ return null;
1184
+ }
1185
+ return null;
1186
+ }
1187
+ function toUtf8(raw) {
1188
+ if (typeof raw === "string") {
1189
+ return raw;
1190
+ }
1191
+ if (raw instanceof ArrayBuffer) {
1192
+ return Buffer.from(raw).toString("utf8");
1193
+ }
1194
+ if (Array.isArray(raw)) {
1195
+ const chunks = raw.map((chunk) => {
1196
+ if (typeof chunk === "string") {
1197
+ return Buffer.from(chunk, "utf8");
1198
+ }
1199
+ return Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
1200
+ });
1201
+ return Buffer.concat(chunks).toString("utf8");
1202
+ }
1203
+ return Buffer.isBuffer(raw) ? raw.toString("utf8") : Buffer.from(raw).toString("utf8");
1204
+ }
1205
+ function mapWebSocketErrorEvent(payload) {
1206
+ if (payload.type !== "error") {
1207
+ return null;
1208
+ }
1209
+ const status = resolveNumericStatus(payload.status) ?? resolveNumericStatus(payload.status_code);
1210
+ if (!status || status < 400) {
1211
+ const message = errorToMessage(payload.error) || "Responses WebSocket returned an error event.";
1212
+ return new Error(message);
1213
+ }
1214
+ const headers = mapErrorHeaders(payload.headers);
1215
+ const body = payload.error && typeof payload.error === "object" ? JSON.stringify({ error: payload.error }, null, 2) : void 0;
1216
+ return new ResponsesWebSocketHttpError({
1217
+ status,
1218
+ message: `Responses WebSocket returned status ${status}.`,
1219
+ body,
1220
+ headers
1221
+ });
1222
+ }
1223
+ function mapErrorHeaders(value) {
1224
+ if (!value || typeof value !== "object") {
1225
+ return void 0;
1226
+ }
1227
+ const headers = {};
1228
+ for (const [key, entry] of Object.entries(value)) {
1229
+ if (typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean") {
1230
+ headers[key.toLowerCase()] = String(entry);
1231
+ }
1232
+ }
1233
+ return Object.keys(headers).length > 0 ? headers : void 0;
1234
+ }
1235
+ function resolveNumericStatus(value) {
1236
+ if (typeof value === "number" && Number.isFinite(value)) {
1237
+ return Math.floor(value);
1238
+ }
1239
+ if (typeof value === "string" && value.trim().length > 0) {
1240
+ const parsed = Number(value);
1241
+ if (Number.isFinite(parsed)) {
1242
+ return Math.floor(parsed);
1243
+ }
1244
+ }
1245
+ return null;
1246
+ }
1247
+ function normalizeFinalResponse(eventType, eventResponse, latestResponse, responseHeaders) {
1248
+ const response = eventResponse && typeof eventResponse === "object" ? { ...eventResponse } : latestResponse ? { ...latestResponse } : {};
1249
+ if (typeof response.status !== "string") {
1250
+ if (eventType === "response.failed") {
1251
+ response.status = "failed";
1252
+ } else if (eventType === "response.done") {
1253
+ response.status = "completed";
1254
+ } else if (eventType === "response.completed") {
1255
+ response.status = "completed";
1256
+ }
1257
+ }
1258
+ const upgradeModel = responseHeaders["openai-model"];
1259
+ if (typeof response.model !== "string" && upgradeModel) {
1260
+ response.model = upgradeModel;
1261
+ }
1262
+ return response;
1263
+ }
1264
+ function serializeRequestPayload(request) {
1265
+ if (!request || typeof request !== "object" || Array.isArray(request)) {
1266
+ throw new Error("Responses WebSocket request must be a JSON object.");
1267
+ }
1268
+ const body = request;
1269
+ const payload = typeof body.type === "string" ? body : { type: "response.create", ...body };
1270
+ return JSON.stringify(payload);
1271
+ }
1272
+ function isObjectWithResponse(event) {
1273
+ return Boolean(event.response && typeof event.response === "object");
1274
+ }
1275
+ function errorToMessage(error) {
1276
+ if (error instanceof Error) {
1277
+ return error.message;
1278
+ }
1279
+ if (typeof error === "string") {
1280
+ return error;
1281
+ }
1282
+ try {
1283
+ return JSON.stringify(error);
1284
+ } catch {
1285
+ return String(error);
1286
+ }
1287
+ }
1288
+ function createAbortError(reason) {
1289
+ const error = new Error(
1290
+ reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "Request aborted."
1291
+ );
1292
+ error.name = "AbortError";
1293
+ return error;
1294
+ }
1295
+
777
1296
  // src/openai/chatgpt-codex.ts
778
1297
  var CHATGPT_CODEX_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
1298
+ var CHATGPT_RESPONSES_EXPERIMENTAL_HEADER = "responses=experimental";
1299
+ var cachedResponsesWebSocketMode = null;
1300
+ var chatGptResponsesWebSocketDisabled = false;
779
1301
  async function streamChatGptCodexResponse(options) {
780
1302
  const { access, accountId } = await getChatGptAuthProfile();
781
- const headers = {
782
- Authorization: `Bearer ${access}`,
783
- "chatgpt-account-id": accountId,
784
- "OpenAI-Beta": "responses=experimental",
785
- originator: "llm",
786
- "User-Agent": buildUserAgent(),
787
- Accept: "text/event-stream",
788
- "Content-Type": "application/json"
1303
+ const mode = resolveChatGptResponsesWebSocketMode();
1304
+ const fallbackStreamFactory = () => {
1305
+ const streamPromise = streamChatGptCodexResponseSse({
1306
+ request: options.request,
1307
+ access,
1308
+ accountId,
1309
+ sessionId: options.sessionId,
1310
+ signal: options.signal
1311
+ });
1312
+ return {
1313
+ async *[Symbol.asyncIterator]() {
1314
+ const stream = await streamPromise;
1315
+ for await (const event of stream) {
1316
+ yield event;
1317
+ }
1318
+ },
1319
+ async finalResponse() {
1320
+ return {};
1321
+ },
1322
+ close() {
1323
+ }
1324
+ };
789
1325
  };
790
- if (options.sessionId) {
791
- headers.session_id = options.sessionId;
1326
+ if (mode === "off" || chatGptResponsesWebSocketDisabled) {
1327
+ return fallbackStreamFactory();
792
1328
  }
1329
+ const websocketHeaders = buildChatGptCodexHeaders({
1330
+ access,
1331
+ accountId,
1332
+ sessionId: options.sessionId,
1333
+ useWebSocket: true
1334
+ });
1335
+ return createAdaptiveResponsesStream({
1336
+ mode,
1337
+ createWebSocketStream: async () => await createResponsesWebSocketStream({
1338
+ url: toWebSocketUrl(CHATGPT_CODEX_ENDPOINT),
1339
+ headers: websocketHeaders,
1340
+ request: options.request,
1341
+ signal: options.signal
1342
+ }),
1343
+ createFallbackStream: fallbackStreamFactory,
1344
+ onWebSocketFallback: () => {
1345
+ chatGptResponsesWebSocketDisabled = true;
1346
+ }
1347
+ });
1348
+ }
1349
+ async function streamChatGptCodexResponseSse(options) {
1350
+ const headers = buildChatGptCodexHeaders({
1351
+ access: options.access,
1352
+ accountId: options.accountId,
1353
+ sessionId: options.sessionId,
1354
+ useWebSocket: false
1355
+ });
1356
+ headers.Accept = "text/event-stream";
1357
+ headers["Content-Type"] = "application/json";
793
1358
  const response = await fetch(CHATGPT_CODEX_ENDPOINT, {
794
1359
  method: "POST",
795
1360
  headers,
@@ -806,20 +1371,67 @@ async function streamChatGptCodexResponse(options) {
806
1371
  }
807
1372
  return parseEventStream(body);
808
1373
  }
1374
+ function resolveChatGptResponsesWebSocketMode() {
1375
+ if (cachedResponsesWebSocketMode) {
1376
+ return cachedResponsesWebSocketMode;
1377
+ }
1378
+ cachedResponsesWebSocketMode = resolveResponsesWebSocketMode(
1379
+ process.env.CHATGPT_RESPONSES_WEBSOCKET_MODE ?? process.env.OPENAI_RESPONSES_WEBSOCKET_MODE,
1380
+ "auto"
1381
+ );
1382
+ return cachedResponsesWebSocketMode;
1383
+ }
1384
+ function buildChatGptCodexHeaders(options) {
1385
+ const openAiBeta = options.useWebSocket ? mergeOpenAiBetaHeader(
1386
+ CHATGPT_RESPONSES_EXPERIMENTAL_HEADER,
1387
+ OPENAI_BETA_RESPONSES_WEBSOCKETS_V2
1388
+ ) : CHATGPT_RESPONSES_EXPERIMENTAL_HEADER;
1389
+ const headers = {
1390
+ Authorization: `Bearer ${options.access}`,
1391
+ "chatgpt-account-id": options.accountId,
1392
+ "OpenAI-Beta": openAiBeta,
1393
+ originator: "llm",
1394
+ "User-Agent": buildUserAgent()
1395
+ };
1396
+ if (options.sessionId) {
1397
+ headers.session_id = options.sessionId;
1398
+ }
1399
+ return headers;
1400
+ }
809
1401
  async function collectChatGptCodexResponse(options) {
810
- let stream;
811
- try {
812
- stream = await streamChatGptCodexResponse(options);
813
- } catch (error) {
814
- if (shouldRetryWithoutReasoningSummary(options.request, error)) {
815
- stream = await streamChatGptCodexResponse({
1402
+ let requestForAttempt = options.request;
1403
+ let retriedWithoutReasoningSummary = false;
1404
+ let retriedViaSseFallback = false;
1405
+ while (true) {
1406
+ let sawAnyDelta = false;
1407
+ try {
1408
+ const stream = await streamChatGptCodexResponse({
816
1409
  ...options,
817
- request: removeReasoningSummary(options.request)
1410
+ request: requestForAttempt
818
1411
  });
819
- } else {
1412
+ return await collectChatGptCodexStream({
1413
+ stream,
1414
+ onDelta: (delta) => {
1415
+ sawAnyDelta = true;
1416
+ options.onDelta?.(delta);
1417
+ }
1418
+ });
1419
+ } catch (error) {
1420
+ if (!sawAnyDelta && !retriedViaSseFallback && shouldRetryViaSseFallback(error) && !chatGptResponsesWebSocketDisabled) {
1421
+ chatGptResponsesWebSocketDisabled = true;
1422
+ retriedViaSseFallback = true;
1423
+ continue;
1424
+ }
1425
+ if (!retriedWithoutReasoningSummary && shouldRetryWithoutReasoningSummary(requestForAttempt, error)) {
1426
+ requestForAttempt = removeReasoningSummary(requestForAttempt);
1427
+ retriedWithoutReasoningSummary = true;
1428
+ continue;
1429
+ }
820
1430
  throw error;
821
1431
  }
822
1432
  }
1433
+ }
1434
+ async function collectChatGptCodexStream(options) {
823
1435
  const toolCalls = /* @__PURE__ */ new Map();
824
1436
  const toolCallOrder = [];
825
1437
  const webSearchCalls = /* @__PURE__ */ new Map();
@@ -832,7 +1444,7 @@ async function collectChatGptCodexResponse(options) {
832
1444
  let model;
833
1445
  let status;
834
1446
  let blocked = false;
835
- for await (const event of stream) {
1447
+ for await (const event of options.stream) {
836
1448
  const type = typeof event.type === "string" ? event.type : void 0;
837
1449
  if (type === "response.output_text.delta") {
838
1450
  const delta = typeof event.delta === "string" ? event.delta : "";
@@ -956,6 +1568,16 @@ function shouldRetryWithoutReasoningSummary(request, error) {
956
1568
  const message = error.message.toLowerCase();
957
1569
  return message.includes("unsupported parameter") && message.includes("reasoning.summary");
958
1570
  }
1571
+ function shouldRetryViaSseFallback(error) {
1572
+ if (!(error instanceof Error)) {
1573
+ return false;
1574
+ }
1575
+ if (error.name === "AbortError") {
1576
+ return false;
1577
+ }
1578
+ const message = error.message.toLowerCase();
1579
+ return message.includes("responses websocket");
1580
+ }
959
1581
  function removeReasoningSummary(request) {
960
1582
  const reasoning = request.reasoning;
961
1583
  if (!reasoning?.summary) {
@@ -1203,14 +1825,16 @@ async function runFireworksCall(fn) {
1203
1825
  }
1204
1826
 
1205
1827
  // src/fireworks/models.ts
1206
- var FIREWORKS_MODEL_IDS = ["kimi-k2.5", "glm-5", "minimax-m2.1"];
1828
+ var FIREWORKS_MODEL_IDS = ["kimi-k2.5", "glm-5", "minimax-m2.1", "gpt-oss-120b"];
1207
1829
  var FIREWORKS_DEFAULT_KIMI_MODEL = "kimi-k2.5";
1208
1830
  var FIREWORKS_DEFAULT_GLM_MODEL = "glm-5";
1209
1831
  var FIREWORKS_DEFAULT_MINIMAX_MODEL = "minimax-m2.1";
1832
+ var FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL = "gpt-oss-120b";
1210
1833
  var FIREWORKS_CANONICAL_MODEL_IDS = {
1211
1834
  "kimi-k2.5": "accounts/fireworks/models/kimi-k2p5",
1212
1835
  "glm-5": "accounts/fireworks/models/glm-5",
1213
- "minimax-m2.1": "accounts/fireworks/models/minimax-m2p1"
1836
+ "minimax-m2.1": "accounts/fireworks/models/minimax-m2p1",
1837
+ "gpt-oss-120b": "accounts/fireworks/models/gpt-oss-120b"
1214
1838
  };
1215
1839
  function isFireworksModelId(value) {
1216
1840
  return FIREWORKS_MODEL_IDS.includes(value.trim());
@@ -1291,6 +1915,7 @@ function getGoogleAuthOptions(scopes) {
1291
1915
  // src/google/client.ts
1292
1916
  var GEMINI_MODEL_IDS = [
1293
1917
  "gemini-3-pro-preview",
1918
+ "gemini-3.1-pro-preview",
1294
1919
  "gemini-3-flash-preview",
1295
1920
  "gemini-2.5-pro",
1296
1921
  "gemini-flash-latest",
@@ -1557,6 +2182,8 @@ var cachedApiKey2 = null;
1557
2182
  var cachedClient2 = null;
1558
2183
  var cachedFetch2 = null;
1559
2184
  var cachedTimeoutMs2 = null;
2185
+ var openAiResponsesWebSocketMode = null;
2186
+ var openAiResponsesWebSocketDisabled = false;
1560
2187
  var DEFAULT_OPENAI_TIMEOUT_MS = 15 * 6e4;
1561
2188
  function resolveOpenAiTimeoutMs() {
1562
2189
  if (cachedTimeoutMs2 !== null) {
@@ -1584,6 +2211,97 @@ function getOpenAiFetch() {
1584
2211
  });
1585
2212
  return cachedFetch2;
1586
2213
  }
2214
+ function resolveOpenAiBaseUrl() {
2215
+ loadLocalEnv();
2216
+ return process.env.OPENAI_BASE_URL?.trim() || "https://api.openai.com/v1";
2217
+ }
2218
+ function resolveOpenAiResponsesWebSocketMode() {
2219
+ if (openAiResponsesWebSocketMode) {
2220
+ return openAiResponsesWebSocketMode;
2221
+ }
2222
+ loadLocalEnv();
2223
+ openAiResponsesWebSocketMode = resolveResponsesWebSocketMode(
2224
+ process.env.OPENAI_RESPONSES_WEBSOCKET_MODE,
2225
+ "auto"
2226
+ );
2227
+ return openAiResponsesWebSocketMode;
2228
+ }
2229
+ function wrapFallbackStream(stream) {
2230
+ return {
2231
+ async *[Symbol.asyncIterator]() {
2232
+ for await (const event of stream) {
2233
+ yield event;
2234
+ }
2235
+ },
2236
+ async finalResponse() {
2237
+ return await stream.finalResponse();
2238
+ },
2239
+ close() {
2240
+ const maybeClose = stream;
2241
+ if (typeof maybeClose.close === "function") {
2242
+ maybeClose.close();
2243
+ }
2244
+ }
2245
+ };
2246
+ }
2247
+ function buildOpenAiResponsesEndpointUrl() {
2248
+ const base = resolveOpenAiBaseUrl();
2249
+ const normalized = base.endsWith("/") ? base : `${base}/`;
2250
+ return new URL("responses", normalized).toString();
2251
+ }
2252
+ function buildOpenAiResponsesWebSocketHeaders(apiKey) {
2253
+ const headers = {
2254
+ Authorization: `Bearer ${apiKey}`,
2255
+ "OpenAI-Beta": mergeOpenAiBetaHeader(
2256
+ process.env.OPENAI_BETA,
2257
+ OPENAI_BETA_RESPONSES_WEBSOCKETS_V2
2258
+ )
2259
+ };
2260
+ const organization = process.env.OPENAI_ORGANIZATION?.trim();
2261
+ if (organization) {
2262
+ headers["OpenAI-Organization"] = organization;
2263
+ }
2264
+ const project = process.env.OPENAI_PROJECT?.trim();
2265
+ if (project) {
2266
+ headers["OpenAI-Project"] = project;
2267
+ }
2268
+ return headers;
2269
+ }
2270
+ function installResponsesWebSocketTransport(client, apiKey) {
2271
+ const responsesApi = client.responses;
2272
+ const streamMethod = responsesApi?.stream;
2273
+ if (typeof streamMethod !== "function") {
2274
+ return;
2275
+ }
2276
+ const originalStream = streamMethod.bind(client.responses);
2277
+ responsesApi.stream = (request, options) => {
2278
+ const mode = resolveOpenAiResponsesWebSocketMode();
2279
+ const fallbackStreamFactory = () => wrapFallbackStream(originalStream(request, options));
2280
+ if (mode === "off" || openAiResponsesWebSocketDisabled) {
2281
+ return fallbackStreamFactory();
2282
+ }
2283
+ const signal = options && typeof options === "object" ? options.signal ?? void 0 : void 0;
2284
+ const websocketUrl = toWebSocketUrl(buildOpenAiResponsesEndpointUrl());
2285
+ const headers = buildOpenAiResponsesWebSocketHeaders(apiKey);
2286
+ const timeoutMs = resolveOpenAiTimeoutMs();
2287
+ return createAdaptiveResponsesStream({
2288
+ mode,
2289
+ createWebSocketStream: async () => await createResponsesWebSocketStream({
2290
+ url: websocketUrl,
2291
+ headers,
2292
+ request,
2293
+ signal,
2294
+ idleTimeoutMs: timeoutMs
2295
+ }),
2296
+ createFallbackStream: fallbackStreamFactory,
2297
+ onWebSocketFallback: (error) => {
2298
+ if (isResponsesWebSocketUnsupportedError(error)) {
2299
+ openAiResponsesWebSocketDisabled = true;
2300
+ }
2301
+ }
2302
+ });
2303
+ };
2304
+ }
1587
2305
  function getOpenAiApiKey() {
1588
2306
  if (cachedApiKey2 !== null) {
1589
2307
  return cachedApiKey2;
@@ -1601,6 +2319,7 @@ function getOpenAiClient() {
1601
2319
  if (cachedClient2) {
1602
2320
  return cachedClient2;
1603
2321
  }
2322
+ loadLocalEnv();
1604
2323
  const apiKey = getOpenAiApiKey();
1605
2324
  const timeoutMs = resolveOpenAiTimeoutMs();
1606
2325
  cachedClient2 = new import_openai2.default({
@@ -1608,6 +2327,7 @@ function getOpenAiClient() {
1608
2327
  fetch: getOpenAiFetch(),
1609
2328
  timeout: timeoutMs
1610
2329
  });
2330
+ installResponsesWebSocketTransport(cachedClient2, apiKey);
1611
2331
  return cachedClient2;
1612
2332
  }
1613
2333
 
@@ -3181,6 +3901,7 @@ function extractFireworksToolCalls(message) {
3181
3901
  function resolveGeminiThinkingConfig(modelId) {
3182
3902
  switch (modelId) {
3183
3903
  case "gemini-3-pro-preview":
3904
+ case "gemini-3.1-pro-preview":
3184
3905
  return { includeThoughts: true };
3185
3906
  case "gemini-3-flash-preview":
3186
3907
  return { includeThoughts: true, thinkingBudget: 16384 };
@@ -6581,6 +7302,7 @@ function mergeToolSets(base, extra) {
6581
7302
  CODEX_APPLY_PATCH_JSON_TOOL_DESCRIPTION,
6582
7303
  CODEX_APPLY_PATCH_LARK_GRAMMAR,
6583
7304
  FIREWORKS_DEFAULT_GLM_MODEL,
7305
+ FIREWORKS_DEFAULT_GPT_OSS_120B_MODEL,
6584
7306
  FIREWORKS_DEFAULT_KIMI_MODEL,
6585
7307
  FIREWORKS_DEFAULT_MINIMAX_MODEL,
6586
7308
  FIREWORKS_MODEL_IDS,